xref: /OK3568_Linux_fs/kernel/crypto/asymmetric_keys/pkcs7_trust.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* Validate the trust chain of a PKCS#7 message.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
5*4882a593Smuzhiyun  * Written by David Howells (dhowells@redhat.com)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #define pr_fmt(fmt) "PKCS7: "fmt
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/export.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/asn1.h>
14*4882a593Smuzhiyun #include <linux/key.h>
15*4882a593Smuzhiyun #include <keys/asymmetric-type.h>
16*4882a593Smuzhiyun #include <crypto/public_key.h>
17*4882a593Smuzhiyun #include "pkcs7_parser.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /**
20*4882a593Smuzhiyun  * Check the trust on one PKCS#7 SignedInfo block.
21*4882a593Smuzhiyun  */
pkcs7_validate_trust_one(struct pkcs7_message * pkcs7,struct pkcs7_signed_info * sinfo,struct key * trust_keyring)22*4882a593Smuzhiyun static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
23*4882a593Smuzhiyun 				    struct pkcs7_signed_info *sinfo,
24*4882a593Smuzhiyun 				    struct key *trust_keyring)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct public_key_signature *sig = sinfo->sig;
27*4882a593Smuzhiyun 	struct x509_certificate *x509, *last = NULL, *p;
28*4882a593Smuzhiyun 	struct key *key;
29*4882a593Smuzhiyun 	int ret;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	kenter(",%u,", sinfo->index);
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	if (sinfo->unsupported_crypto) {
34*4882a593Smuzhiyun 		kleave(" = -ENOPKG [cached]");
35*4882a593Smuzhiyun 		return -ENOPKG;
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
39*4882a593Smuzhiyun 		if (x509->seen) {
40*4882a593Smuzhiyun 			if (x509->verified)
41*4882a593Smuzhiyun 				goto verified;
42*4882a593Smuzhiyun 			kleave(" = -ENOKEY [cached]");
43*4882a593Smuzhiyun 			return -ENOKEY;
44*4882a593Smuzhiyun 		}
45*4882a593Smuzhiyun 		x509->seen = true;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 		/* Look to see if this certificate is present in the trusted
48*4882a593Smuzhiyun 		 * keys.
49*4882a593Smuzhiyun 		 */
50*4882a593Smuzhiyun 		key = find_asymmetric_key(trust_keyring,
51*4882a593Smuzhiyun 					  x509->id, x509->skid, false);
52*4882a593Smuzhiyun 		if (!IS_ERR(key)) {
53*4882a593Smuzhiyun 			/* One of the X.509 certificates in the PKCS#7 message
54*4882a593Smuzhiyun 			 * is apparently the same as one we already trust.
55*4882a593Smuzhiyun 			 * Verify that the trusted variant can also validate
56*4882a593Smuzhiyun 			 * the signature on the descendant.
57*4882a593Smuzhiyun 			 */
58*4882a593Smuzhiyun 			pr_devel("sinfo %u: Cert %u as key %x\n",
59*4882a593Smuzhiyun 				 sinfo->index, x509->index, key_serial(key));
60*4882a593Smuzhiyun 			goto matched;
61*4882a593Smuzhiyun 		}
62*4882a593Smuzhiyun 		if (key == ERR_PTR(-ENOMEM))
63*4882a593Smuzhiyun 			return -ENOMEM;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		 /* Self-signed certificates form roots of their own, and if we
66*4882a593Smuzhiyun 		  * don't know them, then we can't accept them.
67*4882a593Smuzhiyun 		  */
68*4882a593Smuzhiyun 		if (x509->signer == x509) {
69*4882a593Smuzhiyun 			kleave(" = -ENOKEY [unknown self-signed]");
70*4882a593Smuzhiyun 			return -ENOKEY;
71*4882a593Smuzhiyun 		}
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 		might_sleep();
74*4882a593Smuzhiyun 		last = x509;
75*4882a593Smuzhiyun 		sig = last->sig;
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* No match - see if the root certificate has a signer amongst the
79*4882a593Smuzhiyun 	 * trusted keys.
80*4882a593Smuzhiyun 	 */
81*4882a593Smuzhiyun 	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
82*4882a593Smuzhiyun 		key = find_asymmetric_key(trust_keyring,
83*4882a593Smuzhiyun 					  last->sig->auth_ids[0],
84*4882a593Smuzhiyun 					  last->sig->auth_ids[1],
85*4882a593Smuzhiyun 					  false);
86*4882a593Smuzhiyun 		if (!IS_ERR(key)) {
87*4882a593Smuzhiyun 			x509 = last;
88*4882a593Smuzhiyun 			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
89*4882a593Smuzhiyun 				 sinfo->index, x509->index, key_serial(key));
90*4882a593Smuzhiyun 			goto matched;
91*4882a593Smuzhiyun 		}
92*4882a593Smuzhiyun 		if (PTR_ERR(key) != -ENOKEY)
93*4882a593Smuzhiyun 			return PTR_ERR(key);
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	/* As a last resort, see if we have a trusted public key that matches
97*4882a593Smuzhiyun 	 * the signed info directly.
98*4882a593Smuzhiyun 	 */
99*4882a593Smuzhiyun 	key = find_asymmetric_key(trust_keyring,
100*4882a593Smuzhiyun 				  sinfo->sig->auth_ids[0], NULL, false);
101*4882a593Smuzhiyun 	if (!IS_ERR(key)) {
102*4882a593Smuzhiyun 		pr_devel("sinfo %u: Direct signer is key %x\n",
103*4882a593Smuzhiyun 			 sinfo->index, key_serial(key));
104*4882a593Smuzhiyun 		x509 = NULL;
105*4882a593Smuzhiyun 		sig = sinfo->sig;
106*4882a593Smuzhiyun 		goto matched;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 	if (PTR_ERR(key) != -ENOKEY)
109*4882a593Smuzhiyun 		return PTR_ERR(key);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	kleave(" = -ENOKEY [no backref]");
112*4882a593Smuzhiyun 	return -ENOKEY;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun matched:
115*4882a593Smuzhiyun 	ret = verify_signature(key, sig);
116*4882a593Smuzhiyun 	key_put(key);
117*4882a593Smuzhiyun 	if (ret < 0) {
118*4882a593Smuzhiyun 		if (ret == -ENOMEM)
119*4882a593Smuzhiyun 			return ret;
120*4882a593Smuzhiyun 		kleave(" = -EKEYREJECTED [verify %d]", ret);
121*4882a593Smuzhiyun 		return -EKEYREJECTED;
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun verified:
125*4882a593Smuzhiyun 	if (x509) {
126*4882a593Smuzhiyun 		x509->verified = true;
127*4882a593Smuzhiyun 		for (p = sinfo->signer; p != x509; p = p->signer)
128*4882a593Smuzhiyun 			p->verified = true;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 	kleave(" = 0");
131*4882a593Smuzhiyun 	return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun /**
135*4882a593Smuzhiyun  * pkcs7_validate_trust - Validate PKCS#7 trust chain
136*4882a593Smuzhiyun  * @pkcs7: The PKCS#7 certificate to validate
137*4882a593Smuzhiyun  * @trust_keyring: Signing certificates to use as starting points
138*4882a593Smuzhiyun  *
139*4882a593Smuzhiyun  * Validate that the certificate chain inside the PKCS#7 message intersects
140*4882a593Smuzhiyun  * keys we already know and trust.
141*4882a593Smuzhiyun  *
142*4882a593Smuzhiyun  * Returns, in order of descending priority:
143*4882a593Smuzhiyun  *
144*4882a593Smuzhiyun  *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
145*4882a593Smuzhiyun  *	key, or:
146*4882a593Smuzhiyun  *
147*4882a593Smuzhiyun  *  (*) 0 if at least one signature chain intersects with the keys in the trust
148*4882a593Smuzhiyun  *	keyring, or:
149*4882a593Smuzhiyun  *
150*4882a593Smuzhiyun  *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
151*4882a593Smuzhiyun  *	chain.
152*4882a593Smuzhiyun  *
153*4882a593Smuzhiyun  *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
154*4882a593Smuzhiyun  *	the message.
155*4882a593Smuzhiyun  *
156*4882a593Smuzhiyun  * May also return -ENOMEM.
157*4882a593Smuzhiyun  */
pkcs7_validate_trust(struct pkcs7_message * pkcs7,struct key * trust_keyring)158*4882a593Smuzhiyun int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
159*4882a593Smuzhiyun 			 struct key *trust_keyring)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct pkcs7_signed_info *sinfo;
162*4882a593Smuzhiyun 	struct x509_certificate *p;
163*4882a593Smuzhiyun 	int cached_ret = -ENOKEY;
164*4882a593Smuzhiyun 	int ret;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	for (p = pkcs7->certs; p; p = p->next)
167*4882a593Smuzhiyun 		p->seen = false;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
170*4882a593Smuzhiyun 		ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
171*4882a593Smuzhiyun 		switch (ret) {
172*4882a593Smuzhiyun 		case -ENOKEY:
173*4882a593Smuzhiyun 			continue;
174*4882a593Smuzhiyun 		case -ENOPKG:
175*4882a593Smuzhiyun 			if (cached_ret == -ENOKEY)
176*4882a593Smuzhiyun 				cached_ret = -ENOPKG;
177*4882a593Smuzhiyun 			continue;
178*4882a593Smuzhiyun 		case 0:
179*4882a593Smuzhiyun 			cached_ret = 0;
180*4882a593Smuzhiyun 			continue;
181*4882a593Smuzhiyun 		default:
182*4882a593Smuzhiyun 			return ret;
183*4882a593Smuzhiyun 		}
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return cached_ret;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pkcs7_validate_trust);
189