diff options
author | David Howells <dhowells@redhat.com> | 2014-09-16 12:36:13 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2014-09-16 12:36:13 -0400 |
commit | 46963b774d441c833afc1535f6d84b3df2a94204 (patch) | |
tree | 335cbd163ef2581b72d462f49984a6809609a58b /crypto/asymmetric_keys/x509_public_key.c | |
parent | 7901c1a8effbe5f89673bfc09d6e37b8f334f1a7 (diff) |
KEYS: Overhaul key identification when searching for asymmetric keys
Make use of the new match string preparsing to overhaul key identification
when searching for asymmetric keys. The following changes are made:
(1) Use the previously created asymmetric_key_id struct to hold the following
key IDs derived from the X.509 certificate or PKCS#7 message:
id: serial number + issuer
skid: subjKeyId + subject
authority: authKeyId + issuer
(2) Replace the hex fingerprint attached to key->type_data[1] with an
asymmetric_key_ids struct containing the id and the skid (if present).
(3) Make the asymmetric_type match data preparse select one of two searches:
(a) An iterative search for the key ID given if prefixed with "id:". The
prefix is expected to be followed by a hex string giving the ID to
search for. The criterion key ID is checked against all key IDs
recorded on the key.
(b) A direct search if the key ID is not prefixed with "id:". This will
look for an exact match on the key description.
(4) Make x509_request_asymmetric_key() take a key ID. This is then converted
into "id:<hex>" and passed into keyring_search() where match preparsing
will turn it back into a binary ID.
(5) X.509 certificate verification then takes the authority key ID and looks
up a key that matches it to find the public key for the certificate
signature.
(6) PKCS#7 certificate verification then takes the id key ID and looks up a
key that matches it to find the public key for the signed information
block signature.
Additional changes:
(1) Multiple subjKeyId and authKeyId values on an X.509 certificate cause the
cert to be rejected with -EBADMSG.
(2) The 'fingerprint' ID is gone. This was primarily intended to convey PGP
public key fingerprints. If PGP is supported in future, this should
generate a key ID that carries the fingerprint.
(3) Th ca_keyid= kernel command line option is now converted to a key ID and
used to match the authority key ID. Possibly this should only match the
actual authKeyId part and not the issuer as well.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Diffstat (limited to 'crypto/asymmetric_keys/x509_public_key.c')
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index f3d62307e6ee..c60905c3f4d2 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include "x509_parser.h" | 25 | #include "x509_parser.h" |
26 | 26 | ||
27 | static bool use_builtin_keys; | 27 | static bool use_builtin_keys; |
28 | static char *ca_keyid; | 28 | static struct asymmetric_key_id *ca_keyid; |
29 | 29 | ||
30 | #ifndef MODULE | 30 | #ifndef MODULE |
31 | static int __init ca_keys_setup(char *str) | 31 | static int __init ca_keys_setup(char *str) |
@@ -33,10 +33,16 @@ static int __init ca_keys_setup(char *str) | |||
33 | if (!str) /* default system keyring */ | 33 | if (!str) /* default system keyring */ |
34 | return 1; | 34 | return 1; |
35 | 35 | ||
36 | if (strncmp(str, "id:", 3) == 0) | 36 | if (strncmp(str, "id:", 3) == 0) { |
37 | ca_keyid = str; /* owner key 'id:xxxxxx' */ | 37 | struct asymmetric_key_id *p; |
38 | else if (strcmp(str, "builtin") == 0) | 38 | p = asymmetric_key_hex_to_key_id(str); |
39 | if (p == ERR_PTR(-EINVAL)) | ||
40 | pr_err("Unparsable hex string in ca_keys\n"); | ||
41 | else if (!IS_ERR(p)) | ||
42 | ca_keyid = p; /* owner key 'id:xxxxxx' */ | ||
43 | } else if (strcmp(str, "builtin") == 0) { | ||
39 | use_builtin_keys = true; | 44 | use_builtin_keys = true; |
45 | } | ||
40 | 46 | ||
41 | return 1; | 47 | return 1; |
42 | } | 48 | } |
@@ -46,31 +52,28 @@ __setup("ca_keys=", ca_keys_setup); | |||
46 | /** | 52 | /** |
47 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | 53 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. |
48 | * @keyring: The keys to search. | 54 | * @keyring: The keys to search. |
49 | * @subject: The name of the subject to whom the key belongs. | 55 | * @kid: The key ID. |
50 | * @key_id: The subject key ID as a hex string. | ||
51 | * | 56 | * |
52 | * Find a key in the given keyring by subject name and key ID. These might, | 57 | * Find a key in the given keyring by subject name and key ID. These might, |
53 | * for instance, be the issuer name and the authority key ID of an X.509 | 58 | * for instance, be the issuer name and the authority key ID of an X.509 |
54 | * certificate that needs to be verified. | 59 | * certificate that needs to be verified. |
55 | */ | 60 | */ |
56 | struct key *x509_request_asymmetric_key(struct key *keyring, | 61 | struct key *x509_request_asymmetric_key(struct key *keyring, |
57 | const char *subject, | 62 | const struct asymmetric_key_id *kid) |
58 | const char *key_id) | ||
59 | { | 63 | { |
60 | key_ref_t key; | 64 | key_ref_t key; |
61 | size_t subject_len = strlen(subject), key_id_len = strlen(key_id); | 65 | char *id, *p; |
62 | char *id; | ||
63 | 66 | ||
64 | /* Construct an identifier "<subjname>:<keyid>". */ | 67 | /* Construct an identifier "id:<keyid>". */ |
65 | id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL); | 68 | p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL); |
66 | if (!id) | 69 | if (!id) |
67 | return ERR_PTR(-ENOMEM); | 70 | return ERR_PTR(-ENOMEM); |
68 | 71 | ||
69 | memcpy(id, subject, subject_len); | 72 | *p++ = 'i'; |
70 | id[subject_len + 0] = ':'; | 73 | *p++ = 'd'; |
71 | id[subject_len + 1] = ' '; | 74 | *p++ = ':'; |
72 | memcpy(id + subject_len + 2, key_id, key_id_len); | 75 | p = bin2hex(p, kid->data, kid->len); |
73 | id[subject_len + 2 + key_id_len] = 0; | 76 | *p = 0; |
74 | 77 | ||
75 | pr_debug("Look up: \"%s\"\n", id); | 78 | pr_debug("Look up: \"%s\"\n", id); |
76 | 79 | ||
@@ -195,11 +198,10 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
195 | if (!trust_keyring) | 198 | if (!trust_keyring) |
196 | return -EOPNOTSUPP; | 199 | return -EOPNOTSUPP; |
197 | 200 | ||
198 | if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) | 201 | if (ca_keyid && !asymmetric_key_id_same(cert->authority, ca_keyid)) |
199 | return -EPERM; | 202 | return -EPERM; |
200 | 203 | ||
201 | key = x509_request_asymmetric_key(trust_keyring, | 204 | key = x509_request_asymmetric_key(trust_keyring, cert->authority); |
202 | cert->issuer, cert->authority); | ||
203 | if (!IS_ERR(key)) { | 205 | if (!IS_ERR(key)) { |
204 | if (!use_builtin_keys | 206 | if (!use_builtin_keys |
205 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | 207 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) |
@@ -214,9 +216,11 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
214 | */ | 216 | */ |
215 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 217 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
216 | { | 218 | { |
219 | struct asymmetric_key_ids *kids; | ||
217 | struct x509_certificate *cert; | 220 | struct x509_certificate *cert; |
221 | const char *q; | ||
218 | size_t srlen, sulen; | 222 | size_t srlen, sulen; |
219 | char *desc = NULL; | 223 | char *desc = NULL, *p; |
220 | int ret; | 224 | int ret; |
221 | 225 | ||
222 | cert = x509_cert_parse(prep->data, prep->datalen); | 226 | cert = x509_cert_parse(prep->data, prep->datalen); |
@@ -249,19 +253,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
249 | pkey_algo_name[cert->sig.pkey_algo], | 253 | pkey_algo_name[cert->sig.pkey_algo], |
250 | hash_algo_name[cert->sig.pkey_hash_algo]); | 254 | hash_algo_name[cert->sig.pkey_hash_algo]); |
251 | 255 | ||
252 | if (!cert->fingerprint) { | ||
253 | pr_warn("Cert for '%s' must have a SubjKeyId extension\n", | ||
254 | cert->subject); | ||
255 | ret = -EKEYREJECTED; | ||
256 | goto error_free_cert; | ||
257 | } | ||
258 | |||
259 | cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; | 256 | cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; |
260 | cert->pub->id_type = PKEY_ID_X509; | 257 | cert->pub->id_type = PKEY_ID_X509; |
261 | 258 | ||
262 | /* Check the signature on the key if it appears to be self-signed */ | 259 | /* Check the signature on the key if it appears to be self-signed */ |
263 | if (!cert->authority || | 260 | if (!cert->authority || |
264 | strcmp(cert->fingerprint, cert->authority) == 0) { | 261 | asymmetric_key_id_same(cert->skid, cert->authority)) { |
265 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 262 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
266 | if (ret < 0) | 263 | if (ret < 0) |
267 | goto error_free_cert; | 264 | goto error_free_cert; |
@@ -273,31 +270,47 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
273 | 270 | ||
274 | /* Propose a description */ | 271 | /* Propose a description */ |
275 | sulen = strlen(cert->subject); | 272 | sulen = strlen(cert->subject); |
276 | srlen = strlen(cert->fingerprint); | 273 | srlen = cert->raw_serial_size; |
274 | q = cert->raw_serial; | ||
275 | if (srlen > 1 && *q == 0) { | ||
276 | srlen--; | ||
277 | q++; | ||
278 | } | ||
279 | |||
277 | ret = -ENOMEM; | 280 | ret = -ENOMEM; |
278 | desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); | 281 | desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL); |
279 | if (!desc) | 282 | if (!desc) |
280 | goto error_free_cert; | 283 | goto error_free_cert; |
281 | memcpy(desc, cert->subject, sulen); | 284 | p = memcpy(desc, cert->subject, sulen); |
282 | desc[sulen] = ':'; | 285 | p += sulen; |
283 | desc[sulen + 1] = ' '; | 286 | *p++ = ':'; |
284 | memcpy(desc + sulen + 2, cert->fingerprint, srlen); | 287 | *p++ = ' '; |
285 | desc[sulen + 2 + srlen] = 0; | 288 | p = bin2hex(p, q, srlen); |
289 | *p = 0; | ||
290 | |||
291 | kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL); | ||
292 | if (!kids) | ||
293 | goto error_free_desc; | ||
294 | kids->id[0] = cert->id; | ||
295 | kids->id[1] = cert->skid; | ||
286 | 296 | ||
287 | /* We're pinning the module by being linked against it */ | 297 | /* We're pinning the module by being linked against it */ |
288 | __module_get(public_key_subtype.owner); | 298 | __module_get(public_key_subtype.owner); |
289 | prep->type_data[0] = &public_key_subtype; | 299 | prep->type_data[0] = &public_key_subtype; |
290 | prep->type_data[1] = cert->fingerprint; | 300 | prep->type_data[1] = kids; |
291 | prep->payload[0] = cert->pub; | 301 | prep->payload[0] = cert->pub; |
292 | prep->description = desc; | 302 | prep->description = desc; |
293 | prep->quotalen = 100; | 303 | prep->quotalen = 100; |
294 | 304 | ||
295 | /* We've finished with the certificate */ | 305 | /* We've finished with the certificate */ |
296 | cert->pub = NULL; | 306 | cert->pub = NULL; |
297 | cert->fingerprint = NULL; | 307 | cert->id = NULL; |
308 | cert->skid = NULL; | ||
298 | desc = NULL; | 309 | desc = NULL; |
299 | ret = 0; | 310 | ret = 0; |
300 | 311 | ||
312 | error_free_desc: | ||
313 | kfree(desc); | ||
301 | error_free_cert: | 314 | error_free_cert: |
302 | x509_free_certificate(cert); | 315 | x509_free_certificate(cert); |
303 | return ret; | 316 | return ret; |