Messages in this thread Patch in this message | | | Subject | Re: [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file [ver #2] | From | Mimi Zohar <> | Date | Mon, 08 Feb 2016 06:59:41 -0500 |
| |
On Tue, 2016-01-19 at 11:32 +0000, David Howells wrote: > Move the X.509 trust validation code out to its own file so that it can be > generalised. > > Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
> --- > > crypto/asymmetric_keys/Makefile | 2 > crypto/asymmetric_keys/public_key_trust.c | 195 +++++++++++++++++++++++++++++ > crypto/asymmetric_keys/x509_parser.h | 6 + > crypto/asymmetric_keys/x509_public_key.c | 170 ------------------------- > 4 files changed, 202 insertions(+), 171 deletions(-) > create mode 100644 crypto/asymmetric_keys/public_key_trust.c > > diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile > index cd1406f9b14a..3f291bbf7b74 100644 > --- a/crypto/asymmetric_keys/Makefile > +++ b/crypto/asymmetric_keys/Makefile > @@ -6,7 +6,7 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o > > asymmetric_keys-y := asymmetric_type.o signature.o > > -obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o > +obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o public_key_trust.o > obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o > > # > diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c > new file mode 100644 > index 000000000000..9febe612e659 > --- /dev/null > +++ b/crypto/asymmetric_keys/public_key_trust.c > @@ -0,0 +1,195 @@ > +/* Instantiate a public key crypto key from an X.509 Certificate > + * > + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. > + * Written by David Howells (dhowells@redhat.com) > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public Licence > + * as published by the Free Software Foundation; either version > + * 2 of the Licence, or (at your option) any later version. > + */ > + > +#define pr_fmt(fmt) "X.509: "fmt > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/slab.h> > +#include <linux/err.h> > +#include <linux/mpi.h> > +#include <linux/asn1_decoder.h> > +#include <keys/asymmetric-subtype.h> > +#include <keys/asymmetric-parser.h> > +#include <keys/system_keyring.h> > +#include <crypto/hash.h> > +#include "asymmetric_keys.h" > +#include "public_key.h" > +#include "x509_parser.h" > + > +static bool use_builtin_keys; > +static struct asymmetric_key_id *ca_keyid; > + > +#ifndef MODULE > +static struct { > + struct asymmetric_key_id id; > + unsigned char data[10]; > +} cakey; > + > +static int __init ca_keys_setup(char *str) > +{ > + if (!str) /* default system keyring */ > + return 1; > + > + if (strncmp(str, "id:", 3) == 0) { > + struct asymmetric_key_id *p = &cakey.id; > + size_t hexlen = (strlen(str) - 3) / 2; > + int ret; > + > + if (hexlen == 0 || hexlen > sizeof(cakey.data)) { > + pr_err("Missing or invalid ca_keys id\n"); > + return 1; > + } > + > + ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); > + if (ret < 0) > + pr_err("Unparsable ca_keys id hex string\n"); > + else > + ca_keyid = p; /* owner key 'id:xxxxxx' */ > + } else if (strcmp(str, "builtin") == 0) { > + use_builtin_keys = true; > + } > + > + return 1; > +} > +__setup("ca_keys=", ca_keys_setup); > +#endif > + > +/** > + * x509_request_asymmetric_key - Request a key by X.509 certificate params. > + * @keyring: The keys to search. > + * @id: The issuer & serialNumber to look for or NULL. > + * @skid: The subjectKeyIdentifier to look for or NULL. > + * @partial: Use partial match if true, exact if false. > + * > + * Find a key in the given keyring by identifier. The preferred identifier is > + * the issuer + serialNumber and the fallback identifier is the > + * subjectKeyIdentifier. If both are given, the lookup is by the former, but > + * the latter must also match. > + */ > +struct key *x509_request_asymmetric_key(struct key *keyring, > + const struct asymmetric_key_id *id, > + const struct asymmetric_key_id *skid, > + bool partial) > +{ > + struct key *key; > + key_ref_t ref; > + const char *lookup; > + char *req, *p; > + int len; > + > + if (id) { > + lookup = id->data; > + len = id->len; > + } else { > + lookup = skid->data; > + len = skid->len; > + } > + > + /* Construct an identifier "id:<keyid>". */ > + p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); > + if (!req) > + return ERR_PTR(-ENOMEM); > + > + if (partial) { > + *p++ = 'i'; > + *p++ = 'd'; > + } else { > + *p++ = 'e'; > + *p++ = 'x'; > + } > + *p++ = ':'; > + p = bin2hex(p, lookup, len); > + *p = 0; > + > + pr_debug("Look up: \"%s\"\n", req); > + > + ref = keyring_search(make_key_ref(keyring, 1), > + &key_type_asymmetric, req); > + if (IS_ERR(ref)) > + pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); > + kfree(req); > + > + if (IS_ERR(ref)) { > + switch (PTR_ERR(ref)) { > + /* Hide some search errors */ > + case -EACCES: > + case -ENOTDIR: > + case -EAGAIN: > + return ERR_PTR(-ENOKEY); > + default: > + return ERR_CAST(ref); > + } > + } > + > + key = key_ref_to_ptr(ref); > + if (id && skid) { > + const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); > + if (!kids->id[1]) { > + pr_debug("issuer+serial match, but expected SKID missing\n"); > + goto reject; > + } > + if (!asymmetric_key_id_same(skid, kids->id[1])) { > + pr_debug("issuer+serial match, but SKID does not\n"); > + goto reject; > + } > + } > + > + pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); > + return key; > + > +reject: > + key_put(key); > + return ERR_PTR(-EKEYREJECTED); > +} > +EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); > + > +/* > + * Check the new certificate against the ones in the trust keyring. If one of > + * those is the signing key and validates the new certificate, then mark the > + * new certificate as being trusted. > + * > + * Return 0 if the new certificate was successfully validated, 1 if we couldn't > + * find a matching parent certificate in the trusted list and an error if there > + * is a matching certificate but the signature check fails. > + */ > +int x509_validate_trust(struct x509_certificate *cert, > + struct key *trust_keyring) > +{ > + struct public_key_signature *sig = cert->sig; > + struct key *key; > + int ret = 1; > + > + if (!sig->auth_ids[0] && !sig->auth_ids[1]) > + return 1; > + > + if (!trust_keyring) > + return -EOPNOTSUPP; > + if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) > + return -EPERM; > + if (cert->unsupported_sig) > + return -ENOPKG; > + > + key = x509_request_asymmetric_key(trust_keyring, > + sig->auth_ids[0], sig->auth_ids[1], > + false); > + if (IS_ERR(key)) > + return PTR_ERR(key); > + > + if (!use_builtin_keys || > + test_bit(KEY_FLAG_BUILTIN, &key->flags)) { > + ret = public_key_verify_signature( > + key->payload.data[asym_crypto], cert->sig); > + if (ret == -ENOPKG) > + cert->unsupported_sig = true; > + } > + key_put(key); > + return ret; > +} > diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h > index e373e7483812..0cf670b196c8 100644 > --- a/crypto/asymmetric_keys/x509_parser.h > +++ b/crypto/asymmetric_keys/x509_parser.h > @@ -59,3 +59,9 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen, > */ > extern int x509_get_sig_params(struct x509_certificate *cert); > extern int x509_check_for_self_signed(struct x509_certificate *cert); > + > +/* > + * public_key_trust.c > + */ > +extern int x509_validate_trust(struct x509_certificate *cert, > + struct key *trust_keyring); > diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c > index 00aef0d121b2..7397edb6cefb 100644 > --- a/crypto/asymmetric_keys/x509_public_key.c > +++ b/crypto/asymmetric_keys/x509_public_key.c > @@ -24,133 +24,6 @@ > #include "public_key.h" > #include "x509_parser.h" > > -static bool use_builtin_keys; > -static struct asymmetric_key_id *ca_keyid; > - > -#ifndef MODULE > -static struct { > - struct asymmetric_key_id id; > - unsigned char data[10]; > -} cakey; > - > -static int __init ca_keys_setup(char *str) > -{ > - if (!str) /* default system keyring */ > - return 1; > - > - if (strncmp(str, "id:", 3) == 0) { > - struct asymmetric_key_id *p = &cakey.id; > - size_t hexlen = (strlen(str) - 3) / 2; > - int ret; > - > - if (hexlen == 0 || hexlen > sizeof(cakey.data)) { > - pr_err("Missing or invalid ca_keys id\n"); > - return 1; > - } > - > - ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); > - if (ret < 0) > - pr_err("Unparsable ca_keys id hex string\n"); > - else > - ca_keyid = p; /* owner key 'id:xxxxxx' */ > - } else if (strcmp(str, "builtin") == 0) { > - use_builtin_keys = true; > - } > - > - return 1; > -} > -__setup("ca_keys=", ca_keys_setup); > -#endif > - > -/** > - * x509_request_asymmetric_key - Request a key by X.509 certificate params. > - * @keyring: The keys to search. > - * @id: The issuer & serialNumber to look for or NULL. > - * @skid: The subjectKeyIdentifier to look for or NULL. > - * @partial: Use partial match if true, exact if false. > - * > - * Find a key in the given keyring by identifier. The preferred identifier is > - * the issuer + serialNumber and the fallback identifier is the > - * subjectKeyIdentifier. If both are given, the lookup is by the former, but > - * the latter must also match. > - */ > -struct key *x509_request_asymmetric_key(struct key *keyring, > - const struct asymmetric_key_id *id, > - const struct asymmetric_key_id *skid, > - bool partial) > -{ > - struct key *key; > - key_ref_t ref; > - const char *lookup; > - char *req, *p; > - int len; > - > - if (id) { > - lookup = id->data; > - len = id->len; > - } else { > - lookup = skid->data; > - len = skid->len; > - } > - > - /* Construct an identifier "id:<keyid>". */ > - p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); > - if (!req) > - return ERR_PTR(-ENOMEM); > - > - if (partial) { > - *p++ = 'i'; > - *p++ = 'd'; > - } else { > - *p++ = 'e'; > - *p++ = 'x'; > - } > - *p++ = ':'; > - p = bin2hex(p, lookup, len); > - *p = 0; > - > - pr_debug("Look up: \"%s\"\n", req); > - > - ref = keyring_search(make_key_ref(keyring, 1), > - &key_type_asymmetric, req); > - if (IS_ERR(ref)) > - pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); > - kfree(req); > - > - if (IS_ERR(ref)) { > - switch (PTR_ERR(ref)) { > - /* Hide some search errors */ > - case -EACCES: > - case -ENOTDIR: > - case -EAGAIN: > - return ERR_PTR(-ENOKEY); > - default: > - return ERR_CAST(ref); > - } > - } > - > - key = key_ref_to_ptr(ref); > - if (id && skid) { > - const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); > - if (!kids->id[1]) { > - pr_debug("issuer+serial match, but expected SKID missing\n"); > - goto reject; > - } > - if (!asymmetric_key_id_same(skid, kids->id[1])) { > - pr_debug("issuer+serial match, but SKID does not\n"); > - goto reject; > - } > - } > - > - pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); > - return key; > - > -reject: > - key_put(key); > - return ERR_PTR(-EKEYREJECTED); > -} > -EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); > - > /* > * Set up the signature parameters in an X.509 certificate. This involves > * digesting the signed data and extracting the signature. > @@ -294,49 +167,6 @@ not_self_signed: > } > > /* > - * Check the new certificate against the ones in the trust keyring. If one of > - * those is the signing key and validates the new certificate, then mark the > - * new certificate as being trusted. > - * > - * Return 0 if the new certificate was successfully validated, 1 if we couldn't > - * find a matching parent certificate in the trusted list and an error if there > - * is a matching certificate but the signature check fails. > - */ > -static int x509_validate_trust(struct x509_certificate *cert, > - struct key *trust_keyring) > -{ > - struct public_key_signature *sig = cert->sig; > - struct key *key; > - int ret = 1; > - > - if (!sig->auth_ids[0] && !sig->auth_ids[1]) > - return 1; > - > - if (!trust_keyring) > - return -EOPNOTSUPP; > - if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) > - return -EPERM; > - if (cert->unsupported_sig) > - return -ENOPKG; > - > - key = x509_request_asymmetric_key(trust_keyring, > - sig->auth_ids[0], sig->auth_ids[1], > - false); > - if (IS_ERR(key)) > - return PTR_ERR(key); > - > - if (!use_builtin_keys || > - test_bit(KEY_FLAG_BUILTIN, &key->flags)) { > - ret = public_key_verify_signature( > - key->payload.data[asym_crypto], cert->sig); > - if (ret == -ENOPKG) > - cert->unsupported_sig = true; > - } > - key_put(key); > - return ret; > -} > - > -/* > * Attempt to parse a data blob for a key as an X509 certificate. > */ > static int x509_key_preparse(struct key_preparsed_payload *prep)
| |