summaryrefslogtreecommitdiffstats
path: root/freed-ora/current/f18/modsign-upstream-3.7.patch
diff options
context:
space:
mode:
Diffstat (limited to 'freed-ora/current/f18/modsign-upstream-3.7.patch')
-rw-r--r--freed-ora/current/f18/modsign-upstream-3.7.patch10963
1 files changed, 10963 insertions, 0 deletions
diff --git a/freed-ora/current/f18/modsign-upstream-3.7.patch b/freed-ora/current/f18/modsign-upstream-3.7.patch
new file mode 100644
index 000000000..4ed27c8a5
--- /dev/null
+++ b/freed-ora/current/f18/modsign-upstream-3.7.patch
@@ -0,0 +1,10963 @@
+From 9d501208ff48eb3ecc0d1ac8d897c38e99d18161 Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Wed, 26 Sep 2012 10:09:40 +0100
+Subject: [PATCH 01/37] module: signature checking hook
+
+We do a very simple search for a particular string appended to the module
+(which is cache-hot and about to be SHA'd anyway). There's both a config
+option and a boot parameter which control whether we accept or fail with
+unsigned modules and modules that are signed with an unknown key.
+
+If module signing is enabled, the kernel will be tainted if a module is
+loaded that is unsigned or has a signature for which we don't have the
+key.
+
+(Useful feedback and tweaks by David Howells <dhowells@redhat.com>)
+
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ Documentation/kernel-parameters.txt | 6 +++
+ include/linux/module.h | 8 ++++
+ init/Kconfig | 14 ++++++
+ kernel/Makefile | 1 +
+ kernel/module-internal.h | 13 ++++++
+ kernel/module.c | 93 ++++++++++++++++++++++++++++++++++++-
+ kernel/module_signing.c | 23 +++++++++
+ 7 files changed, 157 insertions(+), 1 deletion(-)
+ create mode 100644 kernel/module-internal.h
+ create mode 100644 kernel/module_signing.c
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index ad7e2e5..9b2b8d3 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ log everything. Information is printed at KERN_DEBUG
+ so loglevel=8 may also need to be specified.
+
++ module.sig_enforce
++ [KNL] When CONFIG_MODULE_SIG is set, this means that
++ modules without (valid) signatures will fail to load.
++ Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
++ is always true, so this option does nothing.
++
+ mousedev.tap_time=
+ [MOUSE] Maximum time between finger touching and
+ leaving touchpad surface for touch to be considered
+diff --git a/include/linux/module.h b/include/linux/module.h
+index fbcafe2..7760c6d 100644
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -21,6 +21,9 @@
+ #include <linux/percpu.h>
+ #include <asm/module.h>
+
++/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
++#define MODULE_SIG_STRING "~Module signature appended~\n"
++
+ /* Not Yet Implemented */
+ #define MODULE_SUPPORTED_DEVICE(name)
+
+@@ -260,6 +263,11 @@ struct module
+ const unsigned long *unused_gpl_crcs;
+ #endif
+
++#ifdef CONFIG_MODULE_SIG
++ /* Signature was verified. */
++ bool sig_ok;
++#endif
++
+ /* symbols that will be GPL-only in the near future. */
+ const struct kernel_symbol *gpl_future_syms;
+ const unsigned long *gpl_future_crcs;
+diff --git a/init/Kconfig b/init/Kconfig
+index af6c7f8..7452e19 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL
+ the version). With this option, such a "srcversion" field
+ will be created for all modules. If unsure, say N.
+
++config MODULE_SIG
++ bool "Module signature verification"
++ depends on MODULES
++ help
++ Check modules for valid signatures upon load: the signature
++ is simply appended to the module. For more information see
++ Documentation/module-signing.txt.
++
++config MODULE_SIG_FORCE
++ bool "Require modules to be validly signed"
++ depends on MODULE_SIG
++ help
++ Reject unsigned modules or signed modules for which we don't have a
++ key. Without this, such modules will simply taint the kernel.
+ endif # MODULES
+
+ config INIT_ALL_POSSIBLE
+diff --git a/kernel/Makefile b/kernel/Makefile
+index c0cc67a..08ba8a6 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -55,6 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
+ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += module.o
++obj-$(CONFIG_MODULE_SIG) += module_signing.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+diff --git a/kernel/module-internal.h b/kernel/module-internal.h
+new file mode 100644
+index 0000000..033c17f
+--- /dev/null
++++ b/kernel/module-internal.h
+@@ -0,0 +1,13 @@
++/* Module internals
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++extern int mod_verify_sig(const void *mod, unsigned long modlen,
++ const void *sig, unsigned long siglen);
+diff --git a/kernel/module.c b/kernel/module.c
+index 9ad9ee9..7efb415 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -58,6 +58,7 @@
+ #include <linux/jump_label.h>
+ #include <linux/pfn.h>
+ #include <linux/bsearch.h>
++#include "module-internal.h"
+
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/module.h>
+@@ -102,6 +103,43 @@ static LIST_HEAD(modules);
+ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+ #endif /* CONFIG_KGDB_KDB */
+
++#ifdef CONFIG_MODULE_SIG
++#ifdef CONFIG_MODULE_SIG_FORCE
++static bool sig_enforce = true;
++#else
++static bool sig_enforce = false;
++
++static int param_set_bool_enable_only(const char *val,
++ const struct kernel_param *kp)
++{
++ int err;
++ bool test;
++ struct kernel_param dummy_kp = *kp;
++
++ dummy_kp.arg = &test;
++
++ err = param_set_bool(val, &dummy_kp);
++ if (err)
++ return err;
++
++ /* Don't let them unset it once it's set! */
++ if (!test && sig_enforce)
++ return -EROFS;
++
++ if (test)
++ sig_enforce = true;
++ return 0;
++}
++
++static const struct kernel_param_ops param_ops_bool_enable_only = {
++ .set = param_set_bool_enable_only,
++ .get = param_get_bool,
++};
++#define param_check_bool_enable_only param_check_bool
++
++module_param(sig_enforce, bool_enable_only, 0644);
++#endif /* !CONFIG_MODULE_SIG_FORCE */
++#endif /* CONFIG_MODULE_SIG */
+
+ /* Block module loading/unloading? */
+ int modules_disabled = 0;
+@@ -136,6 +174,7 @@ struct load_info {
+ unsigned long symoffs, stroffs;
+ struct _ddebug *debug;
+ unsigned int num_debug;
++ bool sig_ok;
+ struct {
+ unsigned int sym, str, mod, vers, info, pcpu;
+ } index;
+@@ -2399,7 +2438,49 @@ static inline void kmemleak_load_module(const struct module *mod,
+ }
+ #endif
+
+-/* Sets info->hdr and info->len. */
++#ifdef CONFIG_MODULE_SIG
++static int module_sig_check(struct load_info *info,
++ const void *mod, unsigned long *len)
++{
++ int err = -ENOKEY;
++ const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
++ const void *p = mod, *end = mod + *len;
++
++ /* Poor man's memmem. */
++ while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
++ if (p + markerlen > end)
++ break;
++
++ if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
++ const void *sig = p + markerlen;
++ /* Truncate module up to signature. */
++ *len = p - mod;
++ err = mod_verify_sig(mod, *len, sig, end - sig);
++ break;
++ }
++ p++;
++ }
++
++ if (!err) {
++ info->sig_ok = true;
++ return 0;
++ }
++
++ /* Not having a signature is only an error if we're strict. */
++ if (err == -ENOKEY && !sig_enforce)
++ err = 0;
++
++ return err;
++}
++#else /* !CONFIG_MODULE_SIG */
++static int module_sig_check(struct load_info *info,
++ void *mod, unsigned long *len)
++{
++ return 0;
++}
++#endif /* !CONFIG_MODULE_SIG */
++
++/* Sets info->hdr, info->len and info->sig_ok. */
+ static int copy_and_check(struct load_info *info,
+ const void __user *umod, unsigned long len,
+ const char __user *uargs)
+@@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info,
+ goto free_hdr;
+ }
+
++ err = module_sig_check(info, hdr, &len);
++ if (err)
++ goto free_hdr;
++
+ /* Sanity checks against insmoding binaries or wrong arch,
+ weird elf version */
+ if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
+@@ -2890,6 +2975,12 @@ static struct module *load_module(void __user *umod,
+ goto free_copy;
+ }
+
++#ifdef CONFIG_MODULE_SIG
++ mod->sig_ok = info.sig_ok;
++ if (!mod->sig_ok)
++ add_taint_module(mod, TAINT_FORCED_MODULE);
++#endif
++
+ /* Now module is in final location, initialize linked lists, etc. */
+ err = module_unload_init(mod);
+ if (err)
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+new file mode 100644
+index 0000000..499728a
+--- /dev/null
++++ b/kernel/module_signing.c
+@@ -0,0 +1,23 @@
++/* Module signature checker
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/err.h>
++#include "module-internal.h"
++
++/*
++ * Verify the signature on a module.
++ */
++int mod_verify_sig(const void *mod, unsigned long modlen,
++ const void *sig, unsigned long siglen)
++{
++ return -ENOKEY;
++}
+--
+1.7.12.1
+
+
+From 82400c211d81ea36338fb8266b5c41710101a013 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 13 Sep 2012 13:06:29 +0100
+Subject: [PATCH 02/37] KEYS: Add payload preparsing opportunity prior to key
+ instantiate or update
+
+Give the key type the opportunity to preparse the payload prior to the
+instantiation and update routines being called. This is done with the
+provision of two new key type operations:
+
+ int (*preparse)(struct key_preparsed_payload *prep);
+ void (*free_preparse)(struct key_preparsed_payload *prep);
+
+If the first operation is present, then it is called before key creation (in
+the add/update case) or before the key semaphore is taken (in the update and
+instantiate cases). The second operation is called to clean up if the first
+was called.
+
+preparse() is given the opportunity to fill in the following structure:
+
+ struct key_preparsed_payload {
+ char *description;
+ void *type_data[2];
+ void *payload;
+ const void *data;
+ size_t datalen;
+ size_t quotalen;
+ };
+
+Before the preparser is called, the first three fields will have been cleared,
+the payload pointer and size will be stored in data and datalen and the default
+quota size from the key_type struct will be stored into quotalen.
+
+The preparser may parse the payload in any way it likes and may store data in
+the type_data[] and payload fields for use by the instantiate() and update()
+ops.
+
+The preparser may also propose a description for the key by attaching it as a
+string to the description field. This can be used by passing a NULL or ""
+description to the add_key() system call or the key_create_or_update()
+function. This cannot work with request_key() as that required the description
+to tell the upcall about the key to be created.
+
+This, for example permits keys that store PGP public keys to generate their own
+name from the user ID and public key fingerprint in the key.
+
+The instantiate() and update() operations are then modified to look like this:
+
+ int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
+ int (*update)(struct key *key, struct key_preparsed_payload *prep);
+
+and the new payload data is passed in *prep, whether or not it was preparsed.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ Documentation/security/keys.txt | 50 +++++++++++++-
+ fs/cifs/cifs_spnego.c | 6 +-
+ fs/cifs/cifsacl.c | 8 +--
+ include/keys/user-type.h | 6 +-
+ include/linux/key-type.h | 35 +++++++++-
+ net/ceph/crypto.c | 9 +--
+ net/dns_resolver/dns_key.c | 6 +-
+ net/rxrpc/ar-key.c | 40 +++++------
+ security/keys/encrypted-keys/encrypted.c | 16 +++--
+ security/keys/key.c | 114 ++++++++++++++++++++++---------
+ security/keys/keyctl.c | 18 +++--
+ security/keys/keyring.c | 6 +-
+ security/keys/request_key_auth.c | 8 +--
+ security/keys/trusted.c | 16 +++--
+ security/keys/user_defined.c | 14 ++--
+ 15 files changed, 250 insertions(+), 102 deletions(-)
+
+diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
+index aa0dbd7..7d9ca92 100644
+--- a/Documentation/security/keys.txt
++++ b/Documentation/security/keys.txt
+@@ -412,6 +412,10 @@ The main syscalls are:
+ to the keyring. In this case, an error will be generated if the process
+ does not have permission to write to the keyring.
+
++ If the key type supports it, if the description is NULL or an empty
++ string, the key type will try and generate a description from the content
++ of the payload.
++
+ The payload is optional, and the pointer can be NULL if not required by
+ the type. The payload is plen in size, and plen can be zero for an empty
+ payload.
+@@ -1114,12 +1118,53 @@ The structure has a number of fields, some of which are mandatory:
+ it should return 0.
+
+
+- (*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
++ (*) int (*preparse)(struct key_preparsed_payload *prep);
++
++ This optional method permits the key type to attempt to parse payload
++ before a key is created (add key) or the key semaphore is taken (update or
++ instantiate key). The structure pointed to by prep looks like:
++
++ struct key_preparsed_payload {
++ char *description;
++ void *type_data[2];
++ void *payload;
++ const void *data;
++ size_t datalen;
++ size_t quotalen;
++ };
++
++ Before calling the method, the caller will fill in data and datalen with
++ the payload blob parameters; quotalen will be filled in with the default
++ quota size from the key type and the rest will be cleared.
++
++ If a description can be proposed from the payload contents, that should be
++ attached as a string to the description field. This will be used for the
++ key description if the caller of add_key() passes NULL or "".
++
++ The method can attach anything it likes to type_data[] and payload. These
++ are merely passed along to the instantiate() or update() operations.
++
++ The method should return 0 if success ful or a negative error code
++ otherwise.
++
++
++ (*) void (*free_preparse)(struct key_preparsed_payload *prep);
++
++ This method is only required if the preparse() method is provided,
++ otherwise it is unused. It cleans up anything attached to the
++ description, type_data and payload fields of the key_preparsed_payload
++ struct as filled in by the preparse() method.
++
++
++ (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
+
+ This method is called to attach a payload to a key during construction.
+ The payload attached need not bear any relation to the data passed to this
+ function.
+
++ The prep->data and prep->datalen fields will define the original payload
++ blob. If preparse() was supplied then other fields may be filled in also.
++
+ If the amount of data attached to the key differs from the size in
+ keytype->def_datalen, then key_payload_reserve() should be called.
+
+@@ -1135,6 +1180,9 @@ The structure has a number of fields, some of which are mandatory:
+ If this type of key can be updated, then this method should be provided.
+ It is called to update a key's payload from the blob of data provided.
+
++ The prep->data and prep->datalen fields will define the original payload
++ blob. If preparse() was supplied then other fields may be filled in also.
++
+ key_payload_reserve() should be called if the data length might change
+ before any changes are actually made. Note that if this succeeds, the type
+ is committed to changing the key because it's already been altered, so all
+diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
+index e622863..086f381 100644
+--- a/fs/cifs/cifs_spnego.c
++++ b/fs/cifs/cifs_spnego.c
+@@ -31,18 +31,18 @@
+
+ /* create a new cifs key */
+ static int
+-cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
++cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+ char *payload;
+ int ret;
+
+ ret = -ENOMEM;
+- payload = kmalloc(datalen, GFP_KERNEL);
++ payload = kmalloc(prep->datalen, GFP_KERNEL);
+ if (!payload)
+ goto error;
+
+ /* attach the data */
+- memcpy(payload, data, datalen);
++ memcpy(payload, prep->data, prep->datalen);
+ key->payload.data = payload;
+ ret = 0;
+
+diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
+index 05f4dc2..f3c60e2 100644
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {
+ };
+
+ static int
+-cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
++cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+ char *payload;
+
+- payload = kmalloc(datalen, GFP_KERNEL);
++ payload = kmalloc(prep->datalen, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+- memcpy(payload, data, datalen);
++ memcpy(payload, prep->data, prep->datalen);
+ key->payload.data = payload;
+- key->datalen = datalen;
++ key->datalen = prep->datalen;
+ return 0;
+ }
+
+diff --git a/include/keys/user-type.h b/include/keys/user-type.h
+index bc9ec1d..5e452c8 100644
+--- a/include/keys/user-type.h
++++ b/include/keys/user-type.h
+@@ -35,8 +35,10 @@ struct user_key_payload {
+ extern struct key_type key_type_user;
+ extern struct key_type key_type_logon;
+
+-extern int user_instantiate(struct key *key, const void *data, size_t datalen);
+-extern int user_update(struct key *key, const void *data, size_t datalen);
++struct key_preparsed_payload;
++
++extern int user_instantiate(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_destroy(struct key *key);
+diff --git a/include/linux/key-type.h b/include/linux/key-type.h
+index f0c651c..518a53a 100644
+--- a/include/linux/key-type.h
++++ b/include/linux/key-type.h
+@@ -26,6 +26,27 @@ struct key_construction {
+ struct key *authkey;/* authorisation for key being constructed */
+ };
+
++/*
++ * Pre-parsed payload, used by key add, update and instantiate.
++ *
++ * This struct will be cleared and data and datalen will be set with the data
++ * and length parameters from the caller and quotalen will be set from
++ * def_datalen from the key type. Then if the preparse() op is provided by the
++ * key type, that will be called. Then the struct will be passed to the
++ * instantiate() or the update() op.
++ *
++ * If the preparse() op is given, the free_preparse() op will be called to
++ * clear the contents.
++ */
++struct key_preparsed_payload {
++ char *description; /* Proposed key description (or NULL) */
++ void *type_data[2]; /* Private key-type data */
++ void *payload; /* Proposed payload */
++ const void *data; /* Raw data */
++ size_t datalen; /* Raw datalen */
++ size_t quotalen; /* Quota length for proposed payload */
++};
++
+ typedef int (*request_key_actor_t)(struct key_construction *key,
+ const char *op, void *aux);
+
+@@ -45,18 +66,28 @@ struct key_type {
+ /* vet a description */
+ int (*vet_description)(const char *description);
+
++ /* Preparse the data blob from userspace that is to be the payload,
++ * generating a proposed description and payload that will be handed to
++ * the instantiate() and update() ops.
++ */
++ int (*preparse)(struct key_preparsed_payload *prep);
++
++ /* Free a preparse data structure.
++ */
++ void (*free_preparse)(struct key_preparsed_payload *prep);
++
+ /* instantiate a key of this type
+ * - this method should call key_payload_reserve() to determine if the
+ * user's quota will hold the payload
+ */
+- int (*instantiate)(struct key *key, const void *data, size_t datalen);
++ int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
+
+ /* update a key of this type (optional)
+ * - this method should call key_payload_reserve() to recalculate the
+ * quota consumption
+ * - the key must be locked against read when modifying
+ */
+- int (*update)(struct key *key, const void *data, size_t datalen);
++ 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);
+diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
+index 9da7fdd..af14cb4 100644
+--- a/net/ceph/crypto.c
++++ b/net/ceph/crypto.c
+@@ -423,14 +423,15 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
+ }
+ }
+
+-int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
++int ceph_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+ struct ceph_crypto_key *ckey;
++ size_t datalen = prep->datalen;
+ int ret;
+ void *p;
+
+ ret = -EINVAL;
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ goto err;
+
+ ret = key_payload_reserve(key, datalen);
+@@ -443,8 +444,8 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
+ goto err;
+
+ /* TODO ceph_crypto_key_decode should really take const input */
+- p = (void *)data;
+- ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
++ p = (void *)prep->data;
++ ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
+ if (ret < 0)
+ goto err_ckey;
+
+diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
+index d9507dd..859ab8b 100644
+--- a/net/dns_resolver/dns_key.c
++++ b/net/dns_resolver/dns_key.c
+@@ -59,13 +59,13 @@ const struct cred *dns_resolver_cache;
+ * "ip1,ip2,...#foo=bar"
+ */
+ static int
+-dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
++dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+ struct user_key_payload *upayload;
+ unsigned long derrno;
+ int ret;
+- size_t result_len = 0;
+- const char *data = _data, *end, *opt;
++ size_t datalen = prep->datalen, result_len = 0;
++ const char *data = prep->data, *end, *opt;
+
+ kenter("%%%d,%s,'%*.*s',%zu",
+ key->serial, key->description,
+diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
+index 8b1f9f4..106c5a6 100644
+--- a/net/rxrpc/ar-key.c
++++ b/net/rxrpc/ar-key.c
+@@ -26,8 +26,8 @@
+ #include "ar-internal.h"
+
+ static int rxrpc_vet_description_s(const char *);
+-static int rxrpc_instantiate(struct key *, const void *, size_t);
+-static int rxrpc_instantiate_s(struct key *, const void *, size_t);
++static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
++static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
+ static void rxrpc_destroy(struct key *);
+ static void rxrpc_destroy_s(struct key *);
+ static void rxrpc_describe(const struct key *, struct seq_file *);
+@@ -678,7 +678,7 @@ error:
+ *
+ * if no data is provided, then a no-security key is made
+ */
+-static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
++static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+ const struct rxrpc_key_data_v1 *v1;
+ struct rxrpc_key_token *token, **pp;
+@@ -686,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
+ u32 kver;
+ int ret;
+
+- _enter("{%x},,%zu", key_serial(key), datalen);
++ _enter("{%x},,%zu", key_serial(key), prep->datalen);
+
+ /* handle a no-security key */
+- if (!data && datalen == 0)
++ if (!prep->data && prep->datalen == 0)
+ return 0;
+
+ /* determine if the XDR payload format is being used */
+- if (datalen > 7 * 4) {
+- ret = rxrpc_instantiate_xdr(key, data, datalen);
++ if (prep->datalen > 7 * 4) {
++ ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
+ if (ret != -EPROTO)
+ return ret;
+ }
+
+ /* get the key interface version number */
+ ret = -EINVAL;
+- if (datalen <= 4 || !data)
++ if (prep->datalen <= 4 || !prep->data)
+ goto error;
+- memcpy(&kver, data, sizeof(kver));
+- data += sizeof(kver);
+- datalen -= sizeof(kver);
++ memcpy(&kver, prep->data, sizeof(kver));
++ prep->data += sizeof(kver);
++ prep->datalen -= sizeof(kver);
+
+ _debug("KEY I/F VERSION: %u", kver);
+
+@@ -715,11 +715,11 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
+
+ /* deal with a version 1 key */
+ ret = -EINVAL;
+- if (datalen < sizeof(*v1))
++ if (prep->datalen < sizeof(*v1))
+ goto error;
+
+- v1 = data;
+- if (datalen != sizeof(*v1) + v1->ticket_length)
++ v1 = prep->data;
++ if (prep->datalen != sizeof(*v1) + v1->ticket_length)
+ goto error;
+
+ _debug("SCIX: %u", v1->security_index);
+@@ -784,17 +784,17 @@ error:
+ * instantiate a server secret key
+ * data should be a pointer to the 8-byte secret key
+ */
+-static int rxrpc_instantiate_s(struct key *key, const void *data,
+- size_t datalen)
++static int rxrpc_instantiate_s(struct key *key,
++ struct key_preparsed_payload *prep)
+ {
+ struct crypto_blkcipher *ci;
+
+- _enter("{%x},,%zu", key_serial(key), datalen);
++ _enter("{%x},,%zu", key_serial(key), prep->datalen);
+
+- if (datalen != 8)
++ if (prep->datalen != 8)
+ return -EINVAL;
+
+- memcpy(&key->type_data, data, 8);
++ memcpy(&key->type_data, prep->data, 8);
+
+ ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(ci)) {
+@@ -802,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data,
+ return PTR_ERR(ci);
+ }
+
+- if (crypto_blkcipher_setkey(ci, data, 8) < 0)
++ if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
+ BUG();
+
+ key->payload.data = ci;
+diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
+index 2d1bb8a..9e1e005 100644
+--- a/security/keys/encrypted-keys/encrypted.c
++++ b/security/keys/encrypted-keys/encrypted.c
+@@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload,
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+-static int encrypted_instantiate(struct key *key, const void *data,
+- size_t datalen)
++static int encrypted_instantiate(struct key *key,
++ struct key_preparsed_payload *prep)
+ {
+ struct encrypted_key_payload *epayload = NULL;
+ char *datablob = NULL;
+@@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data,
+ char *master_desc = NULL;
+ char *decrypted_datalen = NULL;
+ char *hex_encoded_iv = NULL;
++ size_t datalen = prep->datalen;
+ int ret;
+
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ return -EINVAL;
+
+ datablob = kmalloc(datalen + 1, GFP_KERNEL);
+ if (!datablob)
+ return -ENOMEM;
+ datablob[datalen] = 0;
+- memcpy(datablob, data, datalen);
++ memcpy(datablob, prep->data, datalen);
+ ret = datablob_parse(datablob, &format, &master_desc,
+ &decrypted_datalen, &hex_encoded_iv);
+ if (ret < 0)
+@@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+-static int encrypted_update(struct key *key, const void *data, size_t datalen)
++static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
+ {
+ struct encrypted_key_payload *epayload = key->payload.data;
+ struct encrypted_key_payload *new_epayload;
+ char *buf;
+ char *new_master_desc = NULL;
+ const char *format = NULL;
++ size_t datalen = prep->datalen;
+ int ret = 0;
+
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ return -EINVAL;
+
+ buf = kmalloc(datalen + 1, GFP_KERNEL);
+@@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
+ return -ENOMEM;
+
+ buf[datalen] = 0;
+- memcpy(buf, data, datalen);
++ memcpy(buf, prep->data, datalen);
+ ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
+ if (ret < 0)
+ goto out;
+diff --git a/security/keys/key.c b/security/keys/key.c
+index 50d96d4..1d039af 100644
+--- a/security/keys/key.c
++++ b/security/keys/key.c
+@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve);
+ * key_construction_mutex.
+ */
+ static int __key_instantiate_and_link(struct key *key,
+- const void *data,
+- size_t datalen,
++ struct key_preparsed_payload *prep,
+ struct key *keyring,
+ struct key *authkey,
+ unsigned long *_prealloc)
+@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key,
+ /* can't instantiate twice */
+ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+ /* instantiate the key */
+- ret = key->type->instantiate(key, data, datalen);
++ ret = key->type->instantiate(key, prep);
+
+ if (ret == 0) {
+ /* mark the key as being instantiated */
+@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key,
+ struct key *keyring,
+ struct key *authkey)
+ {
++ struct key_preparsed_payload prep;
+ unsigned long prealloc;
+ int ret;
+
++ memset(&prep, 0, sizeof(prep));
++ prep.data = data;
++ prep.datalen = datalen;
++ prep.quotalen = key->type->def_datalen;
++ if (key->type->preparse) {
++ ret = key->type->preparse(&prep);
++ if (ret < 0)
++ goto error;
++ }
++
+ if (keyring) {
+ ret = __key_link_begin(keyring, key->type, key->description,
+ &prealloc);
+ if (ret < 0)
+- return ret;
++ goto error_free_preparse;
+ }
+
+- ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
++ ret = __key_instantiate_and_link(key, &prep, keyring, authkey,
+ &prealloc);
+
+ if (keyring)
+ __key_link_end(keyring, key->type, prealloc);
+
++error_free_preparse:
++ if (key->type->preparse)
++ key->type->free_preparse(&prep);
++error:
+ return ret;
+ }
+
+@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype)
+ * if we get an error.
+ */
+ static inline key_ref_t __key_update(key_ref_t key_ref,
+- const void *payload, size_t plen)
++ struct key_preparsed_payload *prep)
+ {
+ struct key *key = key_ref_to_ptr(key_ref);
+ int ret;
+@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
+
+ down_write(&key->sem);
+
+- ret = key->type->update(key, payload, plen);
++ ret = key->type->update(key, prep);
+ if (ret == 0)
+ /* updating a negative key instantiates it */
+ clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
+@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ unsigned long flags)
+ {
+ unsigned long prealloc;
++ struct key_preparsed_payload prep;
+ const struct cred *cred = current_cred();
+ struct key_type *ktype;
+ struct key *keyring, *key = NULL;
+@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ }
+
+ key_ref = ERR_PTR(-EINVAL);
+- if (!ktype->match || !ktype->instantiate)
+- goto error_2;
++ if (!ktype->match || !ktype->instantiate ||
++ (!description && !ktype->preparse))
++ goto error_put_type;
+
+ keyring = key_ref_to_ptr(keyring_ref);
+
+@@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+
+ key_ref = ERR_PTR(-ENOTDIR);
+ if (keyring->type != &key_type_keyring)
+- goto error_2;
++ goto error_put_type;
++
++ memset(&prep, 0, sizeof(prep));
++ prep.data = payload;
++ prep.datalen = plen;
++ prep.quotalen = ktype->def_datalen;
++ if (ktype->preparse) {
++ ret = ktype->preparse(&prep);
++ if (ret < 0) {
++ key_ref = ERR_PTR(ret);
++ goto error_put_type;
++ }
++ if (!description)
++ description = prep.description;
++ key_ref = ERR_PTR(-EINVAL);
++ if (!description)
++ goto error_free_prep;
++ }
+
+ ret = __key_link_begin(keyring, ktype, description, &prealloc);
+- if (ret < 0)
+- goto error_2;
++ if (ret < 0) {
++ key_ref = ERR_PTR(ret);
++ goto error_free_prep;
++ }
+
+ /* if we're going to allocate a new key, we're going to have
+ * to modify the keyring */
+ ret = key_permission(keyring_ref, KEY_WRITE);
+ if (ret < 0) {
+ key_ref = ERR_PTR(ret);
+- goto error_3;
++ goto error_link_end;
+ }
+
+ /* if it's possible to update this type of key, search for an existing
+@@ -840,25 +875,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ perm, flags);
+ if (IS_ERR(key)) {
+ key_ref = ERR_CAST(key);
+- goto error_3;
++ goto error_link_end;
+ }
+
+ /* instantiate it and link it into the target keyring */
+- ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
+- &prealloc);
++ ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc);
+ if (ret < 0) {
+ key_put(key);
+ key_ref = ERR_PTR(ret);
+- goto error_3;
++ goto error_link_end;
+ }
+
+ key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
+
+- error_3:
++error_link_end:
+ __key_link_end(keyring, ktype, prealloc);
+- error_2:
++error_free_prep:
++ if (ktype->preparse)
++ ktype->free_preparse(&prep);
++error_put_type:
+ key_type_put(ktype);
+- error:
++error:
+ return key_ref;
+
+ found_matching_key:
+@@ -866,10 +903,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ * - we can drop the locks first as we have the key pinned
+ */
+ __key_link_end(keyring, ktype, prealloc);
+- key_type_put(ktype);
+
+- key_ref = __key_update(key_ref, payload, plen);
+- goto error;
++ key_ref = __key_update(key_ref, &prep);
++ goto error_free_prep;
+ }
+ EXPORT_SYMBOL(key_create_or_update);
+
+@@ -888,6 +924,7 @@ EXPORT_SYMBOL(key_create_or_update);
+ */
+ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
+ {
++ struct key_preparsed_payload prep;
+ struct key *key = key_ref_to_ptr(key_ref);
+ int ret;
+
+@@ -900,18 +937,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
+
+ /* attempt to update it if supported */
+ ret = -EOPNOTSUPP;
+- if (key->type->update) {
+- down_write(&key->sem);
+-
+- ret = key->type->update(key, payload, plen);
+- if (ret == 0)
+- /* updating a negative key instantiates it */
+- clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
++ if (!key->type->update)
++ goto error;
+
+- up_write(&key->sem);
++ memset(&prep, 0, sizeof(prep));
++ prep.data = payload;
++ prep.datalen = plen;
++ prep.quotalen = key->type->def_datalen;
++ if (key->type->preparse) {
++ ret = key->type->preparse(&prep);
++ if (ret < 0)
++ goto error;
+ }
+
+- error:
++ down_write(&key->sem);
++
++ ret = key->type->update(key, &prep);
++ if (ret == 0)
++ /* updating a negative key instantiates it */
++ clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
++
++ up_write(&key->sem);
++
++ if (key->type->preparse)
++ key->type->free_preparse(&prep);
++error:
+ return ret;
+ }
+ EXPORT_SYMBOL(key_update);
+diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
+index 3364fbf..505d40b 100644
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type,
+ * Extract the description of a new key from userspace and either add it as a
+ * new key to the specified keyring or update a matching key in that keyring.
+ *
++ * If the description is NULL or an empty string, the key type is asked to
++ * generate one from the payload.
++ *
+ * The keyring must be writable so that we can attach the key to it.
+ *
+ * If successful, the new key's serial number is returned, otherwise an error
+@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
+ if (ret < 0)
+ goto error;
+
+- description = strndup_user(_description, PAGE_SIZE);
+- if (IS_ERR(description)) {
+- ret = PTR_ERR(description);
+- goto error;
++ description = NULL;
++ if (_description) {
++ description = strndup_user(_description, PAGE_SIZE);
++ if (IS_ERR(description)) {
++ ret = PTR_ERR(description);
++ goto error;
++ }
++ if (!*description) {
++ kfree(description);
++ description = NULL;
++ }
+ }
+
+ /* pull the payload in if one was supplied */
+diff --git a/security/keys/keyring.c b/security/keys/keyring.c
+index 81e7852..f04d8cf 100644
+--- a/security/keys/keyring.c
++++ b/security/keys/keyring.c
+@@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc)
+ * operations.
+ */
+ static int keyring_instantiate(struct key *keyring,
+- const void *data, size_t datalen);
++ struct key_preparsed_payload *prep);
+ static int keyring_match(const struct key *keyring, const void *criterion);
+ static void keyring_revoke(struct key *keyring);
+ static void keyring_destroy(struct key *keyring);
+@@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring)
+ * Returns 0 on success, -EINVAL if given any data.
+ */
+ static int keyring_instantiate(struct key *keyring,
+- const void *data, size_t datalen)
++ struct key_preparsed_payload *prep)
+ {
+ int ret;
+
+ ret = -EINVAL;
+- if (datalen == 0) {
++ if (prep->datalen == 0) {
+ /* make the keyring available by name if it has one */
+ keyring_publish_name(keyring);
+ ret = 0;
+diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
+index 60d4e3f..85730d5 100644
+--- a/security/keys/request_key_auth.c
++++ b/security/keys/request_key_auth.c
+@@ -19,7 +19,8 @@
+ #include <asm/uaccess.h>
+ #include "internal.h"
+
+-static int request_key_auth_instantiate(struct key *, const void *, size_t);
++static int request_key_auth_instantiate(struct key *,
++ struct key_preparsed_payload *);
+ static void request_key_auth_describe(const struct key *, struct seq_file *);
+ static void request_key_auth_revoke(struct key *);
+ static void request_key_auth_destroy(struct key *);
+@@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = {
+ * Instantiate a request-key authorisation key.
+ */
+ static int request_key_auth_instantiate(struct key *key,
+- const void *data,
+- size_t datalen)
++ struct key_preparsed_payload *prep)
+ {
+- key->payload.data = (struct request_key_auth *) data;
++ key->payload.data = (struct request_key_auth *)prep->data;
+ return 0;
+ }
+
+diff --git a/security/keys/trusted.c b/security/keys/trusted.c
+index 2d5d041..42036c7 100644
+--- a/security/keys/trusted.c
++++ b/security/keys/trusted.c
+@@ -927,22 +927,23 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
+ *
+ * On success, return 0. Otherwise return errno.
+ */
+-static int trusted_instantiate(struct key *key, const void *data,
+- size_t datalen)
++static int trusted_instantiate(struct key *key,
++ struct key_preparsed_payload *prep)
+ {
+ struct trusted_key_payload *payload = NULL;
+ struct trusted_key_options *options = NULL;
++ size_t datalen = prep->datalen;
+ char *datablob;
+ int ret = 0;
+ int key_cmd;
+
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ return -EINVAL;
+
+ datablob = kmalloc(datalen + 1, GFP_KERNEL);
+ if (!datablob)
+ return -ENOMEM;
+- memcpy(datablob, data, datalen);
++ memcpy(datablob, prep->data, datalen);
+ datablob[datalen] = '\0';
+
+ options = trusted_options_alloc();
+@@ -1011,17 +1012,18 @@ static void trusted_rcu_free(struct rcu_head *rcu)
+ /*
+ * trusted_update - reseal an existing key with new PCR values
+ */
+-static int trusted_update(struct key *key, const void *data, size_t datalen)
++static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
+ {
+ struct trusted_key_payload *p = key->payload.data;
+ struct trusted_key_payload *new_p;
+ struct trusted_key_options *new_o;
++ size_t datalen = prep->datalen;
+ char *datablob;
+ int ret = 0;
+
+ if (!p->migratable)
+ return -EPERM;
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ return -EINVAL;
+
+ datablob = kmalloc(datalen + 1, GFP_KERNEL);
+@@ -1038,7 +1040,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
+ goto out;
+ }
+
+- memcpy(datablob, data, datalen);
++ memcpy(datablob, prep->data, datalen);
+ datablob[datalen] = '\0';
+ ret = datablob_parse(datablob, new_p, new_o);
+ if (ret != Opt_update) {
+diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
+index c7660a2..55dc889 100644
+--- a/security/keys/user_defined.c
++++ b/security/keys/user_defined.c
+@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon);
+ /*
+ * instantiate a user defined key
+ */
+-int user_instantiate(struct key *key, const void *data, size_t datalen)
++int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+ struct user_key_payload *upayload;
++ size_t datalen = prep->datalen;
+ int ret;
+
+ ret = -EINVAL;
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ goto error;
+
+ ret = key_payload_reserve(key, datalen);
+@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
+
+ /* attach the data */
+ upayload->datalen = datalen;
+- memcpy(upayload->data, data, datalen);
++ memcpy(upayload->data, prep->data, datalen);
+ rcu_assign_keypointer(key, upayload);
+ ret = 0;
+
+@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate);
+ * update a user defined key
+ * - the key's semaphore is write-locked
+ */
+-int user_update(struct key *key, const void *data, size_t datalen)
++int user_update(struct key *key, struct key_preparsed_payload *prep)
+ {
+ struct user_key_payload *upayload, *zap;
++ size_t datalen = prep->datalen;
+ int ret;
+
+ ret = -EINVAL;
+- if (datalen <= 0 || datalen > 32767 || !data)
++ if (datalen <= 0 || datalen > 32767 || !prep->data)
+ goto error;
+
+ /* construct a replacement payload */
+@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen)
+ goto error;
+
+ upayload->datalen = datalen;
+- memcpy(upayload->data, data, datalen);
++ memcpy(upayload->data, prep->data, datalen);
+
+ /* check the quota and attach the new data */
+ zap = upayload;
+--
+1.7.12.1
+
+
+From 162ce9c1b0f28d36598975f8931f216245b7e778 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 13 Sep 2012 13:09:33 +0100
+Subject: [PATCH 03/37] MPILIB: Provide count_leading/trailing_zeros() based
+ on arch functions
+
+Provide count_leading/trailing_zeros() macros based on extant arch bit scanning
+functions rather than reimplementing from scratch in MPILIB.
+
+Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x).
+
+Also move the definition to asm-generic as other people may be interested in
+using it.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
+Cc: Arnd Bergmann <arnd@arndb.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ include/asm-generic/bitops/count_zeros.h | 57 +++++++++++++
+ lib/mpi/longlong.h | 138 +------------------------------
+ lib/mpi/mpi-bit.c | 2 +-
+ lib/mpi/mpi-pow.c | 4 +-
+ 4 files changed, 62 insertions(+), 139 deletions(-)
+ create mode 100644 include/asm-generic/bitops/count_zeros.h
+
+diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h
+new file mode 100644
+index 0000000..97520d2
+--- /dev/null
++++ b/include/asm-generic/bitops/count_zeros.h
+@@ -0,0 +1,57 @@
++/* Count leading and trailing zeros functions
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
++#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
++
++#include <asm/bitops.h>
++
++/**
++ * count_leading_zeros - Count the number of zeros from the MSB back
++ * @x: The value
++ *
++ * Count the number of leading zeros from the MSB going towards the LSB in @x.
++ *
++ * If the MSB of @x is set, the result is 0.
++ * If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
++ * If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
++ */
++static inline int count_leading_zeros(unsigned long x)
++{
++ if (sizeof(x) == 4)
++ return BITS_PER_LONG - fls(x);
++ else
++ return BITS_PER_LONG - fls64(x);
++}
++
++#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
++
++/**
++ * count_trailing_zeros - Count the number of zeros from the LSB forwards
++ * @x: The value
++ *
++ * Count the number of trailing zeros from the LSB going towards the MSB in @x.
++ *
++ * If the LSB of @x is set, the result is 0.
++ * If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
++ * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
++ */
++static inline int count_trailing_zeros(unsigned long x)
++{
++#define COUNT_TRAILING_ZEROS_0 (-1)
++
++ if (sizeof(x) == 4)
++ return ffs(x);
++ else
++ return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
++}
++
++#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */
+diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h
+index 29f9862..678ce4f 100644
+--- a/lib/mpi/longlong.h
++++ b/lib/mpi/longlong.h
+@@ -19,6 +19,8 @@
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA. */
+
++#include <asm-generic/bitops/count_zeros.h>
++
+ /* You have to define the following before including this file:
+ *
+ * UWtype -- An unsigned type, default type for operations (typically a "word")
+@@ -146,12 +148,6 @@ do { \
+ : "1" ((USItype)(n1)), \
+ "r" ((USItype)(n0)), \
+ "r" ((USItype)(d)))
+-
+-#define count_leading_zeros(count, x) \
+- __asm__ ("clz %0,%1" \
+- : "=r" ((USItype)(count)) \
+- : "r" ((USItype)(x)))
+-#define COUNT_LEADING_ZEROS_0 32
+ #endif /* __a29k__ */
+
+ #if defined(__alpha) && W_TYPE_SIZE == 64
+@@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd();
+ : "1" ((USItype)(nh)), \
+ "0" ((USItype)(nl)), \
+ "g" ((USItype)(d)))
+-#define count_leading_zeros(count, x) \
+- __asm__ ("bsch/1 %1,%0" \
+- : "=g" (count) \
+- : "g" ((USItype)(x)), \
+- "0" ((USItype)0))
+ #endif
+
+ /***************************************
+@@ -354,27 +345,6 @@ do { USItype __r; \
+ } while (0)
+ extern USItype __udiv_qrnnd();
+ #endif /* LONGLONG_STANDALONE */
+-#define count_leading_zeros(count, x) \
+-do { \
+- USItype __tmp; \
+- __asm__ ( \
+- "ldi 1,%0\n" \
+- "extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \
+- "extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n" \
+- "ldo 16(%0),%0 ; Yes. Perform add.\n" \
+- "extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \
+- "extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n" \
+- "ldo 8(%0),%0 ; Yes. Perform add.\n" \
+- "extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \
+- "extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n" \
+- "ldo 4(%0),%0 ; Yes. Perform add.\n" \
+- "extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \
+- "extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n" \
+- "ldo 2(%0),%0 ; Yes. Perform add.\n" \
+- "extru %1,30,1,%1 ; Extract bit 1.\n" \
+- "sub %0,%1,%0 ; Subtract it. " \
+- : "=r" (count), "=r" (__tmp) : "1" (x)); \
+-} while (0)
+ #endif /* hppa */
+
+ /***************************************
+@@ -457,15 +427,6 @@ do { \
+ : "0" ((USItype)(n0)), \
+ "1" ((USItype)(n1)), \
+ "rm" ((USItype)(d)))
+-#define count_leading_zeros(count, x) \
+-do { \
+- USItype __cbtmp; \
+- __asm__ ("bsrl %1,%0" \
+- : "=r" (__cbtmp) : "rm" ((USItype)(x))); \
+- (count) = __cbtmp ^ 31; \
+-} while (0)
+-#define count_trailing_zeros(count, x) \
+- __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
+ #ifndef UMUL_TIME
+ #define UMUL_TIME 40
+ #endif
+@@ -536,15 +497,6 @@ do { \
+ "dI" ((USItype)(d))); \
+ (r) = __rq.__i.__l; (q) = __rq.__i.__h; \
+ } while (0)
+-#define count_leading_zeros(count, x) \
+-do { \
+- USItype __cbtmp; \
+- __asm__ ("scanbit %1,%0" \
+- : "=r" (__cbtmp) \
+- : "r" ((USItype)(x))); \
+- (count) = __cbtmp ^ 31; \
+-} while (0)
+-#define COUNT_LEADING_ZEROS_0 (-32) /* sic */
+ #if defined(__i960mx) /* what is the proper symbol to test??? */
+ #define rshift_rhlc(r, h, l, c) \
+ do { \
+@@ -603,11 +555,6 @@ do { \
+ : "0" ((USItype)(n0)), \
+ "1" ((USItype)(n1)), \
+ "dmi" ((USItype)(d)))
+-#define count_leading_zeros(count, x) \
+- __asm__ ("bfffo %1{%b2:%b2},%0" \
+- : "=d" ((USItype)(count)) \
+- : "od" ((USItype)(x)), "n" (0))
+-#define COUNT_LEADING_ZEROS_0 32
+ #else /* not mc68020 */
+ #define umul_ppmm(xh, xl, a, b) \
+ do { USItype __umul_tmp1, __umul_tmp2; \
+@@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \
+ "rJ" ((USItype)(bh)), \
+ "rJ" ((USItype)(al)), \
+ "rJ" ((USItype)(bl)))
+-#define count_leading_zeros(count, x) \
+-do { \
+- USItype __cbtmp; \
+- __asm__ ("ff1 %0,%1" \
+- : "=r" (__cbtmp) \
+- : "r" ((USItype)(x))); \
+- (count) = __cbtmp ^ 31; \
+-} while (0)
+-#define COUNT_LEADING_ZEROS_0 63 /* sic */
+ #if defined(__m88110__)
+ #define umul_ppmm(wh, wl, u, v) \
+ do { \
+@@ -779,12 +717,6 @@ do { \
+ : "0" (__xx.__ll), \
+ "g" ((USItype)(d))); \
+ (r) = __xx.__i.__l; (q) = __xx.__i.__h; })
+-#define count_trailing_zeros(count, x) \
+-do { \
+- __asm__("ffsd %2,%0" \
+- : "=r"((USItype) (count)) \
+- : "0"((USItype) 0), "r"((USItype) (x))); \
+- } while (0)
+ #endif /* __ns32000__ */
+
+ /***************************************
+@@ -855,11 +787,6 @@ do { \
+ "rI" ((USItype)(al)), \
+ "r" ((USItype)(bl))); \
+ } while (0)
+-#define count_leading_zeros(count, x) \
+- __asm__ ("{cntlz|cntlzw} %0,%1" \
+- : "=r" ((USItype)(count)) \
+- : "r" ((USItype)(x)))
+-#define COUNT_LEADING_ZEROS_0 32
+ #if defined(_ARCH_PPC)
+ #define umul_ppmm(ph, pl, m0, m1) \
+ do { \
+@@ -1001,19 +928,6 @@ do { \
+ } while (0)
+ #define UMUL_TIME 20
+ #define UDIV_TIME 200
+-#define count_leading_zeros(count, x) \
+-do { \
+- if ((x) >= 0x10000) \
+- __asm__ ("clz %0,%1" \
+- : "=r" ((USItype)(count)) \
+- : "r" ((USItype)(x) >> 16)); \
+- else { \
+- __asm__ ("clz %0,%1" \
+- : "=r" ((USItype)(count)) \
+- : "r" ((USItype)(x))); \
+- (count) += 16; \
+- } \
+-} while (0)
+ #endif /* RT/ROMP */
+
+ /***************************************
+@@ -1142,13 +1056,6 @@ do { \
+ "rI" ((USItype)(d)) \
+ : "%g1" __AND_CLOBBER_CC)
+ #define UDIV_TIME 37
+-#define count_leading_zeros(count, x) \
+- __asm__ ("scan %1,0,%0" \
+- : "=r" ((USItype)(x)) \
+- : "r" ((USItype)(count)))
+-/* Early sparclites return 63 for an argument of 0, but they warn that future
+- implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0
+- undefined. */
+ #endif /* __sparclite__ */
+ #endif /* __sparc_v8__ */
+ /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */
+@@ -1454,47 +1361,6 @@ do { \
+ #define udiv_qrnnd __udiv_qrnnd_c
+ #endif
+
+-#undef count_leading_zeros
+-#if !defined(count_leading_zeros)
+- extern
+-#ifdef __STDC__
+- const
+-#endif
+- unsigned char __clz_tab[];
+-#define count_leading_zeros(count, x) \
+-do { \
+- UWtype __xr = (x); \
+- UWtype __a; \
+- \
+- if (W_TYPE_SIZE <= 32) { \
+- __a = __xr < ((UWtype) 1 << 2*__BITS4) \
+- ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \
+- : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
+- } \
+- else { \
+- for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
+- if (((__xr >> __a) & 0xff) != 0) \
+- break; \
+- } \
+- \
+- (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
+-} while (0)
+- /* This version gives a well-defined value for zero. */
+-#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
+-#endif
+-
+-#if !defined(count_trailing_zeros)
+-/* Define count_trailing_zeros using count_leading_zeros. The latter might be
+- defined in asm, but if it is not, the C version above is good enough. */
+-#define count_trailing_zeros(count, x) \
+-do { \
+- UWtype __ctz_x = (x); \
+- UWtype __ctz_c; \
+- count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \
+- (count) = W_TYPE_SIZE - 1 - __ctz_c; \
+-} while (0)
+-#endif
+-
+ #ifndef UDIV_NEEDS_NORMALIZATION
+ #define UDIV_NEEDS_NORMALIZATION 0
+ #endif
+diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c
+index 5687248..503537e 100644
+--- a/lib/mpi/mpi-bit.c
++++ b/lib/mpi/mpi-bit.c
+@@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a)
+ if (a->nlimbs) {
+ mpi_limb_t alimb = a->d[a->nlimbs - 1];
+ if (alimb)
+- count_leading_zeros(n, alimb);
++ n = count_leading_zeros(alimb);
+ else
+ n = BITS_PER_MPI_LIMB;
+ n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
+diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c
+index 67f3e79..5464c87 100644
+--- a/lib/mpi/mpi-pow.c
++++ b/lib/mpi/mpi-pow.c
+@@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
+ mp = mp_marker = mpi_alloc_limb_space(msize);
+ if (!mp)
+ goto enomem;
+- count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]);
++ mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]);
+ if (mod_shift_cnt)
+ mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt);
+ else
+@@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
+
+ i = esize - 1;
+ e = ep[i];
+- count_leading_zeros(c, e);
++ c = count_leading_zeros(e);
+ e = (e << c) << 1; /* shift the exp bits to the left, lose msb */
+ c = BITS_PER_MPI_LIMB - 1 - c;
+
+--
+1.7.12.1
+
+
+From ef184bcab1e58dafae2f02ae30824365bec1d27a Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 13 Sep 2012 15:17:21 +0100
+Subject: [PATCH 04/37] KEYS: Document asymmetric key type
+
+In-source documentation for the asymmetric key type. This will be located in:
+
+ Documentation/crypto/asymmetric-keys.txt
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ Documentation/crypto/asymmetric-keys.txt | 312 +++++++++++++++++++++++++++++++
+ 1 file changed, 312 insertions(+)
+ create mode 100644 Documentation/crypto/asymmetric-keys.txt
+
+diff --git a/Documentation/crypto/asymmetric-keys.txt b/Documentation/crypto/asymmetric-keys.txt
+new file mode 100644
+index 0000000..b767590
+--- /dev/null
++++ b/Documentation/crypto/asymmetric-keys.txt
+@@ -0,0 +1,312 @@
++ =============================================
++ ASYMMETRIC / PUBLIC-KEY CRYPTOGRAPHY KEY TYPE
++ =============================================
++
++Contents:
++
++ - Overview.
++ - Key identification.
++ - Accessing asymmetric keys.
++ - Signature verification.
++ - Asymmetric key subtypes.
++ - Instantiation data parsers.
++
++
++========
++OVERVIEW
++========
++
++The "asymmetric" key type is designed to be a container for the keys used in
++public-key cryptography, without imposing any particular restrictions on the
++form or mechanism of the cryptography or form of the key.
++
++The asymmetric key is given a subtype that defines what sort of data is
++associated with the key and provides operations to describe and destroy it.
++However, no requirement is made that the key data actually be stored in the
++key.
++
++A completely in-kernel key retention and operation subtype can be defined, but
++it would also be possible to provide access to cryptographic hardware (such as
++a TPM) that might be used to both retain the relevant key and perform
++operations using that key. In such a case, the asymmetric key would then
++merely be an interface to the TPM driver.
++
++Also provided is the concept of a data parser. Data parsers are responsible
++for extracting information from the blobs of data passed to the instantiation
++function. The first data parser that recognises the blob gets to set the
++subtype of the key and define the operations that can be done on that key.
++
++A data parser may interpret the data blob as containing the bits representing a
++key, or it may interpret it as a reference to a key held somewhere else in the
++system (for example, a TPM).
++
++
++==================
++KEY IDENTIFICATION
++==================
++
++If a key is added with an empty name, the instantiation data parsers are given
++the opportunity to pre-parse a key and to determine the description the key
++should be given from the content of the key.
++
++This can then be used to refer to the key, either by complete match or by
++partial match. The key type may also use other criteria to refer to a key.
++
++The asymmetric key type's match function can then perform a wider range of
++comparisons than just the straightforward comparison of the description with
++the criterion string:
++
++ (1) If the criterion string is of the form "id:<hexdigits>" then the match
++ function will examine a key's fingerprint to see if the hex digits given
++ after the "id:" match the tail. For instance:
++
++ keyctl search @s asymmetric id:5acc2142
++
++ will match a key with fingerprint:
++
++ 1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142
++
++ (2) If the criterion string is of the form "<subtype>:<hexdigits>" then the
++ match will match the ID as in (1), but with the added restriction that
++ only keys of the specified subtype (e.g. tpm) will be matched. For
++ instance:
++
++ keyctl search @s asymmetric tpm:5acc2142
++
++Looking in /proc/keys, the last 8 hex digits of the key fingerprint are
++displayed, along with the subtype:
++
++ 1a39e171 I----- 1 perm 3f010000 0 0 asymmetri modsign.0: DSA 5acc2142 []
++
++
++=========================
++ACCESSING ASYMMETRIC KEYS
++=========================
++
++For general access to asymmetric keys from within the kernel, the following
++inclusion is required:
++
++ #include <crypto/public_key.h>
++
++This gives access to functions for dealing with asymmetric / public keys.
++Three enums are defined there for representing public-key cryptography
++algorithms:
++
++ enum pkey_algo
++
++digest algorithms used by those:
++
++ enum pkey_hash_algo
++
++and key identifier representations:
++
++ enum pkey_id_type
++
++Note that the key type representation types are required because key
++identifiers from different standards aren't necessarily compatible. For
++instance, PGP generates key identifiers by hashing the key data plus some
++PGP-specific metadata, whereas X.509 has arbitrary certificate identifiers.
++
++The operations defined upon a key are:
++
++ (1) Signature verification.
++
++Other operations are possible (such as encryption) with the same key data
++required for verification, but not currently supported, and others
++(eg. decryption and signature generation) require extra key data.
++
++
++SIGNATURE VERIFICATION
++----------------------
++
++An operation is provided to perform cryptographic signature verification, using
++an asymmetric key to provide or to provide access to the public key.
++
++ int verify_signature(const struct key *key,
++ const struct public_key_signature *sig);
++
++The caller must have already obtained the key from some source and can then use
++it to check the signature. The caller must have parsed the signature and
++transferred the relevant bits to the structure pointed to by sig.
++
++ struct public_key_signature {
++ u8 *digest;
++ u8 digest_size;
++ enum pkey_hash_algo pkey_hash_algo : 8;
++ u8 nr_mpi;
++ union {
++ MPI mpi[2];
++ ...
++ };
++ };
++
++The algorithm used must be noted in sig->pkey_hash_algo, and all the MPIs that
++make up the actual signature must be stored in sig->mpi[] and the count of MPIs
++placed in sig->nr_mpi.
++
++In addition, the data must have been digested by the caller and the resulting
++hash must be pointed to by sig->digest and the size of the hash be placed in
++sig->digest_size.
++
++The function will return 0 upon success or -EKEYREJECTED if the signature
++doesn't match.
++
++The function may also return -ENOTSUPP if an unsupported public-key algorithm
++or public-key/hash algorithm combination is specified or the key doesn't
++support the operation; -EBADMSG or -ERANGE if some of the parameters have weird
++data; or -ENOMEM if an allocation can't be performed. -EINVAL can be returned
++if the key argument is the wrong type or is incompletely set up.
++
++
++=======================
++ASYMMETRIC KEY SUBTYPES
++=======================
++
++Asymmetric keys have a subtype that defines the set of operations that can be
++performed on that key and that determines what data is attached as the key
++payload. The payload format is entirely at the whim of the subtype.
++
++The subtype is selected by the key data parser and the parser must initialise
++the data required for it. The asymmetric key retains a reference on the
++subtype module.
++
++The subtype definition structure can be found in:
++
++ #include <keys/asymmetric-subtype.h>
++
++and looks like the following:
++
++ struct asymmetric_key_subtype {
++ struct module *owner;
++ const char *name;
++
++ void (*describe)(const struct key *key, struct seq_file *m);
++ void (*destroy)(void *payload);
++ int (*verify_signature)(const struct key *key,
++ const struct public_key_signature *sig);
++ };
++
++Asymmetric keys point to this with their type_data[0] member.
++
++The owner and name fields should be set to the owning module and the name of
++the subtype. Currently, the name is only used for print statements.
++
++There are a number of operations defined by the subtype:
++
++ (1) describe().
++
++ Mandatory. This allows the subtype to display something in /proc/keys
++ against the key. For instance the name of the public key algorithm type
++ could be displayed. The key type will display the tail of the key
++ identity string after this.
++
++ (2) destroy().
++
++ Mandatory. This should free the memory associated with the key. The
++ asymmetric key will look after freeing the fingerprint and releasing the
++ reference on the subtype module.
++
++ (3) verify_signature().
++
++ Optional. These are the entry points for the key usage operations.
++ Currently there is only the one defined. If not set, the caller will be
++ given -ENOTSUPP. The subtype may do anything it likes to implement an
++ operation, including offloading to hardware.
++
++
++==========================
++INSTANTIATION DATA PARSERS
++==========================
++
++The asymmetric key type doesn't generally want to store or to deal with a raw
++blob of data that holds the key data. It would have to parse it and error
++check it each time it wanted to use it. Further, the contents of the blob may
++have various checks that can be performed on it (eg. self-signatures, validity
++dates) and may contain useful data about the key (identifiers, capabilities).
++
++Also, the blob may represent a pointer to some hardware containing the key
++rather than the key itself.
++
++Examples of blob formats for which parsers could be implemented include:
++
++ - OpenPGP packet stream [RFC 4880].
++ - X.509 ASN.1 stream.
++ - Pointer to TPM key.
++ - Pointer to UEFI key.
++
++During key instantiation each parser in the list is tried until one doesn't
++return -EBADMSG.
++
++The parser definition structure can be found in:
++
++ #include <keys/asymmetric-parser.h>
++
++and looks like the following:
++
++ struct asymmetric_key_parser {
++ struct module *owner;
++ const char *name;
++
++ int (*parse)(struct key_preparsed_payload *prep);
++ };
++
++The owner and name fields should be set to the owning module and the name of
++the parser.
++
++There is currently only a single operation defined by the parser, and it is
++mandatory:
++
++ (1) parse().
++
++ This is called to preparse the key from the key creation and update paths.
++ In particular, it is called during the key creation _before_ a key is
++ allocated, and as such, is permitted to provide the key's description in
++ the case that the caller declines to do so.
++
++ The caller passes a pointer to the following struct with all of the fields
++ cleared, except for data, datalen and quotalen [see
++ Documentation/security/keys.txt].
++
++ struct key_preparsed_payload {
++ char *description;
++ void *type_data[2];
++ void *payload;
++ const void *data;
++ size_t datalen;
++ size_t quotalen;
++ };
++
++ The instantiation data is in a blob pointed to by data and is datalen in
++ size. The parse() function is not permitted to change these two values at
++ all, and shouldn't change any of the other values _unless_ they are
++ recognise the blob format and will not return -EBADMSG to indicate it is
++ not theirs.
++
++ If the parser is happy with the blob, it should propose a description for
++ the key and attach it to ->description, ->type_data[0] should be set to
++ point to the subtype to be used, ->payload should be set to point to the
++ initialised data for that subtype, ->type_data[1] should point to a hex
++ fingerprint and quotalen should be updated to indicate how much quota this
++ key should account for.
++
++ When clearing up, the data attached to ->type_data[1] and ->description
++ will be kfree()'d and the data attached to ->payload will be passed to the
++ subtype's ->destroy() method to be disposed of. A module reference for
++ the subtype pointed to by ->type_data[0] will be put.
++
++
++ If the data format is not recognised, -EBADMSG should be returned. If it
++ is recognised, but the key cannot for some reason be set up, some other
++ negative error code should be returned. On success, 0 should be returned.
++
++ The key's fingerprint string may be partially matched upon. For a
++ public-key algorithm such as RSA and DSA this will likely be a printable
++ hex version of the key's fingerprint.
++
++Functions are provided to register and unregister parsers:
++
++ int register_asymmetric_key_parser(struct asymmetric_key_parser *parser);
++ void unregister_asymmetric_key_parser(struct asymmetric_key_parser *subtype);
++
++Parsers may not have the same name. The names are otherwise only used for
++displaying in debugging messages.
+--
+1.7.12.1
+
+
+From 0e450d75d1067b6f45f1f6b58a530a5d95144373 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 13 Sep 2012 15:17:21 +0100
+Subject: [PATCH 05/37] KEYS: Implement asymmetric key type
+
+Create a key type that can be used to represent an asymmetric key type for use
+in appropriate cryptographic operations, such as encryption, decryption,
+signature generation and signature verification.
+
+The key type is "asymmetric" and can provide access to a variety of
+cryptographic algorithms.
+
+Possibly, this would be better as "public_key" - but that has the disadvantage
+that "public key" is an overloaded term.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/Kconfig | 1 +
+ crypto/Makefile | 1 +
+ crypto/asymmetric_keys/Kconfig | 13 +++
+ crypto/asymmetric_keys/Makefile | 7 ++
+ crypto/asymmetric_keys/asymmetric_keys.h | 15 +++
+ crypto/asymmetric_keys/asymmetric_type.c | 156 +++++++++++++++++++++++++++++++
+ include/keys/asymmetric-subtype.h | 55 +++++++++++
+ include/keys/asymmetric-type.h | 25 +++++
+ 8 files changed, 273 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/Kconfig
+ create mode 100644 crypto/asymmetric_keys/Makefile
+ create mode 100644 crypto/asymmetric_keys/asymmetric_keys.h
+ create mode 100644 crypto/asymmetric_keys/asymmetric_type.c
+ create mode 100644 include/keys/asymmetric-subtype.h
+ create mode 100644 include/keys/asymmetric-type.h
+
+diff --git a/crypto/Kconfig b/crypto/Kconfig
+index a323805..1ca0b24 100644
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1043,5 +1043,6 @@ config CRYPTO_USER_API_SKCIPHER
+ key cipher algorithms.
+
+ source "drivers/crypto/Kconfig"
++source crypto/asymmetric_keys/Kconfig
+
+ endif # if CRYPTO
+diff --git a/crypto/Makefile b/crypto/Makefile
+index 30f33d6..ced472e 100644
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -96,3 +96,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
+ #
+ obj-$(CONFIG_XOR_BLOCKS) += xor.o
+ obj-$(CONFIG_ASYNC_CORE) += async_tx/
++obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+new file mode 100644
+index 0000000..cad29b3
+--- /dev/null
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -0,0 +1,13 @@
++menuconfig ASYMMETRIC_KEY_TYPE
++ tristate "Asymmetric (public-key cryptographic) key type"
++ depends on KEYS
++ help
++ This option provides support for a key type that holds the data for
++ the asymmetric keys used for public key cryptographic operations such
++ as encryption, decryption, signature generation and signature
++ verification.
++
++if ASYMMETRIC_KEY_TYPE
++
++
++endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+new file mode 100644
+index 0000000..b725bcc
+--- /dev/null
++++ b/crypto/asymmetric_keys/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for asymmetric cryptographic keys
++#
++
++obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
++
++asymmetric_keys-y := asymmetric_type.o
+diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
+new file mode 100644
+index 0000000..515b634
+--- /dev/null
++++ b/crypto/asymmetric_keys/asymmetric_keys.h
+@@ -0,0 +1,15 @@
++/* Internal definitions for asymmetric key type
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++static inline const char *asymmetric_key_id(const struct key *key)
++{
++ return key->type_data.p[1];
++}
+diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
+new file mode 100644
+index 0000000..bfb0424
+--- /dev/null
++++ b/crypto/asymmetric_keys/asymmetric_type.c
+@@ -0,0 +1,156 @@
++/* Asymmetric public-key cryptography key type
++ *
++ * See Documentation/security/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++#include <keys/asymmetric-subtype.h>
++#include <linux/seq_file.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include "asymmetric_keys.h"
++
++MODULE_LICENSE("GPL");
++
++/*
++ * Match asymmetric keys on (part of) their name
++ * We have some shorthand methods for matching keys. We allow:
++ *
++ * "<desc>" - request a key by description
++ * "id:<id>" - request a key matching the ID
++ * "<subtype>:<id>" - request a key of a subtype
++ */
++static int asymmetric_key_match(const struct key *key, const void *description)
++{
++ const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
++ const char *spec = description;
++ const char *id, *kid;
++ ptrdiff_t speclen;
++ size_t idlen, kidlen;
++
++ 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++;
++
++ /* Anything after here requires a partial match on the ID string */
++ kid = asymmetric_key_id(key);
++ if (!kid)
++ return 0;
++
++ idlen = strlen(id);
++ kidlen = strlen(kid);
++ if (idlen > kidlen)
++ return 0;
++
++ kid += kidlen - idlen;
++ if (strcasecmp(id, kid) != 0)
++ return 0;
++
++ if (speclen == 2 &&
++ memcmp(spec, "id", 2) == 0)
++ return 1;
++
++ if (speclen == subtype->name_len &&
++ memcmp(spec, subtype->name, speclen) == 0)
++ return 1;
++
++ return 0;
++}
++
++/*
++ * Describe the asymmetric key
++ */
++static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
++{
++ const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
++ const char *kid = asymmetric_key_id(key);
++ size_t n;
++
++ seq_puts(m, key->description);
++
++ if (subtype) {
++ seq_puts(m, ": ");
++ subtype->describe(key, m);
++
++ if (kid) {
++ seq_putc(m, ' ');
++ n = strlen(kid);
++ if (n <= 8)
++ seq_puts(m, kid);
++ else
++ seq_puts(m, kid + n - 8);
++ }
++
++ seq_puts(m, " [");
++ /* put something here to indicate the key's capabilities */
++ seq_putc(m, ']');
++ }
++}
++
++/*
++ * Instantiate a asymmetric_key defined key. The key was preparsed, so we just
++ * have to transfer the data here.
++ */
++static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
++{
++ return -EOPNOTSUPP;
++}
++
++/*
++ * dispose of the data dangling from the corpse of a asymmetric key
++ */
++static void asymmetric_key_destroy(struct key *key)
++{
++ struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
++ if (subtype) {
++ subtype->destroy(key->payload.data);
++ module_put(subtype->owner);
++ key->type_data.p[0] = NULL;
++ }
++ kfree(key->type_data.p[1]);
++ key->type_data.p[1] = NULL;
++}
++
++struct key_type key_type_asymmetric = {
++ .name = "asymmetric",
++ .instantiate = asymmetric_key_instantiate,
++ .match = asymmetric_key_match,
++ .destroy = asymmetric_key_destroy,
++ .describe = asymmetric_key_describe,
++};
++EXPORT_SYMBOL_GPL(key_type_asymmetric);
++
++/*
++ * Module stuff
++ */
++static int __init asymmetric_key_init(void)
++{
++ return register_key_type(&key_type_asymmetric);
++}
++
++static void __exit asymmetric_key_cleanup(void)
++{
++ unregister_key_type(&key_type_asymmetric);
++}
++
++module_init(asymmetric_key_init);
++module_exit(asymmetric_key_cleanup);
+diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h
+new file mode 100644
+index 0000000..4b840e8
+--- /dev/null
++++ b/include/keys/asymmetric-subtype.h
+@@ -0,0 +1,55 @@
++/* Asymmetric public-key cryptography key subtype
++ *
++ * See Documentation/security/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _KEYS_ASYMMETRIC_SUBTYPE_H
++#define _KEYS_ASYMMETRIC_SUBTYPE_H
++
++#include <linux/seq_file.h>
++#include <keys/asymmetric-type.h>
++
++struct public_key_signature;
++
++/*
++ * Keys of this type declare a subtype that indicates the handlers and
++ * capabilities.
++ */
++struct asymmetric_key_subtype {
++ struct module *owner;
++ const char *name;
++ unsigned short name_len; /* length of name */
++
++ /* Describe a key of this subtype for /proc/keys */
++ void (*describe)(const struct key *key, struct seq_file *m);
++
++ /* Destroy a key of this subtype */
++ void (*destroy)(void *payload);
++
++ /* Verify the signature on a key of this subtype (optional) */
++ int (*verify_signature)(const struct key *key,
++ const struct public_key_signature *sig);
++};
++
++/**
++ * asymmetric_key_subtype - Get the subtype from an asymmetric key
++ * @key: The key of interest.
++ *
++ * Retrieves and returns the subtype pointer of the asymmetric key from the
++ * type-specific data attached to the key.
++ */
++static inline
++struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key)
++{
++ return key->type_data.p[0];
++}
++
++#endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */
+diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
+new file mode 100644
+index 0000000..7dd4734
+--- /dev/null
++++ b/include/keys/asymmetric-type.h
+@@ -0,0 +1,25 @@
++/* Asymmetric Public-key cryptography key type interface
++ *
++ * See Documentation/security/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _KEYS_ASYMMETRIC_TYPE_H
++#define _KEYS_ASYMMETRIC_TYPE_H
++
++#include <linux/key-type.h>
++
++extern struct key_type key_type_asymmetric;
++
++/*
++ * The payload is at the discretion of the subtype.
++ */
++
++#endif /* _KEYS_ASYMMETRIC_TYPE_H */
+--
+1.7.12.1
+
+
+From 6ec62201b26995d57fbd457469314bfc5653f2a0 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 13 Sep 2012 15:17:32 +0100
+Subject: [PATCH 06/37] KEYS: Asymmetric key pluggable data parsers
+
+The instantiation data passed to the asymmetric key type are expected to be
+formatted in some way, and there are several possible standard ways to format
+the data.
+
+The two obvious standards are OpenPGP keys and X.509 certificates. The latter
+is especially useful when dealing with UEFI, and the former might be useful
+when dealing with, say, eCryptfs.
+
+Further, it might be desirable to provide formatted blobs that indicate
+hardware is to be accessed to retrieve the keys or that the keys live
+unretrievably in a hardware store, but that the keys can be used by means of
+the hardware.
+
+From userspace, the keys can be loaded using the keyctl command, for example,
+an X.509 binary certificate:
+
+ keyctl padd asymmetric foo @s <dhowells.pem
+
+or a PGP key:
+
+ keyctl padd asymmetric bar @s <dhowells.pub
+
+or a pointer into the contents of the TPM:
+
+ keyctl add asymmetric zebra "TPM:04982390582905f8" @s
+
+Inside the kernel, pluggable parsers register themselves and then get to
+examine the payload data to see if they can handle it. If they can, they get
+to:
+
+ (1) Propose a name for the key, to be used it the name is "" or NULL.
+
+ (2) Specify the key subtype.
+
+ (3) Provide the data for the subtype.
+
+The key type asks the parser to do its stuff before a key is allocated and thus
+before the name is set. If successful, the parser stores the suggested data
+into the key_preparsed_payload struct, which will be either used (if the key is
+successfully created and instantiated or updated) or discarded.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/asymmetric_type.c | 120 ++++++++++++++++++++++++++++++-
+ include/keys/asymmetric-parser.h | 37 ++++++++++
+ 2 files changed, 156 insertions(+), 1 deletion(-)
+ create mode 100644 include/keys/asymmetric-parser.h
+
+diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
+index bfb0424..cf80765 100644
+--- a/crypto/asymmetric_keys/asymmetric_type.c
++++ b/crypto/asymmetric_keys/asymmetric_type.c
+@@ -11,6 +11,7 @@
+ * 2 of the Licence, or (at your option) any later version.
+ */
+ #include <keys/asymmetric-subtype.h>
++#include <keys/asymmetric-parser.h>
+ #include <linux/seq_file.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+@@ -18,6 +19,9 @@
+
+ MODULE_LICENSE("GPL");
+
++static LIST_HEAD(asymmetric_key_parsers);
++static DECLARE_RWSEM(asymmetric_key_parsers_sem);
++
+ /*
+ * Match asymmetric keys on (part of) their name
+ * We have some shorthand methods for matching keys. We allow:
+@@ -107,12 +111,79 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
+ }
+
+ /*
++ * Preparse a asymmetric payload to get format the contents appropriately for the
++ * internal payload to cut down on the number of scans of the data performed.
++ *
++ * We also generate a proposed description from the contents of the key that
++ * can be used to name the key if the user doesn't want to provide one.
++ */
++static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
++{
++ struct asymmetric_key_parser *parser;
++ int ret;
++
++ pr_devel("==>%s()\n", __func__);
++
++ if (prep->datalen == 0)
++ return -EINVAL;
++
++ down_read(&asymmetric_key_parsers_sem);
++
++ ret = -EBADMSG;
++ list_for_each_entry(parser, &asymmetric_key_parsers, link) {
++ pr_debug("Trying parser '%s'\n", parser->name);
++
++ ret = parser->parse(prep);
++ if (ret != -EBADMSG) {
++ pr_debug("Parser recognised the format (ret %d)\n",
++ ret);
++ break;
++ }
++ }
++
++ up_read(&asymmetric_key_parsers_sem);
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ return ret;
++}
++
++/*
++ * Clean up the preparse data
++ */
++static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
++{
++ struct asymmetric_key_subtype *subtype = prep->type_data[0];
++
++ pr_devel("==>%s()\n", __func__);
++
++ if (subtype) {
++ subtype->destroy(prep->payload);
++ module_put(subtype->owner);
++ }
++ kfree(prep->type_data[1]);
++ kfree(prep->description);
++}
++
++/*
+ * Instantiate a asymmetric_key defined key. The key was preparsed, so we just
+ * have to transfer the data here.
+ */
+ static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+ {
+- return -EOPNOTSUPP;
++ int ret;
++
++ pr_devel("==>%s()\n", __func__);
++
++ ret = key_payload_reserve(key, prep->quotalen);
++ if (ret == 0) {
++ key->type_data.p[0] = prep->type_data[0];
++ key->type_data.p[1] = prep->type_data[1];
++ key->payload.data = prep->payload;
++ prep->type_data[0] = NULL;
++ prep->type_data[1] = NULL;
++ prep->payload = NULL;
++ }
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ return ret;
+ }
+
+ /*
+@@ -132,6 +203,8 @@ static void asymmetric_key_destroy(struct key *key)
+
+ struct key_type key_type_asymmetric = {
+ .name = "asymmetric",
++ .preparse = asymmetric_key_preparse,
++ .free_preparse = asymmetric_key_free_preparse,
+ .instantiate = asymmetric_key_instantiate,
+ .match = asymmetric_key_match,
+ .destroy = asymmetric_key_destroy,
+@@ -139,6 +212,51 @@ struct key_type key_type_asymmetric = {
+ };
+ EXPORT_SYMBOL_GPL(key_type_asymmetric);
+
++/**
++ * register_asymmetric_key_parser - Register a asymmetric key blob parser
++ * @parser: The parser to register
++ */
++int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
++{
++ struct asymmetric_key_parser *cursor;
++ int ret;
++
++ down_write(&asymmetric_key_parsers_sem);
++
++ list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
++ if (strcmp(cursor->name, parser->name) == 0) {
++ pr_err("Asymmetric key parser '%s' already registered\n",
++ parser->name);
++ ret = -EEXIST;
++ goto out;
++ }
++ }
++
++ list_add_tail(&parser->link, &asymmetric_key_parsers);
++
++ pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
++ ret = 0;
++
++out:
++ up_write(&asymmetric_key_parsers_sem);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
++
++/**
++ * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
++ * @parser: The parser to unregister
++ */
++void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
++{
++ down_write(&asymmetric_key_parsers_sem);
++ list_del(&parser->link);
++ up_write(&asymmetric_key_parsers_sem);
++
++ pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
++}
++EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
++
+ /*
+ * Module stuff
+ */
+diff --git a/include/keys/asymmetric-parser.h b/include/keys/asymmetric-parser.h
+new file mode 100644
+index 0000000..09b3b48
+--- /dev/null
++++ b/include/keys/asymmetric-parser.h
+@@ -0,0 +1,37 @@
++/* Asymmetric public-key cryptography data parser
++ *
++ * See Documentation/crypto/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _KEYS_ASYMMETRIC_PARSER_H
++#define _KEYS_ASYMMETRIC_PARSER_H
++
++/*
++ * Key data parser. Called during key instantiation.
++ */
++struct asymmetric_key_parser {
++ struct list_head link;
++ struct module *owner;
++ const char *name;
++
++ /* Attempt to parse a key from the data blob passed to add_key() or
++ * keyctl_instantiate(). Should also generate a proposed description
++ * that the caller can optionally use for the key.
++ *
++ * Return EBADMSG if not recognised.
++ */
++ int (*parse)(struct key_preparsed_payload *prep);
++};
++
++extern int register_asymmetric_key_parser(struct asymmetric_key_parser *);
++extern void unregister_asymmetric_key_parser(struct asymmetric_key_parser *);
++
++#endif /* _KEYS_ASYMMETRIC_PARSER_H */
+--
+1.7.12.1
+
+
+From 390ad626607322c6e4da8a2e6d2a4094e78b919a Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:24:55 +0100
+Subject: [PATCH 07/37] KEYS: Asymmetric public-key algorithm crypto key
+ subtype
+
+Add a subtype for supporting asymmetric public-key encryption algorithms such
+as DSA (FIPS-186) and RSA (PKCS#1 / RFC1337).
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/Kconfig | 8 +++
+ crypto/asymmetric_keys/Makefile | 2 +
+ crypto/asymmetric_keys/public_key.c | 108 ++++++++++++++++++++++++++++++++++++
+ crypto/asymmetric_keys/public_key.h | 28 ++++++++++
+ include/crypto/public_key.h | 104 ++++++++++++++++++++++++++++++++++
+ 5 files changed, 250 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/public_key.c
+ create mode 100644 crypto/asymmetric_keys/public_key.h
+ create mode 100644 include/crypto/public_key.h
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index cad29b3..bbfccaa 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -9,5 +9,13 @@ menuconfig ASYMMETRIC_KEY_TYPE
+
+ if ASYMMETRIC_KEY_TYPE
+
++config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
++ tristate "Asymmetric public-key crypto algorithm subtype"
++ select MPILIB
++ help
++ This option provides support for asymmetric public key type handling.
++ If signature generation and/or verification are to be used,
++ appropriate hash algorithms (such as SHA-1) must be available.
++ ENOPKG will be reported if the requisite algorithm is unavailable.
+
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index b725bcc..5ed46ee 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -5,3 +5,5 @@
+ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
+
+ asymmetric_keys-y := asymmetric_type.o
++
++obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
+new file mode 100644
+index 0000000..cb2e291
+--- /dev/null
++++ b/crypto/asymmetric_keys/public_key.c
+@@ -0,0 +1,108 @@
++/* In-software asymmetric public-key crypto subtype
++ *
++ * See Documentation/crypto/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "PKEY: "fmt
++#include <linux/module.h>
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/seq_file.h>
++#include <keys/asymmetric-subtype.h>
++#include "public_key.h"
++
++MODULE_LICENSE("GPL");
++
++const char *const pkey_algo[PKEY_ALGO__LAST] = {
++ [PKEY_ALGO_DSA] = "DSA",
++ [PKEY_ALGO_RSA] = "RSA",
++};
++EXPORT_SYMBOL_GPL(pkey_algo);
++
++const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
++ [PKEY_HASH_MD4] = "md4",
++ [PKEY_HASH_MD5] = "md5",
++ [PKEY_HASH_SHA1] = "sha1",
++ [PKEY_HASH_RIPE_MD_160] = "rmd160",
++ [PKEY_HASH_SHA256] = "sha256",
++ [PKEY_HASH_SHA384] = "sha384",
++ [PKEY_HASH_SHA512] = "sha512",
++ [PKEY_HASH_SHA224] = "sha224",
++};
++EXPORT_SYMBOL_GPL(pkey_hash_algo);
++
++const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
++ [PKEY_ID_PGP] = "PGP",
++ [PKEY_ID_X509] = "X509",
++};
++EXPORT_SYMBOL_GPL(pkey_id_type);
++
++/*
++ * Provide a part of a description of the key for /proc/keys.
++ */
++static void public_key_describe(const struct key *asymmetric_key,
++ struct seq_file *m)
++{
++ struct public_key *key = asymmetric_key->payload.data;
++
++ if (key)
++ seq_printf(m, "%s.%s",
++ pkey_id_type[key->id_type], key->algo->name);
++}
++
++/*
++ * Destroy a public key algorithm key.
++ */
++void public_key_destroy(void *payload)
++{
++ struct public_key *key = payload;
++ int i;
++
++ if (key) {
++ for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
++ mpi_free(key->mpi[i]);
++ kfree(key);
++ }
++}
++EXPORT_SYMBOL_GPL(public_key_destroy);
++
++/*
++ * Verify a signature using a public key.
++ */
++static int public_key_verify_signature(const struct key *key,
++ const struct public_key_signature *sig)
++{
++ const struct public_key *pk = key->payload.data;
++
++ if (!pk->algo->verify_signature)
++ return -ENOTSUPP;
++
++ if (sig->nr_mpi != pk->algo->n_sig_mpi) {
++ pr_debug("Signature has %u MPI not %u\n",
++ sig->nr_mpi, pk->algo->n_sig_mpi);
++ return -EINVAL;
++ }
++
++ return pk->algo->verify_signature(pk, sig);
++}
++
++/*
++ * Public key algorithm asymmetric key subtype
++ */
++struct asymmetric_key_subtype public_key_subtype = {
++ .owner = THIS_MODULE,
++ .name = "public_key",
++ .describe = public_key_describe,
++ .destroy = public_key_destroy,
++ .verify_signature = public_key_verify_signature,
++};
++EXPORT_SYMBOL_GPL(public_key_subtype);
+diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
+new file mode 100644
+index 0000000..1f86aad
+--- /dev/null
++++ b/crypto/asymmetric_keys/public_key.h
+@@ -0,0 +1,28 @@
++/* Public key algorithm internals
++ *
++ * See Documentation/crypto/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <crypto/public_key.h>
++
++extern struct asymmetric_key_subtype public_key_subtype;
++
++/*
++ * Public key algorithm definition.
++ */
++struct public_key_algorithm {
++ const char *name;
++ u8 n_pub_mpi; /* Number of MPIs in public key */
++ u8 n_sec_mpi; /* Number of MPIs in secret key */
++ u8 n_sig_mpi; /* Number of MPIs in a signature */
++ int (*verify_signature)(const struct public_key *key,
++ const struct public_key_signature *sig);
++};
+diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
+new file mode 100644
+index 0000000..4b8b6c1
+--- /dev/null
++++ b/include/crypto/public_key.h
+@@ -0,0 +1,104 @@
++/* Asymmetric public-key algorithm definitions
++ *
++ * See Documentation/crypto/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _LINUX_PUBLIC_KEY_H
++#define _LINUX_PUBLIC_KEY_H
++
++#include <linux/mpi.h>
++
++enum pkey_algo {
++ PKEY_ALGO_DSA,
++ PKEY_ALGO_RSA,
++ PKEY_ALGO__LAST
++};
++
++extern const char *const pkey_algo[PKEY_ALGO__LAST];
++
++enum pkey_hash_algo {
++ PKEY_HASH_MD4,
++ PKEY_HASH_MD5,
++ PKEY_HASH_SHA1,
++ PKEY_HASH_RIPE_MD_160,
++ PKEY_HASH_SHA256,
++ PKEY_HASH_SHA384,
++ PKEY_HASH_SHA512,
++ PKEY_HASH_SHA224,
++ PKEY_HASH__LAST
++};
++
++extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
++
++enum pkey_id_type {
++ PKEY_ID_PGP, /* OpenPGP generated key ID */
++ PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
++ PKEY_ID_TYPE__LAST
++};
++
++extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST];
++
++/*
++ * Cryptographic data for the public-key subtype of the asymmetric key type.
++ *
++ * Note that this may include private part of the key as well as the public
++ * part.
++ */
++struct public_key {
++ const struct public_key_algorithm *algo;
++ u8 capabilities;
++#define PKEY_CAN_ENCRYPT 0x01
++#define PKEY_CAN_DECRYPT 0x02
++#define PKEY_CAN_SIGN 0x04
++#define PKEY_CAN_VERIFY 0x08
++ enum pkey_id_type id_type : 8;
++ union {
++ MPI mpi[5];
++ struct {
++ MPI p; /* DSA prime */
++ MPI q; /* DSA group order */
++ MPI g; /* DSA group generator */
++ MPI y; /* DSA public-key value = g^x mod p */
++ MPI x; /* DSA secret exponent (if present) */
++ } dsa;
++ struct {
++ MPI n; /* RSA public modulus */
++ MPI e; /* RSA public encryption exponent */
++ MPI d; /* RSA secret encryption exponent (if present) */
++ MPI p; /* RSA secret prime (if present) */
++ MPI q; /* RSA secret prime (if present) */
++ } rsa;
++ };
++};
++
++extern void public_key_destroy(void *payload);
++
++/*
++ * Public key cryptography signature data
++ */
++struct public_key_signature {
++ u8 *digest;
++ u8 digest_size; /* Number of bytes in digest */
++ u8 nr_mpi; /* Occupancy of mpi[] */
++ enum pkey_hash_algo pkey_hash_algo : 8;
++ union {
++ MPI mpi[2];
++ struct {
++ MPI s; /* m^d mod n */
++ } rsa;
++ struct {
++ MPI r;
++ MPI s;
++ } dsa;
++ };
++};
++
++#endif /* _LINUX_PUBLIC_KEY_H */
+--
+1.7.12.1
+
+
+From 13d9a26663043faaa37dbe6c2f214ceef5f00b05 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:25:04 +0100
+Subject: [PATCH 08/37] KEYS: Provide signature verification with an
+ asymmetric key
+
+Provide signature verification using an asymmetric-type key to indicate the
+public key to be used.
+
+The API is a single function that can be found in crypto/public_key.h:
+
+ int verify_signature(const struct key *key,
+ const struct public_key_signature *sig)
+
+The first argument is the appropriate key to be used and the second argument
+is the parsed signature data:
+
+ struct public_key_signature {
+ u8 *digest;
+ u16 digest_size;
+ enum pkey_hash_algo pkey_hash_algo : 8;
+ union {
+ MPI mpi[2];
+ struct {
+ MPI s; /* m^d mod n */
+ } rsa;
+ struct {
+ MPI r;
+ MPI s;
+ } dsa;
+ };
+ };
+
+This should be filled in prior to calling the function. The hash algorithm
+should already have been called and the hash finalised and the output should
+be in a buffer pointed to by the 'digest' member.
+
+Any extra data to be added to the hash by the hash format (eg. PGP) should
+have been added by the caller prior to finalising the hash.
+
+It is assumed that the signature is made up of a number of MPI values. If an
+algorithm becomes available for which this is not the case, the above structure
+will have to change.
+
+It is also assumed that it will have been checked that the signature algorithm
+matches the key algorithm.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/Makefile | 2 +-
+ crypto/asymmetric_keys/signature.c | 49 ++++++++++++++++++++++++++++++++++++++
+ include/crypto/public_key.h | 4 ++++
+ 3 files changed, 54 insertions(+), 1 deletion(-)
+ create mode 100644 crypto/asymmetric_keys/signature.c
+
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 5ed46ee..8dcdf0c 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -4,6 +4,6 @@
+
+ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
+
+-asymmetric_keys-y := asymmetric_type.o
++asymmetric_keys-y := asymmetric_type.o signature.o
+
+ obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
+new file mode 100644
+index 0000000..50b3f88
+--- /dev/null
++++ b/crypto/asymmetric_keys/signature.c
+@@ -0,0 +1,49 @@
++/* Signature verification with an asymmetric key
++ *
++ * See Documentation/security/asymmetric-keys.txt
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <keys/asymmetric-subtype.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <crypto/public_key.h>
++#include "asymmetric_keys.h"
++
++/**
++ * verify_signature - Initiate the use of an asymmetric key to verify a signature
++ * @key: The asymmetric key to verify against
++ * @sig: The signature to check
++ *
++ * Returns 0 if successful or else an error.
++ */
++int verify_signature(const struct key *key,
++ const struct public_key_signature *sig)
++{
++ const struct asymmetric_key_subtype *subtype;
++ int ret;
++
++ pr_devel("==>%s()\n", __func__);
++
++ if (key->type != &key_type_asymmetric)
++ return -EINVAL;
++ subtype = asymmetric_key_subtype(key);
++ if (!subtype ||
++ !key->payload.data)
++ return -EINVAL;
++ if (!subtype->verify_signature)
++ return -ENOTSUPP;
++
++ ret = subtype->verify_signature(key, sig);
++
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(verify_signature);
+diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
+index 4b8b6c1..f5b0224 100644
+--- a/include/crypto/public_key.h
++++ b/include/crypto/public_key.h
+@@ -101,4 +101,8 @@ struct public_key_signature {
+ };
+ };
+
++struct key;
++extern int verify_signature(const struct key *key,
++ const struct public_key_signature *sig);
++
+ #endif /* _LINUX_PUBLIC_KEY_H */
+--
+1.7.12.1
+
+
+From 3d379de76f21782c611b7d409d7374b82bc90220 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:25:22 +0100
+Subject: [PATCH 09/37] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA
+ signature verification
+
+Reinstate and export mpi_cmp() and mpi_cmp_ui() from the MPI library for use by
+RSA signature verification as per RFC3447 section 5.2.2 step 1.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ lib/mpi/Makefile | 1 +
+ lib/mpi/mpi-cmp.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 71 insertions(+)
+ create mode 100644 lib/mpi/mpi-cmp.c
+
+diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile
+index 45ca90a..019a68c 100644
+--- a/lib/mpi/Makefile
++++ b/lib/mpi/Makefile
+@@ -14,6 +14,7 @@ mpi-y = \
+ generic_mpih-add1.o \
+ mpicoder.o \
+ mpi-bit.o \
++ mpi-cmp.o \
+ mpih-cmp.o \
+ mpih-div.o \
+ mpih-mul.o \
+diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c
+new file mode 100644
+index 0000000..1871e7b
+--- /dev/null
++++ b/lib/mpi/mpi-cmp.c
+@@ -0,0 +1,70 @@
++/* mpi-cmp.c - MPI functions
++ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
++ *
++ * This file is part of GnuPG.
++ *
++ * GnuPG is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * GnuPG is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
++ */
++
++#include "mpi-internal.h"
++
++int mpi_cmp_ui(MPI u, unsigned long v)
++{
++ mpi_limb_t limb = v;
++
++ mpi_normalize(u);
++ if (!u->nlimbs && !limb)
++ return 0;
++ if (u->sign)
++ return -1;
++ if (u->nlimbs > 1)
++ return 1;
++
++ if (u->d[0] == limb)
++ return 0;
++ else if (u->d[0] > limb)
++ return 1;
++ else
++ return -1;
++}
++EXPORT_SYMBOL_GPL(mpi_cmp_ui);
++
++int mpi_cmp(MPI u, MPI v)
++{
++ mpi_size_t usize, vsize;
++ int cmp;
++
++ mpi_normalize(u);
++ mpi_normalize(v);
++ usize = u->nlimbs;
++ vsize = v->nlimbs;
++ if (!u->sign && v->sign)
++ return 1;
++ if (u->sign && !v->sign)
++ return -1;
++ if (usize != vsize && !u->sign && !v->sign)
++ return usize - vsize;
++ if (usize != vsize && u->sign && v->sign)
++ return vsize + usize;
++ if (!usize)
++ return 0;
++ cmp = mpihelp_cmp(u->d, v->d, usize);
++ if (!cmp)
++ return 0;
++ if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0))
++ return 1;
++ return -1;
++}
++EXPORT_SYMBOL_GPL(mpi_cmp);
+--
+1.7.12.1
+
+
+From b872c7db2ce34b5f051d1c38216843a1f796aa86 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:25:40 +0100
+Subject: [PATCH 10/37] RSA: Implement signature verification algorithm
+ [PKCS#1 / RFC3447]
+
+Implement RSA public key cryptography [PKCS#1 / RFC3447]. At this time, only
+the signature verification algorithm is supported. This uses the asymmetric
+public key subtype to hold its key data.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/Kconfig | 7 +
+ crypto/asymmetric_keys/Makefile | 1 +
+ crypto/asymmetric_keys/public_key.h | 2 +
+ crypto/asymmetric_keys/rsa.c | 269 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 279 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/rsa.c
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index bbfccaa..561759d 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -18,4 +18,11 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ appropriate hash algorithms (such as SHA-1) must be available.
+ ENOPKG will be reported if the requisite algorithm is unavailable.
+
++config PUBLIC_KEY_ALGO_RSA
++ tristate "RSA public-key algorithm"
++ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
++ select MPILIB_EXTRA
++ help
++ This option enables support for the RSA algorithm (PKCS#1, RFC3447).
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 8dcdf0c..7c92691 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -7,3 +7,4 @@ 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_PUBLIC_KEY_ALGO_RSA) += rsa.o
+diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
+index 1f86aad..5e5e356 100644
+--- a/crypto/asymmetric_keys/public_key.h
++++ b/crypto/asymmetric_keys/public_key.h
+@@ -26,3 +26,5 @@ struct public_key_algorithm {
+ int (*verify_signature)(const struct public_key *key,
+ const struct public_key_signature *sig);
+ };
++
++extern const struct public_key_algorithm RSA_public_key_algorithm;
+diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
+new file mode 100644
+index 0000000..9b31ee2
+--- /dev/null
++++ b/crypto/asymmetric_keys/rsa.c
+@@ -0,0 +1,269 @@
++/* RSA asymmetric public-key algorithm [RFC3447]
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "RSA: "fmt
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include "public_key.h"
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("RSA Public Key Algorithm");
++
++#define kenter(FMT, ...) \
++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
++#define kleave(FMT, ...) \
++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
++
++/*
++ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
++ */
++static const u8 RSA_digest_info_MD5[] = {
++ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
++ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
++ 0x05, 0x00, 0x04, 0x10
++};
++
++static const u8 RSA_digest_info_SHA1[] = {
++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
++ 0x2B, 0x0E, 0x03, 0x02, 0x1A,
++ 0x05, 0x00, 0x04, 0x14
++};
++
++static const u8 RSA_digest_info_RIPE_MD_160[] = {
++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
++ 0x2B, 0x24, 0x03, 0x02, 0x01,
++ 0x05, 0x00, 0x04, 0x14
++};
++
++static const u8 RSA_digest_info_SHA224[] = {
++ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
++ 0x05, 0x00, 0x04, 0x1C
++};
++
++static const u8 RSA_digest_info_SHA256[] = {
++ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
++ 0x05, 0x00, 0x04, 0x20
++};
++
++static const u8 RSA_digest_info_SHA384[] = {
++ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
++ 0x05, 0x00, 0x04, 0x30
++};
++
++static const u8 RSA_digest_info_SHA512[] = {
++ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
++ 0x05, 0x00, 0x04, 0x40
++};
++
++static const struct {
++ const u8 *data;
++ size_t size;
++} RSA_ASN1_templates[PKEY_HASH__LAST] = {
++#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
++ [PKEY_HASH_MD5] = _(MD5),
++ [PKEY_HASH_SHA1] = _(SHA1),
++ [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160),
++ [PKEY_HASH_SHA256] = _(SHA256),
++ [PKEY_HASH_SHA384] = _(SHA384),
++ [PKEY_HASH_SHA512] = _(SHA512),
++ [PKEY_HASH_SHA224] = _(SHA224),
++#undef _
++};
++
++/*
++ * RSAVP1() function [RFC3447 sec 5.2.2]
++ */
++static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
++{
++ MPI m;
++ int ret;
++
++ /* (1) Validate 0 <= s < n */
++ if (mpi_cmp_ui(s, 0) < 0) {
++ kleave(" = -EBADMSG [s < 0]");
++ return -EBADMSG;
++ }
++ if (mpi_cmp(s, key->rsa.n) >= 0) {
++ kleave(" = -EBADMSG [s >= n]");
++ return -EBADMSG;
++ }
++
++ m = mpi_alloc(0);
++ if (!m)
++ return -ENOMEM;
++
++ /* (2) m = s^e mod n */
++ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n);
++ if (ret < 0) {
++ mpi_free(m);
++ return ret;
++ }
++
++ *_m = m;
++ return 0;
++}
++
++/*
++ * Integer to Octet String conversion [RFC3447 sec 4.1]
++ */
++static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
++{
++ unsigned X_size, x_size;
++ int X_sign;
++ u8 *X;
++
++ /* Make sure the string is the right length. The number should begin
++ * with { 0x00, 0x01, ... } so we have to account for 15 leading zero
++ * bits not being reported by MPI.
++ */
++ x_size = mpi_get_nbits(x);
++ pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8);
++ if (x_size != xLen * 8 - 15)
++ return -ERANGE;
++
++ X = mpi_get_buffer(x, &X_size, &X_sign);
++ if (!X)
++ return -ENOMEM;
++ if (X_sign < 0) {
++ kfree(X);
++ return -EBADMSG;
++ }
++ if (X_size != xLen - 1) {
++ kfree(X);
++ return -EBADMSG;
++ }
++
++ *_X = X;
++ return 0;
++}
++
++/*
++ * Perform the RSA signature verification.
++ * @H: Value of hash of data and metadata
++ * @EM: The computed signature value
++ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
++ * @hash_size: The size of H
++ * @asn1_template: The DigestInfo ASN.1 template
++ * @asn1_size: Size of asm1_template[]
++ */
++static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
++ const u8 *asn1_template, size_t asn1_size)
++{
++ unsigned PS_end, T_offset, i;
++
++ kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
++
++ if (k < 2 + 1 + asn1_size + hash_size)
++ return -EBADMSG;
++
++ /* Decode the EMSA-PKCS1-v1_5 */
++ if (EM[1] != 0x01) {
++ kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]);
++ return -EBADMSG;
++ }
++
++ T_offset = k - (asn1_size + hash_size);
++ PS_end = T_offset - 1;
++ if (EM[PS_end] != 0x00) {
++ kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
++ return -EBADMSG;
++ }
++
++ for (i = 2; i < PS_end; i++) {
++ if (EM[i] != 0xff) {
++ kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
++ return -EBADMSG;
++ }
++ }
++
++ if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) {
++ kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
++ return -EBADMSG;
++ }
++
++ if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) {
++ kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
++ return -EKEYREJECTED;
++ }
++
++ kleave(" = 0");
++ return 0;
++}
++
++/*
++ * Perform the verification step [RFC3447 sec 8.2.2].
++ */
++static int RSA_verify_signature(const struct public_key *key,
++ const struct public_key_signature *sig)
++{
++ size_t tsize;
++ int ret;
++
++ /* Variables as per RFC3447 sec 8.2.2 */
++ const u8 *H = sig->digest;
++ u8 *EM = NULL;
++ MPI m = NULL;
++ size_t k;
++
++ kenter("");
++
++ if (!RSA_ASN1_templates[sig->pkey_hash_algo].data)
++ return -ENOTSUPP;
++
++ /* (1) Check the signature size against the public key modulus size */
++ k = (mpi_get_nbits(key->rsa.n) + 7) / 8;
++
++ tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8;
++ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
++ if (tsize != k) {
++ ret = -EBADMSG;
++ goto error;
++ }
++
++ /* (2b) Apply the RSAVP1 verification primitive to the public key */
++ ret = RSAVP1(key, sig->rsa.s, &m);
++ if (ret < 0)
++ goto error;
++
++ /* (2c) Convert the message representative (m) to an encoded message
++ * (EM) of length k octets.
++ *
++ * NOTE! The leading zero byte is suppressed by MPI, so we pass a
++ * pointer to the _preceding_ byte to RSA_verify()!
++ */
++ ret = RSA_I2OSP(m, k, &EM);
++ if (ret < 0)
++ goto error;
++
++ ret = RSA_verify(H, EM - 1, k, sig->digest_size,
++ RSA_ASN1_templates[sig->pkey_hash_algo].data,
++ RSA_ASN1_templates[sig->pkey_hash_algo].size);
++
++error:
++ kfree(EM);
++ mpi_free(m);
++ kleave(" = %d", ret);
++ return ret;
++}
++
++const struct public_key_algorithm RSA_public_key_algorithm = {
++ .name = "RSA",
++ .n_pub_mpi = 2,
++ .n_sec_mpi = 3,
++ .n_sig_mpi = 1,
++ .verify_signature = RSA_verify_signature,
++};
++EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
+--
+1.7.12.1
+
+
+From 362af238a35e095094b3f5a228cf2c0f60c10cd9 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:28:05 +0100
+Subject: [PATCH 11/37] RSA: Fix signature verification for shorter signatures
+
+gpg can produce a signature file where length of signature is less than the
+modulus size because the amount of space an MPI takes up is kept as low as
+possible by discarding leading zeros. This regularly happens for several
+modules during the build.
+
+Fix it by relaxing check in RSA verification code.
+
+Thanks to Tomas Mraz and Miloslav Trmac for help.
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/rsa.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
+index 9b31ee2..4a6a069 100644
+--- a/crypto/asymmetric_keys/rsa.c
++++ b/crypto/asymmetric_keys/rsa.c
+@@ -224,15 +224,23 @@ static int RSA_verify_signature(const struct public_key *key,
+ return -ENOTSUPP;
+
+ /* (1) Check the signature size against the public key modulus size */
+- k = (mpi_get_nbits(key->rsa.n) + 7) / 8;
++ k = mpi_get_nbits(key->rsa.n);
++ tsize = mpi_get_nbits(sig->rsa.s);
+
+- tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8;
++ /* According to RFC 4880 sec 3.2, length of MPI is computed starting
++ * from most significant bit. So the RFC 3447 sec 8.2.2 size check
++ * must be relaxed to conform with shorter signatures - so we fail here
++ * only if signature length is longer than modulus size.
++ */
+ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
+- if (tsize != k) {
++ if (k < tsize) {
+ ret = -EBADMSG;
+ goto error;
+ }
+
++ /* Round up and convert to octets */
++ k = (k + 7) / 8;
++
+ /* (2b) Apply the RSAVP1 verification primitive to the public key */
+ ret = RSAVP1(key, sig->rsa.s, &m);
+ if (ret < 0)
+--
+1.7.12.1
+
+
+From 81451f08c7db892e06144cf3bc89746e68269624 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:30:46 +0100
+Subject: [PATCH 12/37] X.509: Implement simple static OID registry
+
+Implement a simple static OID registry that allows the mapping of an encoded
+OID to an enum value for ease of use.
+
+The OID registry index enum appears in the:
+
+ linux/oid_registry.h
+
+header file. A script generates the registry from lines in the header file
+that look like:
+
+ <sp*>OID_foo,<sp*>/*<sp*>1.2.3.4<sp*>*/
+
+The actual OID is taken to be represented by the numbers with interpolated
+dots in the comment.
+
+All other lines in the header are ignored.
+
+The registry is queries by calling:
+
+ OID look_up_oid(const void *data, size_t datasize);
+
+This returns a number from the registry enum representing the OID if found or
+OID__NR if not.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ include/linux/oid_registry.h | 90 +++++++++++++++++++
+ lib/.gitignore | 2 +-
+ lib/Kconfig | 5 ++
+ lib/Makefile | 16 ++++
+ lib/build_OID_registry | 209 +++++++++++++++++++++++++++++++++++++++++++
+ lib/oid_registry.c | 89 ++++++++++++++++++
+ 6 files changed, 410 insertions(+), 1 deletion(-)
+ create mode 100644 include/linux/oid_registry.h
+ create mode 100755 lib/build_OID_registry
+ create mode 100644 lib/oid_registry.c
+
+diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
+new file mode 100644
+index 0000000..5928546
+--- /dev/null
++++ b/include/linux/oid_registry.h
+@@ -0,0 +1,90 @@
++/* ASN.1 Object identifier (OID) registry
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _LINUX_OID_REGISTRY_H
++#define _LINUX_OID_REGISTRY_H
++
++#include <linux/types.h>
++
++/*
++ * OIDs are turned into these values if possible, or OID__NR if not held here.
++ *
++ * NOTE! Do not mess with the format of each line as this is read by
++ * build_OID_registry.pl to generate the data for look_up_OID().
++ */
++enum OID {
++ OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */
++ OID_id_dsa, /* 1.2.840.10040.4.1 */
++ OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */
++ OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */
++
++ /* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */
++ OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */
++ OID_md2WithRSAEncryption, /* 1.2.840.113549.1.1.2 */
++ OID_md3WithRSAEncryption, /* 1.2.840.113549.1.1.3 */
++ OID_md4WithRSAEncryption, /* 1.2.840.113549.1.1.4 */
++ OID_sha1WithRSAEncryption, /* 1.2.840.113549.1.1.5 */
++ OID_sha256WithRSAEncryption, /* 1.2.840.113549.1.1.11 */
++ OID_sha384WithRSAEncryption, /* 1.2.840.113549.1.1.12 */
++ OID_sha512WithRSAEncryption, /* 1.2.840.113549.1.1.13 */
++ OID_sha224WithRSAEncryption, /* 1.2.840.113549.1.1.14 */
++ /* PKCS#7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)} */
++ OID_data, /* 1.2.840.113549.1.7.1 */
++ OID_signed_data, /* 1.2.840.113549.1.7.2 */
++ /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
++ OID_email_address, /* 1.2.840.113549.1.9.1 */
++ OID_content_type, /* 1.2.840.113549.1.9.3 */
++ OID_messageDigest, /* 1.2.840.113549.1.9.4 */
++ OID_signingTime, /* 1.2.840.113549.1.9.5 */
++ OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
++ OID_smimeAuthenticatedAttrs, /* 1.2.840.113549.1.9.16.2.11 */
++
++ /* {iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2)} */
++ OID_md2, /* 1.2.840.113549.2.2 */
++ OID_md4, /* 1.2.840.113549.2.4 */
++ OID_md5, /* 1.2.840.113549.2.5 */
++
++ OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
++ OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
++ OID_sha1, /* 1.3.14.3.2.26 */
++
++ /* Distinguished Name attribute IDs [RFC 2256] */
++ OID_commonName, /* 2.5.4.3 */
++ OID_surname, /* 2.5.4.4 */
++ OID_countryName, /* 2.5.4.6 */
++ OID_locality, /* 2.5.4.7 */
++ OID_stateOrProvinceName, /* 2.5.4.8 */
++ OID_organizationName, /* 2.5.4.10 */
++ OID_organizationUnitName, /* 2.5.4.11 */
++ OID_title, /* 2.5.4.12 */
++ OID_description, /* 2.5.4.13 */
++ OID_name, /* 2.5.4.41 */
++ OID_givenName, /* 2.5.4.42 */
++ OID_initials, /* 2.5.4.43 */
++ OID_generationalQualifier, /* 2.5.4.44 */
++
++ /* Certificate extension IDs */
++ OID_subjectKeyIdentifier, /* 2.5.29.14 */
++ OID_keyUsage, /* 2.5.29.15 */
++ OID_subjectAltName, /* 2.5.29.17 */
++ OID_issuerAltName, /* 2.5.29.18 */
++ OID_basicConstraints, /* 2.5.29.19 */
++ OID_crlDistributionPoints, /* 2.5.29.31 */
++ OID_certPolicies, /* 2.5.29.32 */
++ OID_authorityKeyIdentifier, /* 2.5.29.35 */
++ OID_extKeyUsage, /* 2.5.29.37 */
++
++ OID__NR
++};
++
++extern enum OID look_up_OID(const void *data, size_t datasize);
++
++#endif /* _LINUX_OID_REGISTRY_H */
+diff --git a/lib/.gitignore b/lib/.gitignore
+index 3bef1ea..09aae85 100644
+--- a/lib/.gitignore
++++ b/lib/.gitignore
+@@ -3,4 +3,4 @@
+ #
+ gen_crc32table
+ crc32table.h
+-
++oid_registry_data.c
+diff --git a/lib/Kconfig b/lib/Kconfig
+index bb94c1b..4b31a46 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -396,4 +396,9 @@ config SIGNATURE
+ config LIBFDT
+ bool
+
++config OID_REGISTRY
++ tristate
++ help
++ Enable fast lookup object identifier registry.
++
+ endmenu
+diff --git a/lib/Makefile b/lib/Makefile
+index 42d283e..b042896 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -150,3 +150,19 @@ quiet_cmd_crc32 = GEN $@
+
+ $(obj)/crc32table.h: $(obj)/gen_crc32table
+ $(call cmd,crc32)
++
++#
++# Build a fast OID lookip registry from include/linux/oid_registry.h
++#
++obj-$(CONFIG_OID_REGISTRY) += oid_registry.o
++
++$(obj)/oid_registry.c: $(obj)/oid_registry_data.c
++
++$(obj)/oid_registry_data.c: $(srctree)/include/linux/oid_registry.h \
++ $(src)/build_OID_registry
++ $(call cmd,build_OID_registry)
++
++quiet_cmd_build_OID_registry = GEN $@
++ cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@
++
++clean-files += oid_registry_data.c
+diff --git a/lib/build_OID_registry b/lib/build_OID_registry
+new file mode 100755
+index 0000000..dfbdaab
+--- /dev/null
++++ b/lib/build_OID_registry
+@@ -0,0 +1,209 @@
++#!/usr/bin/perl -w
++#
++# Build a static ASN.1 Object Identified (OID) registry
++#
++# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++# Written by David Howells (dhowells@redhat.com)
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public Licence
++# as published by the Free Software Foundation; either version
++# 2 of the Licence, or (at your option) any later version.
++#
++
++use strict;
++
++my @names = ();
++my @oids = ();
++
++if ($#ARGV != 1) {
++ print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
++ exit(2);
++}
++
++#
++# Open the file to read from
++#
++open IN_FILE, "<$ARGV[0]" || die;
++while (<IN_FILE>) {
++ chomp;
++ if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {
++ push @names, $1;
++ push @oids, $2;
++ }
++}
++close IN_FILE || die;
++
++#
++# Open the files to write into
++#
++open C_FILE, ">$ARGV[1]" or die;
++print C_FILE "/*\n";
++print C_FILE " * Automatically generated by ", $0, ". Do not edit\n";
++print C_FILE " */\n";
++
++#
++# Split the data up into separate lists and also determine the lengths of the
++# encoded data arrays.
++#
++my @indices = ();
++my @lengths = ();
++my $total_length = 0;
++
++print "Compiling ", $#names + 1, " OIDs\n";
++
++for (my $i = 0; $i <= $#names; $i++) {
++ my $name = $names[$i];
++ my $oid = $oids[$i];
++
++ my @components = split(/[.]/, $oid);
++
++ # Determine the encoded length of this OID
++ my $size = $#components;
++ for (my $loop = 2; $loop <= $#components; $loop++) {
++ my $c = $components[$loop];
++
++ # We will base128 encode the number
++ my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
++ $tmp = int($tmp / 7);
++ $size += $tmp;
++ }
++ push @lengths, $size;
++ push @indices, $total_length;
++ $total_length += $size;
++}
++
++#
++# Emit the look-up-by-OID index table
++#
++print C_FILE "\n";
++if ($total_length <= 255) {
++ print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";
++} else {
++ print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";
++}
++for (my $i = 0; $i <= $#names; $i++) {
++ print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"
++}
++print C_FILE "\t[OID__NR] = ", $total_length, "\n";
++print C_FILE "};\n";
++
++#
++# Encode the OIDs
++#
++my @encoded_oids = ();
++
++for (my $i = 0; $i <= $#names; $i++) {
++ my @octets = ();
++
++ my @components = split(/[.]/, $oids[$i]);
++
++ push @octets, $components[0] * 40 + $components[1];
++
++ for (my $loop = 2; $loop <= $#components; $loop++) {
++ my $c = $components[$loop];
++
++ # Base128 encode the number
++ my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
++ $tmp = int($tmp / 7);
++
++ for (; $tmp > 0; $tmp--) {
++ push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
++ }
++ push @octets, $c & 0x7f;
++ }
++
++ push @encoded_oids, \@octets;
++}
++
++#
++# Create a hash value for each OID
++#
++my @hash_values = ();
++for (my $i = 0; $i <= $#names; $i++) {
++ my @octets = @{$encoded_oids[$i]};
++
++ my $hash = $#octets;
++ foreach (@octets) {
++ $hash += $_ * 33;
++ }
++
++ $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);
++
++ push @hash_values, $hash & 0xff;
++}
++
++#
++# Emit the OID data
++#
++print C_FILE "\n";
++print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";
++for (my $i = 0; $i <= $#names; $i++) {
++ my @octets = @{$encoded_oids[$i]};
++ print C_FILE "\t";
++ print C_FILE $_, ", " foreach (@octets);
++ print C_FILE "\t// ", $names[$i];
++ print C_FILE "\n";
++}
++print C_FILE "};\n";
++
++#
++# Build the search index table (ordered by length then hash then content)
++#
++my @index_table = ( 0 .. $#names );
++
++@index_table = sort {
++ my @octets_a = @{$encoded_oids[$a]};
++ my @octets_b = @{$encoded_oids[$b]};
++
++ return $hash_values[$a] <=> $hash_values[$b]
++ if ($hash_values[$a] != $hash_values[$b]);
++ return $#octets_a <=> $#octets_b
++ if ($#octets_a != $#octets_b);
++ for (my $i = $#octets_a; $i >= 0; $i--) {
++ return $octets_a[$i] <=> $octets_b[$i]
++ if ($octets_a[$i] != $octets_b[$i]);
++ }
++ return 0;
++
++} @index_table;
++
++#
++# Emit the search index and hash value table
++#
++print C_FILE "\n";
++print C_FILE "static const struct {\n";
++print C_FILE "\tunsigned char hash;\n";
++if ($#names <= 255) {
++ print C_FILE "\tenum OID oid : 8;\n";
++} else {
++ print C_FILE "\tenum OID oid : 16;\n";
++}
++print C_FILE "} oid_search_table[OID__NR] = {\n";
++for (my $i = 0; $i <= $#names; $i++) {
++ my @octets = @{$encoded_oids[$index_table[$i]]};
++ printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",
++ $i,
++ $hash_values[$index_table[$i]],
++ $names[$index_table[$i]]);
++ printf C_FILE "%02x", $_ foreach (@octets);
++ print C_FILE "\n";
++}
++print C_FILE "};\n";
++
++#
++# Emit the OID debugging name table
++#
++#print C_FILE "\n";
++#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";
++#
++#for (my $i = 0; $i <= $#names; $i++) {
++# print C_FILE "\t\"", $names[$i], "\",\n"
++#}
++#print C_FILE "\t\"Unknown-OID\"\n";
++#print C_FILE "};\n";
++
++#
++# Polish off
++#
++close C_FILE or die;
+diff --git a/lib/oid_registry.c b/lib/oid_registry.c
+new file mode 100644
+index 0000000..33cfd17
+--- /dev/null
++++ b/lib/oid_registry.c
+@@ -0,0 +1,89 @@
++/* ASN.1 Object identifier (OID) registry
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <linux/export.h>
++#include <linux/oid_registry.h>
++#include "oid_registry_data.c"
++
++/**
++ * look_up_OID - Find an OID registration for the specified data
++ * @data: Binary representation of the OID
++ * @datasize: Size of the binary representation
++ */
++enum OID look_up_OID(const void *data, size_t datasize)
++{
++ const unsigned char *octets = data;
++ enum OID oid;
++ unsigned char xhash;
++ unsigned i, j, k, hash;
++ size_t len;
++
++ /* Hash the OID data */
++ hash = datasize - 1;
++
++ for (i = 0; i < datasize; i++)
++ hash += octets[i] * 33;
++ hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
++ hash &= 0xff;
++
++ /* Binary search the OID registry. OIDs are stored in ascending order
++ * of hash value then ascending order of size and then in ascending
++ * order of reverse value.
++ */
++ i = 0;
++ k = OID__NR;
++ while (i < k) {
++ j = (i + k) / 2;
++
++ xhash = oid_search_table[j].hash;
++ if (xhash > hash) {
++ k = j;
++ continue;
++ }
++ if (xhash < hash) {
++ i = j + 1;
++ continue;
++ }
++
++ oid = oid_search_table[j].oid;
++ len = oid_index[oid + 1] - oid_index[oid];
++ if (len > datasize) {
++ k = j;
++ continue;
++ }
++ if (len < datasize) {
++ i = j + 1;
++ continue;
++ }
++
++ /* Variation is most likely to be at the tail end of the
++ * OID, so do the comparison in reverse.
++ */
++ while (len > 0) {
++ unsigned char a = oid_data[oid_index[oid] + --len];
++ unsigned char b = octets[len];
++ if (a > b) {
++ k = j;
++ goto next;
++ }
++ if (a < b) {
++ i = j + 1;
++ goto next;
++ }
++ }
++ return oid;
++ next:
++ ;
++ }
++
++ return OID__NR;
++}
++EXPORT_SYMBOL_GPL(look_up_OID);
+--
+1.7.12.1
+
+
+From 3e1b30d7c67fd5419d4f6eb5d10b557dda4bc4fd Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:30:51 +0100
+Subject: [PATCH 13/37] X.509: Add utility functions to render OIDs as strings
+
+Add a pair of utility functions to render OIDs as strings. The first takes an
+encoded OID and turns it into a "a.b.c.d" form string:
+
+ int sprint_oid(const void *data, size_t datasize,
+ char *buffer, size_t bufsize);
+
+The second takes an OID enum index and calls the first on the data held
+therein:
+
+ int sprint_OID(enum OID oid, char *buffer, size_t bufsize);
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ include/linux/oid_registry.h | 2 ++
+ lib/oid_registry.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 83 insertions(+)
+
+diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
+index 5928546..6926db7 100644
+--- a/include/linux/oid_registry.h
++++ b/include/linux/oid_registry.h
+@@ -86,5 +86,7 @@ enum OID {
+ };
+
+ extern enum OID look_up_OID(const void *data, size_t datasize);
++extern int sprint_oid(const void *, size_t, char *, size_t);
++extern int sprint_OID(enum OID, char *, size_t);
+
+ #endif /* _LINUX_OID_REGISTRY_H */
+diff --git a/lib/oid_registry.c b/lib/oid_registry.c
+index 33cfd17..d8de11f 100644
+--- a/lib/oid_registry.c
++++ b/lib/oid_registry.c
+@@ -11,6 +11,9 @@
+
+ #include <linux/export.h>
+ #include <linux/oid_registry.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/bug.h>
+ #include "oid_registry_data.c"
+
+ /**
+@@ -87,3 +90,81 @@ enum OID look_up_OID(const void *data, size_t datasize)
+ return OID__NR;
+ }
+ EXPORT_SYMBOL_GPL(look_up_OID);
++
++/*
++ * sprint_OID - Print an Object Identifier into a buffer
++ * @data: The encoded OID to print
++ * @datasize: The size of the encoded OID
++ * @buffer: The buffer to render into
++ * @bufsize: The size of the buffer
++ *
++ * The OID is rendered into the buffer in "a.b.c.d" format and the number of
++ * bytes is returned. -EBADMSG is returned if the data could not be intepreted
++ * and -ENOBUFS if the buffer was too small.
++ */
++int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
++{
++ const unsigned char *v = data, *end = v + datasize;
++ unsigned long num;
++ unsigned char n;
++ size_t ret;
++ int count;
++
++ if (v >= end)
++ return -EBADMSG;
++
++ n = *v++;
++ ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
++ buffer += count;
++ bufsize -= count;
++ if (bufsize == 0)
++ return -ENOBUFS;
++
++ while (v < end) {
++ num = 0;
++ n = *v++;
++ if (!(n & 0x80)) {
++ num = n;
++ } else {
++ num = n & 0x7f;
++ do {
++ if (v >= end)
++ return -EBADMSG;
++ n = *v++;
++ num <<= 7;
++ num |= n & 0x7f;
++ } while (n & 0x80);
++ }
++ ret += count = snprintf(buffer, bufsize, ".%lu", num);
++ buffer += count;
++ bufsize -= count;
++ if (bufsize == 0)
++ return -ENOBUFS;
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(sprint_oid);
++
++/**
++ * sprint_OID - Print an Object Identifier into a buffer
++ * @oid: The OID to print
++ * @buffer: The buffer to render into
++ * @bufsize: The size of the buffer
++ *
++ * The OID is rendered into the buffer in "a.b.c.d" format and the number of
++ * bytes is returned.
++ */
++int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
++{
++ int ret;
++
++ BUG_ON(oid >= OID__NR);
++
++ ret = sprint_oid(oid_data + oid_index[oid],
++ oid_index[oid + 1] - oid_index[oid],
++ buffer, bufsize);
++ BUG_ON(ret == -EBADMSG);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(sprint_OID);
+--
+1.7.12.1
+
+
+From 978cd19071f71ae6a0e622bb2521f88ea633a326 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 21 Sep 2012 23:31:13 +0100
+Subject: [PATCH 14/37] X.509: Add simple ASN.1 grammar compiler
+
+Add a simple ASN.1 grammar compiler. This produces a bytecode output that can
+be fed to a decoder to inform the decoder how to interpret the ASN.1 stream it
+is trying to parse.
+
+Action functions can be specified in the grammar by interpolating:
+
+ ({ foo })
+
+after a type, for example:
+
+ SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier,
+ subjectPublicKey BIT STRING ({ do_key_data })
+ }
+
+The decoder is expected to call these after matching this type and parsing the
+contents if it is a constructed type.
+
+The grammar compiler does not currently support the SET type (though it does
+support SET OF) as I can't see a good way of tracking which members have been
+encountered yet without using up extra stack space.
+
+Currently, the grammar compiler will fail if more than 256 bytes of bytecode
+would be produced or more than 256 actions have been specified as it uses
+8-bit jump values and action indices to keep space usage down.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ include/linux/asn1.h | 67 ++
+ include/linux/asn1_ber_bytecode.h | 87 +++
+ init/Kconfig | 8 +
+ scripts/.gitignore | 1 +
+ scripts/Makefile | 2 +
+ scripts/Makefile.build | 11 +
+ scripts/asn1_compiler.c | 1545 +++++++++++++++++++++++++++++++++++++
+ 7 files changed, 1721 insertions(+)
+ create mode 100644 include/linux/asn1.h
+ create mode 100644 include/linux/asn1_ber_bytecode.h
+ create mode 100644 scripts/asn1_compiler.c
+
+diff --git a/include/linux/asn1.h b/include/linux/asn1.h
+new file mode 100644
+index 0000000..5c3f4e4
+--- /dev/null
++++ b/include/linux/asn1.h
+@@ -0,0 +1,67 @@
++/* ASN.1 BER/DER/CER encoding definitions
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _LINUX_ASN1_H
++#define _LINUX_ASN1_H
++
++/* Class */
++enum asn1_class {
++ ASN1_UNIV = 0, /* Universal */
++ ASN1_APPL = 1, /* Application */
++ ASN1_CONT = 2, /* Context */
++ ASN1_PRIV = 3 /* Private */
++};
++#define ASN1_CLASS_BITS 0xc0
++
++
++enum asn1_method {
++ ASN1_PRIM = 0, /* Primitive */
++ ASN1_CONS = 1 /* Constructed */
++};
++#define ASN1_CONS_BIT 0x20
++
++/* Tag */
++enum asn1_tag {
++ ASN1_EOC = 0, /* End Of Contents or N/A */
++ ASN1_BOOL = 1, /* Boolean */
++ ASN1_INT = 2, /* Integer */
++ ASN1_BTS = 3, /* Bit String */
++ ASN1_OTS = 4, /* Octet String */
++ ASN1_NULL = 5, /* Null */
++ ASN1_OID = 6, /* Object Identifier */
++ ASN1_ODE = 7, /* Object Description */
++ ASN1_EXT = 8, /* External */
++ ASN1_REAL = 9, /* Real float */
++ ASN1_ENUM = 10, /* Enumerated */
++ ASN1_EPDV = 11, /* Embedded PDV */
++ ASN1_UTF8STR = 12, /* UTF8 String */
++ ASN1_RELOID = 13, /* Relative OID */
++ /* 14 - Reserved */
++ /* 15 - Reserved */
++ ASN1_SEQ = 16, /* Sequence and Sequence of */
++ ASN1_SET = 17, /* Set and Set of */
++ ASN1_NUMSTR = 18, /* Numerical String */
++ ASN1_PRNSTR = 19, /* Printable String */
++ ASN1_TEXSTR = 20, /* T61 String / Teletext String */
++ ASN1_VIDSTR = 21, /* Videotex String */
++ ASN1_IA5STR = 22, /* IA5 String */
++ ASN1_UNITIM = 23, /* Universal Time */
++ ASN1_GENTIM = 24, /* General Time */
++ ASN1_GRASTR = 25, /* Graphic String */
++ ASN1_VISSTR = 26, /* Visible String */
++ ASN1_GENSTR = 27, /* General String */
++ ASN1_UNISTR = 28, /* Universal String */
++ ASN1_CHRSTR = 29, /* Character String */
++ ASN1_BMPSTR = 30, /* BMP String */
++ ASN1_LONG_TAG = 31 /* Long form tag */
++};
++
++#endif /* _LINUX_ASN1_H */
+diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h
+new file mode 100644
+index 0000000..945d44a
+--- /dev/null
++++ b/include/linux/asn1_ber_bytecode.h
+@@ -0,0 +1,87 @@
++/* ASN.1 BER/DER/CER parsing state machine internal definitions
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _LINUX_ASN1_BER_BYTECODE_H
++#define _LINUX_ASN1_BER_BYTECODE_H
++
++#ifdef __KERNEL__
++#include <linux/types.h>
++#endif
++#include <linux/asn1.h>
++
++typedef int (*asn1_action_t)(void *context,
++ size_t hdrlen, /* In case of ANY type */
++ unsigned char tag, /* In case of ANY type */
++ const void *value, size_t vlen);
++
++struct asn1_decoder {
++ const unsigned char *machine;
++ size_t machlen;
++ const asn1_action_t *actions;
++};
++
++enum asn1_opcode {
++ /* The tag-matching ops come first and the odd-numbered slots
++ * are for OR_SKIP ops.
++ */
++#define ASN1_OP_MATCH__SKIP 0x01
++#define ASN1_OP_MATCH__ACT 0x02
++#define ASN1_OP_MATCH__JUMP 0x04
++#define ASN1_OP_MATCH__ANY 0x08
++#define ASN1_OP_MATCH__COND 0x10
++
++ ASN1_OP_MATCH = 0x00,
++ ASN1_OP_MATCH_OR_SKIP = 0x01,
++ ASN1_OP_MATCH_ACT = 0x02,
++ ASN1_OP_MATCH_ACT_OR_SKIP = 0x03,
++ ASN1_OP_MATCH_JUMP = 0x04,
++ ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
++ ASN1_OP_MATCH_ANY = 0x08,
++ ASN1_OP_MATCH_ANY_ACT = 0x0a,
++ /* Everything before here matches unconditionally */
++
++ ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
++ ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
++ ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
++ ASN1_OP_COND_MATCH_ANY = 0x18,
++ ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
++
++ /* Everything before here will want a tag from the data */
++#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT
++
++ /* These are here to help fill up space */
++ ASN1_OP_COND_FAIL = 0x1b,
++ ASN1_OP_COMPLETE = 0x1c,
++ ASN1_OP_ACT = 0x1d,
++ ASN1_OP_RETURN = 0x1e,
++
++ /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
++ ASN1_OP_END_SEQ = 0x20,
++ ASN1_OP_END_SET = 0x21,
++ ASN1_OP_END_SEQ_OF = 0x22,
++ ASN1_OP_END_SET_OF = 0x23,
++ ASN1_OP_END_SEQ_ACT = 0x24,
++ ASN1_OP_END_SET_ACT = 0x25,
++ ASN1_OP_END_SEQ_OF_ACT = 0x26,
++ ASN1_OP_END_SET_OF_ACT = 0x27,
++#define ASN1_OP_END__SET 0x01
++#define ASN1_OP_END__OF 0x02
++#define ASN1_OP_END__ACT 0x04
++
++ ASN1_OP__NR
++};
++
++#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG)
++#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG)
++#define _jump_target(N) (N)
++#define _action(N) (N)
++
++#endif /* _LINUX_ASN1_BER_BYTECODE_H */
+diff --git a/init/Kconfig b/init/Kconfig
+index 7452e19..fa8ccad 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1626,4 +1626,12 @@ config PADATA
+ depends on SMP
+ bool
+
++config ASN1
++ tristate
++ help
++ Build a simple ASN.1 grammar compiler that produces a bytecode output
++ that can be interpreted by the ASN.1 stream decoder and used to
++ inform it as to what tags are to be expected in a stream and what
++ functions to call on what tags.
++
+ source "kernel/Kconfig.locks"
+diff --git a/scripts/.gitignore b/scripts/.gitignore
+index 65f362d..fb070fa 100644
+--- a/scripts/.gitignore
++++ b/scripts/.gitignore
+@@ -10,3 +10,4 @@ ihex2fw
+ recordmcount
+ docproc
+ sortextable
++asn1_compiler
+diff --git a/scripts/Makefile b/scripts/Makefile
+index a55b006..01e7adb 100644
+--- a/scripts/Makefile
++++ b/scripts/Makefile
+@@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash
+ hostprogs-$(CONFIG_IKCONFIG) += bin2c
+ hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
+ hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
++hostprogs-$(CONFIG_ASN1) += asn1_compiler
+
+ HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
++HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
+
+ always := $(hostprogs-y) $(hostprogs-m)
+
+diff --git a/scripts/Makefile.build b/scripts/Makefile.build
+index ff1720d..0e801c3 100644
+--- a/scripts/Makefile.build
++++ b/scripts/Makefile.build
+@@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@
+ $(obj)/%.lds: $(src)/%.lds.S FORCE
+ $(call if_changed_dep,cpp_lds_S)
+
++# ASN.1 grammar
++# ---------------------------------------------------------------------------
++quiet_cmd_asn1_compiler = ASN.1 $@
++ cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
++ $(subst .h,.c,$@) $(subst .c,.h,$@)
++
++.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h
++
++$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
++ $(call cmd,asn1_compiler)
++
+ # Build the compiled-in targets
+ # ---------------------------------------------------------------------------
+
+diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c
+new file mode 100644
+index 0000000..db0e5cd
+--- /dev/null
++++ b/scripts/asn1_compiler.c
+@@ -0,0 +1,1545 @@
++/* Simplified ASN.1 notation parser
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <string.h>
++#include <ctype.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/stat.h>
++#include <linux/asn1_ber_bytecode.h>
++
++enum token_type {
++ DIRECTIVE_ABSENT,
++ DIRECTIVE_ALL,
++ DIRECTIVE_ANY,
++ DIRECTIVE_APPLICATION,
++ DIRECTIVE_AUTOMATIC,
++ DIRECTIVE_BEGIN,
++ DIRECTIVE_BIT,
++ DIRECTIVE_BMPString,
++ DIRECTIVE_BOOLEAN,
++ DIRECTIVE_BY,
++ DIRECTIVE_CHARACTER,
++ DIRECTIVE_CHOICE,
++ DIRECTIVE_CLASS,
++ DIRECTIVE_COMPONENT,
++ DIRECTIVE_COMPONENTS,
++ DIRECTIVE_CONSTRAINED,
++ DIRECTIVE_CONTAINING,
++ DIRECTIVE_DEFAULT,
++ DIRECTIVE_DEFINED,
++ DIRECTIVE_DEFINITIONS,
++ DIRECTIVE_EMBEDDED,
++ DIRECTIVE_ENCODED,
++ DIRECTIVE_ENCODING_CONTROL,
++ DIRECTIVE_END,
++ DIRECTIVE_ENUMERATED,
++ DIRECTIVE_EXCEPT,
++ DIRECTIVE_EXPLICIT,
++ DIRECTIVE_EXPORTS,
++ DIRECTIVE_EXTENSIBILITY,
++ DIRECTIVE_EXTERNAL,
++ DIRECTIVE_FALSE,
++ DIRECTIVE_FROM,
++ DIRECTIVE_GeneralString,
++ DIRECTIVE_GeneralizedTime,
++ DIRECTIVE_GraphicString,
++ DIRECTIVE_IA5String,
++ DIRECTIVE_IDENTIFIER,
++ DIRECTIVE_IMPLICIT,
++ DIRECTIVE_IMPLIED,
++ DIRECTIVE_IMPORTS,
++ DIRECTIVE_INCLUDES,
++ DIRECTIVE_INSTANCE,
++ DIRECTIVE_INSTRUCTIONS,
++ DIRECTIVE_INTEGER,
++ DIRECTIVE_INTERSECTION,
++ DIRECTIVE_ISO646String,
++ DIRECTIVE_MAX,
++ DIRECTIVE_MIN,
++ DIRECTIVE_MINUS_INFINITY,
++ DIRECTIVE_NULL,
++ DIRECTIVE_NumericString,
++ DIRECTIVE_OBJECT,
++ DIRECTIVE_OCTET,
++ DIRECTIVE_OF,
++ DIRECTIVE_OPTIONAL,
++ DIRECTIVE_ObjectDescriptor,
++ DIRECTIVE_PATTERN,
++ DIRECTIVE_PDV,
++ DIRECTIVE_PLUS_INFINITY,
++ DIRECTIVE_PRESENT,
++ DIRECTIVE_PRIVATE,
++ DIRECTIVE_PrintableString,
++ DIRECTIVE_REAL,
++ DIRECTIVE_RELATIVE_OID,
++ DIRECTIVE_SEQUENCE,
++ DIRECTIVE_SET,
++ DIRECTIVE_SIZE,
++ DIRECTIVE_STRING,
++ DIRECTIVE_SYNTAX,
++ DIRECTIVE_T61String,
++ DIRECTIVE_TAGS,
++ DIRECTIVE_TRUE,
++ DIRECTIVE_TeletexString,
++ DIRECTIVE_UNION,
++ DIRECTIVE_UNIQUE,
++ DIRECTIVE_UNIVERSAL,
++ DIRECTIVE_UTCTime,
++ DIRECTIVE_UTF8String,
++ DIRECTIVE_UniversalString,
++ DIRECTIVE_VideotexString,
++ DIRECTIVE_VisibleString,
++ DIRECTIVE_WITH,
++ NR__DIRECTIVES,
++ TOKEN_ASSIGNMENT = NR__DIRECTIVES,
++ TOKEN_OPEN_CURLY,
++ TOKEN_CLOSE_CURLY,
++ TOKEN_OPEN_SQUARE,
++ TOKEN_CLOSE_SQUARE,
++ TOKEN_OPEN_ACTION,
++ TOKEN_CLOSE_ACTION,
++ TOKEN_COMMA,
++ TOKEN_NUMBER,
++ TOKEN_TYPE_NAME,
++ TOKEN_ELEMENT_NAME,
++ NR__TOKENS
++};
++
++static const unsigned char token_to_tag[NR__TOKENS] = {
++ /* EOC goes first */
++ [DIRECTIVE_BOOLEAN] = ASN1_BOOL,
++ [DIRECTIVE_INTEGER] = ASN1_INT,
++ [DIRECTIVE_BIT] = ASN1_BTS,
++ [DIRECTIVE_OCTET] = ASN1_OTS,
++ [DIRECTIVE_NULL] = ASN1_NULL,
++ [DIRECTIVE_OBJECT] = ASN1_OID,
++ [DIRECTIVE_ObjectDescriptor] = ASN1_ODE,
++ [DIRECTIVE_EXTERNAL] = ASN1_EXT,
++ [DIRECTIVE_REAL] = ASN1_REAL,
++ [DIRECTIVE_ENUMERATED] = ASN1_ENUM,
++ [DIRECTIVE_EMBEDDED] = 0,
++ [DIRECTIVE_UTF8String] = ASN1_UTF8STR,
++ [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID,
++ /* 14 */
++ /* 15 */
++ [DIRECTIVE_SEQUENCE] = ASN1_SEQ,
++ [DIRECTIVE_SET] = ASN1_SET,
++ [DIRECTIVE_NumericString] = ASN1_NUMSTR,
++ [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
++ [DIRECTIVE_T61String] = ASN1_TEXSTR,
++ [DIRECTIVE_TeletexString] = ASN1_TEXSTR,
++ [DIRECTIVE_VideotexString] = ASN1_VIDSTR,
++ [DIRECTIVE_IA5String] = ASN1_IA5STR,
++ [DIRECTIVE_UTCTime] = ASN1_UNITIM,
++ [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
++ [DIRECTIVE_GraphicString] = ASN1_GRASTR,
++ [DIRECTIVE_VisibleString] = ASN1_VISSTR,
++ [DIRECTIVE_GeneralString] = ASN1_GENSTR,
++ [DIRECTIVE_UniversalString] = ASN1_UNITIM,
++ [DIRECTIVE_CHARACTER] = ASN1_CHRSTR,
++ [DIRECTIVE_BMPString] = ASN1_BMPSTR,
++};
++
++static const char asn1_classes[4][5] = {
++ [ASN1_UNIV] = "UNIV",
++ [ASN1_APPL] = "APPL",
++ [ASN1_CONT] = "CONT",
++ [ASN1_PRIV] = "PRIV"
++};
++
++static const char asn1_methods[2][5] = {
++ [ASN1_UNIV] = "PRIM",
++ [ASN1_APPL] = "CONS"
++};
++
++static const char *const asn1_universal_tags[32] = {
++ "EOC",
++ "BOOL",
++ "INT",
++ "BTS",
++ "OTS",
++ "NULL",
++ "OID",
++ "ODE",
++ "EXT",
++ "REAL",
++ "ENUM",
++ "EPDV",
++ "UTF8STR",
++ "RELOID",
++ NULL, /* 14 */
++ NULL, /* 15 */
++ "SEQ",
++ "SET",
++ "NUMSTR",
++ "PRNSTR",
++ "TEXSTR",
++ "VIDSTR",
++ "IA5STR",
++ "UNITIM",
++ "GENTIM",
++ "GRASTR",
++ "VISSTR",
++ "GENSTR",
++ "UNISTR",
++ "CHRSTR",
++ "BMPSTR",
++ NULL /* 31 */
++};
++
++static const char *filename;
++static const char *grammar_name;
++static const char *outputname;
++static const char *headername;
++
++static const char *const directives[NR__DIRECTIVES] = {
++#define _(X) [DIRECTIVE_##X] = #X
++ _(ABSENT),
++ _(ALL),
++ _(ANY),
++ _(APPLICATION),
++ _(AUTOMATIC),
++ _(BEGIN),
++ _(BIT),
++ _(BMPString),
++ _(BOOLEAN),
++ _(BY),
++ _(CHARACTER),
++ _(CHOICE),
++ _(CLASS),
++ _(COMPONENT),
++ _(COMPONENTS),
++ _(CONSTRAINED),
++ _(CONTAINING),
++ _(DEFAULT),
++ _(DEFINED),
++ _(DEFINITIONS),
++ _(EMBEDDED),
++ _(ENCODED),
++ [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
++ _(END),
++ _(ENUMERATED),
++ _(EXCEPT),
++ _(EXPLICIT),
++ _(EXPORTS),
++ _(EXTENSIBILITY),
++ _(EXTERNAL),
++ _(FALSE),
++ _(FROM),
++ _(GeneralString),
++ _(GeneralizedTime),
++ _(GraphicString),
++ _(IA5String),
++ _(IDENTIFIER),
++ _(IMPLICIT),
++ _(IMPLIED),
++ _(IMPORTS),
++ _(INCLUDES),
++ _(INSTANCE),
++ _(INSTRUCTIONS),
++ _(INTEGER),
++ _(INTERSECTION),
++ _(ISO646String),
++ _(MAX),
++ _(MIN),
++ [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
++ [DIRECTIVE_NULL] = "NULL",
++ _(NumericString),
++ _(OBJECT),
++ _(OCTET),
++ _(OF),
++ _(OPTIONAL),
++ _(ObjectDescriptor),
++ _(PATTERN),
++ _(PDV),
++ [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
++ _(PRESENT),
++ _(PRIVATE),
++ _(PrintableString),
++ _(REAL),
++ [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
++ _(SEQUENCE),
++ _(SET),
++ _(SIZE),
++ _(STRING),
++ _(SYNTAX),
++ _(T61String),
++ _(TAGS),
++ _(TRUE),
++ _(TeletexString),
++ _(UNION),
++ _(UNIQUE),
++ _(UNIVERSAL),
++ _(UTCTime),
++ _(UTF8String),
++ _(UniversalString),
++ _(VideotexString),
++ _(VisibleString),
++ _(WITH)
++};
++
++struct action {
++ struct action *next;
++ unsigned char index;
++ char name[];
++};
++
++static struct action *action_list;
++static unsigned nr_actions;
++
++struct token {
++ unsigned short line;
++ enum token_type token_type : 8;
++ unsigned char size;
++ struct action *action;
++ const char *value;
++ struct type *type;
++};
++
++static struct token *token_list;
++static unsigned nr_tokens;
++
++static int directive_compare(const void *_key, const void *_pdir)
++{
++ const struct token *token = _key;
++ const char *const *pdir = _pdir, *dir = *pdir;
++ size_t dlen, clen;
++ int val;
++
++ dlen = strlen(dir);
++ clen = (dlen < token->size) ? dlen : token->size;
++
++ //printf("cmp(%*.*s,%s) = ",
++ // (int)token->size, (int)token->size, token->value,
++ // dir);
++
++ val = memcmp(token->value, dir, clen);
++ if (val != 0) {
++ //printf("%d [cmp]\n", val);
++ return val;
++ }
++
++ if (dlen == token->size) {
++ //printf("0\n");
++ return 0;
++ }
++ //printf("%d\n", (int)dlen - (int)token->size);
++ return dlen - token->size; /* shorter -> negative */
++}
++
++/*
++ * Tokenise an ASN.1 grammar
++ */
++static void tokenise(char *buffer, char *end)
++{
++ struct token *tokens;
++ char *line, *nl, *p, *q;
++ unsigned tix, lineno;
++
++ /* Assume we're going to have half as many tokens as we have
++ * characters
++ */
++ token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
++ if (!tokens) {
++ perror(NULL);
++ exit(1);
++ }
++ tix = 0;
++
++ lineno = 0;
++ while (buffer < end) {
++ /* First of all, break out a line */
++ lineno++;
++ line = buffer;
++ nl = memchr(line, '\n', end - buffer);
++ if (!nl) {
++ buffer = nl = end;
++ } else {
++ buffer = nl + 1;
++ *nl = '\0';
++ }
++
++ /* Remove "--" comments */
++ p = line;
++ next_comment:
++ while ((p = memchr(p, '-', nl - p))) {
++ if (p[1] == '-') {
++ /* Found a comment; see if there's a terminator */
++ q = p + 2;
++ while ((q = memchr(q, '-', nl - q))) {
++ if (q[1] == '-') {
++ /* There is - excise the comment */
++ q += 2;
++ memmove(p, q, nl - q);
++ goto next_comment;
++ }
++ q++;
++ }
++ *p = '\0';
++ nl = p;
++ break;
++ } else {
++ p++;
++ }
++ }
++
++ p = line;
++ while (p < nl) {
++ /* Skip white space */
++ while (p < nl && isspace(*p))
++ *(p++) = 0;
++ if (p >= nl)
++ break;
++
++ tokens[tix].line = lineno;
++ tokens[tix].value = p;
++
++ /* Handle string tokens */
++ if (isalpha(*p)) {
++ const char **dir;
++
++ /* Can be a directive, type name or element
++ * name. Find the end of the name.
++ */
++ q = p + 1;
++ while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
++ q++;
++ tokens[tix].size = q - p;
++ p = q;
++
++ /* If it begins with a lowercase letter then
++ * it's an element name
++ */
++ if (islower(tokens[tix].value[0])) {
++ tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
++ continue;
++ }
++
++ /* Otherwise we need to search the directive
++ * table
++ */
++ dir = bsearch(&tokens[tix], directives,
++ sizeof(directives) / sizeof(directives[1]),
++ sizeof(directives[1]),
++ directive_compare);
++ if (dir) {
++ tokens[tix++].token_type = dir - directives;
++ continue;
++ }
++
++ tokens[tix++].token_type = TOKEN_TYPE_NAME;
++ continue;
++ }
++
++ /* Handle numbers */
++ if (isdigit(*p)) {
++ /* Find the end of the number */
++ q = p + 1;
++ while (q < nl && (isdigit(*q)))
++ q++;
++ tokens[tix].size = q - p;
++ p = q;
++ tokens[tix++].token_type = TOKEN_NUMBER;
++ continue;
++ }
++
++ if (nl - p >= 3) {
++ if (memcmp(p, "::=", 3) == 0) {
++ p += 3;
++ tokens[tix].size = 3;
++ tokens[tix++].token_type = TOKEN_ASSIGNMENT;
++ continue;
++ }
++ }
++
++ if (nl - p >= 2) {
++ if (memcmp(p, "({", 2) == 0) {
++ p += 2;
++ tokens[tix].size = 2;
++ tokens[tix++].token_type = TOKEN_OPEN_ACTION;
++ continue;
++ }
++ if (memcmp(p, "})", 2) == 0) {
++ p += 2;
++ tokens[tix].size = 2;
++ tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
++ continue;
++ }
++ }
++
++ if (nl - p >= 1) {
++ tokens[tix].size = 1;
++ switch (*p) {
++ case '{':
++ p += 1;
++ tokens[tix++].token_type = TOKEN_OPEN_CURLY;
++ continue;
++ case '}':
++ p += 1;
++ tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
++ continue;
++ case '[':
++ p += 1;
++ tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
++ continue;
++ case ']':
++ p += 1;
++ tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
++ continue;
++ case ',':
++ p += 1;
++ tokens[tix++].token_type = TOKEN_COMMA;
++ continue;
++ default:
++ break;
++ }
++ }
++
++ fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
++ filename, lineno, *p);
++ exit(1);
++ }
++ }
++
++ nr_tokens = tix;
++ printf("Extracted %u tokens\n", nr_tokens);
++
++#if 0
++ {
++ int n;
++ for (n = 0; n < nr_tokens; n++)
++ printf("Token %3u: '%*.*s'\n",
++ n,
++ (int)token_list[n].size, (int)token_list[n].size,
++ token_list[n].value);
++ }
++#endif
++}
++
++static void build_type_list(void);
++static void parse(void);
++static void render(FILE *out, FILE *hdr);
++
++/*
++ *
++ */
++int main(int argc, char **argv)
++{
++ struct stat st;
++ ssize_t readlen;
++ FILE *out, *hdr;
++ char *buffer, *p;
++ int fd;
++
++ if (argc != 4) {
++ fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
++ argv[0]);
++ exit(2);
++ }
++
++ filename = argv[1];
++ outputname = argv[2];
++ headername = argv[3];
++
++ fd = open(filename, O_RDONLY);
++ if (fd < 0) {
++ perror(filename);
++ exit(1);
++ }
++
++ if (fstat(fd, &st) < 0) {
++ perror(filename);
++ exit(1);
++ }
++
++ if (!(buffer = malloc(st.st_size + 1))) {
++ perror(NULL);
++ exit(1);
++ }
++
++ if ((readlen = read(fd, buffer, st.st_size)) < 0) {
++ perror(filename);
++ exit(1);
++ }
++
++ if (close(fd) < 0) {
++ perror(filename);
++ exit(1);
++ }
++
++ if (readlen != st.st_size) {
++ fprintf(stderr, "%s: Short read\n", filename);
++ exit(1);
++ }
++
++ p = strrchr(argv[1], '/');
++ p = p ? p + 1 : argv[1];
++ grammar_name = strdup(p);
++ if (!p) {
++ perror(NULL);
++ exit(1);
++ }
++ p = strchr(grammar_name, '.');
++ if (p)
++ *p = '\0';
++
++ buffer[readlen] = 0;
++ tokenise(buffer, buffer + readlen);
++ build_type_list();
++ parse();
++
++ out = fopen(outputname, "w");
++ if (!out) {
++ perror(outputname);
++ exit(1);
++ }
++
++ hdr = fopen(headername, "w");
++ if (!out) {
++ perror(headername);
++ exit(1);
++ }
++
++ render(out, hdr);
++
++ if (fclose(out) < 0) {
++ perror(outputname);
++ exit(1);
++ }
++
++ if (fclose(hdr) < 0) {
++ perror(headername);
++ exit(1);
++ }
++
++ return 0;
++}
++
++enum compound {
++ NOT_COMPOUND,
++ SET,
++ SET_OF,
++ SEQUENCE,
++ SEQUENCE_OF,
++ CHOICE,
++ ANY,
++ TYPE_REF,
++ TAG_OVERRIDE
++};
++
++struct element {
++ struct type *type_def;
++ struct token *name;
++ struct token *type;
++ struct action *action;
++ struct element *children;
++ struct element *next;
++ struct element *render_next;
++ struct element *list_next;
++ uint8_t n_elements;
++ enum compound compound : 8;
++ enum asn1_class class : 8;
++ enum asn1_method method : 8;
++ uint8_t tag;
++ unsigned entry_index;
++ unsigned flags;
++#define ELEMENT_IMPLICIT 0x0001
++#define ELEMENT_EXPLICIT 0x0002
++#define ELEMENT_MARKED 0x0004
++#define ELEMENT_RENDERED 0x0008
++#define ELEMENT_SKIPPABLE 0x0010
++#define ELEMENT_CONDITIONAL 0x0020
++};
++
++struct type {
++ struct token *name;
++ struct token *def;
++ struct element *element;
++ unsigned ref_count;
++ unsigned flags;
++#define TYPE_STOP_MARKER 0x0001
++#define TYPE_BEGIN 0x0002
++};
++
++static struct type *type_list;
++static struct type **type_index;
++static unsigned nr_types;
++
++static int type_index_compare(const void *_a, const void *_b)
++{
++ const struct type *const *a = _a, *const *b = _b;
++
++ if ((*a)->name->size != (*b)->name->size)
++ return (*a)->name->size - (*b)->name->size;
++ else
++ return memcmp((*a)->name->value, (*b)->name->value,
++ (*a)->name->size);
++}
++
++static int type_finder(const void *_key, const void *_ti)
++{
++ const struct token *token = _key;
++ const struct type *const *ti = _ti;
++ const struct type *type = *ti;
++
++ if (token->size != type->name->size)
++ return token->size - type->name->size;
++ else
++ return memcmp(token->value, type->name->value,
++ token->size);
++}
++
++/*
++ * Build up a list of types and a sorted index to that list.
++ */
++static void build_type_list(void)
++{
++ struct type *types;
++ unsigned nr, t, n;
++
++ nr = 0;
++ for (n = 0; n < nr_tokens - 1; n++)
++ if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
++ token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
++ nr++;
++
++ if (nr == 0) {
++ fprintf(stderr, "%s: No defined types\n", filename);
++ exit(1);
++ }
++
++ nr_types = nr;
++ types = type_list = calloc(nr + 1, sizeof(type_list[0]));
++ if (!type_list) {
++ perror(NULL);
++ exit(1);
++ }
++ type_index = calloc(nr, sizeof(type_index[0]));
++ if (!type_index) {
++ perror(NULL);
++ exit(1);
++ }
++
++ t = 0;
++ types[t].flags |= TYPE_BEGIN;
++ for (n = 0; n < nr_tokens - 1; n++) {
++ if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
++ token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
++ types[t].name = &token_list[n];
++ type_index[t] = &types[t];
++ t++;
++ }
++ }
++ types[t].name = &token_list[n + 1];
++ types[t].flags |= TYPE_STOP_MARKER;
++
++ qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
++
++ printf("Extracted %u types\n", nr_types);
++#if 0
++ for (n = 0; n < nr_types; n++) {
++ struct type *type = type_index[n];
++ printf("- %*.*s\n",
++ (int)type->name->size,
++ (int)type->name->size,
++ type->name->value);
++ }
++#endif
++}
++
++static struct element *parse_type(struct token **_cursor, struct token *stop,
++ struct token *name);
++
++/*
++ * Parse the token stream
++ */
++static void parse(void)
++{
++ struct token *cursor;
++ struct type *type;
++
++ /* Parse one type definition statement at a time */
++ type = type_list;
++ do {
++ cursor = type->name;
++
++ if (cursor[0].token_type != TOKEN_TYPE_NAME ||
++ cursor[1].token_type != TOKEN_ASSIGNMENT)
++ abort();
++ cursor += 2;
++
++ type->element = parse_type(&cursor, type[1].name, NULL);
++ type->element->type_def = type;
++
++ if (cursor != type[1].name) {
++ fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++
++ } while (type++, !(type->flags & TYPE_STOP_MARKER));
++
++ printf("Extracted %u actions\n", nr_actions);
++}
++
++static struct element *element_list;
++
++static struct element *alloc_elem(struct token *type)
++{
++ struct element *e = calloc(1, sizeof(*e));
++ if (!e) {
++ perror(NULL);
++ exit(1);
++ }
++ e->list_next = element_list;
++ element_list = e;
++ return e;
++}
++
++static struct element *parse_compound(struct token **_cursor, struct token *end,
++ int alternates);
++
++/*
++ * Parse one type definition statement
++ */
++static struct element *parse_type(struct token **_cursor, struct token *end,
++ struct token *name)
++{
++ struct element *top, *element;
++ struct action *action, **ppaction;
++ struct token *cursor = *_cursor;
++ struct type **ref;
++ char *p;
++ int labelled = 0, implicit = 0;
++
++ top = element = alloc_elem(cursor);
++ element->class = ASN1_UNIV;
++ element->method = ASN1_PRIM;
++ element->tag = token_to_tag[cursor->token_type];
++ element->name = name;
++
++ /* Extract the tag value if one given */
++ if (cursor->token_type == TOKEN_OPEN_SQUARE) {
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ switch (cursor->token_type) {
++ case DIRECTIVE_UNIVERSAL:
++ element->class = ASN1_UNIV;
++ cursor++;
++ break;
++ case DIRECTIVE_APPLICATION:
++ element->class = ASN1_APPL;
++ cursor++;
++ break;
++ case TOKEN_NUMBER:
++ element->class = ASN1_CONT;
++ break;
++ case DIRECTIVE_PRIVATE:
++ element->class = ASN1_PRIV;
++ cursor++;
++ break;
++ default:
++ fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != TOKEN_NUMBER) {
++ fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++
++ element->tag &= ~0x1f;
++ element->tag |= strtoul(cursor->value, &p, 10);
++ if (p - cursor->value != cursor->size)
++ abort();
++ cursor++;
++
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
++ fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ labelled = 1;
++ }
++
++ /* Handle implicit and explicit markers */
++ if (cursor->token_type == DIRECTIVE_IMPLICIT) {
++ element->flags |= ELEMENT_IMPLICIT;
++ implicit = 1;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
++ element->flags |= ELEMENT_EXPLICIT;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ }
++
++ if (labelled) {
++ if (!implicit)
++ element->method |= ASN1_CONS;
++ element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
++ element->children = alloc_elem(cursor);
++ element = element->children;
++ element->class = ASN1_UNIV;
++ element->method = ASN1_PRIM;
++ element->tag = token_to_tag[cursor->token_type];
++ element->name = name;
++ }
++
++ /* Extract the type we're expecting here */
++ element->type = cursor;
++ switch (cursor->token_type) {
++ case DIRECTIVE_ANY:
++ element->compound = ANY;
++ cursor++;
++ break;
++
++ case DIRECTIVE_NULL:
++ case DIRECTIVE_BOOLEAN:
++ case DIRECTIVE_ENUMERATED:
++ case DIRECTIVE_INTEGER:
++ element->compound = NOT_COMPOUND;
++ cursor++;
++ break;
++
++ case DIRECTIVE_EXTERNAL:
++ element->method = ASN1_CONS;
++
++ case DIRECTIVE_BMPString:
++ case DIRECTIVE_GeneralString:
++ case DIRECTIVE_GraphicString:
++ case DIRECTIVE_IA5String:
++ case DIRECTIVE_ISO646String:
++ case DIRECTIVE_NumericString:
++ case DIRECTIVE_PrintableString:
++ case DIRECTIVE_T61String:
++ case DIRECTIVE_TeletexString:
++ case DIRECTIVE_UniversalString:
++ case DIRECTIVE_UTF8String:
++ case DIRECTIVE_VideotexString:
++ case DIRECTIVE_VisibleString:
++ case DIRECTIVE_ObjectDescriptor:
++ case DIRECTIVE_GeneralizedTime:
++ case DIRECTIVE_UTCTime:
++ element->compound = NOT_COMPOUND;
++ cursor++;
++ break;
++
++ case DIRECTIVE_BIT:
++ case DIRECTIVE_OCTET:
++ element->compound = NOT_COMPOUND;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != DIRECTIVE_STRING)
++ goto parse_error;
++ cursor++;
++ break;
++
++ case DIRECTIVE_OBJECT:
++ element->compound = NOT_COMPOUND;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != DIRECTIVE_IDENTIFIER)
++ goto parse_error;
++ cursor++;
++ break;
++
++ case TOKEN_TYPE_NAME:
++ element->compound = TYPE_REF;
++ ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
++ type_finder);
++ if (!ref) {
++ fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++ cursor->type = *ref;
++ (*ref)->ref_count++;
++ cursor++;
++ break;
++
++ case DIRECTIVE_CHOICE:
++ element->compound = CHOICE;
++ cursor++;
++ element->children = parse_compound(&cursor, end, 1);
++ break;
++
++ case DIRECTIVE_SEQUENCE:
++ element->compound = SEQUENCE;
++ element->method = ASN1_CONS;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type == DIRECTIVE_OF) {
++ element->compound = SEQUENCE_OF;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ element->children = parse_type(&cursor, end, NULL);
++ } else {
++ element->children = parse_compound(&cursor, end, 0);
++ }
++ break;
++
++ case DIRECTIVE_SET:
++ element->compound = SET;
++ element->method = ASN1_CONS;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type == DIRECTIVE_OF) {
++ element->compound = SET_OF;
++ cursor++;
++ if (cursor >= end)
++ goto parse_error;
++ element->children = parse_type(&cursor, end, NULL);
++ } else {
++ element->children = parse_compound(&cursor, end, 1);
++ }
++ break;
++
++ default:
++ fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++
++ /* Handle elements that are optional */
++ if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
++ cursor->token_type == DIRECTIVE_DEFAULT)
++ ) {
++ cursor++;
++ top->flags |= ELEMENT_SKIPPABLE;
++ }
++
++ if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != TOKEN_ELEMENT_NAME) {
++ fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++
++ action = malloc(sizeof(struct action) + cursor->size + 1);
++ if (!action) {
++ perror(NULL);
++ exit(1);
++ }
++ action->index = 0;
++ memcpy(action->name, cursor->value, cursor->size);
++ action->name[cursor->size] = 0;
++
++ for (ppaction = &action_list;
++ *ppaction;
++ ppaction = &(*ppaction)->next
++ ) {
++ int cmp = strcmp(action->name, (*ppaction)->name);
++ if (cmp == 0) {
++ free(action);
++ action = *ppaction;
++ goto found;
++ }
++ if (cmp < 0) {
++ action->next = *ppaction;
++ *ppaction = action;
++ nr_actions++;
++ goto found;
++ }
++ }
++ action->next = NULL;
++ *ppaction = action;
++ nr_actions++;
++ found:
++
++ element->action = action;
++ cursor->action = action;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != TOKEN_CLOSE_ACTION) {
++ fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++ cursor++;
++ }
++
++ *_cursor = cursor;
++ return top;
++
++parse_error:
++ fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++
++overrun_error:
++ fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
++ exit(1);
++}
++
++/*
++ * Parse a compound type list
++ */
++static struct element *parse_compound(struct token **_cursor, struct token *end,
++ int alternates)
++{
++ struct element *children, **child_p = &children, *element;
++ struct token *cursor = *_cursor, *name;
++
++ if (cursor->token_type != TOKEN_OPEN_CURLY) {
++ fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++
++ if (cursor->token_type == TOKEN_OPEN_CURLY) {
++ fprintf(stderr, "%s:%d: Empty compound\n",
++ filename, cursor->line);
++ exit(1);
++ }
++
++ for (;;) {
++ name = NULL;
++ if (cursor->token_type == TOKEN_ELEMENT_NAME) {
++ name = cursor;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ }
++
++ element = parse_type(&cursor, end, name);
++ if (alternates)
++ element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
++
++ *child_p = element;
++ child_p = &element->next;
++
++ if (cursor >= end)
++ goto overrun_error;
++ if (cursor->token_type != TOKEN_COMMA)
++ break;
++ cursor++;
++ if (cursor >= end)
++ goto overrun_error;
++ }
++
++ children->flags &= ~ELEMENT_CONDITIONAL;
++
++ if (cursor->token_type != TOKEN_CLOSE_CURLY) {
++ fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
++ filename, cursor->line,
++ (int)cursor->size, (int)cursor->size, cursor->value);
++ exit(1);
++ }
++ cursor++;
++
++ *_cursor = cursor;
++ return children;
++
++overrun_error:
++ fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
++ exit(1);
++}
++
++static void render_element(FILE *out, struct element *e, struct element *tag);
++static void render_out_of_line_list(FILE *out);
++
++static int nr_entries;
++static int render_depth = 1;
++static struct element *render_list, **render_list_p = &render_list;
++
++__attribute__((format(printf, 2, 3)))
++static void render_opcode(FILE *out, const char *fmt, ...)
++{
++ va_list va;
++
++ if (out) {
++ fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
++ va_start(va, fmt);
++ vfprintf(out, fmt, va);
++ va_end(va);
++ }
++ nr_entries++;
++}
++
++__attribute__((format(printf, 2, 3)))
++static void render_more(FILE *out, const char *fmt, ...)
++{
++ va_list va;
++
++ if (out) {
++ va_start(va, fmt);
++ vfprintf(out, fmt, va);
++ va_end(va);
++ }
++}
++
++/*
++ * Render the grammar into a state machine definition.
++ */
++static void render(FILE *out, FILE *hdr)
++{
++ struct element *e;
++ struct action *action;
++ struct type *root;
++ int index;
++
++ fprintf(hdr, "/*\n");
++ fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
++ fprintf(hdr, " *\n");
++ fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
++ fprintf(hdr, " */\n");
++ fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
++ fprintf(hdr, "\n");
++ fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
++ if (ferror(hdr)) {
++ perror(headername);
++ exit(1);
++ }
++
++ fprintf(out, "/*\n");
++ fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
++ fprintf(out, " *\n");
++ fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
++ fprintf(out, " */\n");
++ fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
++ fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name);
++ fprintf(out, "\n");
++ if (ferror(out)) {
++ perror(outputname);
++ exit(1);
++ }
++
++ /* Tabulate the action functions we might have to call */
++ fprintf(hdr, "\n");
++ index = 0;
++ for (action = action_list; action; action = action->next) {
++ action->index = index++;
++ fprintf(hdr,
++ "extern int %s(void *, size_t, unsigned char,"
++ " const void *, size_t);\n",
++ action->name);
++ }
++ fprintf(hdr, "\n");
++
++ fprintf(out, "enum %s_actions {\n", grammar_name);
++ for (action = action_list; action; action = action->next)
++ fprintf(out, "\tACT_%s = %u,\n",
++ action->name, action->index);
++ fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
++ fprintf(out, "};\n");
++
++ fprintf(out, "\n");
++ fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
++ grammar_name, grammar_name);
++ for (action = action_list; action; action = action->next)
++ fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
++ fprintf(out, "};\n");
++
++ if (ferror(out)) {
++ perror(outputname);
++ exit(1);
++ }
++
++ /* We do two passes - the first one calculates all the offsets */
++ printf("Pass 1\n");
++ nr_entries = 0;
++ root = &type_list[0];
++ render_element(NULL, root->element, NULL);
++ render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
++ render_out_of_line_list(NULL);
++
++ for (e = element_list; e; e = e->list_next)
++ e->flags &= ~ELEMENT_RENDERED;
++
++ /* And then we actually render */
++ printf("Pass 2\n");
++ fprintf(out, "\n");
++ fprintf(out, "static const unsigned char %s_machine[] = {\n",
++ grammar_name);
++
++ nr_entries = 0;
++ root = &type_list[0];
++ render_element(out, root->element, NULL);
++ render_opcode(out, "ASN1_OP_COMPLETE,\n");
++ render_out_of_line_list(out);
++
++ fprintf(out, "};\n");
++
++ fprintf(out, "\n");
++ fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
++ fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
++ fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
++ fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
++ fprintf(out, "};\n");
++}
++
++/*
++ * Render the out-of-line elements
++ */
++static void render_out_of_line_list(FILE *out)
++{
++ struct element *e, *ce;
++ const char *act;
++ int entry;
++
++ while ((e = render_list)) {
++ render_list = e->render_next;
++ if (!render_list)
++ render_list_p = &render_list;
++
++ render_more(out, "\n");
++ e->entry_index = entry = nr_entries;
++ render_depth++;
++ for (ce = e->children; ce; ce = ce->next)
++ render_element(out, ce, NULL);
++ render_depth--;
++
++ act = e->action ? "_ACT" : "";
++ switch (e->compound) {
++ case SEQUENCE:
++ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
++ break;
++ case SEQUENCE_OF:
++ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
++ render_opcode(out, "_jump_target(%u),\n", entry);
++ break;
++ case SET:
++ render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
++ break;
++ case SET_OF:
++ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
++ render_opcode(out, "_jump_target(%u),\n", entry);
++ break;
++ }
++ if (e->action)
++ render_opcode(out, "_action(ACT_%s),\n",
++ e->action->name);
++ render_opcode(out, "ASN1_OP_RETURN,\n");
++ }
++}
++
++/*
++ * Render an element.
++ */
++static void render_element(FILE *out, struct element *e, struct element *tag)
++{
++ struct element *ec;
++ const char *cond, *act;
++ int entry, skippable = 0, outofline = 0;
++
++ if (e->flags & ELEMENT_SKIPPABLE ||
++ (tag && tag->flags & ELEMENT_SKIPPABLE))
++ skippable = 1;
++
++ if ((e->type_def && e->type_def->ref_count > 1) ||
++ skippable)
++ outofline = 1;
++
++ if (e->type_def && out) {
++ render_more(out, "\t// %*.*s\n",
++ (int)e->type_def->name->size, (int)e->type_def->name->size,
++ e->type_def->name->value);
++ }
++
++ /* Render the operation */
++ cond = (e->flags & ELEMENT_CONDITIONAL ||
++ (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
++ act = e->action ? "_ACT" : "";
++ switch (e->compound) {
++ case ANY:
++ render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
++ if (e->name)
++ render_more(out, "\t\t// %*.*s",
++ (int)e->name->size, (int)e->name->size,
++ e->name->value);
++ render_more(out, "\n");
++ goto dont_render_tag;
++
++ case TAG_OVERRIDE:
++ render_element(out, e->children, e);
++ return;
++
++ case SEQUENCE:
++ case SEQUENCE_OF:
++ case SET:
++ case SET_OF:
++ render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
++ cond,
++ outofline ? "_JUMP" : "",
++ skippable ? "_OR_SKIP" : "");
++ break;
++
++ case CHOICE:
++ goto dont_render_tag;
++
++ case TYPE_REF:
++ if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
++ goto dont_render_tag;
++ default:
++ render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
++ cond, act,
++ skippable ? "_OR_SKIP" : "");
++ break;
++ }
++
++ if (e->name)
++ render_more(out, "\t\t// %*.*s",
++ (int)e->name->size, (int)e->name->size,
++ e->name->value);
++ render_more(out, "\n");
++
++ /* Render the tag */
++ if (!tag)
++ tag = e;
++ if (tag->class == ASN1_UNIV &&
++ tag->tag != 14 &&
++ tag->tag != 15 &&
++ tag->tag != 31)
++ render_opcode(out, "_tag(%s, %s, %s),\n",
++ asn1_classes[tag->class],
++ asn1_methods[tag->method | e->method],
++ asn1_universal_tags[tag->tag]);
++ else
++ render_opcode(out, "_tagn(%s, %s, %2u),\n",
++ asn1_classes[tag->class],
++ asn1_methods[tag->method | e->method],
++ tag->tag);
++ tag = NULL;
++dont_render_tag:
++
++ /* Deal with compound types */
++ switch (e->compound) {
++ case TYPE_REF:
++ render_element(out, e->type->type->element, tag);
++ if (e->action)
++ render_opcode(out, "ASN1_OP_ACT,\n");
++ break;
++
++ case SEQUENCE:
++ if (outofline) {
++ /* Render out-of-line for multiple use or
++ * skipability */
++ render_opcode(out, "_jump_target(%u),", e->entry_index);
++ if (e->type_def && e->type_def->name)
++ render_more(out, "\t\t// --> %*.*s",
++ (int)e->type_def->name->size,
++ (int)e->type_def->name->size,
++ e->type_def->name->value);
++ render_more(out, "\n");
++ if (!(e->flags & ELEMENT_RENDERED)) {
++ e->flags |= ELEMENT_RENDERED;
++ *render_list_p = e;
++ render_list_p = &e->render_next;
++ }
++ return;
++ } else {
++ /* Render inline for single use */
++ render_depth++;
++ for (ec = e->children; ec; ec = ec->next)
++ render_element(out, ec, NULL);
++ render_depth--;
++ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
++ }
++ break;
++
++ case SEQUENCE_OF:
++ case SET_OF:
++ if (outofline) {
++ /* Render out-of-line for multiple use or
++ * skipability */
++ render_opcode(out, "_jump_target(%u),", e->entry_index);
++ if (e->type_def && e->type_def->name)
++ render_more(out, "\t\t// --> %*.*s",
++ (int)e->type_def->name->size,
++ (int)e->type_def->name->size,
++ e->type_def->name->value);
++ render_more(out, "\n");
++ if (!(e->flags & ELEMENT_RENDERED)) {
++ e->flags |= ELEMENT_RENDERED;
++ *render_list_p = e;
++ render_list_p = &e->render_next;
++ }
++ return;
++ } else {
++ /* Render inline for single use */
++ entry = nr_entries;
++ render_depth++;
++ render_element(out, e->children, NULL);
++ render_depth--;
++ if (e->compound == SEQUENCE_OF)
++ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
++ else
++ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
++ render_opcode(out, "_jump_target(%u),\n", entry);
++ }
++ break;
++
++ case SET:
++ /* I can't think of a nice way to do SET support without having
++ * a stack of bitmasks to make sure no element is repeated.
++ * The bitmask has also to be checked that no non-optional
++ * elements are left out whilst not preventing optional
++ * elements from being left out.
++ */
++ fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
++ exit(1);
++
++ case CHOICE:
++ for (ec = e->children; ec; ec = ec->next)
++ render_element(out, ec, NULL);
++ if (!skippable)
++ render_opcode(out, "ASN1_OP_COND_FAIL,\n");
++ if (e->action)
++ render_opcode(out, "ASN1_OP_ACT,\n");
++ break;
++
++ default:
++ break;
++ }
++
++ if (e->action)
++ render_opcode(out, "_action(ACT_%s),\n", e->action->name);
++}
+--
+1.7.12.1
+
+
+From 650c728e4b8d58d72b19973e97c3c765178e81b8 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Mon, 24 Sep 2012 17:11:16 +0100
+Subject: [PATCH 15/37] X.509: Add an ASN.1 decoder
+
+Add an ASN.1 BER/DER/CER decoder. This uses the bytecode from the ASN.1
+compiler in the previous patch to inform it as to what to expect to find in the
+encoded byte stream. The output from the compiler also tells it what functions
+to call on what tags, thus allowing the caller to retrieve information.
+
+The decoder is called as follows:
+
+ int asn1_decoder(const struct asn1_decoder *decoder,
+ void *context,
+ const unsigned char *data,
+ size_t datalen);
+
+The decoder argument points to the bytecode from the ASN.1 compiler. context
+is the caller's context and is passed to the action functions. data and
+datalen define the byte stream to be decoded.
+
+Note that the decoder is currently limited to datalen being less than 64K.
+This reduces the amount of stack space used by the decoder because ASN.1 is a
+nested construct. Similarly, the decoder is limited to a maximum of 10 levels
+of constructed data outside of a leaf node also in an effort to keep stack
+usage down.
+
+These restrictions can be raised if necessary.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ include/linux/asn1_decoder.h | 24 +++
+ lib/Makefile | 2 +
+ lib/asn1_decoder.c | 477 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 503 insertions(+)
+ create mode 100644 include/linux/asn1_decoder.h
+ create mode 100644 lib/asn1_decoder.c
+
+diff --git a/include/linux/asn1_decoder.h b/include/linux/asn1_decoder.h
+new file mode 100644
+index 0000000..fa2ff5b
+--- /dev/null
++++ b/include/linux/asn1_decoder.h
+@@ -0,0 +1,24 @@
++/* ASN.1 decoder
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _LINUX_ASN1_DECODER_H
++#define _LINUX_ASN1_DECODER_H
++
++#include <linux/asn1.h>
++
++struct asn1_decoder;
++
++extern int asn1_ber_decoder(const struct asn1_decoder *decoder,
++ void *context,
++ const unsigned char *data,
++ size_t datalen);
++
++#endif /* _LINUX_ASN1_DECODER_H */
+diff --git a/lib/Makefile b/lib/Makefile
+index b042896..ca856b6 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -140,6 +140,8 @@ $(foreach file, $(libfdt_files), \
+ $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt))
+ lib-$(CONFIG_LIBFDT) += $(libfdt_files)
+
++obj-$(CONFIG_ASN1) += asn1_decoder.o
++
+ hostprogs-y := gen_crc32table
+ clean-files := crc32table.h
+
+diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c
+new file mode 100644
+index 0000000..2e4196d
+--- /dev/null
++++ b/lib/asn1_decoder.c
+@@ -0,0 +1,477 @@
++/* Decoder for ASN.1 BER/DER/CER encoded bytestream
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/asn1_decoder.h>
++#include <linux/asn1_ber_bytecode.h>
++
++static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
++ /* OPC TAG JMP ACT */
++ [ASN1_OP_MATCH] = 1 + 1,
++ [ASN1_OP_MATCH_OR_SKIP] = 1 + 1,
++ [ASN1_OP_MATCH_ACT] = 1 + 1 + 1,
++ [ASN1_OP_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
++ [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1,
++ [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
++ [ASN1_OP_MATCH_ANY] = 1,
++ [ASN1_OP_MATCH_ANY_ACT] = 1 + 1,
++ [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1,
++ [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
++ [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
++ [ASN1_OP_COND_MATCH_ANY] = 1,
++ [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1,
++ [ASN1_OP_COND_FAIL] = 1,
++ [ASN1_OP_COMPLETE] = 1,
++ [ASN1_OP_ACT] = 1 + 1,
++ [ASN1_OP_RETURN] = 1,
++ [ASN1_OP_END_SEQ] = 1,
++ [ASN1_OP_END_SEQ_OF] = 1 + 1,
++ [ASN1_OP_END_SET] = 1,
++ [ASN1_OP_END_SET_OF] = 1 + 1,
++ [ASN1_OP_END_SEQ_ACT] = 1 + 1,
++ [ASN1_OP_END_SEQ_OF_ACT] = 1 + 1 + 1,
++ [ASN1_OP_END_SET_ACT] = 1 + 1,
++ [ASN1_OP_END_SET_OF_ACT] = 1 + 1 + 1,
++};
++
++/*
++ * Find the length of an indefinite length object
++ */
++static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen,
++ const char **_errmsg, size_t *_err_dp)
++{
++ unsigned char tag, tmp;
++ size_t dp = 0, len, n;
++ int indef_level = 1;
++
++next_tag:
++ if (unlikely(datalen - dp < 2)) {
++ if (datalen == dp)
++ goto missing_eoc;
++ goto data_overrun_error;
++ }
++
++ /* Extract a tag from the data */
++ tag = data[dp++];
++ if (tag == 0) {
++ /* It appears to be an EOC. */
++ if (data[dp++] != 0)
++ goto invalid_eoc;
++ if (--indef_level <= 0)
++ return dp;
++ goto next_tag;
++ }
++
++ if (unlikely((tag & 0x1f) == 0x1f)) {
++ do {
++ if (unlikely(datalen - dp < 2))
++ goto data_overrun_error;
++ tmp = data[dp++];
++ } while (tmp & 0x80);
++ }
++
++ /* Extract the length */
++ len = data[dp++];
++ if (len < 0x7f) {
++ dp += len;
++ goto next_tag;
++ }
++
++ if (unlikely(len == 0x80)) {
++ /* Indefinite length */
++ if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5))
++ goto indefinite_len_primitive;
++ indef_level++;
++ goto next_tag;
++ }
++
++ n = len - 0x80;
++ if (unlikely(n > sizeof(size_t) - 1))
++ goto length_too_long;
++ if (unlikely(n > datalen - dp))
++ goto data_overrun_error;
++ for (len = 0; n > 0; n--) {
++ len <<= 8;
++ len |= data[dp++];
++ }
++ dp += len;
++ goto next_tag;
++
++length_too_long:
++ *_errmsg = "Unsupported length";
++ goto error;
++indefinite_len_primitive:
++ *_errmsg = "Indefinite len primitive not permitted";
++ goto error;
++invalid_eoc:
++ *_errmsg = "Invalid length EOC";
++ goto error;
++data_overrun_error:
++ *_errmsg = "Data overrun error";
++ goto error;
++missing_eoc:
++ *_errmsg = "Missing EOC in indefinite len cons";
++error:
++ *_err_dp = dp;
++ return -1;
++}
++
++/**
++ * asn1_ber_decoder - Decoder BER/DER/CER ASN.1 according to pattern
++ * @decoder: The decoder definition (produced by asn1_compiler)
++ * @context: The caller's context (to be passed to the action functions)
++ * @data: The encoded data
++ * @datasize: The size of the encoded data
++ *
++ * Decode BER/DER/CER encoded ASN.1 data according to a bytecode pattern
++ * produced by asn1_compiler. Action functions are called on marked tags to
++ * allow the caller to retrieve significant data.
++ *
++ * LIMITATIONS:
++ *
++ * To keep down the amount of stack used by this function, the following limits
++ * have been imposed:
++ *
++ * (1) This won't handle datalen > 65535 without increasing the size of the
++ * cons stack elements and length_too_long checking.
++ *
++ * (2) The stack of constructed types is 10 deep. If the depth of non-leaf
++ * constructed types exceeds this, the decode will fail.
++ *
++ * (3) The SET type (not the SET OF type) isn't really supported as tracking
++ * what members of the set have been seen is a pain.
++ */
++int asn1_ber_decoder(const struct asn1_decoder *decoder,
++ void *context,
++ const unsigned char *data,
++ size_t datalen)
++{
++ const unsigned char *machine = decoder->machine;
++ const asn1_action_t *actions = decoder->actions;
++ size_t machlen = decoder->machlen;
++ enum asn1_opcode op;
++ unsigned char tag = 0, csp = 0, jsp = 0, optag = 0, hdr = 0;
++ const char *errmsg;
++ size_t pc = 0, dp = 0, tdp = 0, len = 0;
++ int ret;
++
++ unsigned char flags = 0;
++#define FLAG_INDEFINITE_LENGTH 0x01
++#define FLAG_MATCHED 0x02
++#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag
++ * - ie. whether or not we are going to parse
++ * a compound type.
++ */
++
++#define NR_CONS_STACK 10
++ unsigned short cons_dp_stack[NR_CONS_STACK];
++ unsigned short cons_datalen_stack[NR_CONS_STACK];
++ unsigned char cons_hdrlen_stack[NR_CONS_STACK];
++#define NR_JUMP_STACK 10
++ unsigned char jump_stack[NR_JUMP_STACK];
++
++ if (datalen > 65535)
++ return -EMSGSIZE;
++
++next_op:
++ pr_debug("next_op: pc=\e[32m%zu\e[m/%zu dp=\e[33m%zu\e[m/%zu C=%d J=%d\n",
++ pc, machlen, dp, datalen, csp, jsp);
++ if (unlikely(pc >= machlen))
++ goto machine_overrun_error;
++ op = machine[pc];
++ if (unlikely(pc + asn1_op_lengths[op] > machlen))
++ goto machine_overrun_error;
++
++ /* If this command is meant to match a tag, then do that before
++ * evaluating the command.
++ */
++ if (op <= ASN1_OP__MATCHES_TAG) {
++ unsigned char tmp;
++
++ /* Skip conditional matches if possible */
++ if ((op & ASN1_OP_MATCH__COND &&
++ flags & FLAG_MATCHED) ||
++ dp == datalen) {
++ pc += asn1_op_lengths[op];
++ goto next_op;
++ }
++
++ flags = 0;
++ hdr = 2;
++
++ /* Extract a tag from the data */
++ if (unlikely(dp >= datalen - 1))
++ goto data_overrun_error;
++ tag = data[dp++];
++ if (unlikely((tag & 0x1f) == 0x1f))
++ goto long_tag_not_supported;
++
++ if (op & ASN1_OP_MATCH__ANY) {
++ pr_debug("- any %02x\n", tag);
++ } else {
++ /* Extract the tag from the machine
++ * - Either CONS or PRIM are permitted in the data if
++ * CONS is not set in the op stream, otherwise CONS
++ * is mandatory.
++ */
++ optag = machine[pc + 1];
++ flags |= optag & FLAG_CONS;
++
++ /* Determine whether the tag matched */
++ tmp = optag ^ tag;
++ tmp &= ~(optag & ASN1_CONS_BIT);
++ pr_debug("- match? %02x %02x %02x\n", tag, optag, tmp);
++ if (tmp != 0) {
++ /* All odd-numbered tags are MATCH_OR_SKIP. */
++ if (op & ASN1_OP_MATCH__SKIP) {
++ pc += asn1_op_lengths[op];
++ dp--;
++ goto next_op;
++ }
++ goto tag_mismatch;
++ }
++ }
++ flags |= FLAG_MATCHED;
++
++ len = data[dp++];
++ if (len > 0x7f) {
++ if (unlikely(len == 0x80)) {
++ /* Indefinite length */
++ if (unlikely(!(tag & ASN1_CONS_BIT)))
++ goto indefinite_len_primitive;
++ flags |= FLAG_INDEFINITE_LENGTH;
++ if (unlikely(2 > datalen - dp))
++ goto data_overrun_error;
++ } else {
++ int n = len - 0x80;
++ if (unlikely(n > 2))
++ goto length_too_long;
++ if (unlikely(dp >= datalen - n))
++ goto data_overrun_error;
++ hdr += n;
++ for (len = 0; n > 0; n--) {
++ len <<= 8;
++ len |= data[dp++];
++ }
++ if (unlikely(len > datalen - dp))
++ goto data_overrun_error;
++ }
++ }
++
++ if (flags & FLAG_CONS) {
++ /* For expected compound forms, we stack the positions
++ * of the start and end of the data.
++ */
++ if (unlikely(csp >= NR_CONS_STACK))
++ goto cons_stack_overflow;
++ cons_dp_stack[csp] = dp;
++ cons_hdrlen_stack[csp] = hdr;
++ if (!(flags & FLAG_INDEFINITE_LENGTH)) {
++ cons_datalen_stack[csp] = datalen;
++ datalen = dp + len;
++ } else {
++ cons_datalen_stack[csp] = 0;
++ }
++ csp++;
++ }
++
++ pr_debug("- TAG: %02x %zu%s\n",
++ tag, len, flags & FLAG_CONS ? " CONS" : "");
++ tdp = dp;
++ }
++
++ /* Decide how to handle the operation */
++ switch (op) {
++ case ASN1_OP_MATCH_ANY_ACT:
++ case ASN1_OP_COND_MATCH_ANY_ACT:
++ ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len);
++ if (ret < 0)
++ return ret;
++ goto skip_data;
++
++ case ASN1_OP_MATCH_ACT:
++ case ASN1_OP_MATCH_ACT_OR_SKIP:
++ case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
++ ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len);
++ if (ret < 0)
++ return ret;
++ goto skip_data;
++
++ case ASN1_OP_MATCH:
++ case ASN1_OP_MATCH_OR_SKIP:
++ case ASN1_OP_MATCH_ANY:
++ case ASN1_OP_COND_MATCH_OR_SKIP:
++ case ASN1_OP_COND_MATCH_ANY:
++ skip_data:
++ if (!(flags & FLAG_CONS)) {
++ if (flags & FLAG_INDEFINITE_LENGTH) {
++ len = asn1_find_indefinite_length(
++ data + dp, datalen - dp, &errmsg, &dp);
++ if (len < 0)
++ goto error;
++ }
++ pr_debug("- LEAF: %zu\n", len);
++ dp += len;
++ }
++ pc += asn1_op_lengths[op];
++ goto next_op;
++
++ case ASN1_OP_MATCH_JUMP:
++ case ASN1_OP_MATCH_JUMP_OR_SKIP:
++ case ASN1_OP_COND_MATCH_JUMP_OR_SKIP:
++ pr_debug("- MATCH_JUMP\n");
++ if (unlikely(jsp == NR_JUMP_STACK))
++ goto jump_stack_overflow;
++ jump_stack[jsp++] = pc + asn1_op_lengths[op];
++ pc = machine[pc + 2];
++ goto next_op;
++
++ case ASN1_OP_COND_FAIL:
++ if (unlikely(!(flags & FLAG_MATCHED)))
++ goto tag_mismatch;
++ pc += asn1_op_lengths[op];
++ goto next_op;
++
++ case ASN1_OP_COMPLETE:
++ if (unlikely(jsp != 0 || csp != 0)) {
++ pr_err("ASN.1 decoder error: Stacks not empty at completion (%u, %u)\n",
++ jsp, csp);
++ return -EBADMSG;
++ }
++ return 0;
++
++ case ASN1_OP_END_SET:
++ case ASN1_OP_END_SET_ACT:
++ if (unlikely(!(flags & FLAG_MATCHED)))
++ goto tag_mismatch;
++ case ASN1_OP_END_SEQ:
++ case ASN1_OP_END_SET_OF:
++ case ASN1_OP_END_SEQ_OF:
++ case ASN1_OP_END_SEQ_ACT:
++ case ASN1_OP_END_SET_OF_ACT:
++ case ASN1_OP_END_SEQ_OF_ACT:
++ if (unlikely(csp <= 0))
++ goto cons_stack_underflow;
++ csp--;
++ tdp = cons_dp_stack[csp];
++ hdr = cons_hdrlen_stack[csp];
++ len = datalen;
++ datalen = cons_datalen_stack[csp];
++ pr_debug("- end cons t=%zu dp=%zu l=%zu/%zu\n",
++ tdp, dp, len, datalen);
++ if (datalen == 0) {
++ /* Indefinite length - check for the EOC. */
++ datalen = len;
++ if (unlikely(datalen - dp < 2))
++ goto data_overrun_error;
++ if (data[dp++] != 0) {
++ if (op & ASN1_OP_END__OF) {
++ dp--;
++ csp++;
++ pc = machine[pc + 1];
++ pr_debug("- continue\n");
++ goto next_op;
++ }
++ goto missing_eoc;
++ }
++ if (data[dp++] != 0)
++ goto invalid_eoc;
++ len = dp - tdp - 2;
++ } else {
++ if (dp < len && (op & ASN1_OP_END__OF)) {
++ datalen = len;
++ csp++;
++ pc = machine[pc + 1];
++ pr_debug("- continue\n");
++ goto next_op;
++ }
++ if (dp != len)
++ goto cons_length_error;
++ len -= tdp;
++ pr_debug("- cons len l=%zu d=%zu\n", len, dp - tdp);
++ }
++
++ if (op & ASN1_OP_END__ACT) {
++ unsigned char act;
++ if (op & ASN1_OP_END__OF)
++ act = machine[pc + 2];
++ else
++ act = machine[pc + 1];
++ ret = actions[act](context, hdr, 0, data + tdp, len);
++ }
++ pc += asn1_op_lengths[op];
++ goto next_op;
++
++ case ASN1_OP_ACT:
++ ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
++ pc += asn1_op_lengths[op];
++ goto next_op;
++
++ case ASN1_OP_RETURN:
++ if (unlikely(jsp <= 0))
++ goto jump_stack_underflow;
++ pc = jump_stack[--jsp];
++ goto next_op;
++
++ default:
++ break;
++ }
++
++ /* Shouldn't reach here */
++ pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op);
++ return -EBADMSG;
++
++data_overrun_error:
++ errmsg = "Data overrun error";
++ goto error;
++machine_overrun_error:
++ errmsg = "Machine overrun error";
++ goto error;
++jump_stack_underflow:
++ errmsg = "Jump stack underflow";
++ goto error;
++jump_stack_overflow:
++ errmsg = "Jump stack overflow";
++ goto error;
++cons_stack_underflow:
++ errmsg = "Cons stack underflow";
++ goto error;
++cons_stack_overflow:
++ errmsg = "Cons stack overflow";
++ goto error;
++cons_length_error:
++ errmsg = "Cons length error";
++ goto error;
++missing_eoc:
++ errmsg = "Missing EOC in indefinite len cons";
++ goto error;
++invalid_eoc:
++ errmsg = "Invalid length EOC";
++ goto error;
++length_too_long:
++ errmsg = "Unsupported length";
++ goto error;
++indefinite_len_primitive:
++ errmsg = "Indefinite len primitive not permitted";
++ goto error;
++tag_mismatch:
++ errmsg = "Unexpected tag";
++ goto error;
++long_tag_not_supported:
++ errmsg = "Long tag not supported";
++error:
++ pr_debug("\nASN1: %s [m=%zu d=%zu ot=%02x t=%02x l=%zu]\n",
++ errmsg, pc, dp, optag, tag, len);
++ return -EBADMSG;
++}
++EXPORT_SYMBOL_GPL(asn1_ber_decoder);
+--
+1.7.12.1
+
+
+From 686b0b5e3549b711c0bcc405d833697ff5e2344d Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Mon, 24 Sep 2012 17:11:27 +0100
+Subject: [PATCH 16/37] MPILIB: Provide a function to read raw data into an
+ MPI
+
+Provide a function to read raw data of a predetermined size into an MPI rather
+than expecting the size to be encoded within the data. The data is assumed to
+represent an unsigned integer, and the resulting MPI will be positive.
+
+The function looks like this:
+
+ MPI mpi_read_raw_data(const void *, size_t);
+
+This is useful for reading ASN.1 integer primitives where the length is encoded
+in the ASN.1 metadata.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ include/linux/mpi.h | 1 +
+ lib/mpi/mpicoder.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 56 insertions(+)
+
+diff --git a/include/linux/mpi.h b/include/linux/mpi.h
+index d02cca6..5af1b81 100644
+--- a/include/linux/mpi.h
++++ b/include/linux/mpi.h
+@@ -76,6 +76,7 @@ void mpi_swap(MPI a, MPI b);
+
+ /*-- mpicoder.c --*/
+ MPI do_encode_md(const void *sha_buffer, unsigned nbits);
++MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes);
+ MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
+ int mpi_fromstr(MPI val, const char *str);
+ u32 mpi_get_keyid(MPI a, u32 *keyid);
+diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
+index f0fa659..3962b7f 100644
+--- a/lib/mpi/mpicoder.c
++++ b/lib/mpi/mpicoder.c
+@@ -18,10 +18,65 @@
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
++#include <linux/bitops.h>
++#include <asm-generic/bitops/count_zeros.h>
+ #include "mpi-internal.h"
+
+ #define MAX_EXTERN_MPI_BITS 16384
+
++/**
++ * mpi_read_raw_data - Read a raw byte stream as a positive integer
++ * @xbuffer: The data to read
++ * @nbytes: The amount of data to read
++ */
++MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes)
++{
++ const uint8_t *buffer = xbuffer;
++ int i, j;
++ unsigned nbits, nlimbs;
++ mpi_limb_t a;
++ MPI val = NULL;
++
++ while (nbytes >= 0 && buffer[0] == 0) {
++ buffer++;
++ nbytes--;
++ }
++
++ nbits = nbytes * 8;
++ if (nbits > MAX_EXTERN_MPI_BITS) {
++ pr_info("MPI: mpi too large (%u bits)\n", nbits);
++ return NULL;
++ }
++ if (nbytes > 0)
++ nbits -= count_leading_zeros(buffer[0]);
++ else
++ nbits = 0;
++
++ nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
++ val = mpi_alloc(nlimbs);
++ if (!val)
++ return NULL;
++ val->nbits = nbits;
++ val->sign = 0;
++ val->nlimbs = nlimbs;
++
++ if (nbytes > 0) {
++ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
++ i %= BYTES_PER_MPI_LIMB;
++ for (j = nlimbs; j > 0; j--) {
++ a = 0;
++ for (; i < BYTES_PER_MPI_LIMB; i++) {
++ a <<= 8;
++ a |= *buffer++;
++ }
++ i = 0;
++ val->d[j - 1] = a;
++ }
++ }
++ return val;
++}
++EXPORT_SYMBOL_GPL(mpi_read_raw_data);
++
+ MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
+ {
+ const uint8_t *buffer = xbuffer;
+--
+1.7.12.1
+
+
+From c6ca1b7770b65d0639fb84a7afead457ff22c8d4 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Mon, 24 Sep 2012 17:11:48 +0100
+Subject: [PATCH 17/37] X.509: Add a crypto key parser for binary (DER) X.509
+ certificates
+
+Add a crypto key parser for binary (DER) encoded X.509 certificates. The
+certificate is parsed and, if possible, the signature is verified.
+
+An X.509 key can be added like this:
+
+ # keyctl padd crypto bar @s </tmp/x509.cert
+ 15768135
+
+and displayed like this:
+
+ # cat /proc/keys
+ 00f09a47 I--Q--- 1 perm 39390000 0 0 asymmetri bar: X509.RSA e9fd6d08 []
+
+Note that this only works with binary certificates. PEM encoded certificates
+are ignored by the parser.
+
+Note also that the X.509 key ID is not congruent with the PGP key ID, but for
+the moment, they will match.
+
+If a NULL or "" name is given to add_key(), then the parser will generate a key
+description from the CertificateSerialNumber and Name fields of the
+TBSCertificate:
+
+ 00aefc4e I--Q--- 1 perm 39390000 0 0 asymmetri bfbc0cd76d050ea4:/C=GB/L=Cambridge/O=Red Hat/CN=kernel key: X509.RSA 0c688c7b []
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/.gitignore | 1 +
+ crypto/asymmetric_keys/Kconfig | 10 +
+ crypto/asymmetric_keys/Makefile | 17 +
+ crypto/asymmetric_keys/x509.asn1 | 60 ++++
+ crypto/asymmetric_keys/x509_cert_parser.c | 497 ++++++++++++++++++++++++++++++
+ crypto/asymmetric_keys/x509_parser.h | 36 +++
+ crypto/asymmetric_keys/x509_public_key.c | 207 +++++++++++++
+ crypto/asymmetric_keys/x509_rsakey.asn1 | 4 +
+ 8 files changed, 832 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/.gitignore
+ create mode 100644 crypto/asymmetric_keys/x509.asn1
+ create mode 100644 crypto/asymmetric_keys/x509_cert_parser.c
+ create mode 100644 crypto/asymmetric_keys/x509_parser.h
+ create mode 100644 crypto/asymmetric_keys/x509_public_key.c
+ create mode 100644 crypto/asymmetric_keys/x509_rsakey.asn1
+
+diff --git a/crypto/asymmetric_keys/.gitignore b/crypto/asymmetric_keys/.gitignore
+new file mode 100644
+index 0000000..ee32837
+--- /dev/null
++++ b/crypto/asymmetric_keys/.gitignore
+@@ -0,0 +1 @@
++*-asn1.[ch]
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 561759d..6d2c2ea 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -25,4 +25,14 @@ config PUBLIC_KEY_ALGO_RSA
+ help
+ This option enables support for the RSA algorithm (PKCS#1, RFC3447).
+
++config X509_CERTIFICATE_PARSER
++ tristate "X.509 certificate parser"
++ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
++ select ASN1
++ select OID_REGISTRY
++ help
++ This option procides support for parsing X.509 format blobs for key
++ data and provides the ability to instantiate a crypto key from a
++ public key packet found inside the certificate.
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 7c92691..0727204 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -8,3 +8,20 @@ asymmetric_keys-y := asymmetric_type.o signature.o
+
+ obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
++
++#
++# X.509 Certificate handling
++#
++obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
++x509_key_parser-y := \
++ x509-asn1.o \
++ x509_rsakey-asn1.o \
++ x509_cert_parser.o \
++ x509_public_key.o
++
++$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h
++$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
++$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
++
++clean-files += x509-asn1.c x509-asn1.h
++clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
+diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
+new file mode 100644
+index 0000000..bf32b3d
+--- /dev/null
++++ b/crypto/asymmetric_keys/x509.asn1
+@@ -0,0 +1,60 @@
++Certificate ::= SEQUENCE {
++ tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }),
++ signatureAlgorithm AlgorithmIdentifier,
++ signature BIT STRING ({ x509_note_signature })
++ }
++
++TBSCertificate ::= SEQUENCE {
++ version [ 0 ] Version DEFAULT,
++ serialNumber CertificateSerialNumber,
++ signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
++ issuer Name ({ x509_note_issuer }),
++ validity Validity,
++ subject Name ({ x509_note_subject }),
++ subjectPublicKeyInfo SubjectPublicKeyInfo,
++ issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
++ subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
++ extensions [ 3 ] Extensions OPTIONAL
++ }
++
++Version ::= INTEGER
++CertificateSerialNumber ::= INTEGER
++
++AlgorithmIdentifier ::= SEQUENCE {
++ algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
++ parameters ANY OPTIONAL
++}
++
++Name ::= SEQUENCE OF RelativeDistinguishedName
++
++RelativeDistinguishedName ::= SET OF AttributeValueAssertion
++
++AttributeValueAssertion ::= SEQUENCE {
++ attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
++ attributeValue ANY ({ x509_extract_name_segment })
++ }
++
++Validity ::= SEQUENCE {
++ notBefore Time ({ x509_note_not_before }),
++ notAfter Time ({ x509_note_not_after })
++ }
++
++Time ::= CHOICE {
++ utcTime UTCTime,
++ generalTime GeneralizedTime
++ }
++
++SubjectPublicKeyInfo ::= SEQUENCE {
++ algorithm AlgorithmIdentifier,
++ subjectPublicKey BIT STRING ({ x509_extract_key_data })
++ }
++
++UniqueIdentifier ::= BIT STRING
++
++Extensions ::= SEQUENCE OF Extension
++
++Extension ::= SEQUENCE {
++ extnid OBJECT IDENTIFIER ({ x509_note_OID }),
++ critical BOOLEAN DEFAULT,
++ extnValue OCTET STRING ({ x509_process_extension })
++ }
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+new file mode 100644
+index 0000000..8fcac94
+--- /dev/null
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -0,0 +1,497 @@
++/* X.509 certificate parser
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "X.509: "fmt
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/oid_registry.h>
++#include "public_key.h"
++#include "x509_parser.h"
++#include "x509-asn1.h"
++#include "x509_rsakey-asn1.h"
++
++struct x509_parse_context {
++ struct x509_certificate *cert; /* Certificate being constructed */
++ unsigned long data; /* Start of data */
++ const void *cert_start; /* Start of cert content */
++ const void *key; /* Key data */
++ size_t key_size; /* Size of key data */
++ enum OID last_oid; /* Last OID encountered */
++ enum OID algo_oid; /* Algorithm OID */
++ unsigned char nr_mpi; /* Number of MPIs stored */
++ u8 o_size; /* Size of organizationName (O) */
++ u8 cn_size; /* Size of commonName (CN) */
++ u8 email_size; /* Size of emailAddress */
++ u16 o_offset; /* Offset of organizationName (O) */
++ u16 cn_offset; /* Offset of commonName (CN) */
++ u16 email_offset; /* Offset of emailAddress */
++};
++
++/*
++ * Free an X.509 certificate
++ */
++void x509_free_certificate(struct x509_certificate *cert)
++{
++ if (cert) {
++ public_key_destroy(cert->pub);
++ kfree(cert->issuer);
++ kfree(cert->subject);
++ kfree(cert->fingerprint);
++ kfree(cert->authority);
++ kfree(cert);
++ }
++}
++
++/*
++ * Parse an X.509 certificate
++ */
++struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
++{
++ struct x509_certificate *cert;
++ struct x509_parse_context *ctx;
++ long ret;
++
++ ret = -ENOMEM;
++ cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
++ if (!cert)
++ goto error_no_cert;
++ cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
++ if (!cert->pub)
++ goto error_no_ctx;
++ ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
++ if (!ctx)
++ goto error_no_ctx;
++
++ ctx->cert = cert;
++ ctx->data = (unsigned long)data;
++
++ /* Attempt to decode the certificate */
++ ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
++ if (ret < 0)
++ goto error_decode;
++
++ /* Decode the public key */
++ ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx,
++ ctx->key, ctx->key_size);
++ if (ret < 0)
++ goto error_decode;
++
++ kfree(ctx);
++ return cert;
++
++error_decode:
++ kfree(ctx);
++error_no_ctx:
++ x509_free_certificate(cert);
++error_no_cert:
++ return ERR_PTR(ret);
++}
++
++/*
++ * Note an OID when we find one for later processing when we know how
++ * to interpret it.
++ */
++int x509_note_OID(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++
++ ctx->last_oid = look_up_OID(value, vlen);
++ if (ctx->last_oid == OID__NR) {
++ char buffer[50];
++ sprint_oid(value, vlen, buffer, sizeof(buffer));
++ pr_debug("Unknown OID: [%zu] %s\n",
++ (unsigned long)value - ctx->data, buffer);
++ }
++ return 0;
++}
++
++/*
++ * Save the position of the TBS data so that we can check the signature over it
++ * later.
++ */
++int x509_note_tbs_certificate(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++
++ pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
++ hdrlen, tag, (unsigned long)value - ctx->data, vlen);
++
++ ctx->cert->tbs = value - hdrlen;
++ ctx->cert->tbs_size = vlen + hdrlen;
++ return 0;
++}
++
++/*
++ * Record the public key algorithm
++ */
++int x509_note_pkey_algo(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++
++ pr_debug("PubKey Algo: %u\n", ctx->last_oid);
++
++ switch (ctx->last_oid) {
++ case OID_md2WithRSAEncryption:
++ case OID_md3WithRSAEncryption:
++ default:
++ return -ENOPKG; /* Unsupported combination */
++
++ case OID_md4WithRSAEncryption:
++ ctx->cert->sig_hash_algo = PKEY_HASH_MD5;
++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ break;
++
++ case OID_sha1WithRSAEncryption:
++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA1;
++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ break;
++
++ case OID_sha256WithRSAEncryption:
++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA256;
++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ break;
++
++ case OID_sha384WithRSAEncryption:
++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA384;
++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ break;
++
++ case OID_sha512WithRSAEncryption:
++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA512;
++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ break;
++
++ case OID_sha224WithRSAEncryption:
++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA224;
++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ break;
++ }
++
++ ctx->algo_oid = ctx->last_oid;
++ return 0;
++}
++
++/*
++ * Note the whereabouts and type of the signature.
++ */
++int x509_note_signature(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++
++ pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
++
++ if (ctx->last_oid != ctx->algo_oid) {
++ pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
++ ctx->algo_oid, ctx->last_oid);
++ return -EINVAL;
++ }
++
++ ctx->cert->sig = value;
++ ctx->cert->sig_size = vlen;
++ return 0;
++}
++
++/*
++ * Note some of the name segments from which we'll fabricate a name.
++ */
++int x509_extract_name_segment(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++
++ switch (ctx->last_oid) {
++ case OID_commonName:
++ ctx->cn_size = vlen;
++ ctx->cn_offset = (unsigned long)value - ctx->data;
++ break;
++ case OID_organizationName:
++ ctx->o_size = vlen;
++ ctx->o_offset = (unsigned long)value - ctx->data;
++ break;
++ case OID_email_address:
++ ctx->email_size = vlen;
++ ctx->email_offset = (unsigned long)value - ctx->data;
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++/*
++ * Fabricate and save the issuer and subject names
++ */
++static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
++ unsigned char tag,
++ char **_name, size_t vlen)
++{
++ const void *name, *data = (const void *)ctx->data;
++ size_t namesize;
++ char *buffer;
++
++ if (*_name)
++ return -EINVAL;
++
++ /* Empty name string if no material */
++ if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
++ buffer = kmalloc(1, GFP_KERNEL);
++ if (!buffer)
++ return -ENOMEM;
++ buffer[0] = 0;
++ goto done;
++ }
++
++ if (ctx->cn_size && ctx->o_size) {
++ /* Consider combining O and CN, but use only the CN if it is
++ * prefixed by the O, or a significant portion thereof.
++ */
++ namesize = ctx->cn_size;
++ name = data + ctx->cn_offset;
++ if (ctx->cn_size >= ctx->o_size &&
++ memcmp(data + ctx->cn_offset, data + ctx->o_offset,
++ ctx->o_size) == 0)
++ goto single_component;
++ if (ctx->cn_size >= 7 &&
++ ctx->o_size >= 7 &&
++ memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
++ goto single_component;
++
++ buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
++ GFP_KERNEL);
++ if (!buffer)
++ return -ENOMEM;
++
++ memcpy(buffer,
++ data + ctx->o_offset, ctx->o_size);
++ buffer[ctx->o_size + 0] = ':';
++ buffer[ctx->o_size + 1] = ' ';
++ memcpy(buffer + ctx->o_size + 2,
++ data + ctx->cn_offset, ctx->cn_size);
++ buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
++ goto done;
++
++ } else if (ctx->cn_size) {
++ namesize = ctx->cn_size;
++ name = data + ctx->cn_offset;
++ } else if (ctx->o_size) {
++ namesize = ctx->o_size;
++ name = data + ctx->o_offset;
++ } else {
++ namesize = ctx->email_size;
++ name = data + ctx->email_offset;
++ }
++
++single_component:
++ buffer = kmalloc(namesize + 1, GFP_KERNEL);
++ if (!buffer)
++ return -ENOMEM;
++ memcpy(buffer, name, namesize);
++ buffer[namesize] = 0;
++
++done:
++ *_name = buffer;
++ ctx->cn_size = 0;
++ ctx->o_size = 0;
++ ctx->email_size = 0;
++ return 0;
++}
++
++int x509_note_issuer(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
++}
++
++int x509_note_subject(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
++}
++
++/*
++ * Extract the data for the public key algorithm
++ */
++int x509_extract_key_data(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++
++ if (ctx->last_oid != OID_rsaEncryption)
++ return -ENOPKG;
++
++ /* There seems to be an extraneous 0 byte on the front of the data */
++ ctx->cert->pkey_algo = PKEY_ALGO_RSA;
++ ctx->key = value + 1;
++ ctx->key_size = vlen - 1;
++ return 0;
++}
++
++/*
++ * Extract a RSA public key value
++ */
++int rsa_extract_mpi(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ MPI mpi;
++
++ if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) {
++ pr_err("Too many public key MPIs in certificate\n");
++ return -EBADMSG;
++ }
++
++ mpi = mpi_read_raw_data(value, vlen);
++ if (!mpi)
++ return -ENOMEM;
++
++ ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi;
++ return 0;
++}
++
++/*
++ * Process certificate extensions that are used to qualify the certificate.
++ */
++int x509_process_extension(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ const unsigned char *v = value;
++ char *f;
++ int i;
++
++ pr_debug("Extension: %u\n", ctx->last_oid);
++
++ if (ctx->last_oid == OID_subjectKeyIdentifier) {
++ /* Get hold of the key fingerprint */
++ if (vlen < 3)
++ return -EBADMSG;
++ if (v[0] != ASN1_OTS || v[1] != vlen - 2)
++ return -EBADMSG;
++ v += 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;
++ return 0;
++ }
++
++ if (ctx->last_oid == OID_authorityKeyIdentifier) {
++ /* Get hold of the CA key fingerprint */
++ if (vlen < 5)
++ return -EBADMSG;
++ if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)) ||
++ v[1] != vlen - 2 ||
++ v[2] != (ASN1_CONT << 6) ||
++ v[3] != vlen - 4)
++ return -EBADMSG;
++ v += 4;
++ vlen -= 4;
++
++ 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("authority %s\n", f);
++ ctx->cert->authority = f;
++ return 0;
++ }
++
++ return 0;
++}
++
++/*
++ * Record a certificate time.
++ */
++static int x509_note_time(time_t *_time, size_t hdrlen,
++ unsigned char tag,
++ const unsigned char *value, size_t vlen)
++{
++ unsigned YY, MM, DD, hh, mm, ss;
++ const unsigned char *p = value;
++
++#define dec2bin(X) ((X) - '0')
++#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
++
++ if (tag == ASN1_UNITIM) {
++ /* UTCTime: YYMMDDHHMMSSZ */
++ if (vlen != 13)
++ goto unsupported_time;
++ YY = DD2bin(p);
++ if (YY > 50)
++ YY += 1900;
++ else
++ YY += 2000;
++ } else if (tag == ASN1_GENTIM) {
++ /* GenTime: YYYYMMDDHHMMSSZ */
++ if (vlen != 15)
++ goto unsupported_time;
++ YY = DD2bin(p) * 100 + DD2bin(p);
++ } else {
++ goto unsupported_time;
++ }
++
++ MM = DD2bin(p);
++ DD = DD2bin(p);
++ hh = DD2bin(p);
++ mm = DD2bin(p);
++ ss = DD2bin(p);
++
++ if (*p != 'Z')
++ goto unsupported_time;
++
++ *_time = mktime(YY, MM, DD, hh, mm, ss);
++ return 0;
++
++unsupported_time:
++ pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n",
++ tag, (int)vlen, (int)vlen, value);
++ return -EBADMSG;
++}
++
++int x509_note_not_before(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
++}
++
++int x509_note_not_after(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
++}
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+new file mode 100644
+index 0000000..635053f
+--- /dev/null
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -0,0 +1,36 @@
++/* X.509 certificate parser internal definitions
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <crypto/public_key.h>
++
++struct x509_certificate {
++ struct x509_certificate *next;
++ struct public_key *pub; /* Public key details */
++ char *issuer; /* Name of certificate issuer */
++ char *subject; /* Name of certificate subject */
++ char *fingerprint; /* Key fingerprint as hex */
++ char *authority; /* Authority key fingerprint as hex */
++ time_t valid_from;
++ time_t valid_to;
++ enum pkey_algo pkey_algo : 8; /* Public key algorithm */
++ enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
++ enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
++ const void *tbs; /* Signed data */
++ size_t tbs_size; /* Size of signed data */
++ const void *sig; /* Signature data */
++ size_t sig_size; /* Size of sigature */
++};
++
++/*
++ * x509_cert_parser.c
++ */
++extern void x509_free_certificate(struct x509_certificate *cert);
++extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+new file mode 100644
+index 0000000..716917c
+--- /dev/null
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -0,0 +1,207 @@
++/* Instantiate a public key crypto key from an X.509 Certificate
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "X.509: "fmt
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/mpi.h>
++#include <linux/asn1_decoder.h>
++#include <keys/asymmetric-subtype.h>
++#include <keys/asymmetric-parser.h>
++#include <crypto/hash.h>
++#include "asymmetric_keys.h"
++#include "public_key.h"
++#include "x509_parser.h"
++
++static const
++struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = {
++ [PKEY_ALGO_DSA] = NULL,
++#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
++ defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
++ [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
++#endif
++};
++
++/*
++ * Check the signature on a certificate using the provided public key
++ */
++static int x509_check_signature(const struct public_key *pub,
++ const struct x509_certificate *cert)
++{
++ struct public_key_signature *sig;
++ struct crypto_shash *tfm;
++ struct shash_desc *desc;
++ size_t digest_size, desc_size;
++ int ret;
++
++ pr_devel("==>%s()\n", __func__);
++
++ /* Allocate the hashing algorithm we're going to need and find out how
++ * big the hash operational data will be.
++ */
++ tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0);
++ if (IS_ERR(tfm))
++ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
++
++ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
++ digest_size = crypto_shash_digestsize(tfm);
++
++ /* We allocate the hash operational data storage on the end of our
++ * context data.
++ */
++ ret = -ENOMEM;
++ sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
++ if (!sig)
++ goto error_no_sig;
++
++ sig->pkey_hash_algo = cert->sig_hash_algo;
++ sig->digest = (u8 *)sig + sizeof(*sig) + desc_size;
++ sig->digest_size = digest_size;
++
++ desc = (void *)sig + sizeof(*sig);
++ desc->tfm = tfm;
++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++
++ ret = crypto_shash_init(desc);
++ if (ret < 0)
++ goto error;
++
++ ret = -ENOMEM;
++ sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
++ if (!sig->rsa.s)
++ goto error;
++
++ ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
++ if (ret < 0)
++ goto error_mpi;
++
++ ret = pub->algo->verify_signature(pub, sig);
++
++ pr_debug("Cert Verification: %d\n", ret);
++
++error_mpi:
++ mpi_free(sig->rsa.s);
++error:
++ kfree(sig);
++error_no_sig:
++ crypto_free_shash(tfm);
++
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ 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)
++{
++ struct x509_certificate *cert;
++ time_t now;
++ size_t srlen, sulen;
++ char *desc = NULL;
++ int ret;
++
++ cert = x509_cert_parse(prep->data, prep->datalen);
++ if (IS_ERR(cert))
++ return PTR_ERR(cert);
++
++ pr_devel("Cert Issuer: %s\n", cert->issuer);
++ pr_devel("Cert Subject: %s\n", cert->subject);
++ pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
++ pr_devel("Cert Valid: %lu - %lu\n", cert->valid_from, cert->valid_to);
++ pr_devel("Cert Signature: %s + %s\n",
++ pkey_algo[cert->sig_pkey_algo],
++ pkey_hash_algo[cert->sig_hash_algo]);
++
++ if (!cert->fingerprint || !cert->authority) {
++ pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
++ cert->subject);
++ ret = -EKEYREJECTED;
++ goto error_free_cert;
++ }
++
++ now = CURRENT_TIME.tv_sec;
++ if (now < cert->valid_from) {
++ pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
++ ret = -EKEYREJECTED;
++ goto error_free_cert;
++ }
++ if (now >= cert->valid_to) {
++ pr_warn("Cert %s has expired\n", cert->fingerprint);
++ ret = -EKEYEXPIRED;
++ goto error_free_cert;
++ }
++
++ cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
++ cert->pub->id_type = PKEY_ID_X509;
++
++ /* Check the signature on the key */
++ if (strcmp(cert->fingerprint, cert->authority) == 0) {
++ ret = x509_check_signature(cert->pub, cert);
++ if (ret < 0)
++ goto error_free_cert;
++ }
++
++ /* Propose a description */
++ sulen = strlen(cert->subject);
++ srlen = strlen(cert->fingerprint);
++ ret = -ENOMEM;
++ desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
++ if (!desc)
++ 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;
++
++ /* We're pinning the module by being linked against it */
++ __module_get(public_key_subtype.owner);
++ prep->type_data[0] = &public_key_subtype;
++ prep->type_data[1] = cert->fingerprint;
++ prep->payload = cert->pub;
++ prep->description = desc;
++ prep->quotalen = 100;
++
++ /* We've finished with the certificate */
++ cert->pub = NULL;
++ cert->fingerprint = NULL;
++ desc = NULL;
++ ret = 0;
++
++error_free_cert:
++ x509_free_certificate(cert);
++ return ret;
++}
++
++static struct asymmetric_key_parser x509_key_parser = {
++ .owner = THIS_MODULE,
++ .name = "x509",
++ .parse = x509_key_preparse,
++};
++
++/*
++ * Module stuff
++ */
++static int __init x509_key_init(void)
++{
++ return register_asymmetric_key_parser(&x509_key_parser);
++}
++
++static void __exit x509_key_exit(void)
++{
++ unregister_asymmetric_key_parser(&x509_key_parser);
++}
++
++module_init(x509_key_init);
++module_exit(x509_key_exit);
+diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1
+new file mode 100644
+index 0000000..4ec7cc6
+--- /dev/null
++++ b/crypto/asymmetric_keys/x509_rsakey.asn1
+@@ -0,0 +1,4 @@
++RSAPublicKey ::= SEQUENCE {
++ modulus INTEGER ({ rsa_extract_mpi }), -- n
++ publicExponent INTEGER ({ rsa_extract_mpi }) -- e
++ }
+--
+1.7.12.1
+
+
+From a4c3000ab42b11536ffc8eb9c1d03a746b424bda Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:09:50 +0100
+Subject: [PATCH 18/37] MODSIGN: Add FIPS policy
+
+If we're in FIPS mode, we should panic if we fail to verify the signature on a
+module or we're asked to load an unsigned module in signature enforcing mode.
+Possibly FIPS mode should automatically enable enforcing mode.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ kernel/module.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/kernel/module.c b/kernel/module.c
+index 7efb415..3e8b1a7 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -58,6 +58,7 @@
+ #include <linux/jump_label.h>
+ #include <linux/pfn.h>
+ #include <linux/bsearch.h>
++#include <linux/fips.h>
+ #include "module-internal.h"
+
+ #define CREATE_TRACE_POINTS
+@@ -2467,6 +2468,9 @@ static int module_sig_check(struct load_info *info,
+ }
+
+ /* Not having a signature is only an error if we're strict. */
++ if (err < 0 && fips_enabled)
++ panic("Module verification failed with error %d in FIPS mode\n",
++ err);
+ if (err == -ENOKEY && !sig_enforce)
+ err = 0;
+
+--
+1.7.12.1
+
+
+From 86342ab6db2c5b10b08bd9d1064b1779070c2a82 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:09:50 +0100
+Subject: [PATCH 19/37] MODSIGN: Provide gitignore and make clean rules for
+ extra files
+
+Provide gitignore and make clean rules for extra files to hide and clean up the
+extra files produced by module signing stuff once it is added. Also add a
+clean up rule for the module content extractor program used to extract the data
+to be signed.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ .gitignore | 14 ++++++++++++++
+ Makefile | 1 +
+ 2 files changed, 15 insertions(+)
+
+diff --git a/.gitignore b/.gitignore
+index 57af07c..0f2f40f 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -14,6 +14,10 @@
+ *.o.*
+ *.a
+ *.s
++*.ko.unsigned
++*.ko.stripped
++*.ko.stripped.dig
++*.ko.stripped.sig
+ *.ko
+ *.so
+ *.so.dbg
+@@ -84,3 +88,13 @@ GTAGS
+ *.orig
+ *~
+ \#*#
++
++#
++# Leavings from module signing
++#
++extra_certificates
++signing_key.priv
++signing_key.x509
++signing_key.x509.keyid
++signing_key.x509.signer
++x509.genkey
+diff --git a/Makefile b/Makefile
+index 6cdadf4..b4f9eb5 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1239,6 +1239,7 @@ clean: $(clean-dirs)
+ $(call cmd,rmfiles)
+ @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
++ -o -name '*.ko.*' \
+ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
+ -o -name '*.symtypes' -o -name 'modules.order' \
+ -o -name modules.builtin -o -name '.tmp_*.o.*' \
+--
+1.7.12.1
+
+
+From c631aa86c295b87aa09188d9313cccf41e5db23f Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:09:50 +0100
+Subject: [PATCH 20/37] MODSIGN: Provide Kconfig options
+
+Provide kernel configuration options for module signing.
+
+The following configuration options are added:
+
+ CONFIG_MODULE_SIG_SHA1
+ CONFIG_MODULE_SIG_SHA224
+ CONFIG_MODULE_SIG_SHA256
+ CONFIG_MODULE_SIG_SHA384
+ CONFIG_MODULE_SIG_SHA512
+
+These select the cryptographic hash used to digest the data prior to signing.
+Additionally, the crypto module selected will be built into the kernel as it
+won't be possible to load it as a module without incurring a circular
+dependency when the kernel tries to check its signature.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ init/Kconfig | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index fa8ccad..00d4579 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1593,12 +1593,50 @@ config MODULE_SIG
+ is simply appended to the module. For more information see
+ Documentation/module-signing.txt.
+
++ !!!WARNING!!! If you enable this option, you MUST make sure that the
++ module DOES NOT get stripped after being signed. This includes the
++ debuginfo strip done by some packagers (such as rpmbuild) and
++ inclusion into an initramfs that wants the module size reduced.
++
+ config MODULE_SIG_FORCE
+ bool "Require modules to be validly signed"
+ depends on MODULE_SIG
+ help
+ Reject unsigned modules or signed modules for which we don't have a
+ key. Without this, such modules will simply taint the kernel.
++
++choice
++ prompt "Which hash algorithm should modules be signed with?"
++ depends on MODULE_SIG
++ help
++ This determines which sort of hashing algorithm will be used during
++ signature generation. This algorithm _must_ be built into the kernel
++ directly so that signature verification can take place. It is not
++ possible to load a signed module containing the algorithm to check
++ the signature on that module.
++
++config MODULE_SIG_SHA1
++ bool "Sign modules with SHA-1"
++ select CRYPTO_SHA1
++
++config MODULE_SIG_SHA224
++ bool "Sign modules with SHA-224"
++ select CRYPTO_SHA256
++
++config MODULE_SIG_SHA256
++ bool "Sign modules with SHA-256"
++ select CRYPTO_SHA256
++
++config MODULE_SIG_SHA384
++ bool "Sign modules with SHA-384"
++ select CRYPTO_SHA512
++
++config MODULE_SIG_SHA512
++ bool "Sign modules with SHA-512"
++ select CRYPTO_SHA512
++
++endchoice
++
+ endif # MODULES
+
+ config INIT_ALL_POSSIBLE
+--
+1.7.12.1
+
+
+From 84d1788d1ea47ecfe2d30d0c2081055d7e89441d Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:09:51 +0100
+Subject: [PATCH 21/37] MODSIGN: Automatically generate module signing keys if
+ missing
+
+Automatically generate keys for module signing if they're absent so that
+allyesconfig doesn't break. The builder should consider generating their own
+key and certificate, however, so that the keys are appropriately named.
+
+The private key for the module signer should be placed in signing_key.priv
+(unencrypted!) and the public key in an X.509 certificate as signing_key.x509.
+
+If a transient key is desired for signing the modules, a config file for
+'openssl req' can be placed in x509.genkey, looking something like the
+following:
+
+ [ req ]
+ default_bits = 4096
+ distinguished_name = req_distinguished_name
+ prompt = no
+ x509_extensions = myexts
+
+ [ req_distinguished_name ]
+ O = Magarathea
+ CN = Glacier signing key
+ emailAddress = slartibartfast@magrathea.h2g2
+
+ [ myexts ]
+ basicConstraints=critical,CA:FALSE
+ keyUsage=digitalSignature
+ subjectKeyIdentifier=hash
+ authorityKeyIdentifier=hash
+
+The build process will use this to configure:
+
+ openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \
+ -x509 -config x509.genkey \
+ -outform DER -out signing_key.x509 \
+ -keyout signing_key.priv
+
+to generate the key.
+
+Note that it is required that the X.509 certificate have a subjectKeyIdentifier
+and an authorityKeyIdentifier. Without those, the certificate will be
+rejected. These can be used to check the validity of a certificate.
+
+Note that 'make distclean' will remove signing_key.{priv,x509} and x509.genkey,
+whether or not they were generated automatically.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ kernel/Makefile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 08ba8a6..58c6f11 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -132,3 +132,52 @@ quiet_cmd_timeconst = TIMEC $@
+ targets += timeconst.h
+ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
+ $(call if_changed,timeconst)
++
++ifeq ($(CONFIG_MODULE_SIG),y)
++
++###############################################################################
++#
++# If module signing is requested, say by allyesconfig, but a key has not been
++# supplied, then one will need to be generated to make sure the build does not
++# fail and that the kernel may be used afterwards.
++#
++###############################################################################
++signing_key.priv signing_key.x509: x509.genkey
++ @echo "###"
++ @echo "### Now generating an X.509 key pair to be used for signing modules."
++ @echo "###"
++ @echo "### If this takes a long time, you might wish to run rngd in the"
++ @echo "### background to keep the supply of entropy topped up. It"
++ @echo "### needs to be run as root, and should use a hardware random"
++ @echo "### number generator if one is available, eg:"
++ @echo "###"
++ @echo "### rngd -r /dev/hwrandom"
++ @echo "###"
++ openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \
++ -x509 -config x509.genkey \
++ -outform DER -out signing_key.x509 \
++ -keyout signing_key.priv
++ @echo "###"
++ @echo "### Key pair generated."
++ @echo "###"
++
++x509.genkey:
++ @echo Generating X.509 key generation config
++ @echo >x509.genkey "[ req ]"
++ @echo >>x509.genkey "default_bits = 4096"
++ @echo >>x509.genkey "distinguished_name = req_distinguished_name"
++ @echo >>x509.genkey "prompt = no"
++ @echo >>x509.genkey "x509_extensions = myexts"
++ @echo >>x509.genkey
++ @echo >>x509.genkey "[ req_distinguished_name ]"
++ @echo >>x509.genkey "O = Magrathea"
++ @echo >>x509.genkey "CN = Glacier signing key"
++ @echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2"
++ @echo >>x509.genkey
++ @echo >>x509.genkey "[ myexts ]"
++ @echo >>x509.genkey "basicConstraints=critical,CA:FALSE"
++ @echo >>x509.genkey "keyUsage=digitalSignature"
++ @echo >>x509.genkey "subjectKeyIdentifier=hash"
++ @echo >>x509.genkey "authorityKeyIdentifier=keyid"
++endif
++CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey
+--
+1.7.12.1
+
+
+From 51da59e56f0666efe97c376830dffefdfcecd21f Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:09:51 +0100
+Subject: [PATCH 22/37] MODSIGN: Provide module signing public keys to the
+ kernel
+
+Include a PGP keyring containing the public keys required to perform module
+verification in the kernel image during build and create a special keyring
+during boot which is then populated with keys of crypto type holding the public
+keys found in the PGP keyring.
+
+These can be seen by root:
+
+[root@andromeda ~]# cat /proc/keys
+07ad4ee0 I----- 1 perm 3f010000 0 0 crypto modsign.0: RSA 87b9b3bd []
+15c7f8c3 I----- 1 perm 1f030000 0 0 keyring .module_sign: 1/4
+...
+
+It is probably worth permitting root to invalidate these keys, resulting in
+their removal and preventing further modules from being loaded with that key.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ kernel/Makefile | 11 ++++-
+ kernel/modsign_pubkey.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/module-internal.h | 2 +
+ 3 files changed, 124 insertions(+), 2 deletions(-)
+ create mode 100644 kernel/modsign_pubkey.c
+
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 58c6f11..111a845 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -55,7 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
+ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += module.o
+-obj-$(CONFIG_MODULE_SIG) += module_signing.o
++obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+@@ -134,6 +134,13 @@ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
+ $(call if_changed,timeconst)
+
+ ifeq ($(CONFIG_MODULE_SIG),y)
++#
++# Pull the signing certificate and any extra certificates into the kernel
++#
++extra_certificates:
++ touch $@
++
++kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
+
+ ###############################################################################
+ #
+@@ -180,4 +187,4 @@ x509.genkey:
+ @echo >>x509.genkey "subjectKeyIdentifier=hash"
+ @echo >>x509.genkey "authorityKeyIdentifier=keyid"
+ endif
+-CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey
++CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates
+diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
+new file mode 100644
+index 0000000..4646eb2
+--- /dev/null
++++ b/kernel/modsign_pubkey.c
+@@ -0,0 +1,113 @@
++/* Public keys for module signature verification
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/cred.h>
++#include <linux/err.h>
++#include <keys/asymmetric-type.h>
++#include "module-internal.h"
++
++struct key *modsign_keyring;
++
++extern __initdata const u8 modsign_certificate_list[];
++extern __initdata const u8 modsign_certificate_list_end[];
++asm(".section .init.data,\"aw\"\n"
++ "modsign_certificate_list:\n"
++ ".incbin \"signing_key.x509\"\n"
++ ".incbin \"extra_certificates\"\n"
++ "modsign_certificate_list_end:"
++ );
++
++/*
++ * We need to make sure ccache doesn't cache the .o file as it doesn't notice
++ * if modsign.pub changes.
++ */
++static __initdata const char annoy_ccache[] = __TIME__ "foo";
++
++/*
++ * Load the compiled-in keys
++ */
++static __init int module_verify_init(void)
++{
++ pr_notice("Initialise module verification\n");
++
++ modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
++ KUIDT_INIT(0), KGIDT_INIT(0),
++ current_cred(),
++ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW | KEY_USR_READ,
++ KEY_ALLOC_NOT_IN_QUOTA);
++ if (IS_ERR(modsign_keyring))
++ panic("Can't allocate module signing keyring\n");
++
++ if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
++ panic("Can't instantiate module signing keyring\n");
++
++ return 0;
++}
++
++/*
++ * Must be initialised before we try and load the keys into the keyring.
++ */
++device_initcall(module_verify_init);
++
++/*
++ * Load the compiled-in keys
++ */
++static __init int load_module_signing_keys(void)
++{
++ key_ref_t key;
++ const u8 *p, *end;
++ size_t plen;
++
++ pr_notice("Loading module verification certificates\n");
++
++ end = modsign_certificate_list_end;
++ p = modsign_certificate_list;
++ while (p < end) {
++ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
++ * than 256 bytes in size.
++ */
++ if (end - p < 4)
++ goto dodgy_cert;
++ if (p[0] != 0x30 &&
++ p[1] != 0x82)
++ goto dodgy_cert;
++ plen = (p[2] << 8) | p[3];
++ plen += 4;
++ if (plen > end - p)
++ goto dodgy_cert;
++
++ key = key_create_or_update(make_key_ref(modsign_keyring, 1),
++ "asymmetric",
++ NULL,
++ p,
++ plen,
++ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW,
++ KEY_ALLOC_NOT_IN_QUOTA);
++ if (IS_ERR(key))
++ pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
++ PTR_ERR(key));
++ else
++ pr_notice("MODSIGN: Loaded cert '%s'\n",
++ key_ref_to_ptr(key)->description);
++ p += plen;
++ }
++
++ return 0;
++
++dodgy_cert:
++ pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
++ return 0;
++}
++late_initcall(load_module_signing_keys);
+diff --git a/kernel/module-internal.h b/kernel/module-internal.h
+index 033c17f..6114a13 100644
+--- a/kernel/module-internal.h
++++ b/kernel/module-internal.h
+@@ -9,5 +9,7 @@
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
++extern struct key *modsign_keyring;
++
+ extern int mod_verify_sig(const void *mod, unsigned long modlen,
+ const void *sig, unsigned long siglen);
+--
+1.7.12.1
+
+
+From 81a8def438b252dac4aa9c7eda39ad517bfe51ac Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:11:03 +0100
+Subject: [PATCH 23/37] MODSIGN: Implement module signature checking
+
+Check the signature on the module against the keys compiled into the kernel or
+available in a hardware key store.
+
+Currently, only RSA keys are supported - though that's easy enough to change,
+and the signature is expected to contain raw components (so not a PGP or
+PKCS#7 formatted blob).
+
+The signature blob is expected to consist of the following pieces in order:
+
+ (1) The binary identifier for the key. This is expected to match the
+ SubjectKeyIdentifier from an X.509 certificate. Only X.509 type
+ identifiers are currently supported.
+
+ (2) The signature data, consisting of a series of MPIs in which each is in
+ the format of a 2-byte BE word sizes followed by the content data.
+
+ (3) A 12 byte information block of the form:
+
+ struct module_signature {
+ enum pkey_algo algo : 8;
+ enum pkey_hash_algo hash : 8;
+ enum pkey_id_type id_type : 8;
+ u8 __pad;
+ __be32 id_length;
+ __be32 sig_length;
+ };
+
+ The three enums are defined in crypto/public_key.h.
+
+ 'algo' contains the public-key algorithm identifier (0->DSA, 1->RSA).
+
+ 'hash' contains the digest algorithm identifier (0->MD4, 1->MD5, 2->SHA1,
+ etc.).
+
+ 'id_type' contains the public-key identifier type (0->PGP, 1->X.509).
+
+ '__pad' should be 0.
+
+ 'id_length' should contain in the binary identifier length in BE form.
+
+ 'sig_length' should contain in the signature data length in BE form.
+
+ The lengths are in BE order rather than CPU order to make dealing with
+ cross-compilation easier.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (minor Kconfig fix)
+---
+ init/Kconfig | 8 ++
+ kernel/module_signing.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 229 insertions(+), 1 deletion(-)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index 00d4579..abc6e63 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1588,6 +1588,14 @@ config MODULE_SRCVERSION_ALL
+ config MODULE_SIG
+ bool "Module signature verification"
+ depends on MODULES
++ select KEYS
++ select CRYPTO
++ select ASYMMETRIC_KEY_TYPE
++ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
++ select PUBLIC_KEY_ALGO_RSA
++ select ASN1
++ select OID_REGISTRY
++ select X509_CERTIFICATE_PARSER
+ help
+ Check modules for valid signatures upon load: the signature
+ is simply appended to the module. For more information see
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index 499728a..6b09f69 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -11,13 +11,233 @@
+
+ #include <linux/kernel.h>
+ #include <linux/err.h>
++#include <crypto/public_key.h>
++#include <crypto/hash.h>
++#include <keys/asymmetric-type.h>
+ #include "module-internal.h"
+
+ /*
++ * Module signature information block.
++ *
++ * The constituents of the signature section are, in order:
++ *
++ * - Signer's name
++ * - Key identifier
++ * - Signature data
++ * - Information block
++ */
++struct module_signature {
++ enum pkey_algo algo : 8; /* Public-key crypto algorithm */
++ enum pkey_hash_algo hash : 8; /* Digest algorithm */
++ enum pkey_id_type id_type : 8; /* Key identifier type */
++ u8 signer_len; /* Length of signer's name */
++ u8 key_id_len; /* Length of key identifier */
++ u8 __pad[3];
++ __be32 sig_len; /* Length of signature data */
++};
++
++/*
++ * Digest the module contents.
++ */
++static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
++ const void *mod,
++ unsigned long modlen)
++{
++ struct public_key_signature *pks;
++ struct crypto_shash *tfm;
++ struct shash_desc *desc;
++ size_t digest_size, desc_size;
++ int ret;
++
++ pr_devel("==>%s()\n", __func__);
++
++ /* Allocate the hashing algorithm we're going to need and find out how
++ * big the hash operational data will be.
++ */
++ tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0);
++ if (IS_ERR(tfm))
++ return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
++
++ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
++ digest_size = crypto_shash_digestsize(tfm);
++
++ /* We allocate the hash operational data storage on the end of our
++ * context data and the digest output buffer on the end of that.
++ */
++ ret = -ENOMEM;
++ pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
++ if (!pks)
++ goto error_no_pks;
++
++ pks->pkey_hash_algo = hash;
++ pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
++ pks->digest_size = digest_size;
++
++ desc = (void *)pks + sizeof(*pks);
++ desc->tfm = tfm;
++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++
++ ret = crypto_shash_init(desc);
++ if (ret < 0)
++ goto error;
++
++ ret = crypto_shash_finup(desc, mod, modlen, pks->digest);
++ if (ret < 0)
++ goto error;
++
++ crypto_free_shash(tfm);
++ pr_devel("<==%s() = ok\n", __func__);
++ return pks;
++
++error:
++ kfree(pks);
++error_no_pks:
++ crypto_free_shash(tfm);
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ return ERR_PTR(ret);
++}
++
++/*
++ * Extract an MPI array from the signature data. This represents the actual
++ * signature. Each raw MPI is prefaced by a BE 2-byte value indicating the
++ * size of the MPI in bytes.
++ *
++ * RSA signatures only have one MPI, so currently we only read one.
++ */
++static int mod_extract_mpi_array(struct public_key_signature *pks,
++ const void *data, size_t len)
++{
++ size_t nbytes;
++ MPI mpi;
++
++ if (len < 3)
++ return -EBADMSG;
++ nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1];
++ data += 2;
++ len -= 2;
++ if (len != nbytes)
++ return -EBADMSG;
++
++ mpi = mpi_read_raw_data(data, nbytes);
++ if (!mpi)
++ return -ENOMEM;
++ pks->mpi[0] = mpi;
++ pks->nr_mpi = 1;
++ return 0;
++}
++
++/*
++ * Request an asymmetric key.
++ */
++static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
++ const u8 *key_id, size_t key_id_len)
++{
++ key_ref_t key;
++ size_t i;
++ char *id, *q;
++
++ pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len);
++
++ /* Construct an identifier. */
++ id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL);
++ if (!id)
++ return ERR_PTR(-ENOKEY);
++
++ memcpy(id, signer, signer_len);
++
++ q = id + signer_len;
++ *q++ = ':';
++ *q++ = ' ';
++ for (i = 0; i < key_id_len; i++) {
++ *q++ = hex_asc[*key_id >> 4];
++ *q++ = hex_asc[*key_id++ & 0x0f];
++ }
++
++ *q = 0;
++
++ pr_debug("Look up: \"%s\"\n", id);
++
++ key = keyring_search(make_key_ref(modsign_keyring, 1),
++ &key_type_asymmetric, id);
++ if (IS_ERR(key))
++ pr_warn("Request for unknown module key '%s' err %ld\n",
++ id, PTR_ERR(key));
++ kfree(id);
++
++ if (IS_ERR(key)) {
++ switch (PTR_ERR(key)) {
++ /* Hide some search errors */
++ case -EACCES:
++ case -ENOTDIR:
++ case -EAGAIN:
++ return ERR_PTR(-ENOKEY);
++ default:
++ return ERR_CAST(key);
++ }
++ }
++
++ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
++ return key_ref_to_ptr(key);
++}
++
++/*
+ * Verify the signature on a module.
+ */
+ int mod_verify_sig(const void *mod, unsigned long modlen,
+ const void *sig, unsigned long siglen)
+ {
+- return -ENOKEY;
++ struct public_key_signature *pks;
++ struct module_signature ms;
++ struct key *key;
++ size_t sig_len;
++ int ret;
++
++ pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen);
++
++ if (siglen <= sizeof(ms))
++ return -EBADMSG;
++
++ memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms));
++ siglen -= sizeof(ms);
++
++ sig_len = be32_to_cpu(ms.sig_len);
++ if (sig_len >= siglen ||
++ siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len)
++ return -EBADMSG;
++
++ /* For the moment, only support RSA and X.509 identifiers */
++ if (ms.algo != PKEY_ALGO_RSA ||
++ ms.id_type != PKEY_ID_X509)
++ return -ENOPKG;
++
++ if (ms.hash >= PKEY_HASH__LAST ||
++ !pkey_hash_algo[ms.hash])
++ return -ENOPKG;
++
++ key = request_asymmetric_key(sig, ms.signer_len,
++ sig + ms.signer_len, ms.key_id_len);
++ if (IS_ERR(key))
++ return PTR_ERR(key);
++
++ pks = mod_make_digest(ms.hash, mod, modlen);
++ if (IS_ERR(pks)) {
++ ret = PTR_ERR(pks);
++ goto error_put_key;
++ }
++
++ ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len,
++ sig_len);
++ if (ret < 0)
++ goto error_free_pks;
++
++ ret = verify_signature(key, pks);
++ pr_devel("verify_signature() = %d\n", ret);
++
++error_free_pks:
++ mpi_free(pks->rsa.s);
++ kfree(pks);
++error_put_key:
++ key_put(key);
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ return ret;
+ }
+--
+1.7.12.1
+
+
+From 952f5922dd45a25f7896843df02aec2250c41f42 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:11:06 +0100
+Subject: [PATCH 24/37] MODSIGN: Provide a script for generating a key ID from
+ an X.509 cert
+
+Provide a script to parse an X.509 certificate and certain pieces of
+information from it in order to generate a key identifier to be included within
+a module signature.
+
+The script takes the Subject Name and extracts (if present) the
+organizationName (O), the commonName (CN) and the emailAddress and fabricates
+the signer's name from them:
+
+ (1) If both O and CN exist, then the name will be "O: CN", unless:
+
+ (a) CN is prefixed by O, in which case only CN is used.
+
+ (b) CN and O share at least the first 7 characters, in which case only CN
+ is used.
+
+ (2) Otherwise, CN is used if present.
+
+ (3) Otherwise, O is used if present.
+
+ (4) Otherwise the emailAddress is used, if present.
+
+ (5) Otherwise a blank name is used.
+
+The script emits a binary encoded identifier in the following form:
+
+ - 2 BE bytes indicating the length of the signer's name.
+
+ - 2 BE bytes indicating the length of the subject key identifier.
+
+ - The characters of the signer's name.
+
+ - The bytes of the subject key identifier.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ scripts/x509keyid | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 268 insertions(+)
+ create mode 100755 scripts/x509keyid
+
+diff --git a/scripts/x509keyid b/scripts/x509keyid
+new file mode 100755
+index 0000000..c8e91a4
+--- /dev/null
++++ b/scripts/x509keyid
+@@ -0,0 +1,268 @@
++#!/usr/bin/perl -w
++#
++# Generate an identifier from an X.509 certificate that can be placed in a
++# module signature to indentify the key to use.
++#
++# Format:
++#
++# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id>
++#
++# We read the DER-encoded X509 certificate and parse it to extract the Subject
++# name and Subject Key Identifier. The provide the data we need to build the
++# certificate identifier.
++#
++# The signer's name part of the identifier is fabricated from the commonName,
++# the organizationName or the emailAddress components of the X.509 subject
++# name and written to the second named file.
++#
++# The subject key ID to select which of that signer's certificates we're
++# intending to use to sign the module is written to the third named file.
++#
++use strict;
++
++my $raw_data;
++
++die "Need three filenames\n" if ($#ARGV != 2);
++
++my $src = $ARGV[0];
++
++open(FD, "<$src") || die $src;
++binmode FD;
++my @st = stat(FD);
++die $src if (!@st);
++read(FD, $raw_data, $st[7]) || die $src;
++close(FD);
++
++my $UNIV = 0 << 6;
++my $APPL = 1 << 6;
++my $CONT = 2 << 6;
++my $PRIV = 3 << 6;
++
++my $CONS = 0x20;
++
++my $BOOLEAN = 0x01;
++my $INTEGER = 0x02;
++my $BIT_STRING = 0x03;
++my $OCTET_STRING = 0x04;
++my $NULL = 0x05;
++my $OBJ_ID = 0x06;
++my $UTF8String = 0x0c;
++my $SEQUENCE = 0x10;
++my $SET = 0x11;
++my $UTCTime = 0x17;
++my $GeneralizedTime = 0x18;
++
++my %OIDs = (
++ pack("CCC", 85, 4, 3) => "commonName",
++ pack("CCC", 85, 4, 6) => "countryName",
++ pack("CCC", 85, 4, 10) => "organizationName",
++ pack("CCC", 85, 4, 11) => "organizationUnitName",
++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
++ pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
++ pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
++ pack("CCC", 85, 29, 19) => "basicConstraints"
++);
++
++###############################################################################
++#
++# Extract an ASN.1 element from a string and return information about it.
++#
++###############################################################################
++sub asn1_extract($$@)
++{
++ my ($cursor, $expected_tag, $optional) = @_;
++
++ return [ -1 ]
++ if ($cursor->[1] == 0 && $optional);
++
++ die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
++ if ($cursor->[1] < 2);
++
++ my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
++
++ if ($expected_tag != -1 && $tag != $expected_tag) {
++ return [ -1 ]
++ if ($optional);
++ die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
++ " not ", $expected_tag, ")\n";
++ }
++
++ $cursor->[0] += 2;
++ $cursor->[1] -= 2;
++
++ die $src, ": ", $cursor->[0], ": ASN.1 long tag\n"
++ if (($tag & 0x1f) == 0x1f);
++ die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
++ if ($len == 0x80);
++
++ if ($len > 0x80) {
++ my $l = $len - 0x80;
++ die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
++ if ($cursor->[1] < $l);
++
++ if ($l == 0x1) {
++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
++ } elsif ($l = 0x2) {
++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
++ } elsif ($l = 0x3) {
++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
++ } elsif ($l = 0x4) {
++ $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
++ } else {
++ die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
++ }
++
++ $cursor->[0] += $l;
++ $cursor->[1] -= $l;
++ }
++
++ die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
++ if ($cursor->[1] < $len);
++
++ my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
++ $cursor->[0] += $len;
++ $cursor->[1] -= $len;
++
++ return $ret;
++}
++
++###############################################################################
++#
++# Retrieve the data referred to by a cursor
++#
++###############################################################################
++sub asn1_retrieve($)
++{
++ my ($cursor) = @_;
++ my ($offset, $len, $data) = @$cursor;
++ return substr($$data, $offset, $len);
++}
++
++###############################################################################
++#
++# Roughly parse the X.509 certificate
++#
++###############################################################################
++my $cursor = [ 0, length($raw_data), \$raw_data ];
++
++my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
++my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
++my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
++my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
++my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
++my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
++my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
++
++my $subject_key_id = ();
++my $authority_key_id = ();
++
++#
++# Parse the extension list
++#
++if ($extension_list->[0] != -1) {
++ my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
++
++ while ($extensions->[1]->[1] > 0) {
++ my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
++ my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
++ my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
++ my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
++
++ my $raw_oid = asn1_retrieve($x_oid->[1]);
++ next if (!exists($OIDs{$raw_oid}));
++ my $x_type = $OIDs{$raw_oid};
++
++ my $raw_value = asn1_retrieve($x_val->[1]);
++
++ if ($x_type eq "subjectKeyIdentifier") {
++ my $vcursor = [ 0, length($raw_value), \$raw_value ];
++
++ $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
++ }
++ }
++}
++
++###############################################################################
++#
++# Determine what we're going to use as the signer's name. In order of
++# preference, take one of: commonName, organizationName or emailAddress.
++#
++###############################################################################
++my $org = "";
++my $cn = "";
++my $email = "";
++
++while ($subject->[1]->[1] > 0) {
++ my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
++ my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
++ my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
++ my $n_val = asn1_extract($attr->[1], -1);
++
++ my $raw_oid = asn1_retrieve($n_oid->[1]);
++ next if (!exists($OIDs{$raw_oid}));
++ my $n_type = $OIDs{$raw_oid};
++
++ my $raw_value = asn1_retrieve($n_val->[1]);
++
++ if ($n_type eq "organizationName") {
++ $org = $raw_value;
++ } elsif ($n_type eq "commonName") {
++ $cn = $raw_value;
++ } elsif ($n_type eq "emailAddress") {
++ $email = $raw_value;
++ }
++}
++
++my $id_name = $email;
++
++if ($org && $cn) {
++ # Don't use the organizationName if the commonName repeats it
++ if (length($org) <= length($cn) &&
++ substr($cn, 0, length($org)) eq $org) {
++ $id_name = $cn;
++ goto got_id_name;
++ }
++
++ # Or a signifcant chunk of it
++ if (length($org) >= 7 &&
++ length($cn) >= 7 &&
++ substr($cn, 0, 7) eq substr($org, 0, 7)) {
++ $id_name = $cn;
++ goto got_id_name;
++ }
++
++ $id_name = $org . ": " . $cn;
++} elsif ($org) {
++ $id_name = $org;
++} elsif ($cn) {
++ $id_name = $cn;
++}
++
++got_id_name:
++
++###############################################################################
++#
++# Output the signer's name and the key identifier that we're going to include
++# in module signatures.
++#
++###############################################################################
++die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
++ if (!$subject_key_id);
++
++my $id_key_id = asn1_retrieve($subject_key_id->[1]);
++
++open(OUTFD, ">$ARGV[1]") || die $ARGV[1];
++print OUTFD $id_name;
++close OUTFD || die $ARGV[1];
++
++open(OUTFD, ">$ARGV[2]") || die $ARGV[2];
++print OUTFD $id_key_id;
++close OUTFD || die $ARGV[2];
+--
+1.7.12.1
+
+
+From 52a1f2ba9612d689f1a5ed6c1a03bd784f34bf1c Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 26 Sep 2012 10:11:06 +0100
+Subject: [PATCH 25/37] MODSIGN: Sign modules during the build process
+
+If CONFIG_MODULE_SIG is set, then this patch will cause all modules files to
+to have signatures added. The following steps will occur:
+
+ (1) The module will be linked to foo.ko.unsigned instead of foo.ko
+
+ (2) The module will be stripped using both "strip -x -g" and "eu-strip" to
+ ensure minimal size for inclusion in an initramfs.
+
+ (3) The signature will be generated on the stripped module.
+
+ (4) The signature will be appended to the module, along with some information
+ about the signature and a magic string that indicates the presence of the
+ signature.
+
+Step (3) requires private and public keys to be available. By default these
+are expected to be found in files:
+
+ signing_key.priv
+ signing_key.x509
+
+in the base directory of the build. The first is the private key in PEM form
+and the second is the X.509 certificate in DER form as can be generated from
+openssl:
+
+ openssl req \
+ -new -x509 -outform PEM -out signing_key.x509 \
+ -keyout signing_key.priv -nodes \
+ -subj "/CN=H2G2/O=Magrathea/CN=Slartibartfast"
+
+If the secret key is not found then signing will be skipped and the unsigned
+module from (1) will just be copied to foo.ko.
+
+If signing occurs, lines like the following will be seen:
+
+ LD [M] fs/foo/foo.ko.unsigned
+ STRIP [M] fs/foo/foo.ko.stripped
+ SIGN [M] fs/foo/foo.ko
+
+will appear in the build log. If the signature step will be skipped and the
+following will be seen:
+
+ LD [M] fs/foo/foo.ko.unsigned
+ STRIP [M] fs/foo/foo.ko.stripped
+ NO SIGN [M] fs/foo/foo.ko
+
+NOTE! After the signature step, the signed module _must_not_ be passed through
+strip. The unstripped, unsigned module is still available at the name on the
+LD [M] line. This restriction may affect packaging tools (such as rpmbuild)
+and initramfs composition tools.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ scripts/Makefile.modpost | 77 ++++++++++++++++++++++++++++++-
+ scripts/sign-file | 115 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 191 insertions(+), 1 deletion(-)
+ create mode 100644 scripts/sign-file
+
+diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
+index 08dce14..2a4d1a1 100644
+--- a/scripts/Makefile.modpost
++++ b/scripts/Makefile.modpost
+@@ -14,7 +14,8 @@
+ # 3) create one <module>.mod.c file pr. module
+ # 4) create one Module.symvers file with CRC for all exported symbols
+ # 5) compile all <module>.mod.c files
+-# 6) final link of the module to a <module.ko> file
++# 6) final link of the module to a <module.ko> (or <module.unsigned>) file
++# 7) signs the modules to a <module.ko> file
+
+ # Step 3 is used to place certain information in the module's ELF
+ # section, including information such as:
+@@ -32,6 +33,8 @@
+ # Step 4 is solely used to allow module versioning in external modules,
+ # where the CRC of each module is retrieved from the Module.symvers file.
+
++# Step 7 is dependent on CONFIG_MODULE_SIG being enabled.
++
+ # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
+ # symbols in the final module linking stage
+ # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
+@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
+ targets += $(modules:.ko=.mod.o)
+
+ # Step 6), final link of the modules
++ifneq ($(CONFIG_MODULE_SIG),y)
+ quiet_cmd_ld_ko_o = LD [M] $@
+ cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
+ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
+@@ -125,7 +129,78 @@ $(modules): %.ko :%.o %.mod.o FORCE
+ $(call if_changed,ld_ko_o)
+
+ targets += $(modules)
++else
++quiet_cmd_ld_ko_unsigned_o = LD [M] $@
++ cmd_ld_ko_unsigned_o = \
++ $(LD) -r $(LDFLAGS) \
++ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
++ -o $@ $(filter-out FORCE,$^) \
++ $(if $(AFTER_LINK),; $(AFTER_LINK))
++
++$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
++ $(call if_changed,ld_ko_unsigned_o)
++
++targets += $(modules:.ko=.ko.unsigned)
++
++# Step 7), sign the modules
++MODSECKEY = ./signing_key.priv
++MODPUBKEY = ./signing_key.x509
++
++ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY))
++ifeq ($(KBUILD_SRC),)
++ # no O= is being used
++ SCRIPTS_DIR := scripts
++else
++ SCRIPTS_DIR := $(KBUILD_SRC)/scripts
++endif
++SIGN_MODULES := 1
++else
++SIGN_MODULES := 0
++endif
++
++# only sign if it's an in-tree module
++ifneq ($(KBUILD_EXTMOD),)
++SIGN_MODULES := 0
++endif
+
++# We strip the module as best we can - note that using both strip and eu-strip
++# results in a smaller module than using either alone.
++EU_STRIP = $(shell which eu-strip || echo true)
++
++quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
++ cmd_sign_ko_stripped_ko_unsigned = \
++ cp $< $@ && \
++ strip -x -g $@ && \
++ $(EU_STRIP) $@
++
++ifeq ($(SIGN_MODULES),1)
++
++quiet_cmd_genkeyid = GENKEYID $@
++ cmd_genkeyid = \
++ perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid
++
++%.signer %.keyid: %
++ $(call if_changed,genkeyid)
++
++KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid
++quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@
++ cmd_sign_ko_ko_stripped = \
++ sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@
++else
++KEYRING_DEP :=
++quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
++ cmd_sign_ko_ko_unsigned = \
++ cp $< $@
++endif
++
++$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE
++ $(call if_changed,sign_ko_ko_stripped)
++
++$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE
++ $(call if_changed,sign_ko_stripped_ko_unsigned)
++
++targets += $(modules)
++endif
+
+ # Add FORCE to the prequisites of a target to force it to be always rebuilt.
+ # ---------------------------------------------------------------------------
+diff --git a/scripts/sign-file b/scripts/sign-file
+new file mode 100644
+index 0000000..e58e34e
+--- /dev/null
++++ b/scripts/sign-file
+@@ -0,0 +1,115 @@
++#!/bin/sh
++#
++# Sign a module file using the given key.
++#
++# Format: sign-file <key> <x509> <src-file> <dst-file>
++#
++
++scripts=`dirname $0`
++
++CONFIG_MODULE_SIG_SHA512=y
++if [ -r .config ]
++then
++ . ./.config
++fi
++
++key="$1"
++x509="$2"
++src="$3"
++dst="$4"
++
++if [ ! -r "$key" ]
++then
++ echo "Can't read private key" >&2
++ exit 2
++fi
++
++if [ ! -r "$x509" ]
++then
++ echo "Can't read X.509 certificate" >&2
++ exit 2
++fi
++if [ ! -r "$x509.signer" ]
++then
++ echo "Can't read Signer name" >&2
++ exit 2;
++fi
++if [ ! -r "$x509.keyid" ]
++then
++ echo "Can't read Key identifier" >&2
++ exit 2;
++fi
++
++#
++# Signature parameters
++#
++algo=1 # Public-key crypto algorithm: RSA
++hash= # Digest algorithm
++id_type=1 # Identifier type: X.509
++
++#
++# Digest the data
++#
++dgst=
++if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ]
++then
++ prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14"
++ dgst=-sha1
++ hash=2
++elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ]
++then
++ prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C"
++ dgst=-sha224
++ hash=7
++elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ]
++then
++ prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20"
++ dgst=-sha256
++ hash=4
++elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ]
++then
++ prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30"
++ dgst=-sha384
++ hash=5
++elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ]
++then
++ prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40"
++ dgst=-sha512
++ hash=6
++else
++ echo "$0: Can't determine hash algorithm" >&2
++ exit 2
++fi
++
++(
++perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $?
++openssl dgst $dgst -binary $src || exit $?
++) >$src.dig || exit $?
++
++#
++# Generate the binary signature, which will be just the integer that comprises
++# the signature with no metadata attached.
++#
++openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $?
++signerlen=`stat -c %s $x509.signer`
++keyidlen=`stat -c %s $x509.keyid`
++siglen=`stat -c %s $src.sig`
++
++#
++# Build the signed binary
++#
++(
++ cat $src || exit $?
++ echo '~Module signature appended~' || exit $?
++ cat $x509.signer $x509.keyid || exit $?
++
++ # Preface each signature integer with a 2-byte BE length
++ perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $?
++ cat $src.sig || exit $?
++
++ # Generate the information block
++ perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $?
++) >$dst~ || exit $?
++
++# Permit in-place signing
++mv $dst~ $dst || exit $?
+--
+1.7.12.1
+
+
+From 1e9ce85a6c40e2c0ba6c589605ceb565b1c83784 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 28 Sep 2012 11:16:57 +0100
+Subject: [PATCH 26/37] MODSIGN: Use the same digest for the autogen key sig
+ as for the module sig
+
+Use the same digest type for the autogenerated key signature as for the module
+signature so that the hash algorithm is guaranteed to be present in the kernel.
+
+Without this, the X.509 certificate loader may reject the X.509 certificate so
+generated because it was self-signed and the signature will be checked against
+itself - but this won't work if the digest algorithm must be loaded as a
+module.
+
+The symptom is that the key fails to load with the following message emitted
+into the kernel log:
+
+ MODSIGN: Problem loading in-kernel X.509 certificate (-65)
+
+the error in brackets being -ENOPKG. What you should see is something like:
+
+ MODSIGN: Loaded cert 'Magarathea: Glacier signing key: 9588321144239a119d3406d4c4cf1fbae1836fa0'
+
+Note that this doesn't apply to certificates that are not self-signed as we
+don't check those currently as they require the parent CA certificate to be
+available.
+
+Reported-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ kernel/Makefile | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 111a845..a799029 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -149,6 +149,26 @@ kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
+ # fail and that the kernel may be used afterwards.
+ #
+ ###############################################################################
++sign_key_with_hash :=
++ifeq ($(CONFIG_MODULE_SIG_SHA1),y)
++sign_key_with_hash := -sha1
++endif
++ifeq ($(CONFIG_MODULE_SIG_SHA224),y)
++sign_key_with_hash := -sha224
++endif
++ifeq ($(CONFIG_MODULE_SIG_SHA256),y)
++sign_key_with_hash := -sha256
++endif
++ifeq ($(CONFIG_MODULE_SIG_SHA384),y)
++sign_key_with_hash := -sha384
++endif
++ifeq ($(CONFIG_MODULE_SIG_SHA512),y)
++sign_key_with_hash := -sha512
++endif
++ifeq ($(sign_key_with_hash),)
++$(error Could not determine digest type to use from kernel config)
++endif
++
+ signing_key.priv signing_key.x509: x509.genkey
+ @echo "###"
+ @echo "### Now generating an X.509 key pair to be used for signing modules."
+@@ -160,7 +180,7 @@ signing_key.priv signing_key.x509: x509.genkey
+ @echo "###"
+ @echo "### rngd -r /dev/hwrandom"
+ @echo "###"
+- openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \
++ openssl req -new -nodes -utf8 $(sign_key_with_hash) -days 36500 -batch \
+ -x509 -config x509.genkey \
+ -outform DER -out signing_key.x509 \
+ -keyout signing_key.priv
+--
+1.7.12.1
+
+
+From 4c13d777ecee93ae75dae3184473003acff05a53 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 28 Sep 2012 11:16:57 +0100
+Subject: [PATCH 27/37] MODSIGN: Use utf8 strings in signer's name in
+ autogenerated X.509 certs
+
+Place an indication that the certificate should use utf8 strings into the
+x509.genkey template generated by kernel/Makefile.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ kernel/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/kernel/Makefile b/kernel/Makefile
+index a799029..e951adf 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -194,6 +194,7 @@ x509.genkey:
+ @echo >>x509.genkey "default_bits = 4096"
+ @echo >>x509.genkey "distinguished_name = req_distinguished_name"
+ @echo >>x509.genkey "prompt = no"
++ @echo >>x509.genkey "string_mask = utf8only"
+ @echo >>x509.genkey "x509_extensions = myexts"
+ @echo >>x509.genkey
+ @echo >>x509.genkey "[ req_distinguished_name ]"
+--
+1.7.12.1
+
+
+From 836513a2dd15675d4ad5fefa585d1b866bec4995 Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Tue, 2 Oct 2012 14:35:24 +0930
+Subject: [PATCH 28/37] MODSIGN: Make mrproper should remove generated files.
+
+It doesn't, because the clean targets don't include kernel/Makefile, and
+because two files were missing from the list.
+
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ Makefile | 5 ++++-
+ kernel/Makefile | 1 -
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index b4f9eb5..e4292ea 100644
+--- a/Makefile
++++ b/Makefile
+@@ -995,7 +995,10 @@ MRPROPER_DIRS += include/config usr/include include/generated \
+ arch/*/include/generated
+ MRPROPER_FILES += .config .config.old .version .old_version \
+ include/linux/version.h \
+- Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
++ Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
++ signing_key.priv signing_key.x509 x509.genkey \
++ extra_certificates signing_key.x509.keyid \
++ signing_key.x509.signer
+
+ # clean - Delete most, but leave enough to build external modules
+ #
+diff --git a/kernel/Makefile b/kernel/Makefile
+index e951adf..d3611c8 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -208,4 +208,3 @@ x509.genkey:
+ @echo >>x509.genkey "subjectKeyIdentifier=hash"
+ @echo >>x509.genkey "authorityKeyIdentifier=keyid"
+ endif
+-CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates
+--
+1.7.12.1
+
+
+From 855c92bdf2fb006e4190650b809a6216579395d5 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 2 Oct 2012 14:36:16 +0100
+Subject: [PATCH 29/37] MODSIGN: Fix 32-bit overflow in X.509 certificate
+ validity date checking
+
+The current choice of lifetime for the autogenerated X.509 of 100 years,
+putting the validTo date in 2112, causes problems on 32-bit systems where a
+32-bit time_t wraps in 2106. 64-bit x86_64 systems seem to be unaffected.
+
+This can result in something like:
+
+ Loading module verification certificates
+ X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired
+ MODSIGN: Problem loading in-kernel X.509 certificate (-127)
+
+Or:
+
+ X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 is not yet valid
+ MODSIGN: Problem loading in-kernel X.509 certificate (-129)
+
+Instead of turning the dates into time_t values and comparing, turn the system
+clock and the ASN.1 dates into tm structs and compare those piecemeal instead.
+
+Reported-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Acked-by: Josh Boyer <jwboyer@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/x509_cert_parser.c | 25 +++++++++---------
+ crypto/asymmetric_keys/x509_parser.h | 4 +--
+ crypto/asymmetric_keys/x509_public_key.c | 42 +++++++++++++++++++++++++++----
+ 3 files changed, 51 insertions(+), 20 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+index 8fcac94..db07e8c 100644
+--- a/crypto/asymmetric_keys/x509_cert_parser.c
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -434,11 +434,10 @@ int x509_process_extension(void *context, size_t hdrlen,
+ /*
+ * Record a certificate time.
+ */
+-static int x509_note_time(time_t *_time, size_t hdrlen,
++static int x509_note_time(struct tm *tm, size_t hdrlen,
+ unsigned char tag,
+ const unsigned char *value, size_t vlen)
+ {
+- unsigned YY, MM, DD, hh, mm, ss;
+ const unsigned char *p = value;
+
+ #define dec2bin(X) ((X) - '0')
+@@ -448,30 +447,30 @@ static int x509_note_time(time_t *_time, size_t hdrlen,
+ /* UTCTime: YYMMDDHHMMSSZ */
+ if (vlen != 13)
+ goto unsupported_time;
+- YY = DD2bin(p);
+- if (YY > 50)
+- YY += 1900;
++ tm->tm_year = DD2bin(p);
++ if (tm->tm_year >= 50)
++ tm->tm_year += 1900;
+ else
+- YY += 2000;
++ tm->tm_year += 2000;
+ } else if (tag == ASN1_GENTIM) {
+ /* GenTime: YYYYMMDDHHMMSSZ */
+ if (vlen != 15)
+ goto unsupported_time;
+- YY = DD2bin(p) * 100 + DD2bin(p);
++ tm->tm_year = DD2bin(p) * 100 + DD2bin(p);
+ } else {
+ goto unsupported_time;
+ }
+
+- MM = DD2bin(p);
+- DD = DD2bin(p);
+- hh = DD2bin(p);
+- mm = DD2bin(p);
+- ss = DD2bin(p);
++ tm->tm_year -= 1900;
++ tm->tm_mon = DD2bin(p) - 1;
++ tm->tm_mday = DD2bin(p);
++ tm->tm_hour = DD2bin(p);
++ tm->tm_min = DD2bin(p);
++ tm->tm_sec = DD2bin(p);
+
+ if (*p != 'Z')
+ goto unsupported_time;
+
+- *_time = mktime(YY, MM, DD, hh, mm, ss);
+ return 0;
+
+ unsupported_time:
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index 635053f..f86dc5f 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -18,8 +18,8 @@ struct x509_certificate {
+ char *subject; /* Name of certificate subject */
+ char *fingerprint; /* Key fingerprint as hex */
+ char *authority; /* Authority key fingerprint as hex */
+- time_t valid_from;
+- time_t valid_to;
++ struct tm valid_from;
++ struct tm valid_to;
+ enum pkey_algo pkey_algo : 8; /* Public key algorithm */
+ enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
+ enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index 716917c..5ab736d 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -106,7 +106,7 @@ error_no_sig:
+ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ {
+ struct x509_certificate *cert;
+- time_t now;
++ struct tm now;
+ size_t srlen, sulen;
+ char *desc = NULL;
+ int ret;
+@@ -118,7 +118,14 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ pr_devel("Cert Issuer: %s\n", cert->issuer);
+ pr_devel("Cert Subject: %s\n", cert->subject);
+ pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
+- pr_devel("Cert Valid: %lu - %lu\n", cert->valid_from, cert->valid_to);
++ printk("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
++ cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
++ cert->valid_from.tm_mday, cert->valid_from.tm_hour,
++ cert->valid_from.tm_min, cert->valid_from.tm_sec);
++ printk("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
++ cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
++ cert->valid_to.tm_mday, cert->valid_to.tm_hour,
++ cert->valid_to.tm_min, cert->valid_to.tm_sec);
+ pr_devel("Cert Signature: %s + %s\n",
+ pkey_algo[cert->sig_pkey_algo],
+ pkey_hash_algo[cert->sig_hash_algo]);
+@@ -130,13 +137,38 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ goto error_free_cert;
+ }
+
+- now = CURRENT_TIME.tv_sec;
+- if (now < cert->valid_from) {
++ time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
++ printk("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
++ now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
++ now.tm_hour, now.tm_min, now.tm_sec);
++ if (now.tm_year < cert->valid_from.tm_year ||
++ (now.tm_year == cert->valid_from.tm_year &&
++ (now.tm_mon < cert->valid_from.tm_mon ||
++ (now.tm_mon == cert->valid_from.tm_mon &&
++ (now.tm_mday < cert->valid_from.tm_mday ||
++ (now.tm_mday == cert->valid_from.tm_mday &&
++ (now.tm_hour < cert->valid_from.tm_hour ||
++ (now.tm_hour == cert->valid_from.tm_hour &&
++ (now.tm_min < cert->valid_from.tm_min ||
++ (now.tm_min == cert->valid_from.tm_min &&
++ (now.tm_sec < cert->valid_from.tm_sec
++ ))))))))))) {
+ pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
+ ret = -EKEYREJECTED;
+ goto error_free_cert;
+ }
+- if (now >= cert->valid_to) {
++ if (now.tm_year > cert->valid_to.tm_year ||
++ (now.tm_year == cert->valid_to.tm_year &&
++ (now.tm_mon > cert->valid_to.tm_mon ||
++ (now.tm_mon == cert->valid_to.tm_mon &&
++ (now.tm_mday > cert->valid_to.tm_mday ||
++ (now.tm_mday == cert->valid_to.tm_mday &&
++ (now.tm_hour > cert->valid_to.tm_hour ||
++ (now.tm_hour == cert->valid_to.tm_hour &&
++ (now.tm_min > cert->valid_to.tm_min ||
++ (now.tm_min == cert->valid_to.tm_min &&
++ (now.tm_sec > cert->valid_to.tm_sec
++ ))))))))))) {
+ pr_warn("Cert %s has expired\n", cert->fingerprint);
+ ret = -EKEYEXPIRED;
+ goto error_free_cert;
+--
+1.7.12.1
+
+
+From f69bc56c32645bcc0b1a9ee88be662e8246398b4 Mon Sep 17 00:00:00 2001
+From: Randy Dunlap <rdunlap@xenotime.net>
+Date: Wed, 3 Oct 2012 16:04:46 -0700
+Subject: [PATCH 30/37] asymmetric keys: fix printk format warning
+
+Fix printk format warning in x509_cert_parser.c:
+
+crypto/asymmetric_keys/x509_cert_parser.c: In function 'x509_note_OID':
+crypto/asymmetric_keys/x509_cert_parser.c:113:3: warning: format '%zu' expects type 'size_t', but argument 2 has type 'long unsigned int'
+
+Builds cleanly on i386 and x86_64.
+
+Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
+Cc: David Howells <dhowells@redhat.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: linux-crypto@vger.kernel.org
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/x509_cert_parser.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+index db07e8c..7fabc4c 100644
+--- a/crypto/asymmetric_keys/x509_cert_parser.c
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -110,7 +110,7 @@ int x509_note_OID(void *context, size_t hdrlen,
+ if (ctx->last_oid == OID__NR) {
+ char buffer[50];
+ sprint_oid(value, vlen, buffer, sizeof(buffer));
+- pr_debug("Unknown OID: [%zu] %s\n",
++ pr_debug("Unknown OID: [%lu] %s\n",
+ (unsigned long)value - ctx->data, buffer);
+ }
+ return 0;
+--
+1.7.12.1
+
+
+From 81338d71c284b7d001004e4a03abfce2d2144087 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 4 Oct 2012 14:21:23 +0100
+Subject: [PATCH 31/37] X.509: Convert some printk calls to pr_devel
+
+Some debugging printk() calls should've been converted to pr_devel() calls.
+Do that now.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ crypto/asymmetric_keys/x509_public_key.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index 5ab736d..06007f0 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -118,11 +118,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ pr_devel("Cert Issuer: %s\n", cert->issuer);
+ pr_devel("Cert Subject: %s\n", cert->subject);
+ pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
+- printk("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
++ pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
+ cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
+ cert->valid_from.tm_mday, cert->valid_from.tm_hour,
+ cert->valid_from.tm_min, cert->valid_from.tm_sec);
+- printk("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
++ pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
+ cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
+ cert->valid_to.tm_mday, cert->valid_to.tm_hour,
+ cert->valid_to.tm_min, cert->valid_to.tm_sec);
+@@ -138,7 +138,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ }
+
+ time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
+- printk("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
++ pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
+ now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
+ now.tm_hour, now.tm_min, now.tm_sec);
+ if (now.tm_year < cert->valid_from.tm_year ||
+--
+1.7.12.1
+
+
+From 1054ea17fe1bf8f2087197c453626153d4649ac5 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 4 Oct 2012 14:21:23 +0100
+Subject: [PATCH 32/37] X.509: Fix indefinite length element skip error
+ handling
+
+asn1_find_indefinite_length() returns an error indicator of -1, which the
+caller asn1_ber_decoder() places in a size_t (which is usually unsigned) and
+then checks to see whether it is less than 0 (which it can't be). This can
+lead to the following warning:
+
+ lib/asn1_decoder.c:320 asn1_ber_decoder()
+ warn: unsigned 'len' is never less than zero.
+
+Instead, asn1_find_indefinite_length() update the caller's idea of the data
+cursor and length separately from returning the error code.
+
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+---
+ lib/asn1_decoder.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c
+index 2e4196d..de2c8b5 100644
+--- a/lib/asn1_decoder.c
++++ b/lib/asn1_decoder.c
+@@ -46,12 +46,18 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
+
+ /*
+ * Find the length of an indefinite length object
++ * @data: The data buffer
++ * @datalen: The end of the innermost containing element in the buffer
++ * @_dp: The data parse cursor (updated before returning)
++ * @_len: Where to return the size of the element.
++ * @_errmsg: Where to return a pointer to an error message on error
+ */
+ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen,
+- const char **_errmsg, size_t *_err_dp)
++ size_t *_dp, size_t *_len,
++ const char **_errmsg)
+ {
+ unsigned char tag, tmp;
+- size_t dp = 0, len, n;
++ size_t dp = *_dp, len, n;
+ int indef_level = 1;
+
+ next_tag:
+@@ -67,8 +73,11 @@ next_tag:
+ /* It appears to be an EOC. */
+ if (data[dp++] != 0)
+ goto invalid_eoc;
+- if (--indef_level <= 0)
+- return dp;
++ if (--indef_level <= 0) {
++ *_len = dp - *_dp;
++ *_dp = dp;
++ return 0;
++ }
+ goto next_tag;
+ }
+
+@@ -122,7 +131,7 @@ data_overrun_error:
+ missing_eoc:
+ *_errmsg = "Missing EOC in indefinite len cons";
+ error:
+- *_err_dp = dp;
++ *_dp = dp;
+ return -1;
+ }
+
+@@ -315,13 +324,14 @@ next_op:
+ skip_data:
+ if (!(flags & FLAG_CONS)) {
+ if (flags & FLAG_INDEFINITE_LENGTH) {
+- len = asn1_find_indefinite_length(
+- data + dp, datalen - dp, &errmsg, &dp);
+- if (len < 0)
++ ret = asn1_find_indefinite_length(
++ data, datalen, &dp, &len, &errmsg);
++ if (ret < 0)
+ goto error;
++ } else {
++ dp += len;
+ }
+ pr_debug("- LEAF: %zu\n", len);
+- dp += len;
+ }
+ pc += asn1_op_lengths[op];
+ goto next_op;
+--
+1.7.12.1
+
+
+From 4ae37452e7450971072481b98f6e1c29e5165c1e Mon Sep 17 00:00:00 2001
+From: Rusty Russell <rusty@rustcorp.com.au>
+Date: Fri, 19 Oct 2012 11:53:15 +1030
+Subject: [PATCH 33/37] kbuild: sign the modules at install time
+
+Linus deleted the old code and put signing on the install command,
+I fixed it to extract the keyid and signer-name within sign-file
+and cleaned up that script now it always signs in-place.
+
+Some enthusiast should convert sign-key to perl and pull
+x509keyid into it.
+
+Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ Makefile | 11 +++++++
+ scripts/Makefile.modinst | 2 +-
+ scripts/Makefile.modpost | 77 +-----------------------------------------------
+ scripts/sign-file | 44 +++++++++++----------------
+ scripts/x509keyid | 16 +++++-----
+ 5 files changed, 39 insertions(+), 111 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index e4292ea..1cc5de4 100644
+--- a/Makefile
++++ b/Makefile
+@@ -714,6 +714,17 @@ endif # INSTALL_MOD_STRIP
+ export mod_strip_cmd
+
+
++ifeq ($(CONFIG_MODULE_SIG),y)
++MODSECKEY = ./signing_key.priv
++MODPUBKEY = ./signing_key.x509
++export MODPUBKEY
++mod_sign_cmd = sh $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY) $(srctree)/scripts/x509keyid
++else
++mod_sign_cmd = true
++endif
++export mod_sign_cmd
++
++
+ ifeq ($(KBUILD_EXTMOD),)
+ core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+
+diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
+index efa5d94..38367bd 100644
+--- a/scripts/Makefile.modinst
++++ b/scripts/Makefile.modinst
+@@ -17,7 +17,7 @@ __modinst: $(modules)
+ @:
+
+ quiet_cmd_modules_install = INSTALL $@
+- cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@)
++ cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@)
+
+ # Modules built outside the kernel source tree go into extra by default
+ INSTALL_MOD_DIR ?= extra
+diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
+index 2a4d1a1..08dce14 100644
+--- a/scripts/Makefile.modpost
++++ b/scripts/Makefile.modpost
+@@ -14,8 +14,7 @@
+ # 3) create one <module>.mod.c file pr. module
+ # 4) create one Module.symvers file with CRC for all exported symbols
+ # 5) compile all <module>.mod.c files
+-# 6) final link of the module to a <module.ko> (or <module.unsigned>) file
+-# 7) signs the modules to a <module.ko> file
++# 6) final link of the module to a <module.ko> file
+
+ # Step 3 is used to place certain information in the module's ELF
+ # section, including information such as:
+@@ -33,8 +32,6 @@
+ # Step 4 is solely used to allow module versioning in external modules,
+ # where the CRC of each module is retrieved from the Module.symvers file.
+
+-# Step 7 is dependent on CONFIG_MODULE_SIG being enabled.
+-
+ # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
+ # symbols in the final module linking stage
+ # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
+@@ -119,7 +116,6 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
+ targets += $(modules:.ko=.mod.o)
+
+ # Step 6), final link of the modules
+-ifneq ($(CONFIG_MODULE_SIG),y)
+ quiet_cmd_ld_ko_o = LD [M] $@
+ cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
+ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
+@@ -129,78 +125,7 @@ $(modules): %.ko :%.o %.mod.o FORCE
+ $(call if_changed,ld_ko_o)
+
+ targets += $(modules)
+-else
+-quiet_cmd_ld_ko_unsigned_o = LD [M] $@
+- cmd_ld_ko_unsigned_o = \
+- $(LD) -r $(LDFLAGS) \
+- $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
+- -o $@ $(filter-out FORCE,$^) \
+- $(if $(AFTER_LINK),; $(AFTER_LINK))
+-
+-$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
+- $(call if_changed,ld_ko_unsigned_o)
+-
+-targets += $(modules:.ko=.ko.unsigned)
+-
+-# Step 7), sign the modules
+-MODSECKEY = ./signing_key.priv
+-MODPUBKEY = ./signing_key.x509
+-
+-ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY))
+-ifeq ($(KBUILD_SRC),)
+- # no O= is being used
+- SCRIPTS_DIR := scripts
+-else
+- SCRIPTS_DIR := $(KBUILD_SRC)/scripts
+-endif
+-SIGN_MODULES := 1
+-else
+-SIGN_MODULES := 0
+-endif
+-
+-# only sign if it's an in-tree module
+-ifneq ($(KBUILD_EXTMOD),)
+-SIGN_MODULES := 0
+-endif
+
+-# We strip the module as best we can - note that using both strip and eu-strip
+-# results in a smaller module than using either alone.
+-EU_STRIP = $(shell which eu-strip || echo true)
+-
+-quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
+- cmd_sign_ko_stripped_ko_unsigned = \
+- cp $< $@ && \
+- strip -x -g $@ && \
+- $(EU_STRIP) $@
+-
+-ifeq ($(SIGN_MODULES),1)
+-
+-quiet_cmd_genkeyid = GENKEYID $@
+- cmd_genkeyid = \
+- perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid
+-
+-%.signer %.keyid: %
+- $(call if_changed,genkeyid)
+-
+-KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid
+-quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@
+- cmd_sign_ko_ko_stripped = \
+- sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@
+-else
+-KEYRING_DEP :=
+-quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
+- cmd_sign_ko_ko_unsigned = \
+- cp $< $@
+-endif
+-
+-$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE
+- $(call if_changed,sign_ko_ko_stripped)
+-
+-$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE
+- $(call if_changed,sign_ko_stripped_ko_unsigned)
+-
+-targets += $(modules)
+-endif
+
+ # Add FORCE to the prequisites of a target to force it to be always rebuilt.
+ # ---------------------------------------------------------------------------
+diff --git a/scripts/sign-file b/scripts/sign-file
+index e58e34e..095a953 100644
+--- a/scripts/sign-file
++++ b/scripts/sign-file
+@@ -1,8 +1,8 @@
+-#!/bin/sh
++#!/bin/bash
+ #
+ # Sign a module file using the given key.
+ #
+-# Format: sign-file <key> <x509> <src-file> <dst-file>
++# Format: sign-file <key> <x509> <keyid-script> <module>
+ #
+
+ scripts=`dirname $0`
+@@ -15,8 +15,8 @@ fi
+
+ key="$1"
+ x509="$2"
+-src="$3"
+-dst="$4"
++keyid_script="$3"
++mod="$4"
+
+ if [ ! -r "$key" ]
+ then
+@@ -29,16 +29,6 @@ then
+ echo "Can't read X.509 certificate" >&2
+ exit 2
+ fi
+-if [ ! -r "$x509.signer" ]
+-then
+- echo "Can't read Signer name" >&2
+- exit 2;
+-fi
+-if [ ! -r "$x509.keyid" ]
+-then
+- echo "Can't read Key identifier" >&2
+- exit 2;
+-fi
+
+ #
+ # Signature parameters
+@@ -83,33 +73,35 @@ fi
+
+ (
+ perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $?
+-openssl dgst $dgst -binary $src || exit $?
+-) >$src.dig || exit $?
++openssl dgst $dgst -binary $mod || exit $?
++) >$mod.dig || exit $?
+
+ #
+ # Generate the binary signature, which will be just the integer that comprises
+ # the signature with no metadata attached.
+ #
+-openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $?
+-signerlen=`stat -c %s $x509.signer`
+-keyidlen=`stat -c %s $x509.keyid`
+-siglen=`stat -c %s $src.sig`
++openssl rsautl -sign -inkey $key -keyform PEM -in $mod.dig -out $mod.sig || exit $?
++
++SIGNER="`perl $keyid_script $x509 signer-name`"
++KEYID="`perl $keyid_script $x509 keyid`"
++keyidlen=${#KEYID}
++siglen=${#SIGNER}
+
+ #
+ # Build the signed binary
+ #
+ (
+- cat $src || exit $?
++ cat $mod || exit $?
+ echo '~Module signature appended~' || exit $?
+- cat $x509.signer $x509.keyid || exit $?
++ echo -n "$SIGNER" || exit $?
++ echo -n "$KEYID" || exit $?
+
+ # Preface each signature integer with a 2-byte BE length
+ perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $?
+- cat $src.sig || exit $?
++ cat $mod.sig || exit $?
+
+ # Generate the information block
+ perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $?
+-) >$dst~ || exit $?
++) >$mod~ || exit $?
+
+-# Permit in-place signing
+-mv $dst~ $dst || exit $?
++mv $mod~ $mod || exit $?
+diff --git a/scripts/x509keyid b/scripts/x509keyid
+index c8e91a4..4241ec6 100755
+--- a/scripts/x509keyid
++++ b/scripts/x509keyid
+@@ -22,7 +22,7 @@ use strict;
+
+ my $raw_data;
+
+-die "Need three filenames\n" if ($#ARGV != 2);
++die "Need a filename [keyid|signer-name]\n" if ($#ARGV != 1);
+
+ my $src = $ARGV[0];
+
+@@ -259,10 +259,10 @@ die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
+
+ my $id_key_id = asn1_retrieve($subject_key_id->[1]);
+
+-open(OUTFD, ">$ARGV[1]") || die $ARGV[1];
+-print OUTFD $id_name;
+-close OUTFD || die $ARGV[1];
+-
+-open(OUTFD, ">$ARGV[2]") || die $ARGV[2];
+-print OUTFD $id_key_id;
+-close OUTFD || die $ARGV[2];
++if ($ARGV[1] eq "signer-name") {
++ print $id_name;
++} elsif ($ARGV[1] eq "keyid") {
++ print $id_key_id;
++} else {
++ die "Unknown arg";
++}
+--
+1.7.12.1
+
+
+From 4aa23562520f07f4f27edb5c289bc289438005a0 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Fri, 19 Oct 2012 12:43:19 -0700
+Subject: [PATCH 34/37] kbuild: Fix module signature generation
+
+Rusty had clearly not actually tested his module signing changes that I
+(trustingly) applied as commit e2a666d52b48 ("kbuild: sign the modules
+at install time"). That commit had multiple bugs:
+
+ - using "${#VARIABLE}" to get the number of characters in a shell
+ variable may look clever, but it's locale-dependent: it returns the
+ number of *characters*, not bytes. And we do need bytes.
+
+ So don't use "${#..}" expansion, do the stupid "wc -c" thing instead
+ (where "c" stands for "bytes", not "characters", despite the letter.
+
+ - Rusty had confused "siglen" and "signerlen", and his conversion
+ didn't set "signerlen" at all, and incorrectly set "siglen" to the
+ size of the signer, not the size of the signature.
+
+End result: the modified sign-file script did create something that
+superficially *looked* like a signature, but didn't actually work at
+all, and would fail the signature check. Oops.
+
+Tssk, tssk, Rusty.
+
+But Rusty was definitely right that this whole thing should be rewritten
+in perl by somebody who has the perl-fu to do so. That is not me,
+though - I'm just doing an emergency fix for the shell script.
+
+Cc: Rusty Russell <rusty@rustcorp.com.au>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ scripts/sign-file | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/scripts/sign-file b/scripts/sign-file
+index 095a953..d014abd 100644
+--- a/scripts/sign-file
++++ b/scripts/sign-file
+@@ -81,11 +81,12 @@ openssl dgst $dgst -binary $mod || exit $?
+ # the signature with no metadata attached.
+ #
+ openssl rsautl -sign -inkey $key -keyform PEM -in $mod.dig -out $mod.sig || exit $?
++siglen=`stat -c %s $mod.sig`
+
+ SIGNER="`perl $keyid_script $x509 signer-name`"
+ KEYID="`perl $keyid_script $x509 keyid`"
+-keyidlen=${#KEYID}
+-siglen=${#SIGNER}
++keyidlen=$(echo -n "$KEYID" | wc -c)
++signerlen=$(echo -n "$SIGNER" | wc -c)
+
+ #
+ # Build the signed binary
+--
+1.7.12.1
+
+
+From f51b71db2cae9539acaa4d64a9e708d7aac1f879 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 19 Oct 2012 23:56:37 +0100
+Subject: [PATCH 35/37] MODSIGN: perlify sign-file and merge in x509keyid
+
+Turn sign-file into perl and merge in x509keyid. The latter doesn't
+need to be a separate script as it doesn't actually need to work out the
+SHA1 sum of the X.509 certificate itself, since it can get that from the
+X.509 certificate.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ Makefile | 2 +-
+ scripts/sign-file | 477 +++++++++++++++++++++++++++++++++++++++++++++---------
+ scripts/x509keyid | 268 ------------------------------
+ 3 files changed, 400 insertions(+), 347 deletions(-)
+ mode change 100644 => 100755 scripts/sign-file
+ delete mode 100755 scripts/x509keyid
+
+diff --git a/Makefile b/Makefile
+index 1cc5de4..f4f9cdb 100644
+--- a/Makefile
++++ b/Makefile
+@@ -718,7 +718,7 @@ ifeq ($(CONFIG_MODULE_SIG),y)
+ MODSECKEY = ./signing_key.priv
+ MODPUBKEY = ./signing_key.x509
+ export MODPUBKEY
+-mod_sign_cmd = sh $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY) $(srctree)/scripts/x509keyid
++mod_sign_cmd = perl $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY)
+ else
+ mod_sign_cmd = true
+ endif
+diff --git a/scripts/sign-file b/scripts/sign-file
+old mode 100644
+new mode 100755
+index d014abd..d37d130
+--- a/scripts/sign-file
++++ b/scripts/sign-file
+@@ -1,108 +1,429 @@
+-#!/bin/bash
++#!/usr/bin/perl -w
+ #
+ # Sign a module file using the given key.
+ #
+-# Format: sign-file <key> <x509> <keyid-script> <module>
++# Format:
+ #
++# ./scripts/sign-file [-v] <key> <x509> <module> [<dest>]
++#
++#
++use strict;
++use FileHandle;
++use IPC::Open2;
++
++my $verbose = 0;
++if ($#ARGV >= 0 && $ARGV[0] eq "-v") {
++ $verbose = 1;
++ shift;
++}
++
++die "Format: ./scripts/sign-file [-v] <key> <x509> <module> [<dest>]\n"
++ if ($#ARGV != 2 && $#ARGV != 3);
++
++my $private_key = $ARGV[0];
++my $x509 = $ARGV[1];
++my $module = $ARGV[2];
++my $dest = ($#ARGV == 3) ? $ARGV[3] : $ARGV[2] . "~";
++
++die "Can't read private key\n" unless (-r $private_key);
++die "Can't read X.509 certificate\n" unless (-r $x509);
++die "Can't read module\n" unless (-r $module);
++
++#
++# Read the kernel configuration
++#
++my %config = (
++ CONFIG_MODULE_SIG_SHA512 => 1
++ );
++
++if (-r ".config") {
++ open(FD, "<.config") || die ".config";
++ while (<FD>) {
++ if ($_ =~ /^(CONFIG_.*)=[ym]/) {
++ $config{$1} = 1;
++ }
++ }
++ close(FD);
++}
+
+-scripts=`dirname $0`
++#
++# Function to read the contents of a file into a variable.
++#
++sub read_file($)
++{
++ my ($file) = @_;
++ my $contents;
++ my $len;
++
++ open(FD, "<$file") || die $file;
++ binmode FD;
++ my @st = stat(FD);
++ die $file if (!@st);
++ $len = read(FD, $contents, $st[7]) || die $file;
++ close(FD) || die $file;
++ die "$file: Wanted length ", $st[7], ", got ", $len, "\n"
++ if ($len != $st[7]);
++ return $contents;
++}
++
++###############################################################################
++#
++# First of all, we have to parse the X.509 certificate to find certain details
++# about it.
++#
++# We read the DER-encoded X509 certificate and parse it to extract the Subject
++# name and Subject Key Identifier. Theis provides the data we need to build
++# the certificate identifier.
++#
++# The signer's name part of the identifier is fabricated from the commonName,
++# the organizationName or the emailAddress components of the X.509 subject
++# name.
++#
++# The subject key ID is used to select which of that signer's certificates
++# we're intending to use to sign the module.
++#
++###############################################################################
++my $x509_certificate = read_file($x509);
+
+-CONFIG_MODULE_SIG_SHA512=y
+-if [ -r .config ]
+-then
+- . ./.config
+-fi
++my $UNIV = 0 << 6;
++my $APPL = 1 << 6;
++my $CONT = 2 << 6;
++my $PRIV = 3 << 6;
+
+-key="$1"
+-x509="$2"
+-keyid_script="$3"
+-mod="$4"
++my $CONS = 0x20;
+
+-if [ ! -r "$key" ]
+-then
+- echo "Can't read private key" >&2
+- exit 2
+-fi
++my $BOOLEAN = 0x01;
++my $INTEGER = 0x02;
++my $BIT_STRING = 0x03;
++my $OCTET_STRING = 0x04;
++my $NULL = 0x05;
++my $OBJ_ID = 0x06;
++my $UTF8String = 0x0c;
++my $SEQUENCE = 0x10;
++my $SET = 0x11;
++my $UTCTime = 0x17;
++my $GeneralizedTime = 0x18;
+
+-if [ ! -r "$x509" ]
+-then
+- echo "Can't read X.509 certificate" >&2
+- exit 2
+-fi
++my %OIDs = (
++ pack("CCC", 85, 4, 3) => "commonName",
++ pack("CCC", 85, 4, 6) => "countryName",
++ pack("CCC", 85, 4, 10) => "organizationName",
++ pack("CCC", 85, 4, 11) => "organizationUnitName",
++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
++ pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
++ pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
++ pack("CCC", 85, 29, 19) => "basicConstraints"
++);
++
++###############################################################################
++#
++# Extract an ASN.1 element from a string and return information about it.
++#
++###############################################################################
++sub asn1_extract($$@)
++{
++ my ($cursor, $expected_tag, $optional) = @_;
++
++ return [ -1 ]
++ if ($cursor->[1] == 0 && $optional);
++
++ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
++ if ($cursor->[1] < 2);
++
++ my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
++
++ if ($expected_tag != -1 && $tag != $expected_tag) {
++ return [ -1 ]
++ if ($optional);
++ die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
++ " not ", $expected_tag, ")\n";
++ }
++
++ $cursor->[0] += 2;
++ $cursor->[1] -= 2;
++
++ die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n"
++ if (($tag & 0x1f) == 0x1f);
++ die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
++ if ($len == 0x80);
++
++ if ($len > 0x80) {
++ my $l = $len - 0x80;
++ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
++ if ($cursor->[1] < $l);
++
++ if ($l == 0x1) {
++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
++ } elsif ($l = 0x2) {
++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
++ } elsif ($l = 0x3) {
++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
++ } elsif ($l = 0x4) {
++ $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
++ } else {
++ die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
++ }
++
++ $cursor->[0] += $l;
++ $cursor->[1] -= $l;
++ }
++
++ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
++ if ($cursor->[1] < $len);
++
++ my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
++ $cursor->[0] += $len;
++ $cursor->[1] -= $len;
++
++ return $ret;
++}
++
++###############################################################################
++#
++# Retrieve the data referred to by a cursor
++#
++###############################################################################
++sub asn1_retrieve($)
++{
++ my ($cursor) = @_;
++ my ($offset, $len, $data) = @$cursor;
++ return substr($$data, $offset, $len);
++}
++
++###############################################################################
++#
++# Roughly parse the X.509 certificate
++#
++###############################################################################
++my $cursor = [ 0, length($x509_certificate), \$x509_certificate ];
++
++my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
++my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
++my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
++my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
++my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
++my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
++my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
++my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
++
++my $subject_key_id = ();
++my $authority_key_id = ();
++
++#
++# Parse the extension list
++#
++if ($extension_list->[0] != -1) {
++ my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
++
++ while ($extensions->[1]->[1] > 0) {
++ my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
++ my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
++ my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
++ my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
++
++ my $raw_oid = asn1_retrieve($x_oid->[1]);
++ next if (!exists($OIDs{$raw_oid}));
++ my $x_type = $OIDs{$raw_oid};
++
++ my $raw_value = asn1_retrieve($x_val->[1]);
++
++ if ($x_type eq "subjectKeyIdentifier") {
++ my $vcursor = [ 0, length($raw_value), \$raw_value ];
++
++ $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
++ }
++ }
++}
++
++###############################################################################
++#
++# Determine what we're going to use as the signer's name. In order of
++# preference, take one of: commonName, organizationName or emailAddress.
++#
++###############################################################################
++my $org = "";
++my $cn = "";
++my $email = "";
++
++while ($subject->[1]->[1] > 0) {
++ my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
++ my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
++ my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
++ my $n_val = asn1_extract($attr->[1], -1);
++
++ my $raw_oid = asn1_retrieve($n_oid->[1]);
++ next if (!exists($OIDs{$raw_oid}));
++ my $n_type = $OIDs{$raw_oid};
++
++ my $raw_value = asn1_retrieve($n_val->[1]);
++
++ if ($n_type eq "organizationName") {
++ $org = $raw_value;
++ } elsif ($n_type eq "commonName") {
++ $cn = $raw_value;
++ } elsif ($n_type eq "emailAddress") {
++ $email = $raw_value;
++ }
++}
++
++my $signers_name = $email;
++
++if ($org && $cn) {
++ # Don't use the organizationName if the commonName repeats it
++ if (length($org) <= length($cn) &&
++ substr($cn, 0, length($org)) eq $org) {
++ $signers_name = $cn;
++ goto got_id_name;
++ }
++
++ # Or a signifcant chunk of it
++ if (length($org) >= 7 &&
++ length($cn) >= 7 &&
++ substr($cn, 0, 7) eq substr($org, 0, 7)) {
++ $signers_name = $cn;
++ goto got_id_name;
++ }
++
++ $signers_name = $org . ": " . $cn;
++} elsif ($org) {
++ $signers_name = $org;
++} elsif ($cn) {
++ $signers_name = $cn;
++}
++
++got_id_name:
++
++die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
++ if (!$subject_key_id);
++
++my $key_identifier = asn1_retrieve($subject_key_id->[1]);
++
++###############################################################################
++#
++# Create and attach the module signature
++#
++###############################################################################
+
+ #
+ # Signature parameters
+ #
+-algo=1 # Public-key crypto algorithm: RSA
+-hash= # Digest algorithm
+-id_type=1 # Identifier type: X.509
++my $algo = 1; # Public-key crypto algorithm: RSA
++my $hash = 0; # Digest algorithm
++my $id_type = 1; # Identifier type: X.509
+
+ #
+ # Digest the data
+ #
+-dgst=
+-if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ]
+-then
+- prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14"
+- dgst=-sha1
+- hash=2
+-elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ]
+-then
+- prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C"
+- dgst=-sha224
+- hash=7
+-elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ]
+-then
+- prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20"
+- dgst=-sha256
+- hash=4
+-elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ]
+-then
+- prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30"
+- dgst=-sha384
+- hash=5
+-elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ]
+-then
+- prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40"
+- dgst=-sha512
+- hash=6
+-else
+- echo "$0: Can't determine hash algorithm" >&2
+- exit 2
+-fi
+-
+-(
+-perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $?
+-openssl dgst $dgst -binary $mod || exit $?
+-) >$mod.dig || exit $?
++my ($dgst, $prologue) = ();
++if (exists $config{"CONFIG_MODULE_SIG_SHA1"}) {
++ $prologue = pack("C*",
++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
++ 0x2B, 0x0E, 0x03, 0x02, 0x1A,
++ 0x05, 0x00, 0x04, 0x14);
++ $dgst = "-sha1";
++ $hash = 2;
++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA224"}) {
++ $prologue = pack("C*",
++ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
++ 0x05, 0x00, 0x04, 0x1C);
++ $dgst = "-sha224";
++ $hash = 7;
++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA256"}) {
++ $prologue = pack("C*",
++ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
++ 0x05, 0x00, 0x04, 0x20);
++ $dgst = "-sha256";
++ $hash = 4;
++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA384"}) {
++ $prologue = pack("C*",
++ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
++ 0x05, 0x00, 0x04, 0x30);
++ $dgst = "-sha384";
++ $hash = 5;
++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA512"}) {
++ $prologue = pack("C*",
++ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
++ 0x05, 0x00, 0x04, 0x40);
++ $dgst = "-sha512";
++ $hash = 6;
++} else {
++ die "Can't determine hash algorithm";
++}
++
++#
++# Generate the digest and read from openssl's stdout
++#
++my $digest;
++$digest = readpipe("openssl dgst $dgst -binary $module") || die "openssl dgst";
+
+ #
+ # Generate the binary signature, which will be just the integer that comprises
+ # the signature with no metadata attached.
+ #
+-openssl rsautl -sign -inkey $key -keyform PEM -in $mod.dig -out $mod.sig || exit $?
+-siglen=`stat -c %s $mod.sig`
++my $pid;
++$pid = open2(*read_from, *write_to,
++ "openssl rsautl -sign -inkey $private_key -keyform PEM") ||
++ die "openssl rsautl";
++binmode write_to;
++print write_to $prologue . $digest || die "pipe to openssl rsautl";
++close(write_to) || die "pipe to openssl rsautl";
++
++binmode read_from;
++my $signature;
++read(read_from, $signature, 4096) || die "pipe from openssl rsautl";
++close(read_from) || die "pipe from openssl rsautl";
++$signature = pack("n", length($signature)) . $signature,
+
+-SIGNER="`perl $keyid_script $x509 signer-name`"
+-KEYID="`perl $keyid_script $x509 keyid`"
+-keyidlen=$(echo -n "$KEYID" | wc -c)
+-signerlen=$(echo -n "$SIGNER" | wc -c)
++waitpid($pid, 0) || die;
++die "openssl rsautl died: $?" if ($? >> 8);
+
+ #
+ # Build the signed binary
+ #
+-(
+- cat $mod || exit $?
+- echo '~Module signature appended~' || exit $?
+- echo -n "$SIGNER" || exit $?
+- echo -n "$KEYID" || exit $?
++my $unsigned_module = read_file($module);
++
++my $magic_number = "~Module signature appended~\n";
++
++my $info = pack("CCCCCxxxN",
++ $algo, $hash, $id_type,
++ length($signers_name),
++ length($key_identifier),
++ length($signature));
+
+- # Preface each signature integer with a 2-byte BE length
+- perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $?
+- cat $mod.sig || exit $?
++if ($verbose) {
++ print "Size of unsigned module: ", length($unsigned_module), "\n";
++ print "Size of magic number : ", length($magic_number), "\n";
++ print "Size of signer's name : ", length($signers_name), "\n";
++ print "Size of key identifier : ", length($key_identifier), "\n";
++ print "Size of signature : ", length($signature), "\n";
++ print "Size of informaton : ", length($info), "\n";
++ print "Signer's name : '", $signers_name, "'\n";
++ print "Digest : $dgst\n";
++}
+
+- # Generate the information block
+- perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $?
+-) >$mod~ || exit $?
++open(FD, ">$dest") || die $dest;
++binmode FD;
++print FD
++ $unsigned_module,
++ $magic_number,
++ $signers_name,
++ $key_identifier,
++ $signature,
++ $info
++ ;
++close FD || die $dest;
+
+-mv $mod~ $mod || exit $?
++if ($#ARGV != 3) {
++ rename($dest, $module) || die $module;
++}
+diff --git a/scripts/x509keyid b/scripts/x509keyid
+deleted file mode 100755
+index 4241ec6..0000000
+--- a/scripts/x509keyid
++++ /dev/null
+@@ -1,268 +0,0 @@
+-#!/usr/bin/perl -w
+-#
+-# Generate an identifier from an X.509 certificate that can be placed in a
+-# module signature to indentify the key to use.
+-#
+-# Format:
+-#
+-# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id>
+-#
+-# We read the DER-encoded X509 certificate and parse it to extract the Subject
+-# name and Subject Key Identifier. The provide the data we need to build the
+-# certificate identifier.
+-#
+-# The signer's name part of the identifier is fabricated from the commonName,
+-# the organizationName or the emailAddress components of the X.509 subject
+-# name and written to the second named file.
+-#
+-# The subject key ID to select which of that signer's certificates we're
+-# intending to use to sign the module is written to the third named file.
+-#
+-use strict;
+-
+-my $raw_data;
+-
+-die "Need a filename [keyid|signer-name]\n" if ($#ARGV != 1);
+-
+-my $src = $ARGV[0];
+-
+-open(FD, "<$src") || die $src;
+-binmode FD;
+-my @st = stat(FD);
+-die $src if (!@st);
+-read(FD, $raw_data, $st[7]) || die $src;
+-close(FD);
+-
+-my $UNIV = 0 << 6;
+-my $APPL = 1 << 6;
+-my $CONT = 2 << 6;
+-my $PRIV = 3 << 6;
+-
+-my $CONS = 0x20;
+-
+-my $BOOLEAN = 0x01;
+-my $INTEGER = 0x02;
+-my $BIT_STRING = 0x03;
+-my $OCTET_STRING = 0x04;
+-my $NULL = 0x05;
+-my $OBJ_ID = 0x06;
+-my $UTF8String = 0x0c;
+-my $SEQUENCE = 0x10;
+-my $SET = 0x11;
+-my $UTCTime = 0x17;
+-my $GeneralizedTime = 0x18;
+-
+-my %OIDs = (
+- pack("CCC", 85, 4, 3) => "commonName",
+- pack("CCC", 85, 4, 6) => "countryName",
+- pack("CCC", 85, 4, 10) => "organizationName",
+- pack("CCC", 85, 4, 11) => "organizationUnitName",
+- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
+- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
+- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
+- pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
+- pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
+- pack("CCC", 85, 29, 19) => "basicConstraints"
+-);
+-
+-###############################################################################
+-#
+-# Extract an ASN.1 element from a string and return information about it.
+-#
+-###############################################################################
+-sub asn1_extract($$@)
+-{
+- my ($cursor, $expected_tag, $optional) = @_;
+-
+- return [ -1 ]
+- if ($cursor->[1] == 0 && $optional);
+-
+- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
+- if ($cursor->[1] < 2);
+-
+- my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
+-
+- if ($expected_tag != -1 && $tag != $expected_tag) {
+- return [ -1 ]
+- if ($optional);
+- die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
+- " not ", $expected_tag, ")\n";
+- }
+-
+- $cursor->[0] += 2;
+- $cursor->[1] -= 2;
+-
+- die $src, ": ", $cursor->[0], ": ASN.1 long tag\n"
+- if (($tag & 0x1f) == 0x1f);
+- die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
+- if ($len == 0x80);
+-
+- if ($len > 0x80) {
+- my $l = $len - 0x80;
+- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
+- if ($cursor->[1] < $l);
+-
+- if ($l == 0x1) {
+- $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
+- } elsif ($l = 0x2) {
+- $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
+- } elsif ($l = 0x3) {
+- $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
+- $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
+- } elsif ($l = 0x4) {
+- $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
+- } else {
+- die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
+- }
+-
+- $cursor->[0] += $l;
+- $cursor->[1] -= $l;
+- }
+-
+- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
+- if ($cursor->[1] < $len);
+-
+- my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
+- $cursor->[0] += $len;
+- $cursor->[1] -= $len;
+-
+- return $ret;
+-}
+-
+-###############################################################################
+-#
+-# Retrieve the data referred to by a cursor
+-#
+-###############################################################################
+-sub asn1_retrieve($)
+-{
+- my ($cursor) = @_;
+- my ($offset, $len, $data) = @$cursor;
+- return substr($$data, $offset, $len);
+-}
+-
+-###############################################################################
+-#
+-# Roughly parse the X.509 certificate
+-#
+-###############################################################################
+-my $cursor = [ 0, length($raw_data), \$raw_data ];
+-
+-my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
+-my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
+-my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
+-my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
+-my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+-my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+-my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+-my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+-my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+-my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
+-my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
+-my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
+-
+-my $subject_key_id = ();
+-my $authority_key_id = ();
+-
+-#
+-# Parse the extension list
+-#
+-if ($extension_list->[0] != -1) {
+- my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
+-
+- while ($extensions->[1]->[1] > 0) {
+- my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
+- my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
+- my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
+- my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
+-
+- my $raw_oid = asn1_retrieve($x_oid->[1]);
+- next if (!exists($OIDs{$raw_oid}));
+- my $x_type = $OIDs{$raw_oid};
+-
+- my $raw_value = asn1_retrieve($x_val->[1]);
+-
+- if ($x_type eq "subjectKeyIdentifier") {
+- my $vcursor = [ 0, length($raw_value), \$raw_value ];
+-
+- $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
+- }
+- }
+-}
+-
+-###############################################################################
+-#
+-# Determine what we're going to use as the signer's name. In order of
+-# preference, take one of: commonName, organizationName or emailAddress.
+-#
+-###############################################################################
+-my $org = "";
+-my $cn = "";
+-my $email = "";
+-
+-while ($subject->[1]->[1] > 0) {
+- my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
+- my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
+- my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
+- my $n_val = asn1_extract($attr->[1], -1);
+-
+- my $raw_oid = asn1_retrieve($n_oid->[1]);
+- next if (!exists($OIDs{$raw_oid}));
+- my $n_type = $OIDs{$raw_oid};
+-
+- my $raw_value = asn1_retrieve($n_val->[1]);
+-
+- if ($n_type eq "organizationName") {
+- $org = $raw_value;
+- } elsif ($n_type eq "commonName") {
+- $cn = $raw_value;
+- } elsif ($n_type eq "emailAddress") {
+- $email = $raw_value;
+- }
+-}
+-
+-my $id_name = $email;
+-
+-if ($org && $cn) {
+- # Don't use the organizationName if the commonName repeats it
+- if (length($org) <= length($cn) &&
+- substr($cn, 0, length($org)) eq $org) {
+- $id_name = $cn;
+- goto got_id_name;
+- }
+-
+- # Or a signifcant chunk of it
+- if (length($org) >= 7 &&
+- length($cn) >= 7 &&
+- substr($cn, 0, 7) eq substr($org, 0, 7)) {
+- $id_name = $cn;
+- goto got_id_name;
+- }
+-
+- $id_name = $org . ": " . $cn;
+-} elsif ($org) {
+- $id_name = $org;
+-} elsif ($cn) {
+- $id_name = $cn;
+-}
+-
+-got_id_name:
+-
+-###############################################################################
+-#
+-# Output the signer's name and the key identifier that we're going to include
+-# in module signatures.
+-#
+-###############################################################################
+-die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
+- if (!$subject_key_id);
+-
+-my $id_key_id = asn1_retrieve($subject_key_id->[1]);
+-
+-if ($ARGV[1] eq "signer-name") {
+- print $id_name;
+-} elsif ($ARGV[1] eq "keyid") {
+- print $id_key_id;
+-} else {
+- die "Unknown arg";
+-}
+--
+1.7.12.1
+
+
+From 02c76d9df8ff5387b9131799750895475f87c351 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 19 Oct 2012 23:56:45 +0100
+Subject: [PATCH 36/37] MODSIGN: Cleanup .gitignore
+
+The module build process no longer creates intermediate files for module
+signing, so remove them from .gitignore.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ .gitignore | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/.gitignore b/.gitignore
+index 0f2f40f..92bd0e4 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -14,10 +14,6 @@
+ *.o.*
+ *.a
+ *.s
+-*.ko.unsigned
+-*.ko.stripped
+-*.ko.stripped.dig
+-*.ko.stripped.sig
+ *.ko
+ *.so
+ *.so.dbg
+@@ -95,6 +91,4 @@ GTAGS
+ extra_certificates
+ signing_key.priv
+ signing_key.x509
+-signing_key.x509.keyid
+-signing_key.x509.signer
+ x509.genkey
+--
+1.7.12.1
+
+
+From fd08dfdc1a0022b48b7a5d4599cb4d46bf099882 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Sat, 20 Oct 2012 01:19:29 +0100
+Subject: [PATCH 37/37] MODSIGN: Move the magic string to the end of a module
+ and eliminate the search
+
+Emit the magic string that indicates a module has a signature after the
+signature data instead of before it. This allows module_sig_check() to
+be made simpler and faster by the elimination of the search for the
+magic string. Instead we just need to do a single memcmp().
+
+This works because at the end of the signature data there is the
+fixed-length signature information block. This block then falls
+immediately prior to the magic number.
+
+From the contents of the information block, it is trivial to calculate
+the size of the signature data and thus the size of the actual module
+data.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ kernel/module-internal.h | 3 +--
+ kernel/module.c | 26 +++++++++-----------------
+ kernel/module_signing.c | 24 +++++++++++++++---------
+ scripts/sign-file | 6 +++---
+ 4 files changed, 28 insertions(+), 31 deletions(-)
+
+diff --git a/kernel/module-internal.h b/kernel/module-internal.h
+index 6114a13..24f9247 100644
+--- a/kernel/module-internal.h
++++ b/kernel/module-internal.h
+@@ -11,5 +11,4 @@
+
+ extern struct key *modsign_keyring;
+
+-extern int mod_verify_sig(const void *mod, unsigned long modlen,
+- const void *sig, unsigned long siglen);
++extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
+diff --git a/kernel/module.c b/kernel/module.c
+index 3e8b1a7..0cfcccc 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2441,25 +2441,17 @@ static inline void kmemleak_load_module(const struct module *mod,
+
+ #ifdef CONFIG_MODULE_SIG
+ static int module_sig_check(struct load_info *info,
+- const void *mod, unsigned long *len)
++ const void *mod, unsigned long *_len)
+ {
+ int err = -ENOKEY;
+- const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+- const void *p = mod, *end = mod + *len;
+-
+- /* Poor man's memmem. */
+- while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
+- if (p + markerlen > end)
+- break;
+-
+- if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
+- const void *sig = p + markerlen;
+- /* Truncate module up to signature. */
+- *len = p - mod;
+- err = mod_verify_sig(mod, *len, sig, end - sig);
+- break;
+- }
+- p++;
++ unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
++ unsigned long len = *_len;
++
++ if (len > markerlen &&
++ memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
++ /* We truncate the module to discard the signature */
++ *_len -= markerlen;
++ err = mod_verify_sig(mod, _len);
+ }
+
+ if (!err) {
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index 6b09f69..d492a23 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -183,27 +183,33 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
+ /*
+ * Verify the signature on a module.
+ */
+-int mod_verify_sig(const void *mod, unsigned long modlen,
+- const void *sig, unsigned long siglen)
++int mod_verify_sig(const void *mod, unsigned long *_modlen)
+ {
+ struct public_key_signature *pks;
+ struct module_signature ms;
+ struct key *key;
+- size_t sig_len;
++ const void *sig;
++ size_t modlen = *_modlen, sig_len;
+ int ret;
+
+- pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen);
++ pr_devel("==>%s(,%lu)\n", __func__, modlen);
+
+- if (siglen <= sizeof(ms))
++ if (modlen <= sizeof(ms))
+ return -EBADMSG;
+
+- memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms));
+- siglen -= sizeof(ms);
++ memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
++ modlen -= sizeof(ms);
+
+ sig_len = be32_to_cpu(ms.sig_len);
+- if (sig_len >= siglen ||
+- siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len)
++ if (sig_len >= modlen)
+ return -EBADMSG;
++ modlen -= sig_len;
++ if ((size_t)ms.signer_len + ms.key_id_len >= modlen)
++ return -EBADMSG;
++ modlen -= (size_t)ms.signer_len + ms.key_id_len;
++
++ *_modlen = modlen;
++ sig = mod + modlen;
+
+ /* For the moment, only support RSA and X.509 identifiers */
+ if (ms.algo != PKEY_ALGO_RSA ||
+diff --git a/scripts/sign-file b/scripts/sign-file
+index d37d130..87ca59d 100755
+--- a/scripts/sign-file
++++ b/scripts/sign-file
+@@ -403,11 +403,11 @@ my $info = pack("CCCCCxxxN",
+
+ if ($verbose) {
+ print "Size of unsigned module: ", length($unsigned_module), "\n";
+- print "Size of magic number : ", length($magic_number), "\n";
+ print "Size of signer's name : ", length($signers_name), "\n";
+ print "Size of key identifier : ", length($key_identifier), "\n";
+ print "Size of signature : ", length($signature), "\n";
+ print "Size of informaton : ", length($info), "\n";
++ print "Size of magic number : ", length($magic_number), "\n";
+ print "Signer's name : '", $signers_name, "'\n";
+ print "Digest : $dgst\n";
+ }
+@@ -416,11 +416,11 @@ open(FD, ">$dest") || die $dest;
+ binmode FD;
+ print FD
+ $unsigned_module,
+- $magic_number,
+ $signers_name,
+ $key_identifier,
+ $signature,
+- $info
++ $info,
++ $magic_number
+ ;
+ close FD || die $dest;
+
+--
+1.7.12.1
+
OpenPOWER on IntegriCloud