Blame view

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