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 */ |
