From: Mimi Zohar <zohar@linux.vnet.ibm.com>
To: David Howells <dhowells@redhat.com>
Cc: linux-security-module@vger.kernel.org, keyrings@vger.kernel.org,
petkan@mip-labs.com, linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file [ver #2]
Date: Mon, 08 Feb 2016 06:59:41 -0500 [thread overview]
Message-ID: <1454932781.2648.144.camel@linux.vnet.ibm.com> (raw)
In-Reply-To: <20160119113203.23238.71230.stgit@warthog.procyon.org.uk>
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)
next prev parent reply other threads:[~2016-02-08 12:00 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-19 11:30 [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2] David Howells
2016-01-19 11:30 ` [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key " David Howells
2016-01-20 18:58 ` Mimi Zohar
2016-02-03 15:30 ` David Howells
2016-01-19 11:30 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring " David Howells
2016-01-20 19:31 ` Mimi Zohar
2016-02-03 15:27 ` David Howells
2016-02-08 13:34 ` Mimi Zohar
2016-02-08 13:55 ` David Howells
2016-02-08 15:03 ` Mimi Zohar
2016-02-08 15:53 ` How to add additional blacklist entries? David Howells
2016-02-08 16:32 ` Mimi Zohar
2016-02-08 16:43 ` David Howells
2016-02-08 19:28 ` Mimi Zohar
2016-02-09 10:42 ` David Howells
2016-02-10 14:07 ` Mimi Zohar
2016-02-08 14:55 ` [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells
2016-02-08 16:39 ` Mimi Zohar
2016-02-19 11:48 ` David Howells
2016-01-20 20:26 ` Mimi Zohar
2016-02-03 15:29 ` David Howells
2016-01-19 11:30 ` [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted " David Howells
2016-01-20 20:33 ` Mimi Zohar
2016-02-03 15:46 ` David Howells
2016-02-05 16:16 ` Mimi Zohar
2016-01-19 11:30 ` [RFC PATCH 04/20] X.509: Don't treat self-signed keys specially " David Howells
2016-01-20 20:40 ` Mimi Zohar
2016-01-19 11:31 ` [RFC PATCH 05/20] KEYS: Generalise system_verify_data() to provide access to internal content " David Howells
2016-01-19 11:31 ` [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring " David Howells
2016-01-19 11:31 ` [RFC PATCH 07/20] KEYS: Add a facility to restrict new links into a " David Howells
2016-02-08 11:59 ` Mimi Zohar
2016-02-29 15:49 ` David Howells
2016-01-19 11:31 ` [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key " David Howells
2016-01-19 11:31 ` [RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct " David Howells
2016-01-19 11:31 ` [RFC PATCH 10/20] X.509: Retain the key verification data " David Howells
2016-01-19 11:31 ` [RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier " David Howells
2016-01-19 11:31 ` [RFC PATCH 12/20] PKCS#7: Make the signature a pointer rather than embedding it " David Howells
2016-02-08 12:00 ` Mimi Zohar
2016-02-19 11:56 ` David Howells
2016-01-19 11:32 ` [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file " David Howells
2016-02-08 11:59 ` Mimi Zohar [this message]
2016-01-19 11:32 ` [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() " David Howells
2016-02-08 11:59 ` Mimi Zohar
2016-01-19 11:32 ` [RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() " David Howells
2016-01-19 11:32 ` [RFC PATCH 16/20] KEYS: Remove KEY_FLAG_TRUSTED and KEY_ALLOC_TRUSTED " David Howells
2016-01-19 11:32 ` [RFC PATCH 17/20] PKCS#7: Handle blacklisted certificates " David Howells
2016-01-19 11:32 ` [RFC PATCH 18/20] IMA: Use the system blacklist keyring " David Howells
2016-02-10 19:12 ` Mimi Zohar
2016-02-19 11:58 ` David Howells
2016-02-19 12:16 ` Mimi Zohar
2016-01-19 11:32 ` [RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically " David Howells
2016-01-19 11:32 ` [RFC PATCH 20/20] IMA: Replace the .ima_mok keyring with the secondary system keyring " David Howells
2016-01-20 17:24 ` [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings " Petko Manolov
2016-02-03 15:47 ` David Howells
2016-01-20 18:57 ` Mimi Zohar
2016-02-03 15:56 ` David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1454932781.2648.144.camel@linux.vnet.ibm.com \
--to=zohar@linux.vnet.ibm.com \
--cc=dhowells@redhat.com \
--cc=keyrings@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=petkan@mip-labs.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.