lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 08 Feb 2016 06:59:41 -0500
From:	Mimi Zohar <zohar@...ux.vnet.ibm.com>
To:	David Howells <dhowells@...hat.com>
Cc:	linux-security-module@...r.kernel.org, keyrings@...r.kernel.org,
	petkan@...-labs.com, linux-kernel@...r.kernel.org
Subject: Re: [RFC PATCH 13/20] X.509: Move the trust validation code out to
 its own file [ver #2]

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@...hat.com>

Reviewed-by:  Mimi Zohar <zohar@...ux.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@...hat.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)


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ