diff options
author | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2013-08-20 14:36:27 -0400 |
---|---|---|
committer | Mimi Zohar <zohar@linux.vnet.ibm.com> | 2014-07-17 09:35:15 -0400 |
commit | 3be4beaf7c91ec9c6fefa5f11173af37113d10ae (patch) | |
tree | c4007c5fc0ddd6bccb279fbae8a5ee52f7af01de /crypto | |
parent | a4e3b8d79a5c6d40f4a9703abf7fe3abcc6c3b8d (diff) |
KEYS: verify a certificate is signed by a 'trusted' key
Only public keys, with certificates signed by an existing
'trusted' key on the system trusted keyring, should be added
to a trusted keyring. This patch adds support for verifying
a certificate's signature.
This is derived from David Howells pkcs7_request_asymmetric_key() patch.
Changelog v6:
- on error free key - Dmitry
- validate trust only for not already trusted keys - Dmitry
- formatting cleanup
Changelog:
- define get_system_trusted_keyring() to fix kbuild issues
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 382ef0d2ff2e..436fbd8552fc 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -18,12 +18,62 @@ | |||
18 | #include <linux/asn1_decoder.h> | 18 | #include <linux/asn1_decoder.h> |
19 | #include <keys/asymmetric-subtype.h> | 19 | #include <keys/asymmetric-subtype.h> |
20 | #include <keys/asymmetric-parser.h> | 20 | #include <keys/asymmetric-parser.h> |
21 | #include <keys/system_keyring.h> | ||
21 | #include <crypto/hash.h> | 22 | #include <crypto/hash.h> |
22 | #include "asymmetric_keys.h" | 23 | #include "asymmetric_keys.h" |
23 | #include "public_key.h" | 24 | #include "public_key.h" |
24 | #include "x509_parser.h" | 25 | #include "x509_parser.h" |
25 | 26 | ||
26 | /* | 27 | /* |
28 | * Find a key in the given keyring by issuer and authority. | ||
29 | */ | ||
30 | static struct key *x509_request_asymmetric_key(struct key *keyring, | ||
31 | const char *signer, | ||
32 | size_t signer_len, | ||
33 | const char *authority, | ||
34 | size_t auth_len) | ||
35 | { | ||
36 | key_ref_t key; | ||
37 | char *id; | ||
38 | |||
39 | /* Construct an identifier. */ | ||
40 | id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); | ||
41 | if (!id) | ||
42 | return ERR_PTR(-ENOMEM); | ||
43 | |||
44 | memcpy(id, signer, signer_len); | ||
45 | id[signer_len + 0] = ':'; | ||
46 | id[signer_len + 1] = ' '; | ||
47 | memcpy(id + signer_len + 2, authority, auth_len); | ||
48 | id[signer_len + 2 + auth_len] = 0; | ||
49 | |||
50 | pr_debug("Look up: \"%s\"\n", id); | ||
51 | |||
52 | key = keyring_search(make_key_ref(keyring, 1), | ||
53 | &key_type_asymmetric, id); | ||
54 | if (IS_ERR(key)) | ||
55 | pr_debug("Request for module key '%s' err %ld\n", | ||
56 | id, PTR_ERR(key)); | ||
57 | kfree(id); | ||
58 | |||
59 | if (IS_ERR(key)) { | ||
60 | switch (PTR_ERR(key)) { | ||
61 | /* Hide some search errors */ | ||
62 | case -EACCES: | ||
63 | case -ENOTDIR: | ||
64 | case -EAGAIN: | ||
65 | return ERR_PTR(-ENOKEY); | ||
66 | default: | ||
67 | return ERR_CAST(key); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | pr_devel("<==%s() = 0 [%x]\n", __func__, | ||
72 | key_serial(key_ref_to_ptr(key))); | ||
73 | return key_ref_to_ptr(key); | ||
74 | } | ||
75 | |||
76 | /* | ||
27 | * Set up the signature parameters in an X.509 certificate. This involves | 77 | * Set up the signature parameters in an X.509 certificate. This involves |
28 | * digesting the signed data and extracting the signature. | 78 | * digesting the signed data and extracting the signature. |
29 | */ | 79 | */ |
@@ -103,6 +153,37 @@ int x509_check_signature(const struct public_key *pub, | |||
103 | EXPORT_SYMBOL_GPL(x509_check_signature); | 153 | EXPORT_SYMBOL_GPL(x509_check_signature); |
104 | 154 | ||
105 | /* | 155 | /* |
156 | * Check the new certificate against the ones in the trust keyring. If one of | ||
157 | * those is the signing key and validates the new certificate, then mark the | ||
158 | * new certificate as being trusted. | ||
159 | * | ||
160 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | ||
161 | * find a matching parent certificate in the trusted list and an error if there | ||
162 | * is a matching certificate but the signature check fails. | ||
163 | */ | ||
164 | static int x509_validate_trust(struct x509_certificate *cert, | ||
165 | struct key *trust_keyring) | ||
166 | { | ||
167 | const struct public_key *pk; | ||
168 | struct key *key; | ||
169 | int ret = 1; | ||
170 | |||
171 | if (!trust_keyring) | ||
172 | return -EOPNOTSUPP; | ||
173 | |||
174 | key = x509_request_asymmetric_key(trust_keyring, | ||
175 | cert->issuer, strlen(cert->issuer), | ||
176 | cert->authority, | ||
177 | strlen(cert->authority)); | ||
178 | if (!IS_ERR(key)) { | ||
179 | pk = key->payload.data; | ||
180 | ret = x509_check_signature(pk, cert); | ||
181 | key_put(key); | ||
182 | } | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /* | ||
106 | * Attempt to parse a data blob for a key as an X509 certificate. | 187 | * Attempt to parse a data blob for a key as an X509 certificate. |
107 | */ | 188 | */ |
108 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 189 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
@@ -155,9 +236,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
155 | /* Check the signature on the key if it appears to be self-signed */ | 236 | /* Check the signature on the key if it appears to be self-signed */ |
156 | if (!cert->authority || | 237 | if (!cert->authority || |
157 | strcmp(cert->fingerprint, cert->authority) == 0) { | 238 | strcmp(cert->fingerprint, cert->authority) == 0) { |
158 | ret = x509_check_signature(cert->pub, cert); | 239 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
159 | if (ret < 0) | 240 | if (ret < 0) |
160 | goto error_free_cert; | 241 | goto error_free_cert; |
242 | } else if (!prep->trusted) { | ||
243 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
244 | if (!ret) | ||
245 | prep->trusted = 1; | ||
161 | } | 246 | } |
162 | 247 | ||
163 | /* Propose a description */ | 248 | /* Propose a description */ |