Browse Source

Merge tag 'keys-next-20140922' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into next

James Morris 11 years ago
parent
commit
35e1efd25a

+ 52 - 13
Documentation/security/keys.txt

@@ -888,11 +888,11 @@ payload contents" for more information.
 				const char *callout_info);
 				const char *callout_info);
 
 
     This is used to request a key or keyring with a description that matches
     This is used to request a key or keyring with a description that matches
-    the description specified according to the key type's match function. This
-    permits approximate matching to occur. If callout_string is not NULL, then
-    /sbin/request-key will be invoked in an attempt to obtain the key from
-    userspace. In that case, callout_string will be passed as an argument to
-    the program.
+    the description specified according to the key type's match_preparse()
+    method. This permits approximate matching to occur. If callout_string is
+    not NULL, then /sbin/request-key will be invoked in an attempt to obtain
+    the key from userspace. In that case, callout_string will be passed as an
+    argument to the program.
 
 
     Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
     Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
     returned.
     returned.
@@ -1170,7 +1170,7 @@ The structure has a number of fields, some of which are mandatory:
      The method should return 0 if successful or a negative error code
      The method should return 0 if successful or a negative error code
      otherwise.
      otherwise.
 
 
-     
+
  (*) void (*free_preparse)(struct key_preparsed_payload *prep);
  (*) void (*free_preparse)(struct key_preparsed_payload *prep);
 
 
      This method is only required if the preparse() method is provided,
      This method is only required if the preparse() method is provided,
@@ -1225,16 +1225,55 @@ The structure has a number of fields, some of which are mandatory:
      It is safe to sleep in this method.
      It is safe to sleep in this method.
 
 
 
 
- (*) int (*match)(const struct key *key, const void *desc);
+ (*) int (*match_preparse)(struct key_match_data *match_data);
+
+     This method is optional.  It is called when a key search is about to be
+     performed.  It is given the following structure:
 
 
-     This method is called to match a key against a description. It should
-     return non-zero if the two match, zero if they don't.
+	struct key_match_data {
+		bool (*cmp)(const struct key *key,
+			    const struct key_match_data *match_data);
+		const void	*raw_data;
+		void		*preparsed;
+		unsigned	lookup_type;
+	};
 
 
-     This method should not need to lock the key in any way. The type and
-     description can be considered invariant, and the payload should not be
-     accessed (the key may not yet be instantiated).
+     On entry, raw_data will be pointing to the criteria to be used in matching
+     a key by the caller and should not be modified.  (*cmp)() will be pointing
+     to the default matcher function (which does an exact description match
+     against raw_data) and lookup_type will be set to indicate a direct lookup.
 
 
-     It is not safe to sleep in this method; the caller may hold spinlocks.
+     The following lookup_type values are available:
+
+      [*] KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and
+      	  description to narrow down the search to a small number of keys.
+
+      [*] KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the
+      	  keys in the keyring until one is matched.  This must be used for any
+      	  search that's not doing a simple direct match on the key description.
+
+     The method may set cmp to point to a function of its choice that does some
+     other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE
+     and may attach something to the preparsed pointer for use by (*cmp)().
+     (*cmp)() should return true if a key matches and false otherwise.
+
+     If preparsed is set, it may be necessary to use the match_free() method to
+     clean it up.
+
+     The method should return 0 if successful or a negative error code
+     otherwise.
+
+     It is permitted to sleep in this method, but (*cmp)() may not sleep as
+     locks will be held over it.
+
+     If match_preparse() is not provided, keys of this type will be matched
+     exactly by their description.
+
+
+ (*) void (*match_free)(struct key_match_data *match_data);
+
+     This method is optional.  If given, it called to clean up
+     match_data->preparsed after a successful call to match_preparse().
 
 
 
 
  (*) void (*revoke)(struct key *key);
  (*) void (*revoke)(struct key *key);

+ 6 - 2
crypto/asymmetric_keys/asymmetric_keys.h

@@ -9,9 +9,13 @@
  * 2 of the Licence, or (at your option) any later version.
  * 2 of the Licence, or (at your option) any later version.
  */
  */
 
 
-int asymmetric_keyid_match(const char *kid, const char *id);
+extern bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
+				     const struct asymmetric_key_id *match_id);
 
 
-static inline const char *asymmetric_key_id(const struct key *key)
+extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
+
+static inline
+const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
 {
 {
 	return key->type_data.p[1];
 	return key->type_data.p[1];
 }
 }

+ 160 - 63
crypto/asymmetric_keys/asymmetric_type.c

@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/ctype.h>
 #include "asymmetric_keys.h"
 #include "asymmetric_keys.h"
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
@@ -22,85 +23,166 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(asymmetric_key_parsers);
 static LIST_HEAD(asymmetric_key_parsers);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 
 
-/*
- * Match asymmetric key id with partial match
- * @id:		key id to match in a form "id:<id>"
+/**
+ * asymmetric_key_generate_id: Construct an asymmetric key ID
+ * @val_1: First binary blob
+ * @len_1: Length of first binary blob
+ * @val_2: Second binary blob
+ * @len_2: Length of second binary blob
+ *
+ * Construct an asymmetric key ID from a pair of binary blobs.
+ */
+struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+						     size_t len_1,
+						     const void *val_2,
+						     size_t len_2)
+{
+	struct asymmetric_key_id *kid;
+
+	kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
+		      GFP_KERNEL);
+	if (!kid)
+		return ERR_PTR(-ENOMEM);
+	kid->len = len_1 + len_2;
+	memcpy(kid->data, val_1, len_1);
+	memcpy(kid->data + len_1, val_2, len_2);
+	return kid;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
+
+/**
+ * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
+ * @kid_1, @kid_2: The key IDs to compare
  */
  */
-int asymmetric_keyid_match(const char *kid, const char *id)
+bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+			    const struct asymmetric_key_id *kid2)
 {
 {
-	size_t idlen, kidlen;
+	if (!kid1 || !kid2)
+		return false;
+	if (kid1->len != kid2->len)
+		return false;
+	return memcmp(kid1->data, kid2->data, kid1->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
 
 
-	if (!kid || !id)
-		return 0;
+/**
+ * asymmetric_match_key_ids - Search asymmetric key IDs
+ * @kids: The list of key IDs to check
+ * @match_id: The key ID we're looking for
+ */
+bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
+			      const struct asymmetric_key_id *match_id)
+{
+	if (!kids || !match_id)
+		return false;
+	if (asymmetric_key_id_same(kids->id[0], match_id))
+		return true;
+	if (asymmetric_key_id_same(kids->id[1], match_id))
+		return true;
+	return false;
+}
+EXPORT_SYMBOL_GPL(asymmetric_match_key_ids);
 
 
-	/* make it possible to use id as in the request: "id:<id>" */
-	if (strncmp(id, "id:", 3) == 0)
-		id += 3;
+/**
+ * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
+ * @id: The ID as a hex string.
+ */
+struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
+{
+	struct asymmetric_key_id *match_id;
+	size_t hexlen;
+	int ret;
 
 
-	/* Anything after here requires a partial match on the ID string */
-	idlen = strlen(id);
-	kidlen = strlen(kid);
-	if (idlen > kidlen)
-		return 0;
+	if (!*id)
+		return ERR_PTR(-EINVAL);
+	hexlen = strlen(id);
+	if (hexlen & 1)
+		return ERR_PTR(-EINVAL);
+
+	match_id = kmalloc(sizeof(struct asymmetric_key_id) + hexlen / 2,
+			   GFP_KERNEL);
+	if (!match_id)
+		return ERR_PTR(-ENOMEM);
+	match_id->len = hexlen / 2;
+	ret = hex2bin(match_id->data, id, hexlen / 2);
+	if (ret < 0) {
+		kfree(match_id);
+		return ERR_PTR(-EINVAL);
+	}
+	return match_id;
+}
 
 
-	kid += kidlen - idlen;
-	if (strcasecmp(id, kid) != 0)
-		return 0;
+/*
+ * Match asymmetric keys by ID.
+ */
+static bool asymmetric_key_cmp(const struct key *key,
+			       const struct key_match_data *match_data)
+{
+	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+	const struct asymmetric_key_id *match_id = match_data->preparsed;
 
 
-	return 1;
+	return asymmetric_match_key_ids(kids, match_id);
 }
 }
-EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
 
 
 /*
 /*
- * Match asymmetric keys on (part of) their name
- * We have some shorthand methods for matching keys.  We allow:
+ * Preparse the match criterion.  If we don't set lookup_type and cmp,
+ * the default will be an exact match on the key description.
+ *
+ * There are some specifiers for matching key IDs rather than by the key
+ * description:
  *
  *
- *	"<desc>"	- request a key by description
- *	"id:<id>"	- request a key matching the ID
- *	"<subtype>:<id>" - request a key of a subtype
+ *	"id:<id>" - request a key by any available ID
+ *
+ * These have to be searched by iteration rather than by direct lookup because
+ * the key is hashed according to its description.
  */
  */
-static int asymmetric_key_match(const struct key *key, const void *description)
+static int asymmetric_key_match_preparse(struct key_match_data *match_data)
 {
 {
-	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
-	const char *spec = description;
+	struct asymmetric_key_id *match_id;
+	const char *spec = match_data->raw_data;
 	const char *id;
 	const char *id;
-	ptrdiff_t speclen;
 
 
-	if (!subtype || !spec || !*spec)
-		return 0;
-
-	/* See if the full key description matches as is */
-	if (key->description && strcmp(key->description, description) == 0)
-		return 1;
-
-	/* All tests from here on break the criterion description into a
-	 * specifier, a colon and then an identifier.
-	 */
-	id = strchr(spec, ':');
-	if (!id)
-		return 0;
-
-	speclen = id - spec;
-	id++;
+	if (!spec || !*spec)
+		return -EINVAL;
+	if (spec[0] == 'i' &&
+	    spec[1] == 'd' &&
+	    spec[2] == ':') {
+		id = spec + 3;
+	} else {
+		goto default_match;
+	}
 
 
-	if (speclen == 2 && memcmp(spec, "id", 2) == 0)
-		return asymmetric_keyid_match(asymmetric_key_id(key), id);
+	match_id = asymmetric_key_hex_to_key_id(id);
+	if (!match_id)
+		return -ENOMEM;
 
 
-	if (speclen == subtype->name_len &&
-	    memcmp(spec, subtype->name, speclen) == 0)
-		return 1;
+	match_data->preparsed = match_id;
+	match_data->cmp = asymmetric_key_cmp;
+	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+	return 0;
 
 
+default_match:
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Free the preparsed the match criterion.
+ */
+static void asymmetric_key_match_free(struct key_match_data *match_data)
+{
+	kfree(match_data->preparsed);
+}
+
 /*
 /*
  * Describe the asymmetric key
  * Describe the asymmetric key
  */
  */
 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
 {
 {
 	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
 	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
-	const char *kid = asymmetric_key_id(key);
-	size_t n;
+	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+	const struct asymmetric_key_id *kid;
+	const unsigned char *p;
+	int n;
 
 
 	seq_puts(m, key->description);
 	seq_puts(m, key->description);
 
 
@@ -108,13 +190,16 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
 		seq_puts(m, ": ");
 		seq_puts(m, ": ");
 		subtype->describe(key, m);
 		subtype->describe(key, m);
 
 
-		if (kid) {
+		if (kids && kids->id[0]) {
+			kid = kids->id[0];
 			seq_putc(m, ' ');
 			seq_putc(m, ' ');
-			n = strlen(kid);
-			if (n <= 8)
-				seq_puts(m, kid);
-			else
-				seq_puts(m, kid + n - 8);
+			n = kid->len;
+			p = kid->data;
+			if (n > 8) {
+				p += n - 8;
+				n = 8;
+			}
+			seq_printf(m, "%*phN", n, p);
 		}
 		}
 
 
 		seq_puts(m, " [");
 		seq_puts(m, " [");
@@ -165,6 +250,7 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 {
 {
 	struct asymmetric_key_subtype *subtype = prep->type_data[0];
 	struct asymmetric_key_subtype *subtype = prep->type_data[0];
+	struct asymmetric_key_ids *kids = prep->type_data[1];
 
 
 	pr_devel("==>%s()\n", __func__);
 	pr_devel("==>%s()\n", __func__);
 
 
@@ -172,7 +258,11 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 		subtype->destroy(prep->payload[0]);
 		subtype->destroy(prep->payload[0]);
 		module_put(subtype->owner);
 		module_put(subtype->owner);
 	}
 	}
-	kfree(prep->type_data[1]);
+	if (kids) {
+		kfree(kids->id[0]);
+		kfree(kids->id[1]);
+		kfree(kids);
+	}
 	kfree(prep->description);
 	kfree(prep->description);
 }
 }
 
 
@@ -182,13 +272,20 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_destroy(struct key *key)
 static void asymmetric_key_destroy(struct key *key)
 {
 {
 	struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
 	struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+	struct asymmetric_key_ids *kids = key->type_data.p[1];
+
 	if (subtype) {
 	if (subtype) {
 		subtype->destroy(key->payload.data);
 		subtype->destroy(key->payload.data);
 		module_put(subtype->owner);
 		module_put(subtype->owner);
 		key->type_data.p[0] = NULL;
 		key->type_data.p[0] = NULL;
 	}
 	}
-	kfree(key->type_data.p[1]);
-	key->type_data.p[1] = NULL;
+
+	if (kids) {
+		kfree(kids->id[0]);
+		kfree(kids->id[1]);
+		kfree(kids);
+		key->type_data.p[1] = NULL;
+	}
 }
 }
 
 
 struct key_type key_type_asymmetric = {
 struct key_type key_type_asymmetric = {
@@ -196,10 +293,10 @@ struct key_type key_type_asymmetric = {
 	.preparse	= asymmetric_key_preparse,
 	.preparse	= asymmetric_key_preparse,
 	.free_preparse	= asymmetric_key_free_preparse,
 	.free_preparse	= asymmetric_key_free_preparse,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= asymmetric_key_match,
+	.match_preparse	= asymmetric_key_match_preparse,
+	.match_free	= asymmetric_key_match_free,
 	.destroy	= asymmetric_key_destroy,
 	.destroy	= asymmetric_key_destroy,
 	.describe	= asymmetric_key_describe,
 	.describe	= asymmetric_key_describe,
-	.def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
 };
 };
 EXPORT_SYMBOL_GPL(key_type_asymmetric);
 EXPORT_SYMBOL_GPL(key_type_asymmetric);
 
 

+ 0 - 2
crypto/asymmetric_keys/pkcs7_key_type.c

@@ -72,11 +72,9 @@ error:
  */
  */
 static struct key_type key_type_pkcs7 = {
 static struct key_type key_type_pkcs7 = {
 	.name			= "pkcs7_test",
 	.name			= "pkcs7_test",
-	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.preparse		= pkcs7_preparse,
 	.preparse		= pkcs7_preparse,
 	.free_preparse		= user_free_preparse,
 	.free_preparse		= user_free_preparse,
 	.instantiate		= generic_key_instantiate,
 	.instantiate		= generic_key_instantiate,
-	.match			= user_match,
 	.revoke			= user_revoke,
 	.revoke			= user_revoke,
 	.destroy		= user_destroy,
 	.destroy		= user_destroy,
 	.describe		= user_describe,
 	.describe		= user_describe,

+ 60 - 39
crypto/asymmetric_keys/pkcs7_parser.c

@@ -29,8 +29,25 @@ struct pkcs7_parse_context {
 	enum OID	last_oid;		/* Last OID encountered */
 	enum OID	last_oid;		/* Last OID encountered */
 	unsigned	x509_index;
 	unsigned	x509_index;
 	unsigned	sinfo_index;
 	unsigned	sinfo_index;
+	const void	*raw_serial;
+	unsigned	raw_serial_size;
+	unsigned	raw_issuer_size;
+	const void	*raw_issuer;
 };
 };
 
 
+/*
+ * Free a signed information block.
+ */
+static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
+{
+	if (sinfo) {
+		mpi_free(sinfo->sig.mpi[0]);
+		kfree(sinfo->sig.digest);
+		kfree(sinfo->signing_cert_id);
+		kfree(sinfo);
+	}
+}
+
 /**
 /**
  * pkcs7_free_message - Free a PKCS#7 message
  * pkcs7_free_message - Free a PKCS#7 message
  * @pkcs7: The PKCS#7 message to free
  * @pkcs7: The PKCS#7 message to free
@@ -54,9 +71,7 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7)
 		while (pkcs7->signed_infos) {
 		while (pkcs7->signed_infos) {
 			sinfo = pkcs7->signed_infos;
 			sinfo = pkcs7->signed_infos;
 			pkcs7->signed_infos = sinfo->next;
 			pkcs7->signed_infos = sinfo->next;
-			mpi_free(sinfo->sig.mpi[0]);
-			kfree(sinfo->sig.digest);
-			kfree(sinfo);
+			pkcs7_free_signed_info(sinfo);
 		}
 		}
 		kfree(pkcs7);
 		kfree(pkcs7);
 	}
 	}
@@ -71,51 +86,46 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message);
 struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
 struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
 {
 {
 	struct pkcs7_parse_context *ctx;
 	struct pkcs7_parse_context *ctx;
-	struct pkcs7_message *msg;
-	long ret;
+	struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
+	int ret;
 
 
-	ret = -ENOMEM;
-	msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
-	if (!msg)
-		goto error_no_sig;
 	ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
 	ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
 	if (!ctx)
 	if (!ctx)
-		goto error_no_ctx;
+		goto out_no_ctx;
+	ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
+	if (!ctx->msg)
+		goto out_no_msg;
 	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 	if (!ctx->sinfo)
 	if (!ctx->sinfo)
-		goto error_no_sinfo;
+		goto out_no_sinfo;
 
 
-	ctx->msg = msg;
 	ctx->data = (unsigned long)data;
 	ctx->data = (unsigned long)data;
 	ctx->ppcerts = &ctx->certs;
 	ctx->ppcerts = &ctx->certs;
 	ctx->ppsinfo = &ctx->msg->signed_infos;
 	ctx->ppsinfo = &ctx->msg->signed_infos;
 
 
 	/* Attempt to decode the signature */
 	/* Attempt to decode the signature */
 	ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
 	ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
-	if (ret < 0)
-		goto error_decode;
+	if (ret < 0) {
+		msg = ERR_PTR(ret);
+		goto out;
+	}
 
 
+	msg = ctx->msg;
+	ctx->msg = NULL;
+
+out:
 	while (ctx->certs) {
 	while (ctx->certs) {
 		struct x509_certificate *cert = ctx->certs;
 		struct x509_certificate *cert = ctx->certs;
 		ctx->certs = cert->next;
 		ctx->certs = cert->next;
 		x509_free_certificate(cert);
 		x509_free_certificate(cert);
 	}
 	}
-	mpi_free(ctx->sinfo->sig.mpi[0]);
-	kfree(ctx->sinfo->sig.digest);
-	kfree(ctx->sinfo);
+	pkcs7_free_signed_info(ctx->sinfo);
+out_no_sinfo:
+	pkcs7_free_message(ctx->msg);
+out_no_msg:
 	kfree(ctx);
 	kfree(ctx);
+out_no_ctx:
 	return msg;
 	return msg;
-
-error_decode:
-	mpi_free(ctx->sinfo->sig.mpi[0]);
-	kfree(ctx->sinfo->sig.digest);
-	kfree(ctx->sinfo);
-error_no_sinfo:
-	kfree(ctx);
-error_no_ctx:
-	pkcs7_free_message(msg);
-error_no_sig:
-	return ERR_PTR(ret);
 }
 }
 EXPORT_SYMBOL_GPL(pkcs7_parse_message);
 EXPORT_SYMBOL_GPL(pkcs7_parse_message);
 
 
@@ -246,10 +256,10 @@ int pkcs7_extract_cert(void *context, size_t hdrlen,
 	if (IS_ERR(x509))
 	if (IS_ERR(x509))
 		return PTR_ERR(x509);
 		return PTR_ERR(x509);
 
 
-	pr_debug("Got cert for %s\n", x509->subject);
-	pr_debug("- fingerprint %s\n", x509->fingerprint);
-
 	x509->index = ++ctx->x509_index;
 	x509->index = ++ctx->x509_index;
+	pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
+	pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
+
 	*ctx->ppcerts = x509;
 	*ctx->ppcerts = x509;
 	ctx->ppcerts = &x509->next;
 	ctx->ppcerts = &x509->next;
 	return 0;
 	return 0;
@@ -338,8 +348,8 @@ int pkcs7_sig_note_serial(void *context, size_t hdrlen,
 			  const void *value, size_t vlen)
 			  const void *value, size_t vlen)
 {
 {
 	struct pkcs7_parse_context *ctx = context;
 	struct pkcs7_parse_context *ctx = context;
-	ctx->sinfo->raw_serial = value;
-	ctx->sinfo->raw_serial_size = vlen;
+	ctx->raw_serial = value;
+	ctx->raw_serial_size = vlen;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -351,8 +361,8 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
 			  const void *value, size_t vlen)
 			  const void *value, size_t vlen)
 {
 {
 	struct pkcs7_parse_context *ctx = context;
 	struct pkcs7_parse_context *ctx = context;
-	ctx->sinfo->raw_issuer = value;
-	ctx->sinfo->raw_issuer_size = vlen;
+	ctx->raw_issuer = value;
+	ctx->raw_issuer_size = vlen;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -385,10 +395,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
 			   const void *value, size_t vlen)
 			   const void *value, size_t vlen)
 {
 {
 	struct pkcs7_parse_context *ctx = context;
 	struct pkcs7_parse_context *ctx = context;
-
-	ctx->sinfo->index = ++ctx->sinfo_index;
-	*ctx->ppsinfo = ctx->sinfo;
-	ctx->ppsinfo = &ctx->sinfo->next;
+	struct pkcs7_signed_info *sinfo = ctx->sinfo;
+	struct asymmetric_key_id *kid;
+
+	/* Generate cert issuer + serial number key ID */
+	kid = asymmetric_key_generate_id(ctx->raw_serial,
+					 ctx->raw_serial_size,
+					 ctx->raw_issuer,
+					 ctx->raw_issuer_size);
+	if (IS_ERR(kid))
+		return PTR_ERR(kid);
+
+	sinfo->signing_cert_id = kid;
+	sinfo->index = ++ctx->sinfo_index;
+	*ctx->ppsinfo = sinfo;
+	ctx->ppsinfo = &sinfo->next;
 	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 	if (!ctx->sinfo)
 	if (!ctx->sinfo)
 		return -ENOMEM;
 		return -ENOMEM;

+ 2 - 4
crypto/asymmetric_keys/pkcs7_parser.h

@@ -23,6 +23,7 @@ struct pkcs7_signed_info {
 	struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
 	struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
 	unsigned index;
 	unsigned index;
 	bool trusted;
 	bool trusted;
+	bool unsupported_crypto;	/* T if not usable due to missing crypto */
 
 
 	/* Message digest - the digest of the Content Data (or NULL) */
 	/* Message digest - the digest of the Content Data (or NULL) */
 	const void	*msgdigest;
 	const void	*msgdigest;
@@ -33,10 +34,7 @@ struct pkcs7_signed_info {
 	const void	*authattrs;
 	const void	*authattrs;
 
 
 	/* Issuing cert serial number and issuer's name */
 	/* Issuing cert serial number and issuer's name */
-	const void	*raw_serial;
-	unsigned	raw_serial_size;
-	unsigned	raw_issuer_size;
-	const void	*raw_issuer;
+	struct asymmetric_key_id *signing_cert_id;
 
 
 	/* Message signature.
 	/* Message signature.
 	 *
 	 *

+ 59 - 28
crypto/asymmetric_keys/pkcs7_trust.c

@@ -23,9 +23,9 @@
 /**
 /**
  * Check the trust on one PKCS#7 SignedInfo block.
  * Check the trust on one PKCS#7 SignedInfo block.
  */
  */
-int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
-			     struct pkcs7_signed_info *sinfo,
-			     struct key *trust_keyring)
+static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
+				    struct pkcs7_signed_info *sinfo,
+				    struct key *trust_keyring)
 {
 {
 	struct public_key_signature *sig = &sinfo->sig;
 	struct public_key_signature *sig = &sinfo->sig;
 	struct x509_certificate *x509, *last = NULL, *p;
 	struct x509_certificate *x509, *last = NULL, *p;
@@ -35,6 +35,11 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 
 	kenter(",%u,", sinfo->index);
 	kenter(",%u,", sinfo->index);
 
 
+	if (sinfo->unsupported_crypto) {
+		kleave(" = -ENOPKG [cached]");
+		return -ENOPKG;
+	}
+
 	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
 	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
 		if (x509->seen) {
 		if (x509->seen) {
 			if (x509->verified) {
 			if (x509->verified) {
@@ -49,15 +54,17 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 		/* Look to see if this certificate is present in the trusted
 		/* Look to see if this certificate is present in the trusted
 		 * keys.
 		 * keys.
 		 */
 		 */
-		key = x509_request_asymmetric_key(trust_keyring, x509->subject,
-						  x509->fingerprint);
-		if (!IS_ERR(key))
+		key = x509_request_asymmetric_key(trust_keyring, x509->id);
+		if (!IS_ERR(key)) {
 			/* One of the X.509 certificates in the PKCS#7 message
 			/* One of the X.509 certificates in the PKCS#7 message
 			 * is apparently the same as one we already trust.
 			 * is apparently the same as one we already trust.
 			 * Verify that the trusted variant can also validate
 			 * Verify that the trusted variant can also validate
 			 * the signature on the descendant.
 			 * the signature on the descendant.
 			 */
 			 */
+			pr_devel("sinfo %u: Cert %u as key %x\n",
+				 sinfo->index, x509->index, key_serial(key));
 			goto matched;
 			goto matched;
+		}
 		if (key == ERR_PTR(-ENOMEM))
 		if (key == ERR_PTR(-ENOMEM))
 			return -ENOMEM;
 			return -ENOMEM;
 
 
@@ -77,16 +84,34 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	/* No match - see if the root certificate has a signer amongst the
 	/* No match - see if the root certificate has a signer amongst the
 	 * trusted keys.
 	 * trusted keys.
 	 */
 	 */
-	if (!last || !last->issuer || !last->authority) {
-		kleave(" = -ENOKEY [no backref]");
-		return -ENOKEY;
+	if (last && last->authority) {
+		key = x509_request_asymmetric_key(trust_keyring, last->authority);
+		if (!IS_ERR(key)) {
+			x509 = last;
+			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
+				 sinfo->index, x509->index, key_serial(key));
+			goto matched;
+		}
+		if (PTR_ERR(key) != -ENOKEY)
+			return PTR_ERR(key);
+	}
+
+	/* As a last resort, see if we have a trusted public key that matches
+	 * the signed info directly.
+	 */
+	key = x509_request_asymmetric_key(trust_keyring,
+					  sinfo->signing_cert_id);
+	if (!IS_ERR(key)) {
+		pr_devel("sinfo %u: Direct signer is key %x\n",
+			 sinfo->index, key_serial(key));
+		x509 = NULL;
+		goto matched;
 	}
 	}
+	if (PTR_ERR(key) != -ENOKEY)
+		return PTR_ERR(key);
 
 
-	key = x509_request_asymmetric_key(trust_keyring, last->issuer,
-					  last->authority);
-	if (IS_ERR(key))
-		return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
-	x509 = last;
+	kleave(" = -ENOKEY [no backref]");
+	return -ENOKEY;
 
 
 matched:
 matched:
 	ret = verify_signature(key, sig);
 	ret = verify_signature(key, sig);
@@ -100,10 +125,12 @@ matched:
 	}
 	}
 
 
 verified:
 verified:
-	x509->verified = true;
-	for (p = sinfo->signer; p != x509; p = p->signer) {
-		p->verified = true;
-		p->trusted = trusted;
+	if (x509) {
+		x509->verified = true;
+		for (p = sinfo->signer; p != x509; p = p->signer) {
+			p->verified = true;
+			p->trusted = trusted;
+		}
 	}
 	}
 	sinfo->trusted = trusted;
 	sinfo->trusted = trusted;
 	kleave(" = 0");
 	kleave(" = 0");
@@ -141,24 +168,28 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
 {
 {
 	struct pkcs7_signed_info *sinfo;
 	struct pkcs7_signed_info *sinfo;
 	struct x509_certificate *p;
 	struct x509_certificate *p;
-	int cached_ret = 0, ret;
+	int cached_ret = -ENOKEY;
+	int ret;
 
 
 	for (p = pkcs7->certs; p; p = p->next)
 	for (p = pkcs7->certs; p; p = p->next)
 		p->seen = false;
 		p->seen = false;
 
 
 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
 		ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
 		ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
-		if (ret < 0) {
-			if (ret == -ENOPKG) {
+		switch (ret) {
+		case -ENOKEY:
+			continue;
+		case -ENOPKG:
+			if (cached_ret == -ENOKEY)
 				cached_ret = -ENOPKG;
 				cached_ret = -ENOPKG;
-			} else if (ret == -ENOKEY) {
-				if (cached_ret == 0)
-					cached_ret = -ENOKEY;
-			} else {
-				return ret;
-			}
+			continue;
+		case 0:
+			*_trusted |= sinfo->trusted;
+			cached_ret = 0;
+			continue;
+		default:
+			return ret;
 		}
 		}
-		*_trusted |= sinfo->trusted;
 	}
 	}
 
 
 	return cached_ret;
 	return cached_ret;

+ 71 - 31
crypto/asymmetric_keys/pkcs7_verify.c

@@ -131,8 +131,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 	struct x509_certificate *x509;
 	struct x509_certificate *x509;
 	unsigned certix = 1;
 	unsigned certix = 1;
 
 
-	kenter("%u,%u,%u",
-	       sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
+	kenter("%u", sinfo->index);
 
 
 	for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
 	for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
 		/* I'm _assuming_ that the generator of the PKCS#7 message will
 		/* I'm _assuming_ that the generator of the PKCS#7 message will
@@ -140,21 +139,11 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 		 * PKCS#7 message - but I can't be 100% sure of that.  It's
 		 * PKCS#7 message - but I can't be 100% sure of that.  It's
 		 * possible this will need element-by-element comparison.
 		 * possible this will need element-by-element comparison.
 		 */
 		 */
-		if (x509->raw_serial_size != sinfo->raw_serial_size ||
-		    memcmp(x509->raw_serial, sinfo->raw_serial,
-			   sinfo->raw_serial_size) != 0)
+		if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
 			continue;
 			continue;
 		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
 		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
 			 sinfo->index, certix);
 			 sinfo->index, certix);
 
 
-		if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
-		    memcmp(x509->raw_issuer, sinfo->raw_issuer,
-			   sinfo->raw_issuer_size) != 0) {
-			pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
-				sinfo->index);
-			continue;
-		}
-
 		if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
 		if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
 			pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
 			pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
 				sinfo->index);
 				sinfo->index);
@@ -164,9 +153,14 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 		sinfo->signer = x509;
 		sinfo->signer = x509;
 		return 0;
 		return 0;
 	}
 	}
-	pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
-		sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
-	return -ENOKEY;
+
+	/* The relevant X.509 cert isn't found here, but it might be found in
+	 * the trust keyring.
+	 */
+	pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
+		 sinfo->index,
+		 sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
+	return 0;
 }
 }
 
 
 /*
 /*
@@ -184,15 +178,18 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		p->seen = false;
 		p->seen = false;
 
 
 	for (;;) {
 	for (;;) {
-		pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
+		pr_debug("verify %s: %*phN\n",
+			 x509->subject,
+			 x509->raw_serial_size, x509->raw_serial);
 		x509->seen = true;
 		x509->seen = true;
 		ret = x509_get_sig_params(x509);
 		ret = x509_get_sig_params(x509);
 		if (ret < 0)
 		if (ret < 0)
-			return ret;
+			goto maybe_missing_crypto_in_x509;
 
 
 		pr_debug("- issuer %s\n", x509->issuer);
 		pr_debug("- issuer %s\n", x509->issuer);
 		if (x509->authority)
 		if (x509->authority)
-			pr_debug("- authkeyid %s\n", x509->authority);
+			pr_debug("- authkeyid %*phN\n",
+				 x509->authority->len, x509->authority->data);
 
 
 		if (!x509->authority ||
 		if (!x509->authority ||
 		    strcmp(x509->subject, x509->issuer) == 0) {
 		    strcmp(x509->subject, x509->issuer) == 0) {
@@ -209,7 +206,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 
 
 			ret = x509_check_signature(x509->pub, x509);
 			ret = x509_check_signature(x509->pub, x509);
 			if (ret < 0)
 			if (ret < 0)
-				return ret;
+				goto maybe_missing_crypto_in_x509;
 			x509->signer = x509;
 			x509->signer = x509;
 			pr_debug("- self-signed\n");
 			pr_debug("- self-signed\n");
 			return 0;
 			return 0;
@@ -218,13 +215,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		/* Look through the X.509 certificates in the PKCS#7 message's
 		/* Look through the X.509 certificates in the PKCS#7 message's
 		 * list to see if the next one is there.
 		 * list to see if the next one is there.
 		 */
 		 */
-		pr_debug("- want %s\n", x509->authority);
+		pr_debug("- want %*phN\n",
+			 x509->authority->len, x509->authority->data);
 		for (p = pkcs7->certs; p; p = p->next) {
 		for (p = pkcs7->certs; p; p = p->next) {
-			pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
-			if (p->raw_subject_size == x509->raw_issuer_size &&
-			    strcmp(p->fingerprint, x509->authority) == 0 &&
-			    memcmp(p->raw_subject, x509->raw_issuer,
-				   x509->raw_issuer_size) == 0)
+			if (!p->skid)
+				continue;
+			pr_debug("- cmp [%u] %*phN\n",
+				 p->index, p->skid->len, p->skid->data);
+			if (asymmetric_key_id_same(p->skid, x509->authority))
 				goto found_issuer;
 				goto found_issuer;
 		}
 		}
 
 
@@ -233,7 +231,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		return 0;
 		return 0;
 
 
 	found_issuer:
 	found_issuer:
-		pr_debug("- issuer %s\n", p->subject);
+		pr_debug("- subject %s\n", p->subject);
 		if (p->seen) {
 		if (p->seen) {
 			pr_warn("Sig %u: X.509 chain contains loop\n",
 			pr_warn("Sig %u: X.509 chain contains loop\n",
 				sinfo->index);
 				sinfo->index);
@@ -250,6 +248,17 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		x509 = p;
 		x509 = p;
 		might_sleep();
 		might_sleep();
 	}
 	}
+
+maybe_missing_crypto_in_x509:
+	/* Just prune the certificate chain at this point if we lack some
+	 * crypto module to go further.  Note, however, we don't want to set
+	 * sinfo->missing_crypto as the signed info block may still be
+	 * validatable against an X.509 cert lower in the chain that we have a
+	 * trusted copy of.
+	 */
+	if (ret == -ENOPKG)
+		return 0;
+	return ret;
 }
 }
 
 
 /*
 /*
@@ -269,11 +278,14 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	/* Find the key for the signature */
+	/* Find the key for the signature if there is one */
 	ret = pkcs7_find_key(pkcs7, sinfo);
 	ret = pkcs7_find_key(pkcs7, sinfo);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
+	if (!sinfo->signer)
+		return 0;
+
 	pr_devel("Using X.509[%u] for sig %u\n",
 	pr_devel("Using X.509[%u] for sig %u\n",
 		 sinfo->signer->index, sinfo->index);
 		 sinfo->signer->index, sinfo->index);
 
 
@@ -291,11 +303,33 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 /**
 /**
  * pkcs7_verify - Verify a PKCS#7 message
  * pkcs7_verify - Verify a PKCS#7 message
  * @pkcs7: The PKCS#7 message to be verified
  * @pkcs7: The PKCS#7 message to be verified
+ *
+ * Verify a PKCS#7 message is internally consistent - that is, the data digest
+ * matches the digest in the AuthAttrs and any signature in the message or one
+ * of the X.509 certificates it carries that matches another X.509 cert in the
+ * message can be verified.
+ *
+ * This does not look to match the contents of the PKCS#7 message against any
+ * external public keys.
+ *
+ * Returns, in order of descending priority:
+ *
+ *  (*) -EKEYREJECTED if a signature failed to match for which we found an
+ *	appropriate X.509 certificate, or:
+ *
+ *  (*) -EBADMSG if some part of the message was invalid, or:
+ *
+ *  (*) -ENOPKG if none of the signature chains are verifiable because suitable
+ *	crypto modules couldn't be found, or:
+ *
+ *  (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
+ *	(note that a signature chain may be of zero length), or:
  */
  */
 int pkcs7_verify(struct pkcs7_message *pkcs7)
 int pkcs7_verify(struct pkcs7_message *pkcs7)
 {
 {
 	struct pkcs7_signed_info *sinfo;
 	struct pkcs7_signed_info *sinfo;
 	struct x509_certificate *x509;
 	struct x509_certificate *x509;
+	int enopkg = -ENOPKG;
 	int ret, n;
 	int ret, n;
 
 
 	kenter("");
 	kenter("");
@@ -304,18 +338,24 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
 		ret = x509_get_sig_params(x509);
 		ret = x509_get_sig_params(x509);
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
-		pr_debug("X.509[%u] %s\n", n, x509->authority);
+		pr_debug("X.509[%u] %*phN\n",
+			 n, x509->authority->len, x509->authority->data);
 	}
 	}
 
 
 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
 	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
 		ret = pkcs7_verify_one(pkcs7, sinfo);
 		ret = pkcs7_verify_one(pkcs7, sinfo);
 		if (ret < 0) {
 		if (ret < 0) {
+			if (ret == -ENOPKG) {
+				sinfo->unsupported_crypto = true;
+				continue;
+			}
 			kleave(" = %d", ret);
 			kleave(" = %d", ret);
 			return ret;
 			return ret;
 		}
 		}
+		enopkg = 0;
 	}
 	}
 
 
-	kleave(" = 0");
-	return 0;
+	kleave(" = %d", enopkg);
+	return enopkg;
 }
 }
 EXPORT_SYMBOL_GPL(pkcs7_verify);
 EXPORT_SYMBOL_GPL(pkcs7_verify);

+ 33 - 22
crypto/asymmetric_keys/x509_cert_parser.c

@@ -46,7 +46,8 @@ void x509_free_certificate(struct x509_certificate *cert)
 		public_key_destroy(cert->pub);
 		public_key_destroy(cert->pub);
 		kfree(cert->issuer);
 		kfree(cert->issuer);
 		kfree(cert->subject);
 		kfree(cert->subject);
-		kfree(cert->fingerprint);
+		kfree(cert->id);
+		kfree(cert->skid);
 		kfree(cert->authority);
 		kfree(cert->authority);
 		kfree(cert->sig.digest);
 		kfree(cert->sig.digest);
 		mpi_free(cert->sig.rsa.s);
 		mpi_free(cert->sig.rsa.s);
@@ -62,6 +63,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 {
 {
 	struct x509_certificate *cert;
 	struct x509_certificate *cert;
 	struct x509_parse_context *ctx;
 	struct x509_parse_context *ctx;
+	struct asymmetric_key_id *kid;
 	long ret;
 	long ret;
 
 
 	ret = -ENOMEM;
 	ret = -ENOMEM;
@@ -89,6 +91,17 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 	if (ret < 0)
 	if (ret < 0)
 		goto error_decode;
 		goto error_decode;
 
 
+	/* Generate cert issuer + serial number key ID */
+	kid = asymmetric_key_generate_id(cert->raw_serial,
+					 cert->raw_serial_size,
+					 cert->raw_issuer,
+					 cert->raw_issuer_size);
+	if (IS_ERR(kid)) {
+		ret = PTR_ERR(kid);
+		goto error_decode;
+	}
+	cert->id = kid;
+
 	kfree(ctx);
 	kfree(ctx);
 	return cert;
 	return cert;
 
 
@@ -407,36 +420,34 @@ int x509_process_extension(void *context, size_t hdrlen,
 			   const void *value, size_t vlen)
 			   const void *value, size_t vlen)
 {
 {
 	struct x509_parse_context *ctx = context;
 	struct x509_parse_context *ctx = context;
+	struct asymmetric_key_id *kid;
 	const unsigned char *v = value;
 	const unsigned char *v = value;
-	char *f;
 	int i;
 	int i;
 
 
 	pr_debug("Extension: %u\n", ctx->last_oid);
 	pr_debug("Extension: %u\n", ctx->last_oid);
 
 
 	if (ctx->last_oid == OID_subjectKeyIdentifier) {
 	if (ctx->last_oid == OID_subjectKeyIdentifier) {
 		/* Get hold of the key fingerprint */
 		/* Get hold of the key fingerprint */
-		if (vlen < 3)
+		if (ctx->cert->skid || vlen < 3)
 			return -EBADMSG;
 			return -EBADMSG;
 		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
 		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
 			return -EBADMSG;
 			return -EBADMSG;
 		v += 2;
 		v += 2;
 		vlen -= 2;
 		vlen -= 2;
 
 
-		f = kmalloc(vlen * 2 + 1, GFP_KERNEL);
-		if (!f)
-			return -ENOMEM;
-		for (i = 0; i < vlen; i++)
-			sprintf(f + i * 2, "%02x", v[i]);
-		pr_debug("fingerprint %s\n", f);
-		ctx->cert->fingerprint = f;
+		kid = asymmetric_key_generate_id(v, vlen,
+						 ctx->cert->raw_subject,
+						 ctx->cert->raw_subject_size);
+		if (IS_ERR(kid))
+			return PTR_ERR(kid);
+		ctx->cert->skid = kid;
+		pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
 		return 0;
 		return 0;
 	}
 	}
 
 
 	if (ctx->last_oid == OID_authorityKeyIdentifier) {
 	if (ctx->last_oid == OID_authorityKeyIdentifier) {
-		size_t key_len;
-
 		/* Get hold of the CA key fingerprint */
 		/* Get hold of the CA key fingerprint */
-		if (vlen < 5)
+		if (ctx->cert->authority || vlen < 5)
 			return -EBADMSG;
 			return -EBADMSG;
 
 
 		/* Authority Key Identifier must be a Constructed SEQUENCE */
 		/* Authority Key Identifier must be a Constructed SEQUENCE */
@@ -454,7 +465,7 @@ int x509_process_extension(void *context, size_t hdrlen,
 			    v[3] > vlen - 4)
 			    v[3] > vlen - 4)
 				return -EBADMSG;
 				return -EBADMSG;
 
 
-			key_len = v[3];
+			vlen = v[3];
 			v += 4;
 			v += 4;
 		} else {
 		} else {
 			/* Long Form length */
 			/* Long Form length */
@@ -476,17 +487,17 @@ int x509_process_extension(void *context, size_t hdrlen,
 			    v[sub + 1] > vlen - 4 - sub)
 			    v[sub + 1] > vlen - 4 - sub)
 				return -EBADMSG;
 				return -EBADMSG;
 
 
-			key_len = v[sub + 1];
+			vlen = v[sub + 1];
 			v += (sub + 2);
 			v += (sub + 2);
 		}
 		}
 
 
-		f = kmalloc(key_len * 2 + 1, GFP_KERNEL);
-		if (!f)
-			return -ENOMEM;
-		for (i = 0; i < key_len; i++)
-			sprintf(f + i * 2, "%02x", v[i]);
-		pr_debug("authority   %s\n", f);
-		ctx->cert->authority = f;
+		kid = asymmetric_key_generate_id(v, vlen,
+						 ctx->cert->raw_issuer,
+						 ctx->cert->raw_issuer_size);
+		if (IS_ERR(kid))
+			return PTR_ERR(kid);
+		pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+		ctx->cert->authority = kid;
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 4 - 2
crypto/asymmetric_keys/x509_parser.h

@@ -19,8 +19,9 @@ struct x509_certificate {
 	struct public_key_signature sig;	/* Signature parameters */
 	struct public_key_signature sig;	/* Signature parameters */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*subject;		/* Name of certificate subject */
 	char		*subject;		/* Name of certificate subject */
-	char		*fingerprint;		/* Key fingerprint as hex */
-	char		*authority;		/* Authority key fingerprint as hex */
+	struct asymmetric_key_id *id;		/* Issuer + serial number */
+	struct asymmetric_key_id *skid;		/* Subject key identifier */
+	struct asymmetric_key_id *authority;	/* Authority key identifier */
 	struct tm	valid_from;
 	struct tm	valid_from;
 	struct tm	valid_to;
 	struct tm	valid_to;
 	const void	*tbs;			/* Signed data */
 	const void	*tbs;			/* Signed data */
@@ -37,6 +38,7 @@ struct x509_certificate {
 	bool		seen;			/* Infinite recursion prevention */
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
 	bool		verified;
 	bool		trusted;
 	bool		trusted;
+	bool		unsupported_crypto;	/* T if can't be verified due to missing crypto */
 };
 };
 
 
 /*
 /*

+ 62 - 40
crypto/asymmetric_keys/x509_public_key.c

@@ -25,7 +25,7 @@
 #include "x509_parser.h"
 #include "x509_parser.h"
 
 
 static bool use_builtin_keys;
 static bool use_builtin_keys;
-static char *ca_keyid;
+static struct asymmetric_key_id *ca_keyid;
 
 
 #ifndef MODULE
 #ifndef MODULE
 static int __init ca_keys_setup(char *str)
 static int __init ca_keys_setup(char *str)
@@ -33,10 +33,16 @@ static int __init ca_keys_setup(char *str)
 	if (!str)		/* default system keyring */
 	if (!str)		/* default system keyring */
 		return 1;
 		return 1;
 
 
-	if (strncmp(str, "id:", 3) == 0)
-		ca_keyid = str;	/* owner key 'id:xxxxxx' */
-	else if (strcmp(str, "builtin") == 0)
+	if (strncmp(str, "id:", 3) == 0) {
+		struct asymmetric_key_id *p;
+		p = asymmetric_key_hex_to_key_id(str);
+		if (p == ERR_PTR(-EINVAL))
+			pr_err("Unparsable hex string in ca_keys\n");
+		else if (!IS_ERR(p))
+			ca_keyid = p;	/* owner key 'id:xxxxxx' */
+	} else if (strcmp(str, "builtin") == 0) {
 		use_builtin_keys = true;
 		use_builtin_keys = true;
+	}
 
 
 	return 1;
 	return 1;
 }
 }
@@ -46,31 +52,28 @@ __setup("ca_keys=", ca_keys_setup);
 /**
 /**
  * x509_request_asymmetric_key - Request a key by X.509 certificate params.
  * x509_request_asymmetric_key - Request a key by X.509 certificate params.
  * @keyring: The keys to search.
  * @keyring: The keys to search.
- * @subject: The name of the subject to whom the key belongs.
- * @key_id: The subject key ID as a hex string.
+ * @kid: The key ID.
  *
  *
  * Find a key in the given keyring by subject name and key ID.  These might,
  * Find a key in the given keyring by subject name and key ID.  These might,
  * for instance, be the issuer name and the authority key ID of an X.509
  * for instance, be the issuer name and the authority key ID of an X.509
  * certificate that needs to be verified.
  * certificate that needs to be verified.
  */
  */
 struct key *x509_request_asymmetric_key(struct key *keyring,
 struct key *x509_request_asymmetric_key(struct key *keyring,
-					const char *subject,
-					const char *key_id)
+					const struct asymmetric_key_id *kid)
 {
 {
 	key_ref_t key;
 	key_ref_t key;
-	size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
-	char *id;
+	char *id, *p;
 
 
-	/* Construct an identifier "<subjname>:<keyid>". */
-	id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
+	/* Construct an identifier "id:<keyid>". */
+	p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
 	if (!id)
 	if (!id)
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 
 
-	memcpy(id, subject, subject_len);
-	id[subject_len + 0] = ':';
-	id[subject_len + 1] = ' ';
-	memcpy(id + subject_len + 2, key_id, key_id_len);
-	id[subject_len + 2 + key_id_len] = 0;
+	*p++ = 'i';
+	*p++ = 'd';
+	*p++ = ':';
+	p = bin2hex(p, kid->data, kid->len);
+	*p = 0;
 
 
 	pr_debug("Look up: \"%s\"\n", id);
 	pr_debug("Look up: \"%s\"\n", id);
 
 
@@ -112,6 +115,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
 
 	pr_devel("==>%s()\n", __func__);
 	pr_devel("==>%s()\n", __func__);
 
 
+	if (cert->unsupported_crypto)
+		return -ENOPKG;
 	if (cert->sig.rsa.s)
 	if (cert->sig.rsa.s)
 		return 0;
 		return 0;
 
 
@@ -124,8 +129,13 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	 * big the hash operational data will be.
 	 * big the hash operational data will be.
 	 */
 	 */
 	tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
 	tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
-	if (IS_ERR(tfm))
-		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+	if (IS_ERR(tfm)) {
+		if (PTR_ERR(tfm) == -ENOENT) {
+			cert->unsupported_crypto = true;
+			return -ENOPKG;
+		}
+		return PTR_ERR(tfm);
+	}
 
 
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
 	digest_size = crypto_shash_digestsize(tfm);
 	digest_size = crypto_shash_digestsize(tfm);
@@ -172,6 +182,8 @@ int x509_check_signature(const struct public_key *pub,
 		return ret;
 		return ret;
 
 
 	ret = public_key_verify_signature(pub, &cert->sig);
 	ret = public_key_verify_signature(pub, &cert->sig);
+	if (ret == -ENOPKG)
+		cert->unsupported_crypto = true;
 	pr_debug("Cert Verification: %d\n", ret);
 	pr_debug("Cert Verification: %d\n", ret);
 	return ret;
 	return ret;
 }
 }
@@ -195,11 +207,10 @@ static int x509_validate_trust(struct x509_certificate *cert,
 	if (!trust_keyring)
 	if (!trust_keyring)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
-	if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
+	if (ca_keyid && !asymmetric_key_id_same(cert->authority, ca_keyid))
 		return -EPERM;
 		return -EPERM;
 
 
-	key = x509_request_asymmetric_key(trust_keyring,
-					  cert->issuer, cert->authority);
+	key = x509_request_asymmetric_key(trust_keyring, cert->authority);
 	if (!IS_ERR(key))  {
 	if (!IS_ERR(key))  {
 		if (!use_builtin_keys
 		if (!use_builtin_keys
 		    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
 		    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
@@ -214,9 +225,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
  */
  */
 static int x509_key_preparse(struct key_preparsed_payload *prep)
 static int x509_key_preparse(struct key_preparsed_payload *prep)
 {
 {
+	struct asymmetric_key_ids *kids;
 	struct x509_certificate *cert;
 	struct x509_certificate *cert;
+	const char *q;
 	size_t srlen, sulen;
 	size_t srlen, sulen;
-	char *desc = NULL;
+	char *desc = NULL, *p;
 	int ret;
 	int ret;
 
 
 	cert = x509_cert_parse(prep->data, prep->datalen);
 	cert = x509_cert_parse(prep->data, prep->datalen);
@@ -249,19 +262,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 		 pkey_algo_name[cert->sig.pkey_algo],
 		 pkey_algo_name[cert->sig.pkey_algo],
 		 hash_algo_name[cert->sig.pkey_hash_algo]);
 		 hash_algo_name[cert->sig.pkey_hash_algo]);
 
 
-	if (!cert->fingerprint) {
-		pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
-			cert->subject);
-		ret = -EKEYREJECTED;
-		goto error_free_cert;
-	}
-
 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
 	cert->pub->id_type = PKEY_ID_X509;
 	cert->pub->id_type = PKEY_ID_X509;
 
 
 	/* Check the signature on the key if it appears to be self-signed */
 	/* Check the signature on the key if it appears to be self-signed */
 	if (!cert->authority ||
 	if (!cert->authority ||
-	    strcmp(cert->fingerprint, cert->authority) == 0) {
+	    asymmetric_key_id_same(cert->skid, cert->authority)) {
 		ret = x509_check_signature(cert->pub, cert); /* self-signed */
 		ret = x509_check_signature(cert->pub, cert); /* self-signed */
 		if (ret < 0)
 		if (ret < 0)
 			goto error_free_cert;
 			goto error_free_cert;
@@ -273,31 +279,47 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
 
 	/* Propose a description */
 	/* Propose a description */
 	sulen = strlen(cert->subject);
 	sulen = strlen(cert->subject);
-	srlen = strlen(cert->fingerprint);
+	srlen = cert->raw_serial_size;
+	q = cert->raw_serial;
+	if (srlen > 1 && *q == 0) {
+		srlen--;
+		q++;
+	}
+
 	ret = -ENOMEM;
 	ret = -ENOMEM;
-	desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
+	desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
 	if (!desc)
 	if (!desc)
 		goto error_free_cert;
 		goto error_free_cert;
-	memcpy(desc, cert->subject, sulen);
-	desc[sulen] = ':';
-	desc[sulen + 1] = ' ';
-	memcpy(desc + sulen + 2, cert->fingerprint, srlen);
-	desc[sulen + 2 + srlen] = 0;
+	p = memcpy(desc, cert->subject, sulen);
+	p += sulen;
+	*p++ = ':';
+	*p++ = ' ';
+	p = bin2hex(p, q, srlen);
+	*p = 0;
+
+	kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
+	if (!kids)
+		goto error_free_desc;
+	kids->id[0] = cert->id;
+	kids->id[1] = cert->skid;
 
 
 	/* We're pinning the module by being linked against it */
 	/* We're pinning the module by being linked against it */
 	__module_get(public_key_subtype.owner);
 	__module_get(public_key_subtype.owner);
 	prep->type_data[0] = &public_key_subtype;
 	prep->type_data[0] = &public_key_subtype;
-	prep->type_data[1] = cert->fingerprint;
+	prep->type_data[1] = kids;
 	prep->payload[0] = cert->pub;
 	prep->payload[0] = cert->pub;
 	prep->description = desc;
 	prep->description = desc;
 	prep->quotalen = 100;
 	prep->quotalen = 100;
 
 
 	/* We've finished with the certificate */
 	/* We've finished with the certificate */
 	cert->pub = NULL;
 	cert->pub = NULL;
-	cert->fingerprint = NULL;
+	cert->id = NULL;
+	cert->skid = NULL;
 	desc = NULL;
 	desc = NULL;
 	ret = 0;
 	ret = 0;
 
 
+error_free_desc:
+	kfree(desc);
 error_free_cert:
 error_free_cert:
 	x509_free_certificate(cert);
 	x509_free_certificate(cert);
 	return ret;
 	return ret;

+ 0 - 1
fs/cifs/cifs_spnego.c

@@ -62,7 +62,6 @@ cifs_spnego_key_destroy(struct key *key)
 struct key_type cifs_spnego_key_type = {
 struct key_type cifs_spnego_key_type = {
 	.name		= "cifs.spnego",
 	.name		= "cifs.spnego",
 	.instantiate	= cifs_spnego_key_instantiate,
 	.instantiate	= cifs_spnego_key_instantiate,
-	.match		= user_match,
 	.destroy	= cifs_spnego_key_destroy,
 	.destroy	= cifs_spnego_key_destroy,
 	.describe	= user_describe,
 	.describe	= user_describe,
 };
 };

+ 0 - 1
fs/cifs/cifsacl.c

@@ -84,7 +84,6 @@ static struct key_type cifs_idmap_key_type = {
 	.instantiate = cifs_idmap_key_instantiate,
 	.instantiate = cifs_idmap_key_instantiate,
 	.destroy     = cifs_idmap_key_destroy,
 	.destroy     = cifs_idmap_key_destroy,
 	.describe    = user_describe,
 	.describe    = user_describe,
-	.match       = user_match,
 };
 };
 
 
 static char *
 static char *

+ 0 - 2
fs/nfs/idmap.c

@@ -177,7 +177,6 @@ static struct key_type key_type_id_resolver = {
 	.preparse	= user_preparse,
 	.preparse	= user_preparse,
 	.free_preparse	= user_free_preparse,
 	.free_preparse	= user_free_preparse,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= user_match,
 	.revoke		= user_revoke,
 	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.destroy	= user_destroy,
 	.describe	= user_describe,
 	.describe	= user_describe,
@@ -401,7 +400,6 @@ static struct key_type key_type_id_resolver_legacy = {
 	.preparse	= user_preparse,
 	.preparse	= user_preparse,
 	.free_preparse	= user_free_preparse,
 	.free_preparse	= user_free_preparse,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= user_match,
 	.revoke		= user_revoke,
 	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.destroy	= user_destroy,
 	.describe	= user_describe,
 	.describe	= user_describe,

+ 3 - 2
include/crypto/public_key.h

@@ -15,6 +15,7 @@
 #define _LINUX_PUBLIC_KEY_H
 #define _LINUX_PUBLIC_KEY_H
 
 
 #include <linux/mpi.h>
 #include <linux/mpi.h>
+#include <keys/asymmetric-type.h>
 #include <crypto/hash_info.h>
 #include <crypto/hash_info.h>
 
 
 enum pkey_algo {
 enum pkey_algo {
@@ -98,8 +99,8 @@ struct key;
 extern int verify_signature(const struct key *key,
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
 			    const struct public_key_signature *sig);
 
 
+struct asymmetric_key_id;
 extern struct key *x509_request_asymmetric_key(struct key *keyring,
 extern struct key *x509_request_asymmetric_key(struct key *keyring,
-					       const char *issuer,
-					       const char *key_id);
+					       const struct asymmetric_key_id *kid);
 
 
 #endif /* _LINUX_PUBLIC_KEY_H */
 #endif /* _LINUX_PUBLIC_KEY_H */

+ 38 - 0
include/keys/asymmetric-type.h

@@ -18,6 +18,44 @@
 
 
 extern struct key_type key_type_asymmetric;
 extern struct key_type key_type_asymmetric;
 
 
+/*
+ * Identifiers for an asymmetric key ID.  We have three ways of looking up a
+ * key derived from an X.509 certificate:
+ *
+ * (1) Serial Number & Issuer.  Non-optional.  This is the only valid way to
+ *     map a PKCS#7 signature to an X.509 certificate.
+ *
+ * (2) Issuer & Subject Unique IDs.  Optional.  These were the original way to
+ *     match X.509 certificates, but have fallen into disuse in favour of (3).
+ *
+ * (3) Auth & Subject Key Identifiers.  Optional.  SKIDs are only provided on
+ *     CA keys that are intended to sign other keys, so don't appear in end
+ *     user certificates unless forced.
+ *
+ * We could also support an PGP key identifier, which is just a SHA1 sum of the
+ * public key and certain parameters, but since we don't support PGP keys at
+ * the moment, we shall ignore those.
+ *
+ * What we actually do is provide a place where binary identifiers can be
+ * stashed and then compare against them when checking for an id match.
+ */
+struct asymmetric_key_id {
+	unsigned short	len;
+	unsigned char	data[];
+};
+
+struct asymmetric_key_ids {
+	void		*id[2];
+};
+
+extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+				   const struct asymmetric_key_id *kid2);
+
+extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+							    size_t len_1,
+							    const void *val_2,
+							    size_t len_2);
+
 /*
 /*
  * The payload is at the discretion of the subtype.
  * The payload is at the discretion of the subtype.
  */
  */

+ 0 - 1
include/keys/user-type.h

@@ -40,7 +40,6 @@ struct key_preparsed_payload;
 extern int user_preparse(struct key_preparsed_payload *prep);
 extern int user_preparse(struct key_preparsed_payload *prep);
 extern void user_free_preparse(struct key_preparsed_payload *prep);
 extern void user_free_preparse(struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
-extern int user_match(const struct key *key, const void *criterion);
 extern void user_revoke(struct key *key);
 extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
 extern void user_destroy(struct key *key);
 extern void user_describe(const struct key *user, struct seq_file *m);
 extern void user_describe(const struct key *user, struct seq_file *m);

+ 1 - 0
include/linux/kernel.h

@@ -500,6 +500,7 @@ static inline char * __deprecated pack_hex_byte(char *buf, u8 byte)
 
 
 extern int hex_to_bin(char ch);
 extern int hex_to_bin(char ch);
 extern int __must_check hex2bin(u8 *dst, const char *src, size_t count);
 extern int __must_check hex2bin(u8 *dst, const char *src, size_t count);
+extern char *bin2hex(char *dst, const void *src, size_t count);
 
 
 int mac_pton(const char *s, u8 *mac);
 int mac_pton(const char *s, u8 *mac);
 
 

+ 27 - 7
include/linux/key-type.h

@@ -52,6 +52,24 @@ struct key_preparsed_payload {
 typedef int (*request_key_actor_t)(struct key_construction *key,
 typedef int (*request_key_actor_t)(struct key_construction *key,
 				   const char *op, void *aux);
 				   const char *op, void *aux);
 
 
+/*
+ * Preparsed matching criterion.
+ */
+struct key_match_data {
+	/* Comparison function, defaults to exact description match, but can be
+	 * overridden by type->match_preparse().  Should return true if a match
+	 * is found and false if not.
+	 */
+	bool (*cmp)(const struct key *key,
+		    const struct key_match_data *match_data);
+
+	const void	*raw_data;	/* Raw match data */
+	void		*preparsed;	/* For ->match_preparse() to stash stuff */
+	unsigned	lookup_type;	/* Type of lookup for this search. */
+#define KEYRING_SEARCH_LOOKUP_DIRECT	0x0000	/* Direct lookup by description. */
+#define KEYRING_SEARCH_LOOKUP_ITERATE	0x0001	/* Iterative search. */
+};
+
 /*
 /*
  * kernel managed key type definition
  * kernel managed key type definition
  */
  */
@@ -65,11 +83,6 @@ struct key_type {
 	 */
 	 */
 	size_t def_datalen;
 	size_t def_datalen;
 
 
-	/* Default key search algorithm. */
-	unsigned def_lookup_type;
-#define KEYRING_SEARCH_LOOKUP_DIRECT	0x0000	/* Direct lookup by description. */
-#define KEYRING_SEARCH_LOOKUP_ITERATE	0x0001	/* Iterative search. */
-
 	/* vet a description */
 	/* vet a description */
 	int (*vet_description)(const char *description);
 	int (*vet_description)(const char *description);
 
 
@@ -96,8 +109,15 @@ struct key_type {
 	 */
 	 */
 	int (*update)(struct key *key, struct key_preparsed_payload *prep);
 	int (*update)(struct key *key, struct key_preparsed_payload *prep);
 
 
-	/* match a key against a description */
-	int (*match)(const struct key *key, const void *desc);
+	/* Preparse the data supplied to ->match() (optional).  The
+	 * data to be preparsed can be found in match_data->raw_data.
+	 * The lookup type can also be set by this function.
+	 */
+	int (*match_preparse)(struct key_match_data *match_data);
+
+	/* Free preparsed match data (optional).  This should be supplied it
+	 * ->match_preparse() is supplied. */
+	void (*match_free)(struct key_match_data *match_data);
 
 
 	/* clear some of the data from a key on revokation (optional)
 	/* clear some of the data from a key on revokation (optional)
 	 * - the key's semaphore will be write-locked by the caller
 	 * - the key's semaphore will be write-locked by the caller

+ 16 - 0
lib/hexdump.c

@@ -58,6 +58,22 @@ int hex2bin(u8 *dst, const char *src, size_t count)
 }
 }
 EXPORT_SYMBOL(hex2bin);
 EXPORT_SYMBOL(hex2bin);
 
 
+/**
+ * bin2hex - convert binary data to an ascii hexadecimal string
+ * @dst: ascii hexadecimal result
+ * @src: binary data
+ * @count: binary data length
+ */
+char *bin2hex(char *dst, const void *src, size_t count)
+{
+	const unsigned char *_src = src;
+
+	while (count--)
+		dst = hex_byte_pack(dst, *_src++);
+	return dst;
+}
+EXPORT_SYMBOL(bin2hex);
+
 /**
 /**
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * @buf: data blob to dump
  * @buf: data blob to dump

+ 0 - 1
net/ceph/crypto.c

@@ -476,7 +476,6 @@ struct key_type key_type_ceph = {
 	.preparse	= ceph_key_preparse,
 	.preparse	= ceph_key_preparse,
 	.free_preparse	= ceph_key_free_preparse,
 	.free_preparse	= ceph_key_free_preparse,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= user_match,
 	.destroy	= ceph_key_destroy,
 	.destroy	= ceph_key_destroy,
 };
 };
 
 

+ 14 - 4
net/dns_resolver/dns_key.c

@@ -176,11 +176,11 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
  * The domain name may be a simple name or an absolute domain name (which
  * The domain name may be a simple name or an absolute domain name (which
  * should end with a period).  The domain name is case-independent.
  * should end with a period).  The domain name is case-independent.
  */
  */
-static int
-dns_resolver_match(const struct key *key, const void *description)
+static bool dns_resolver_cmp(const struct key *key,
+			     const struct key_match_data *match_data)
 {
 {
 	int slen, dlen, ret = 0;
 	int slen, dlen, ret = 0;
-	const char *src = key->description, *dsp = description;
+	const char *src = key->description, *dsp = match_data->raw_data;
 
 
 	kenter("%s,%s", src, dsp);
 	kenter("%s,%s", src, dsp);
 
 
@@ -208,6 +208,16 @@ no_match:
 	return ret;
 	return ret;
 }
 }
 
 
+/*
+ * Preparse the match criterion.
+ */
+static int dns_resolver_match_preparse(struct key_match_data *match_data)
+{
+	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+	match_data->cmp = dns_resolver_cmp;
+	return 0;
+}
+
 /*
 /*
  * Describe a DNS key
  * Describe a DNS key
  */
  */
@@ -242,7 +252,7 @@ struct key_type key_type_dns_resolver = {
 	.preparse	= dns_resolver_preparse,
 	.preparse	= dns_resolver_preparse,
 	.free_preparse	= dns_resolver_free_preparse,
 	.free_preparse	= dns_resolver_free_preparse,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= dns_resolver_match,
+	.match_preparse	= dns_resolver_match_preparse,
 	.revoke		= user_revoke,
 	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.destroy	= user_destroy,
 	.describe	= dns_resolver_describe,
 	.describe	= dns_resolver_describe,

+ 0 - 2
net/rxrpc/ar-key.c

@@ -44,7 +44,6 @@ struct key_type key_type_rxrpc = {
 	.preparse	= rxrpc_preparse,
 	.preparse	= rxrpc_preparse,
 	.free_preparse	= rxrpc_free_preparse,
 	.free_preparse	= rxrpc_free_preparse,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= user_match,
 	.destroy	= rxrpc_destroy,
 	.destroy	= rxrpc_destroy,
 	.describe	= rxrpc_describe,
 	.describe	= rxrpc_describe,
 	.read		= rxrpc_read,
 	.read		= rxrpc_read,
@@ -61,7 +60,6 @@ struct key_type key_type_rxrpc_s = {
 	.preparse	= rxrpc_preparse_s,
 	.preparse	= rxrpc_preparse_s,
 	.free_preparse	= rxrpc_free_preparse_s,
 	.free_preparse	= rxrpc_free_preparse_s,
 	.instantiate	= generic_key_instantiate,
 	.instantiate	= generic_key_instantiate,
-	.match		= user_match,
 	.destroy	= rxrpc_destroy_s,
 	.destroy	= rxrpc_destroy_s,
 	.describe	= rxrpc_describe,
 	.describe	= rxrpc_describe,
 };
 };

+ 0 - 2
security/keys/big_key.c

@@ -33,11 +33,9 @@ MODULE_LICENSE("GPL");
  */
  */
 struct key_type key_type_big_key = {
 struct key_type key_type_big_key = {
 	.name			= "big_key",
 	.name			= "big_key",
-	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.preparse		= big_key_preparse,
 	.preparse		= big_key_preparse,
 	.free_preparse		= big_key_free_preparse,
 	.free_preparse		= big_key_free_preparse,
 	.instantiate		= generic_key_instantiate,
 	.instantiate		= generic_key_instantiate,
-	.match			= user_match,
 	.revoke			= big_key_revoke,
 	.revoke			= big_key_revoke,
 	.destroy		= big_key_destroy,
 	.destroy		= big_key_destroy,
 	.describe		= big_key_describe,
 	.describe		= big_key_describe,

+ 0 - 1
security/keys/encrypted-keys/encrypted.c

@@ -970,7 +970,6 @@ struct key_type key_type_encrypted = {
 	.name = "encrypted",
 	.name = "encrypted",
 	.instantiate = encrypted_instantiate,
 	.instantiate = encrypted_instantiate,
 	.update = encrypted_update,
 	.update = encrypted_update,
-	.match = user_match,
 	.destroy = encrypted_destroy,
 	.destroy = encrypted_destroy,
 	.describe = user_describe,
 	.describe = user_describe,
 	.read = encrypted_read,
 	.read = encrypted_read,

+ 10 - 11
security/keys/internal.h

@@ -107,20 +107,16 @@ extern int iterate_over_keyring(const struct key *keyring,
 				int (*func)(const struct key *key, void *data),
 				int (*func)(const struct key *key, void *data),
 				void *data);
 				void *data);
 
 
-typedef int (*key_match_func_t)(const struct key *, const void *);
-
 struct keyring_search_context {
 struct keyring_search_context {
 	struct keyring_index_key index_key;
 	struct keyring_index_key index_key;
 	const struct cred	*cred;
 	const struct cred	*cred;
-	key_match_func_t	match;
-	const void		*match_data;
+	struct key_match_data	match_data;
 	unsigned		flags;
 	unsigned		flags;
-#define KEYRING_SEARCH_LOOKUP_TYPE	0x0001	/* [as type->def_lookup_type] */
-#define KEYRING_SEARCH_NO_STATE_CHECK	0x0002	/* Skip state checks */
-#define KEYRING_SEARCH_DO_STATE_CHECK	0x0004	/* Override NO_STATE_CHECK */
-#define KEYRING_SEARCH_NO_UPDATE_TIME	0x0008	/* Don't update times */
-#define KEYRING_SEARCH_NO_CHECK_PERM	0x0010	/* Don't check permissions */
-#define KEYRING_SEARCH_DETECT_TOO_DEEP	0x0020	/* Give an error on excessive depth */
+#define KEYRING_SEARCH_NO_STATE_CHECK	0x0001	/* Skip state checks */
+#define KEYRING_SEARCH_DO_STATE_CHECK	0x0002	/* Override NO_STATE_CHECK */
+#define KEYRING_SEARCH_NO_UPDATE_TIME	0x0004	/* Don't update times */
+#define KEYRING_SEARCH_NO_CHECK_PERM	0x0008	/* Don't check permissions */
+#define KEYRING_SEARCH_DETECT_TOO_DEEP	0x0010	/* Give an error on excessive depth */
 
 
 	int (*iterator)(const void *object, void *iterator_data);
 	int (*iterator)(const void *object, void *iterator_data);
 
 
@@ -131,6 +127,8 @@ struct keyring_search_context {
 	struct timespec		now;
 	struct timespec		now;
 };
 };
 
 
+extern bool key_default_cmp(const struct key *key,
+			    const struct key_match_data *match_data);
 extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
 extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
 				    struct keyring_search_context *ctx);
 				    struct keyring_search_context *ctx);
 
 
@@ -152,7 +150,8 @@ extern struct key *request_key_and_link(struct key_type *type,
 					struct key *dest_keyring,
 					struct key *dest_keyring,
 					unsigned long flags);
 					unsigned long flags);
 
 
-extern int lookup_user_key_possessed(const struct key *key, const void *target);
+extern bool lookup_user_key_possessed(const struct key *key,
+				      const struct key_match_data *match_data);
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
 				 key_perm_t perm);
 				 key_perm_t perm);
 #define KEY_LOOKUP_CREATE	0x01
 #define KEY_LOOKUP_CREATE	0x01

+ 1 - 1
security/keys/key.c

@@ -799,7 +799,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	}
 	}
 
 
 	key_ref = ERR_PTR(-EINVAL);
 	key_ref = ERR_PTR(-EINVAL);
-	if (!index_key.type->match || !index_key.type->instantiate ||
+	if (!index_key.type->instantiate ||
 	    (!index_key.description && !index_key.type->preparse))
 	    (!index_key.description && !index_key.type->preparse))
 		goto error_put_type;
 		goto error_put_type;
 
 

+ 2 - 0
security/keys/keyctl.c

@@ -37,6 +37,8 @@ static int key_get_type_from_user(char *type,
 		return ret;
 		return ret;
 	if (ret == 0 || ret >= len)
 	if (ret == 0 || ret >= len)
 		return -EINVAL;
 		return -EINVAL;
+	if (type[0] == '.')
+		return -EPERM;
 	type[len - 1] = '\0';
 	type[len - 1] = '\0';
 	return 0;
 	return 0;
 }
 }

+ 37 - 21
security/keys/keyring.c

@@ -89,7 +89,6 @@ struct key_type key_type_keyring = {
 	.preparse	= keyring_preparse,
 	.preparse	= keyring_preparse,
 	.free_preparse	= keyring_free_preparse,
 	.free_preparse	= keyring_free_preparse,
 	.instantiate	= keyring_instantiate,
 	.instantiate	= keyring_instantiate,
-	.match		= user_match,
 	.revoke		= keyring_revoke,
 	.revoke		= keyring_revoke,
 	.destroy	= keyring_destroy,
 	.destroy	= keyring_destroy,
 	.describe	= keyring_describe,
 	.describe	= keyring_describe,
@@ -511,6 +510,15 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 }
 }
 EXPORT_SYMBOL(keyring_alloc);
 EXPORT_SYMBOL(keyring_alloc);
 
 
+/*
+ * By default, we keys found by getting an exact match on their descriptions.
+ */
+bool key_default_cmp(const struct key *key,
+		     const struct key_match_data *match_data)
+{
+	return strcmp(key->description, match_data->raw_data) == 0;
+}
+
 /*
 /*
  * Iteration function to consider each key found.
  * Iteration function to consider each key found.
  */
  */
@@ -545,7 +553,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
 	}
 	}
 
 
 	/* keys that don't match */
 	/* keys that don't match */
-	if (!ctx->match(key, ctx->match_data)) {
+	if (!ctx->match_data.cmp(key, &ctx->match_data)) {
 		kleave(" = 0 [!match]");
 		kleave(" = 0 [!match]");
 		return 0;
 		return 0;
 	}
 	}
@@ -585,8 +593,7 @@ skipped:
  */
  */
 static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
 static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
 {
 {
-	if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) ==
-	    KEYRING_SEARCH_LOOKUP_DIRECT) {
+	if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
 		const void *object;
 		const void *object;
 
 
 		object = assoc_array_find(&keyring->keys,
 		object = assoc_array_find(&keyring->keys,
@@ -627,7 +634,7 @@ static bool search_nested_keyrings(struct key *keyring,
 	/* Check to see if this top-level keyring is what we are looking for
 	/* Check to see if this top-level keyring is what we are looking for
 	 * and whether it is valid or not.
 	 * and whether it is valid or not.
 	 */
 	 */
-	if (ctx->flags & KEYRING_SEARCH_LOOKUP_ITERATE ||
+	if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
 	    keyring_compare_object(keyring, &ctx->index_key)) {
 	    keyring_compare_object(keyring, &ctx->index_key)) {
 		ctx->skipped_ret = 2;
 		ctx->skipped_ret = 2;
 		ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
 		ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
@@ -885,16 +892,25 @@ key_ref_t keyring_search(key_ref_t keyring,
 		.index_key.type		= type,
 		.index_key.type		= type,
 		.index_key.description	= description,
 		.index_key.description	= description,
 		.cred			= current_cred(),
 		.cred			= current_cred(),
-		.match			= type->match,
-		.match_data		= description,
-		.flags			= (type->def_lookup_type |
-					   KEYRING_SEARCH_DO_STATE_CHECK),
+		.match_data.cmp		= key_default_cmp,
+		.match_data.raw_data	= description,
+		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
+		.flags			= KEYRING_SEARCH_DO_STATE_CHECK,
 	};
 	};
+	key_ref_t key;
+	int ret;
 
 
-	if (!ctx.match)
-		return ERR_PTR(-ENOKEY);
+	if (type->match_preparse) {
+		ret = type->match_preparse(&ctx.match_data);
+		if (ret < 0)
+			return ERR_PTR(ret);
+	}
 
 
-	return keyring_search_aux(keyring, &ctx);
+	key = keyring_search_aux(keyring, &ctx);
+
+	if (type->match_free)
+		type->match_free(&ctx.match_data);
+	return key;
 }
 }
 EXPORT_SYMBOL(keyring_search);
 EXPORT_SYMBOL(keyring_search);
 
 
@@ -1014,7 +1030,7 @@ static int keyring_detect_cycle_iterator(const void *object,
 
 
 	/* We might get a keyring with matching index-key that is nonetheless a
 	/* We might get a keyring with matching index-key that is nonetheless a
 	 * different keyring. */
 	 * different keyring. */
-	if (key != ctx->match_data)
+	if (key != ctx->match_data.raw_data)
 		return 0;
 		return 0;
 
 
 	ctx->result = ERR_PTR(-EDEADLK);
 	ctx->result = ERR_PTR(-EDEADLK);
@@ -1031,14 +1047,14 @@ static int keyring_detect_cycle_iterator(const void *object,
 static int keyring_detect_cycle(struct key *A, struct key *B)
 static int keyring_detect_cycle(struct key *A, struct key *B)
 {
 {
 	struct keyring_search_context ctx = {
 	struct keyring_search_context ctx = {
-		.index_key	= A->index_key,
-		.match_data	= A,
-		.iterator	= keyring_detect_cycle_iterator,
-		.flags		= (KEYRING_SEARCH_LOOKUP_DIRECT |
-				   KEYRING_SEARCH_NO_STATE_CHECK |
-				   KEYRING_SEARCH_NO_UPDATE_TIME |
-				   KEYRING_SEARCH_NO_CHECK_PERM |
-				   KEYRING_SEARCH_DETECT_TOO_DEEP),
+		.index_key		= A->index_key,
+		.match_data.raw_data	= A,
+		.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+		.iterator		= keyring_detect_cycle_iterator,
+		.flags			= (KEYRING_SEARCH_NO_STATE_CHECK |
+					   KEYRING_SEARCH_NO_UPDATE_TIME |
+					   KEYRING_SEARCH_NO_CHECK_PERM |
+					   KEYRING_SEARCH_DETECT_TOO_DEEP),
 	};
 	};
 
 
 	rcu_read_lock();
 	rcu_read_lock();

+ 4 - 4
security/keys/proc.c

@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v)
 		.index_key.type		= key->type,
 		.index_key.type		= key->type,
 		.index_key.description	= key->description,
 		.index_key.description	= key->description,
 		.cred			= current_cred(),
 		.cred			= current_cred(),
-		.match			= lookup_user_key_possessed,
-		.match_data		= key,
-		.flags			= (KEYRING_SEARCH_NO_STATE_CHECK |
-					   KEYRING_SEARCH_LOOKUP_DIRECT),
+		.match_data.cmp		= lookup_user_key_possessed,
+		.match_data.raw_data	= key,
+		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
+		.flags			= KEYRING_SEARCH_NO_STATE_CHECK,
 	};
 	};
 
 
 	key_ref = make_key_ref(key, 0);
 	key_ref = make_key_ref(key, 0);

+ 7 - 6
security/keys/process_keys.c

@@ -489,9 +489,10 @@ found:
 /*
 /*
  * See if the key we're looking at is the target key.
  * See if the key we're looking at is the target key.
  */
  */
-int lookup_user_key_possessed(const struct key *key, const void *target)
+bool lookup_user_key_possessed(const struct key *key,
+			       const struct key_match_data *match_data)
 {
 {
-	return key == target;
+	return key == match_data->raw_data;
 }
 }
 
 
 /*
 /*
@@ -516,9 +517,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
 			  key_perm_t perm)
 			  key_perm_t perm)
 {
 {
 	struct keyring_search_context ctx = {
 	struct keyring_search_context ctx = {
-		.match	= lookup_user_key_possessed,
-		.flags	= (KEYRING_SEARCH_NO_STATE_CHECK |
-			   KEYRING_SEARCH_LOOKUP_DIRECT),
+		.match_data.cmp		= lookup_user_key_possessed,
+		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
+		.flags			= KEYRING_SEARCH_NO_STATE_CHECK,
 	};
 	};
 	struct request_key_auth *rka;
 	struct request_key_auth *rka;
 	struct key *key;
 	struct key *key;
@@ -673,7 +674,7 @@ try_again:
 		ctx.index_key.type		= key->type;
 		ctx.index_key.type		= key->type;
 		ctx.index_key.description	= key->description;
 		ctx.index_key.description	= key->description;
 		ctx.index_key.desc_len		= strlen(key->description);
 		ctx.index_key.desc_len		= strlen(key->description);
-		ctx.match_data			= key;
+		ctx.match_data.raw_data		= key;
 		kdebug("check possessed");
 		kdebug("check possessed");
 		skey_ref = search_process_keyrings(&ctx);
 		skey_ref = search_process_keyrings(&ctx);
 		kdebug("possessed=%p", skey_ref);
 		kdebug("possessed=%p", skey_ref);

+ 16 - 5
security/keys/request_key.c

@@ -531,9 +531,9 @@ struct key *request_key_and_link(struct key_type *type,
 		.index_key.type		= type,
 		.index_key.type		= type,
 		.index_key.description	= description,
 		.index_key.description	= description,
 		.cred			= current_cred(),
 		.cred			= current_cred(),
-		.match			= type->match,
-		.match_data		= description,
-		.flags			= KEYRING_SEARCH_LOOKUP_DIRECT,
+		.match_data.cmp		= key_default_cmp,
+		.match_data.raw_data	= description,
+		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	};
 	};
 	struct key *key;
 	struct key *key;
 	key_ref_t key_ref;
 	key_ref_t key_ref;
@@ -543,6 +543,14 @@ struct key *request_key_and_link(struct key_type *type,
 	       ctx.index_key.type->name, ctx.index_key.description,
 	       ctx.index_key.type->name, ctx.index_key.description,
 	       callout_info, callout_len, aux, dest_keyring, flags);
 	       callout_info, callout_len, aux, dest_keyring, flags);
 
 
+	if (type->match_preparse) {
+		ret = type->match_preparse(&ctx.match_data);
+		if (ret < 0) {
+			key = ERR_PTR(ret);
+			goto error;
+		}
+	}
+
 	/* search all the process keyrings for a key */
 	/* search all the process keyrings for a key */
 	key_ref = search_process_keyrings(&ctx);
 	key_ref = search_process_keyrings(&ctx);
 
 
@@ -555,7 +563,7 @@ struct key *request_key_and_link(struct key_type *type,
 			if (ret < 0) {
 			if (ret < 0) {
 				key_put(key);
 				key_put(key);
 				key = ERR_PTR(ret);
 				key = ERR_PTR(ret);
-				goto error;
+				goto error_free;
 			}
 			}
 		}
 		}
 	} else if (PTR_ERR(key_ref) != -EAGAIN) {
 	} else if (PTR_ERR(key_ref) != -EAGAIN) {
@@ -565,12 +573,15 @@ struct key *request_key_and_link(struct key_type *type,
 		 * should consult userspace if we can */
 		 * should consult userspace if we can */
 		key = ERR_PTR(-ENOKEY);
 		key = ERR_PTR(-ENOKEY);
 		if (!callout_info)
 		if (!callout_info)
-			goto error;
+			goto error_free;
 
 
 		key = construct_key_and_link(&ctx, callout_info, callout_len,
 		key = construct_key_and_link(&ctx, callout_info, callout_len,
 					     aux, dest_keyring, flags);
 					     aux, dest_keyring, flags);
 	}
 	}
 
 
+error_free:
+	if (type->match_free)
+		type->match_free(&ctx.match_data);
 error:
 error:
 	kleave(" = %p", key);
 	kleave(" = %p", key);
 	return key;
 	return key;

+ 5 - 5
security/keys/request_key_auth.c

@@ -44,12 +44,12 @@ struct key_type key_type_request_key_auth = {
 	.read		= request_key_auth_read,
 	.read		= request_key_auth_read,
 };
 };
 
 
-int request_key_auth_preparse(struct key_preparsed_payload *prep)
+static int request_key_auth_preparse(struct key_preparsed_payload *prep)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
+static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
 {
 {
 }
 }
 
 
@@ -246,9 +246,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
 		.index_key.type		= &key_type_request_key_auth,
 		.index_key.type		= &key_type_request_key_auth,
 		.index_key.description	= description,
 		.index_key.description	= description,
 		.cred			= current_cred(),
 		.cred			= current_cred(),
-		.match			= user_match,
-		.match_data		= description,
-		.flags			= KEYRING_SEARCH_LOOKUP_DIRECT,
+		.match_data.cmp		= key_default_cmp,
+		.match_data.raw_data	= description,
+		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	};
 	};
 	struct key *authkey;
 	struct key *authkey;
 	key_ref_t authkey_ref;
 	key_ref_t authkey_ref;

+ 0 - 1
security/keys/trusted.c

@@ -1096,7 +1096,6 @@ struct key_type key_type_trusted = {
 	.name = "trusted",
 	.name = "trusted",
 	.instantiate = trusted_instantiate,
 	.instantiate = trusted_instantiate,
 	.update = trusted_update,
 	.update = trusted_update,
-	.match = user_match,
 	.destroy = trusted_destroy,
 	.destroy = trusted_destroy,
 	.describe = user_describe,
 	.describe = user_describe,
 	.read = trusted_read,
 	.read = trusted_read,

+ 0 - 14
security/keys/user_defined.c

@@ -26,12 +26,10 @@ static int logon_vet_description(const char *desc);
  */
  */
 struct key_type key_type_user = {
 struct key_type key_type_user = {
 	.name			= "user",
 	.name			= "user",
-	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.preparse		= user_preparse,
 	.preparse		= user_preparse,
 	.free_preparse		= user_free_preparse,
 	.free_preparse		= user_free_preparse,
 	.instantiate		= generic_key_instantiate,
 	.instantiate		= generic_key_instantiate,
 	.update			= user_update,
 	.update			= user_update,
-	.match			= user_match,
 	.revoke			= user_revoke,
 	.revoke			= user_revoke,
 	.destroy		= user_destroy,
 	.destroy		= user_destroy,
 	.describe		= user_describe,
 	.describe		= user_describe,
@@ -48,12 +46,10 @@ EXPORT_SYMBOL_GPL(key_type_user);
  */
  */
 struct key_type key_type_logon = {
 struct key_type key_type_logon = {
 	.name			= "logon",
 	.name			= "logon",
-	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.preparse		= user_preparse,
 	.preparse		= user_preparse,
 	.free_preparse		= user_free_preparse,
 	.free_preparse		= user_free_preparse,
 	.instantiate		= generic_key_instantiate,
 	.instantiate		= generic_key_instantiate,
 	.update			= user_update,
 	.update			= user_update,
-	.match			= user_match,
 	.revoke			= user_revoke,
 	.revoke			= user_revoke,
 	.destroy		= user_destroy,
 	.destroy		= user_destroy,
 	.describe		= user_describe,
 	.describe		= user_describe,
@@ -138,16 +134,6 @@ error:
 
 
 EXPORT_SYMBOL_GPL(user_update);
 EXPORT_SYMBOL_GPL(user_update);
 
 
-/*
- * match users on their name
- */
-int user_match(const struct key *key, const void *description)
-{
-	return strcmp(key->description, description) == 0;
-}
-
-EXPORT_SYMBOL_GPL(user_match);
-
 /*
 /*
  * dispose of the links from a revoked keyring
  * dispose of the links from a revoked keyring
  * - called with the key sem write-locked
  * - called with the key sem write-locked