diff options
author | David Howells <dhowells@redhat.com> | 2014-07-22 16:54:43 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2014-07-22 16:54:43 -0400 |
commit | 64724cfc6eea920dbaada14f0fb978b1dd31192d (patch) | |
tree | d2f491be07a05e2d96b5c8b8e5a0a878f285eb22 /crypto | |
parent | 6204e0025566ad3992ce649d4f44b7e8cdde2293 (diff) | |
parent | 7d2ce2320e8efdc4a6dcbae7b329ed3f0d1cd778 (diff) |
Merge remote-tracking branch 'integrity/next-with-keys' into keys-next
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_keys.h | 2 | ||||
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 51 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 109 |
3 files changed, 142 insertions, 20 deletions
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h index 515b63430812..a63c551c6557 100644 --- a/crypto/asymmetric_keys/asymmetric_keys.h +++ b/crypto/asymmetric_keys/asymmetric_keys.h | |||
@@ -9,6 +9,8 @@ | |||
9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | int asymmetric_keyid_match(const char *kid, const char *id); | ||
13 | |||
12 | static inline const char *asymmetric_key_id(const struct key *key) | 14 | static inline const char *asymmetric_key_id(const struct key *key) |
13 | { | 15 | { |
14 | return key->type_data.p[1]; | 16 | return key->type_data.p[1]; |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 21960a4e74e8..eb8cd46961a5 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
@@ -23,6 +23,35 @@ static LIST_HEAD(asymmetric_key_parsers); | |||
23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Match asymmetric key id with partial match | ||
27 | * @id: key id to match in a form "id:<id>" | ||
28 | */ | ||
29 | int asymmetric_keyid_match(const char *kid, const char *id) | ||
30 | { | ||
31 | size_t idlen, kidlen; | ||
32 | |||
33 | if (!kid || !id) | ||
34 | return 0; | ||
35 | |||
36 | /* make it possible to use id as in the request: "id:<id>" */ | ||
37 | if (strncmp(id, "id:", 3) == 0) | ||
38 | id += 3; | ||
39 | |||
40 | /* Anything after here requires a partial match on the ID string */ | ||
41 | idlen = strlen(id); | ||
42 | kidlen = strlen(kid); | ||
43 | if (idlen > kidlen) | ||
44 | return 0; | ||
45 | |||
46 | kid += kidlen - idlen; | ||
47 | if (strcasecmp(id, kid) != 0) | ||
48 | return 0; | ||
49 | |||
50 | return 1; | ||
51 | } | ||
52 | EXPORT_SYMBOL_GPL(asymmetric_keyid_match); | ||
53 | |||
54 | /* | ||
26 | * Match asymmetric keys on (part of) their name | 55 | * Match asymmetric keys on (part of) their name |
27 | * We have some shorthand methods for matching keys. We allow: | 56 | * We have some shorthand methods for matching keys. We allow: |
28 | * | 57 | * |
@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) | |||
34 | { | 63 | { |
35 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | 64 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); |
36 | const char *spec = description; | 65 | const char *spec = description; |
37 | const char *id, *kid; | 66 | const char *id; |
38 | ptrdiff_t speclen; | 67 | ptrdiff_t speclen; |
39 | size_t idlen, kidlen; | ||
40 | 68 | ||
41 | if (!subtype || !spec || !*spec) | 69 | if (!subtype || !spec || !*spec) |
42 | return 0; | 70 | return 0; |
@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) | |||
55 | speclen = id - spec; | 83 | speclen = id - spec; |
56 | id++; | 84 | id++; |
57 | 85 | ||
58 | /* Anything after here requires a partial match on the ID string */ | 86 | if (speclen == 2 && memcmp(spec, "id", 2) == 0) |
59 | kid = asymmetric_key_id(key); | 87 | return asymmetric_keyid_match(asymmetric_key_id(key), id); |
60 | if (!kid) | ||
61 | return 0; | ||
62 | |||
63 | idlen = strlen(id); | ||
64 | kidlen = strlen(kid); | ||
65 | if (idlen > kidlen) | ||
66 | return 0; | ||
67 | |||
68 | kid += kidlen - idlen; | ||
69 | if (strcasecmp(id, kid) != 0) | ||
70 | return 0; | ||
71 | |||
72 | if (speclen == 2 && | ||
73 | memcmp(spec, "id", 2) == 0) | ||
74 | return 1; | ||
75 | 88 | ||
76 | if (speclen == subtype->name_len && | 89 | if (speclen == subtype->name_len && |
77 | memcmp(spec, subtype->name, speclen) == 0) | 90 | memcmp(spec, subtype->name, speclen) == 0) |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 3fc8a0634ed7..a0f7cd196c9b 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -18,11 +18,80 @@ | |||
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 | ||
27 | static bool use_builtin_keys; | ||
28 | static char *ca_keyid; | ||
29 | |||
30 | #ifndef MODULE | ||
31 | static int __init ca_keys_setup(char *str) | ||
32 | { | ||
33 | if (!str) /* default system keyring */ | ||
34 | return 1; | ||
35 | |||
36 | if (strncmp(str, "id:", 3) == 0) | ||
37 | ca_keyid = str; /* owner key 'id:xxxxxx' */ | ||
38 | else if (strcmp(str, "builtin") == 0) | ||
39 | use_builtin_keys = true; | ||
40 | |||
41 | return 1; | ||
42 | } | ||
43 | __setup("ca_keys=", ca_keys_setup); | ||
44 | #endif | ||
45 | |||
46 | /* | ||
47 | * Find a key in the given keyring by issuer and authority. | ||
48 | */ | ||
49 | static struct key *x509_request_asymmetric_key(struct key *keyring, | ||
50 | const char *signer, | ||
51 | size_t signer_len, | ||
52 | const char *authority, | ||
53 | size_t auth_len) | ||
54 | { | ||
55 | key_ref_t key; | ||
56 | char *id; | ||
57 | |||
58 | /* Construct an identifier. */ | ||
59 | id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); | ||
60 | if (!id) | ||
61 | return ERR_PTR(-ENOMEM); | ||
62 | |||
63 | memcpy(id, signer, signer_len); | ||
64 | id[signer_len + 0] = ':'; | ||
65 | id[signer_len + 1] = ' '; | ||
66 | memcpy(id + signer_len + 2, authority, auth_len); | ||
67 | id[signer_len + 2 + auth_len] = 0; | ||
68 | |||
69 | pr_debug("Look up: \"%s\"\n", id); | ||
70 | |||
71 | key = keyring_search(make_key_ref(keyring, 1), | ||
72 | &key_type_asymmetric, id); | ||
73 | if (IS_ERR(key)) | ||
74 | pr_debug("Request for module key '%s' err %ld\n", | ||
75 | id, PTR_ERR(key)); | ||
76 | kfree(id); | ||
77 | |||
78 | if (IS_ERR(key)) { | ||
79 | switch (PTR_ERR(key)) { | ||
80 | /* Hide some search errors */ | ||
81 | case -EACCES: | ||
82 | case -ENOTDIR: | ||
83 | case -EAGAIN: | ||
84 | return ERR_PTR(-ENOKEY); | ||
85 | default: | ||
86 | return ERR_CAST(key); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | pr_devel("<==%s() = 0 [%x]\n", __func__, | ||
91 | key_serial(key_ref_to_ptr(key))); | ||
92 | return key_ref_to_ptr(key); | ||
93 | } | ||
94 | |||
26 | /* | 95 | /* |
27 | * Set up the signature parameters in an X.509 certificate. This involves | 96 | * Set up the signature parameters in an X.509 certificate. This involves |
28 | * digesting the signed data and extracting the signature. | 97 | * digesting the signed data and extracting the signature. |
@@ -103,6 +172,40 @@ int x509_check_signature(const struct public_key *pub, | |||
103 | EXPORT_SYMBOL_GPL(x509_check_signature); | 172 | EXPORT_SYMBOL_GPL(x509_check_signature); |
104 | 173 | ||
105 | /* | 174 | /* |
175 | * Check the new certificate against the ones in the trust keyring. If one of | ||
176 | * those is the signing key and validates the new certificate, then mark the | ||
177 | * new certificate as being trusted. | ||
178 | * | ||
179 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | ||
180 | * find a matching parent certificate in the trusted list and an error if there | ||
181 | * is a matching certificate but the signature check fails. | ||
182 | */ | ||
183 | static int x509_validate_trust(struct x509_certificate *cert, | ||
184 | struct key *trust_keyring) | ||
185 | { | ||
186 | struct key *key; | ||
187 | int ret = 1; | ||
188 | |||
189 | if (!trust_keyring) | ||
190 | return -EOPNOTSUPP; | ||
191 | |||
192 | if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) | ||
193 | return -EPERM; | ||
194 | |||
195 | key = x509_request_asymmetric_key(trust_keyring, | ||
196 | cert->issuer, strlen(cert->issuer), | ||
197 | cert->authority, | ||
198 | strlen(cert->authority)); | ||
199 | if (!IS_ERR(key)) { | ||
200 | if (!use_builtin_keys | ||
201 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
202 | ret = x509_check_signature(key->payload.data, cert); | ||
203 | key_put(key); | ||
204 | } | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | /* | ||
106 | * Attempt to parse a data blob for a key as an X509 certificate. | 209 | * Attempt to parse a data blob for a key as an X509 certificate. |
107 | */ | 210 | */ |
108 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 211 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
@@ -155,9 +258,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 */ | 258 | /* Check the signature on the key if it appears to be self-signed */ |
156 | if (!cert->authority || | 259 | if (!cert->authority || |
157 | strcmp(cert->fingerprint, cert->authority) == 0) { | 260 | strcmp(cert->fingerprint, cert->authority) == 0) { |
158 | ret = x509_check_signature(cert->pub, cert); | 261 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
159 | if (ret < 0) | 262 | if (ret < 0) |
160 | goto error_free_cert; | 263 | goto error_free_cert; |
264 | } else if (!prep->trusted) { | ||
265 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
266 | if (!ret) | ||
267 | prep->trusted = 1; | ||
161 | } | 268 | } |
162 | 269 | ||
163 | /* Propose a description */ | 270 | /* Propose a description */ |