Skip to content

Commit 4573b64

Browse files
committed
X.509: Support X.509 lookup by Issuer+Serial form AuthorityKeyIdentifier
If an X.509 certificate has an AuthorityKeyIdentifier extension that provides an issuer and serialNumber, then make it so that these are used in preference to the keyIdentifier field also held therein for searching for the signing certificate. If both the issuer+serialNumber and the keyIdentifier are supplied, then the certificate is looked up by the former but the latter is checked as well. If the latter doesn't match the subjectKeyIdentifier of the parent certificate, EKEYREJECTED is returned. This makes it possible to chain X.509 certificates based on the issuer and serialNumber fields rather than on subjectKeyIdentifier. This is necessary as we are having to deal with keys that are represented by X.509 certificates that lack a subjectKeyIdentifier. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Vivek Goyal <vgoyal@redhat.com>
1 parent b92e657 commit 4573b64

File tree

4 files changed

+103
-41
lines changed

4 files changed

+103
-41
lines changed

crypto/asymmetric_keys/pkcs7_trust.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
5454
/* Look to see if this certificate is present in the trusted
5555
* keys.
5656
*/
57-
key = x509_request_asymmetric_key(trust_keyring, x509->id,
57+
key = x509_request_asymmetric_key(trust_keyring,
58+
x509->id, x509->skid,
5859
false);
5960
if (!IS_ERR(key)) {
6061
/* One of the X.509 certificates in the PKCS#7 message
@@ -85,8 +86,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
8586
/* No match - see if the root certificate has a signer amongst the
8687
* trusted keys.
8788
*/
88-
if (last && last->akid_skid) {
89-
key = x509_request_asymmetric_key(trust_keyring, last->akid_skid,
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,
9093
false);
9194
if (!IS_ERR(key)) {
9295
x509 = last;
@@ -103,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
103106
*/
104107
key = x509_request_asymmetric_key(trust_keyring,
105108
sinfo->signing_cert_id,
109+
NULL,
106110
false);
107111
if (!IS_ERR(key)) {
108112
pr_devel("sinfo %u: Direct signer is key %x\n",

crypto/asymmetric_keys/pkcs7_verify.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
170170
struct pkcs7_signed_info *sinfo)
171171
{
172172
struct x509_certificate *x509 = sinfo->signer, *p;
173+
struct asymmetric_key_id *auth;
173174
int ret;
174175

175176
kenter("");
@@ -187,11 +188,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
187188
goto maybe_missing_crypto_in_x509;
188189

189190
pr_debug("- issuer %s\n", x509->issuer);
191+
if (x509->akid_id)
192+
pr_debug("- authkeyid.id %*phN\n",
193+
x509->akid_id->len, x509->akid_id->data);
190194
if (x509->akid_skid)
191-
pr_debug("- authkeyid %*phN\n",
195+
pr_debug("- authkeyid.skid %*phN\n",
192196
x509->akid_skid->len, x509->akid_skid->data);
193197

194-
if (!x509->akid_skid ||
198+
if ((!x509->akid_id && !x509->akid_skid) ||
195199
strcmp(x509->subject, x509->issuer) == 0) {
196200
/* If there's no authority certificate specified, then
197201
* the certificate must be self-signed and is the root
@@ -215,21 +219,42 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
215219
/* Look through the X.509 certificates in the PKCS#7 message's
216220
* list to see if the next one is there.
217221
*/
218-
pr_debug("- want %*phN\n",
219-
x509->akid_skid->len, x509->akid_skid->data);
220-
for (p = pkcs7->certs; p; p = p->next) {
221-
if (!p->skid)
222-
continue;
223-
pr_debug("- cmp [%u] %*phN\n",
224-
p->index, p->skid->len, p->skid->data);
225-
if (asymmetric_key_id_same(p->skid, x509->akid_skid))
226-
goto found_issuer;
222+
auth = x509->akid_id;
223+
if (auth) {
224+
pr_debug("- want %*phN\n", auth->len, auth->data);
225+
for (p = pkcs7->certs; p; p = p->next) {
226+
pr_debug("- cmp [%u] %*phN\n",
227+
p->index, p->id->len, p->id->data);
228+
if (asymmetric_key_id_same(p->id, auth))
229+
goto found_issuer_check_skid;
230+
}
231+
} else {
232+
auth = x509->akid_skid;
233+
pr_debug("- want %*phN\n", auth->len, auth->data);
234+
for (p = pkcs7->certs; p; p = p->next) {
235+
if (!p->skid)
236+
continue;
237+
pr_debug("- cmp [%u] %*phN\n",
238+
p->index, p->skid->len, p->skid->data);
239+
if (asymmetric_key_id_same(p->skid, auth))
240+
goto found_issuer;
241+
}
227242
}
228243

229244
/* We didn't find the root of this chain */
230245
pr_debug("- top\n");
231246
return 0;
232247

248+
found_issuer_check_skid:
249+
/* We matched issuer + serialNumber, but if there's an
250+
* authKeyId.keyId, that must match the CA subjKeyId also.
251+
*/
252+
if (x509->akid_skid &&
253+
!asymmetric_key_id_same(p->skid, x509->akid_skid)) {
254+
pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
255+
sinfo->index, x509->index, p->index);
256+
return -EKEYREJECTED;
257+
}
233258
found_issuer:
234259
pr_debug("- subject %s\n", p->subject);
235260
if (p->seen) {

crypto/asymmetric_keys/x509_public_key.c

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup);
6565
/**
6666
* x509_request_asymmetric_key - Request a key by X.509 certificate params.
6767
* @keyring: The keys to search.
68-
* @kid: The key ID.
68+
* @id: The issuer & serialNumber to look for or NULL.
69+
* @skid: The subjectKeyIdentifier to look for or NULL.
6970
* @partial: Use partial match if true, exact if false.
7071
*
71-
* Find a key in the given keyring by subject name and key ID. These might,
72-
* for instance, be the issuer name and the authority key ID of an X.509
73-
* certificate that needs to be verified.
72+
* Find a key in the given keyring by identifier. The preferred identifier is
73+
* the issuer + serialNumber and the fallback identifier is the
74+
* subjectKeyIdentifier. If both are given, the lookup is by the former, but
75+
* the latter must also match.
7476
*/
7577
struct key *x509_request_asymmetric_key(struct key *keyring,
76-
const struct asymmetric_key_id *kid,
78+
const struct asymmetric_key_id *id,
79+
const struct asymmetric_key_id *skid,
7780
bool partial)
7881
{
79-
key_ref_t key;
80-
char *id, *p;
81-
82+
struct key *key;
83+
key_ref_t ref;
84+
const char *lookup;
85+
char *req, *p;
86+
int len;
87+
88+
if (id) {
89+
lookup = id->data;
90+
len = id->len;
91+
} else {
92+
lookup = skid->data;
93+
len = skid->len;
94+
}
95+
8296
/* Construct an identifier "id:<keyid>". */
83-
p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
84-
if (!id)
97+
p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
98+
if (!req)
8599
return ERR_PTR(-ENOMEM);
86100

87101
if (partial) {
@@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
92106
*p++ = 'x';
93107
}
94108
*p++ = ':';
95-
p = bin2hex(p, kid->data, kid->len);
109+
p = bin2hex(p, lookup, len);
96110
*p = 0;
97111

98-
pr_debug("Look up: \"%s\"\n", id);
112+
pr_debug("Look up: \"%s\"\n", req);
99113

100-
key = keyring_search(make_key_ref(keyring, 1),
101-
&key_type_asymmetric, id);
102-
if (IS_ERR(key))
103-
pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
104-
kfree(id);
114+
ref = keyring_search(make_key_ref(keyring, 1),
115+
&key_type_asymmetric, req);
116+
if (IS_ERR(ref))
117+
pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
118+
kfree(req);
105119

106-
if (IS_ERR(key)) {
107-
switch (PTR_ERR(key)) {
120+
if (IS_ERR(ref)) {
121+
switch (PTR_ERR(ref)) {
108122
/* Hide some search errors */
109123
case -EACCES:
110124
case -ENOTDIR:
111125
case -EAGAIN:
112126
return ERR_PTR(-ENOKEY);
113127
default:
114-
return ERR_CAST(key);
128+
return ERR_CAST(ref);
129+
}
130+
}
131+
132+
key = key_ref_to_ptr(ref);
133+
if (id && skid) {
134+
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
135+
if (!kids->id[1]) {
136+
pr_debug("issuer+serial match, but expected SKID missing\n");
137+
goto reject;
138+
}
139+
if (!asymmetric_key_id_same(skid, kids->id[1])) {
140+
pr_debug("issuer+serial match, but SKID does not\n");
141+
goto reject;
115142
}
116143
}
144+
145+
pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
146+
return key;
117147

118-
pr_devel("<==%s() = 0 [%x]\n", __func__,
119-
key_serial(key_ref_to_ptr(key)));
120-
return key_ref_to_ptr(key);
148+
reject:
149+
key_put(key);
150+
return ERR_PTR(-EKEYREJECTED);
121151
}
122152
EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
123153

@@ -230,7 +260,8 @@ static int x509_validate_trust(struct x509_certificate *cert,
230260
if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
231261
return -EPERM;
232262

233-
key = x509_request_asymmetric_key(trust_keyring, cert->akid_skid,
263+
key = x509_request_asymmetric_key(trust_keyring,
264+
cert->akid_id, cert->akid_skid,
234265
false);
235266
if (!IS_ERR(key)) {
236267
if (!use_builtin_keys
@@ -287,8 +318,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
287318
cert->pub->id_type = PKEY_ID_X509;
288319

289320
/* Check the signature on the key if it appears to be self-signed */
290-
if (!cert->akid_skid ||
291-
asymmetric_key_id_same(cert->skid, cert->akid_skid)) {
321+
if ((!cert->akid_skid && !cert->akid_id) ||
322+
asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
323+
asymmetric_key_id_same(cert->id, cert->akid_id)) {
292324
ret = x509_check_signature(cert->pub, cert); /* self-signed */
293325
if (ret < 0)
294326
goto error_free_cert;

include/crypto/public_key.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ extern int verify_signature(const struct key *key,
101101

102102
struct asymmetric_key_id;
103103
extern struct key *x509_request_asymmetric_key(struct key *keyring,
104-
const struct asymmetric_key_id *kid,
104+
const struct asymmetric_key_id *id,
105+
const struct asymmetric_key_id *skid,
105106
bool partial);
106107

107108
#endif /* _LINUX_PUBLIC_KEY_H */

0 commit comments

Comments
 (0)