Commit 09fbc47373826d67531380662b516de2da120545

Authored by Mimi Zohar
Committed by David Howells
1 parent af34cb0c3d

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.

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: David Howells <dhowells@redhat.com>

Showing 1 changed file with 80 additions and 1 deletions Side-by-side Diff

crypto/asymmetric_keys/x509_public_key.c
... ... @@ -18,12 +18,60 @@
18 18 #include <linux/asn1_decoder.h>
19 19 #include <keys/asymmetric-subtype.h>
20 20 #include <keys/asymmetric-parser.h>
  21 +#include <keys/system_keyring.h>
21 22 #include <crypto/hash.h>
22 23 #include "asymmetric_keys.h"
23 24 #include "public_key.h"
24 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(
  31 + struct key *keyring,
  32 + const char *signer, size_t signer_len,
  33 + const char *authority, size_t auth_len)
  34 +{
  35 + key_ref_t key;
  36 + char *id;
  37 +
  38 + /* Construct an identifier. */
  39 + id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
  40 + if (!id)
  41 + return ERR_PTR(-ENOMEM);
  42 +
  43 + memcpy(id, signer, signer_len);
  44 + id[signer_len + 0] = ':';
  45 + id[signer_len + 1] = ' ';
  46 + memcpy(id + signer_len + 2, authority, auth_len);
  47 + id[signer_len + 2 + auth_len] = 0;
  48 +
  49 + pr_debug("Look up: \"%s\"\n", id);
  50 +
  51 + key = keyring_search(make_key_ref(keyring, 1),
  52 + &key_type_asymmetric, id);
  53 + if (IS_ERR(key))
  54 + pr_debug("Request for module key '%s' err %ld\n",
  55 + id, PTR_ERR(key));
  56 + kfree(id);
  57 +
  58 + if (IS_ERR(key)) {
  59 + switch (PTR_ERR(key)) {
  60 + /* Hide some search errors */
  61 + case -EACCES:
  62 + case -ENOTDIR:
  63 + case -EAGAIN:
  64 + return ERR_PTR(-ENOKEY);
  65 + default:
  66 + return ERR_CAST(key);
  67 + }
  68 + }
  69 +
  70 + pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
  71 + return key_ref_to_ptr(key);
  72 +}
  73 +
  74 +/*
27 75 * Set up the signature parameters in an X.509 certificate. This involves
28 76 * digesting the signed data and extracting the signature.
29 77 */
... ... @@ -103,6 +151,33 @@
103 151 EXPORT_SYMBOL_GPL(x509_check_signature);
104 152  
105 153 /*
  154 + * Check the new certificate against the ones in the trust keyring. If one of
  155 + * those is the signing key and validates the new certificate, then mark the
  156 + * new certificate as being trusted.
  157 + *
  158 + * Return 0 if the new certificate was successfully validated, 1 if we couldn't
  159 + * find a matching parent certificate in the trusted list and an error if there
  160 + * is a matching certificate but the signature check fails.
  161 + */
  162 +static int x509_validate_trust(struct x509_certificate *cert,
  163 + struct key *trust_keyring)
  164 +{
  165 + const struct public_key *pk;
  166 + struct key *key;
  167 + int ret = 1;
  168 +
  169 + key = x509_request_asymmetric_key(trust_keyring,
  170 + cert->issuer, strlen(cert->issuer),
  171 + cert->authority,
  172 + strlen(cert->authority));
  173 + if (!IS_ERR(key)) {
  174 + pk = key->payload.data;
  175 + ret = x509_check_signature(pk, cert);
  176 + }
  177 + return ret;
  178 +}
  179 +
  180 +/*
106 181 * Attempt to parse a data blob for a key as an X509 certificate.
107 182 */
108 183 static int x509_key_preparse(struct key_preparsed_payload *prep)
109 184  
... ... @@ -155,9 +230,13 @@
155 230 /* Check the signature on the key if it appears to be self-signed */
156 231 if (!cert->authority ||
157 232 strcmp(cert->fingerprint, cert->authority) == 0) {
158   - ret = x509_check_signature(cert->pub, cert);
  233 + ret = x509_check_signature(cert->pub, cert); /* self-signed */
159 234 if (ret < 0)
160 235 goto error_free_cert;
  236 + } else {
  237 + ret = x509_validate_trust(cert, system_trusted_keyring);
  238 + if (!ret)
  239 + prep->trusted = 1;
161 240 }
162 241  
163 242 /* Propose a description */