summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Oliva <lxoliva@fsfla.org>2012-11-05 09:21:20 +0000
committerAlexandre Oliva <lxoliva@fsfla.org>2012-11-05 09:21:20 +0000
commit2804429a1593bc8782054bdf07b295cd75f30bea (patch)
tree8fa80c7cf93dbfe07849ff1563d55d5e4f8e943d
parent74959ab527be63474583cf16cb3d4f1b087969fe (diff)
downloadlinux-libre-raptor-2804429a1593bc8782054bdf07b295cd75f30bea.tar.gz
linux-libre-raptor-2804429a1593bc8782054bdf07b295cd75f30bea.zip
3.6.5-2.fc18.gnu
-rw-r--r--freed-ora/current/f18/config-x86-generic2
-rw-r--r--freed-ora/current/f18/kernel.spec26
-rwxr-xr-xfreed-ora/current/f18/mod-extra-sign.sh2
-rw-r--r--freed-ora/current/f18/modsign-post-KS-jwb.patch9240
-rw-r--r--freed-ora/current/f18/modsign-upstream-3.7.patch10963
-rw-r--r--freed-ora/current/f18/secure-boot-20121026.patch (renamed from freed-ora/current/f18/secure-boot-20120924.patch)691
6 files changed, 11686 insertions, 9238 deletions
diff --git a/freed-ora/current/f18/config-x86-generic b/freed-ora/current/f18/config-x86-generic
index 09d63d401..b26f42d9f 100644
--- a/freed-ora/current/f18/config-x86-generic
+++ b/freed-ora/current/f18/config-x86-generic
@@ -430,3 +430,5 @@ CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_SHA1 is not set
CONFIG_MODULE_SIG_SHA256=y
# CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_MODULE_SIG_BLACKLIST=y
+CONFIG_MODULE_SIG_UEFI=y
diff --git a/freed-ora/current/f18/kernel.spec b/freed-ora/current/f18/kernel.spec
index 7b6a87e7b..7a1eb3376 100644
--- a/freed-ora/current/f18/kernel.spec
+++ b/freed-ora/current/f18/kernel.spec
@@ -62,7 +62,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be appended after the rcX and
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
#
-%global baserelease 1
+%global baserelease 2
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@@ -741,10 +741,11 @@ Patch700: linux-2.6-e1000-ich9-montevina.patch
Patch800: linux-2.6-crash-driver.patch
# crypto/
-Patch900: modsign-post-KS-jwb.patch
+Patch900: modsign-upstream-3.7.patch
+Patch901: modsign-post-KS-jwb.patch
# secure boot
-Patch1000: secure-boot-20120924.patch
+Patch1000: secure-boot-20121026.patch
# Improve PCI support on UEFI
Patch1100: handle-efi-roms.patch
@@ -1558,10 +1559,11 @@ ApplyPatch linux-2.6-crash-driver.patch
ApplyPatch linux-2.6-e1000-ich9-montevina.patch
# crypto/
+ApplyPatch modsign-upstream-3.7.patch
ApplyPatch modsign-post-KS-jwb.patch
# secure boot
-ApplyPatch secure-boot-20120924.patch
+ApplyPatch secure-boot-20121026.patch
# Improved PCI support for UEFI
ApplyPatch handle-efi-roms.patch
@@ -1685,10 +1687,6 @@ find . \( -name "*.orig" -o -name "*~" \) -exec rm -f {} \; >/dev/null
# remove unnecessary SCM files
find . -name .gitignore -exec rm -f {} \; >/dev/null
-%if %{signmodules}
-cp %{SOURCE11} .
-%endif
-
cd ..
###
@@ -1758,6 +1756,12 @@ BuildKernel() {
make -s mrproper
cp configs/$Config .config
+ %if %{signmodules}
+ cp %{SOURCE11} .
+ %endif
+
+ chmod +x scripts/sign-file
+
Arch=`head -1 .config | cut -b 3-`
echo USING ARCH=$Arch
@@ -2501,10 +2505,14 @@ fi
# ||----w |
# || ||
%changelog
+* Wed Oct 31 2012 Josh Boyer <jwboyer@redhat.com> - 3.6.5-2
+- Update modsign to what is currently in 3.7-rc2
+- Update secure boot support for UEFI cert importing.
+
* Wed Oct 31 2012 Alexandre Oliva <lxoliva@fsfla.org> -libre
- GNU Linux-libre 3.6.5-gnu.
-* Wed Oct 30 2012 Josh Boyer <jwboyer@redhat.com> - 3.6.5-1
+* Wed Oct 31 2012 Josh Boyer <jwboyer@redhat.com> - 3.6.5-1
- Linux v3.6.5
- CVE-2012-4565 net: divide by zero in tcp algorithm illinois (rhbz 871848 871923)
diff --git a/freed-ora/current/f18/mod-extra-sign.sh b/freed-ora/current/f18/mod-extra-sign.sh
index a4b2c8cf7..9b24a4098 100755
--- a/freed-ora/current/f18/mod-extra-sign.sh
+++ b/freed-ora/current/f18/mod-extra-sign.sh
@@ -21,7 +21,7 @@ do
dir=`dirname $mod`
file=`basename $mod`
- sh ./scripts/sign-file ${MODSECKEY} ${MODPUBKEY} ${dir}/${file} \
+ ./scripts/sign-file ${MODSECKEY} ${MODPUBKEY} ${dir}/${file} \
${dir}/${file}.signed
mv ${dir}/${file}.signed ${dir}/${file}
rm -f ${dir}/${file}.{sig,dig}
diff --git a/freed-ora/current/f18/modsign-post-KS-jwb.patch b/freed-ora/current/f18/modsign-post-KS-jwb.patch
index ec61f3472..ba942170f 100644
--- a/freed-ora/current/f18/modsign-post-KS-jwb.patch
+++ b/freed-ora/current/f18/modsign-post-KS-jwb.patch
@@ -1,8800 +1,7 @@
-From 2cdfd353ac1a5b9f62398ef59b4a08b5b55ac089 Mon Sep 17 00:00:00 2001
-From: Rusty Russell <rusty@rustcorp.com.au>
-Date: Wed, 5 Sep 2012 12:32:17 +0930
-Subject: [PATCH 01/26] 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 (and taint) or
-fail with unsigned modules.
-
-Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
----
- Documentation/kernel-parameters.txt | 6 +++
- include/linux/module.h | 8 ++++
- init/Kconfig | 14 ++++++
- kernel/module.c | 88 ++++++++++++++++++++++++++++++++++++-
- 4 files changed, 115 insertions(+), 1 deletion(-)
-
-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/module.c b/kernel/module.c
-index 4edbd9c..5c6f65c 100644
---- a/kernel/module.c
-+++ b/kernel/module.c
-@@ -102,6 +102,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 +173,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 +2437,45 @@ 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 = 0;
-+ const unsigned long markerlen = strlen(MODULE_SIG_STRING);
-+ 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,
-+ &info->sig_ok);
-+ break;
-+ }
-+ p++;
-+ }
-+
-+ /* Not having a signature is only an error if we're strict. */
-+ if (!err && !info->sig_ok && sig_enforce)
-+ err = -EKEYREJECTED;
-+ 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 +2495,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
-@@ -2886,6 +2966,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)
---
-1.7.11.4
-
-
-From d4f65b5d2497b2fd9c45f06b71deb4ab084a5b66 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/26] 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>
----
- 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.11.4
-
-
-From a3f7dff6cbc2eb6be871a58fef34cacf7f78abf8 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/26] 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>
----
- 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.11.4
-
-
-From 79e4c942f35117b405402acf0f075ff79260e546 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/26] 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>
----
- 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.11.4
-
-
-From 2fb78e0d337ac41f2cddad18fc5c34374e5298ab 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/26] 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>
----
- 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.11.4
-
-
-From d28ffd9e0c8987e5af59ae38bb48779b0d221f00 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/26] 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>
----
- 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.11.4
-
-
-From 171881bb3693176db4d0f85f78066fcdb6266525 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/26] 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>
----
- 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.11.4
-
-
-From 8e45e274bb3f8bb90306e0102a2c48ea1ef179fb 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/26] 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>
----
- 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.11.4
-
-
-From 941e72448fc68f41a56798112a6f20df6bcd0ad0 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/26] 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>
----
- 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.11.4
-
-
-From ca876ff8fde3c6febb8a8578ca0e1608576071bf 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/26] 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>
----
- 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.11.4
-
-
-From e179a9b04469ea018a8fdb53f11c57222ba540a0 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/26] 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>
----
- 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.11.4
-
-
-From d412c256ea6170b6aeceb9f1eb1737d991473634 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/26] 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>
----
- 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.11.4
-
-
-From 098335ed1edc5ec7ae7a346416654e12bb9bcd65 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/26] 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>
----
- 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.11.4
-
-
-From 3ddb8a2f1fe420777491641d39328741d9a28565 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/26] 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>
----
- 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 af6c7f8..66cc885 100644
---- a/init/Kconfig
-+++ b/init/Kconfig
-@@ -1612,4 +1612,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.11.4
-
-
-From 8ea3f94cc16a23e3edbebf12f4223e654eb8219d 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/26] 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>
----
- 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.11.4
-
-
-From f055a9091c35be0171d39ca8e76bb4677d89eef1 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/26] 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>
----
- 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.11.4
-
-
-From 3d816cdad8cdd5412ecc8f539bb09daef52ba361 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/26] 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>
----
- 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.11.4
-
-
-From 955fc6ec995f6bec6c487eb46027e108e240ebe3 Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:25 +0100
-Subject: [PATCH 18/26] MOD: Fix Rusty's module_sig_check()
-
-Make the following fixes to Rusty's module_sig_check() function:
-
- (1) mod_verify_sig() is not defined, resulting in a compilation error and
- thereby breaking git bisect, so provide a dummy that returns an error.
-
- (2) Using strlen() on a static string is a waste of resources. Further, you
- may end up with two copies of the string emitted.
-
- (3) Doing a memchr() of the bytes beyond the last position that the marker
- can be in is a waste of resources.
-
-While we're at it, push responsibility for the return value entirely off to
-mod_verify_sig() if we find a signature.
-
-Signed-off-by: David Howells <dhowells@redhat.com>
----
- kernel/Makefile | 1 +
- kernel/module-internal.h | 14 ++++++++++++++
- kernel/module.c | 41 +++++++++++++++++++++++------------------
- kernel/module_signing.c | 23 +++++++++++++++++++++++
- 4 files changed, 61 insertions(+), 18 deletions(-)
- create mode 100644 kernel/module-internal.h
- create mode 100644 kernel/module_signing.c
-
-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..14da0ea
---- /dev/null
-+++ b/kernel/module-internal.h
-@@ -0,0 +1,14 @@
-+/* 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,
-+ bool *_sig_ok);
-diff --git a/kernel/module.c b/kernel/module.c
-index 5c6f65c..ab69599 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>
-@@ -2438,34 +2439,38 @@ static inline void kmemleak_load_module(const struct module *mod,
- #endif
-
- #ifdef CONFIG_MODULE_SIG
-+
- static int module_sig_check(struct load_info *info,
- const void *mod, unsigned long *len)
- {
-+ static const char module_sig_string[] = MODULE_SIG_STRING;
- int err = 0;
-- const unsigned long markerlen = strlen(MODULE_SIG_STRING);
-- 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,
-- &info->sig_ok);
-- break;
-- }
-- p++;
-+ const unsigned long markerlen = sizeof(module_sig_string) - 1;
-+ const void *p = mod, *end = mod + *len, *sig;
-+ const void *limit = end - markerlen - 1;
-+
-+ if (markerlen < *len) {
-+ /* Poor man's memmem. */
-+ do {
-+ p = memchr(p, MODULE_SIG_STRING[0], limit - p);
-+ if (!p)
-+ break;
-+ if (memcmp(p, module_sig_string, markerlen) != 0)
-+ continue;
-+ goto found_marker;
-+ } while (++p < limit);
- }
-
- /* Not having a signature is only an error if we're strict. */
- if (!err && !info->sig_ok && sig_enforce)
- err = -EKEYREJECTED;
- return err;
-+
-+found_marker:
-+ sig = p + markerlen;
-+ /* Truncate module up to signature. */
-+ *len = p - mod;
-+ return mod_verify_sig(mod, *len, sig, end - sig, &info->sig_ok);
- }
- #else /* !CONFIG_MODULE_SIG */
- static int module_sig_check(struct load_info *info,
-diff --git a/kernel/module_signing.c b/kernel/module_signing.c
-new file mode 100644
-index 0000000..0af10a5
---- /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 "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,
-+ bool *_sig_ok)
-+{
-+ return -EKEYREJECTED;
-+}
---
-1.7.11.4
-
-
-From 4c31831859550149cdba65a37d72416c87dbbef6 Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:25 +0100
-Subject: [PATCH 19/26] 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>
----
- .gitignore | 13 +++++++++++++
- Makefile | 1 +
- 2 files changed, 14 insertions(+)
-
-diff --git a/.gitignore b/.gitignore
-index 57af07c..9736304 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,12 @@ GTAGS
- *.orig
- *~
- \#*#
-+
-+#
-+# Leavings from module signing
-+#
-+extra_certificates
-+signing_key.priv
-+signing_key.x509
-+signing_key.x509.keyid
-+signing_key.x509.signer
-diff --git a/Makefile b/Makefile
-index 371ce88..644048d 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.11.4
-
-
-From 6977e69eef4379f34a2ad264856d74ac292284df Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:25 +0100
-Subject: [PATCH 20/26] 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>
----
- 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.11.4
-
-
-From 60378703cf88ed221ee602727c37ae241565d44a Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:25 +0100
-Subject: [PATCH 21/26] 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>
----
- kernel/Makefile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 49 insertions(+)
-
-diff --git a/kernel/Makefile b/kernel/Makefile
-index 08ba8a6..83f1565 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 = Magarathea"
-+ @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.11.4
-
-
-From 798049d9df83c8fd87fd5ddb97a77054558f4361 Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:25 +0100
-Subject: [PATCH 22/26] 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>
----
- kernel/Makefile | 11 ++++-
- kernel/modsign_pubkey.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++
- kernel/module-internal.h | 2 +
- 3 files changed, 123 insertions(+), 2 deletions(-)
- create mode 100644 kernel/modsign_pubkey.c
-
-diff --git a/kernel/Makefile b/kernel/Makefile
-index 83f1565..63f8386 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..f504d9f
---- /dev/null
-+++ b/kernel/modsign_pubkey.c
-@@ -0,0 +1,112 @@
-+/* 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",
-+ 0, 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 14da0ea..648f481 100644
---- a/kernel/module-internal.h
-+++ b/kernel/module-internal.h
-@@ -9,6 +9,8 @@
- * 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,
- bool *_sig_ok);
---
-1.7.11.4
-
-
-From dcac300c703bc9a237deab7c7f0301f3803a3a9a Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:26 +0100
-Subject: [PATCH 23/26] 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>
----
- init/Kconfig | 8 ++
- kernel/module_signing.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 230 insertions(+), 1 deletion(-)
-
-diff --git a/init/Kconfig b/init/Kconfig
-index 00d4579..63fcbeb 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 CONFIG_KEYS
-+ select CONFIG_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 0af10a5..83eb505 100644
---- a/kernel/module_signing.c
-+++ b/kernel/module_signing.c
-@@ -10,14 +10,235 @@
- */
-
- #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);
-+ 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,
- bool *_sig_ok)
- {
-- return -EKEYREJECTED;
-+ 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);
-+
-+ if (ret == 0)
-+ *_sig_ok = true;
-+
-+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.11.4
-
-
-From 89fbf1de73ed1ef29a3943d9f3bcf69a433191da Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 17:13:26 +0100
-Subject: [PATCH 24/26] 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>
----
- 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.11.4
-
-
-From 007c8fc3412f0a55cd3a32c5e42236703a17d1c1 Mon Sep 17 00:00:00 2001
+From f1fa90d02f50078a89da602d73dc9ab7743439ba Mon Sep 17 00:00:00 2001
From: Josh Boyer <jwboyer@redhat.com>
Date: Mon, 24 Sep 2012 10:46:36 -0400
-Subject: [PATCH 25/26] MODSIGN: Add modules_sign make target
+Subject: [PATCH 2/2] MODSIGN: Add modules_sign make target
If CONFIG_MODULE_SIG is set, and 'make modules_sign' is called then this
patch will cause the modules to get a signature installed. The make target
@@ -8839,18 +46,16 @@ packaging tools (such as rpmbuild) and initramfs composition tools.
Based heavily on work by: David Howells <dhowells@redhat.com>
Signed-off-by: Josh Boyer <jwboyer@redhat.com>
---
- Makefile | 6 +++
- scripts/Makefile.modsign | 72 +++++++++++++++++++++++++++++
- scripts/sign-file | 115 +++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 193 insertions(+)
+ Makefile | 6 ++++++
+ scripts/Makefile.modsign | 32 ++++++++++++++++++++++++++++++++
+ 2 files changed, 38 insertions(+)
create mode 100644 scripts/Makefile.modsign
- create mode 100644 scripts/sign-file
diff --git a/Makefile b/Makefile
-index 644048d..4479147 100644
+index 89a2e2c..ac04c11 100644
--- a/Makefile
+++ b/Makefile
-@@ -965,6 +965,12 @@ _modinst_post: _modinst_
+@@ -981,6 +981,12 @@ _modinst_post: _modinst_
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst
$(call cmd,depmod)
@@ -8865,10 +70,10 @@ index 644048d..4479147 100644
# Modules not configured
diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign
new file mode 100644
-index 0000000..17326bc
+index 0000000..670d5dc
--- /dev/null
+++ b/scripts/Makefile.modsign
-@@ -0,0 +1,72 @@
+@@ -0,0 +1,32 @@
+# ==========================================================================
+# Signing modules
+# ==========================================================================
@@ -8885,48 +90,8 @@ index 0000000..17326bc
+__modsign: $(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
-+
-+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 = SIGN [M] $(2)/$(notdir $@)
-+ cmd_sign_ko = \
-+ sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) \
-+ $(2)/$(notdir $@) $(2)/$(notdir $@).signed && \
-+ mv $(2)/$(notdir $@).signed $(2)/$(notdir $@) && \
-+ rm -rf $(2)/$(notdir $@).{dig,sig}
-+else
-+KEYRING_DEP :=
-+quiet_cmd_sign_ko = NO SIGN [M] $@
-+ cmd_sign_ko = \
-+ true
-+endif
++ cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@)
+
+# Modules built outside the kernel source tree go into extra by default
+INSTALL_MOD_DIR ?= extra
@@ -8934,394 +99,13 @@ index 0000000..17326bc
+
+modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
+
-+$(modules): $(KEYRING_DEP)
++$(modules):
+ $(call cmd,sign_ko,$(MODLIB)/$(modinst_dir))
+
+# Declare the contents of the .PHONY variable as phony. We keep that
+# # information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
-diff --git a/scripts/sign-file b/scripts/sign-file
-new file mode 100644
-index 0000000..1a472bb
---- /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
-+ source ./.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.11.4
-
-
-From 33c6737b352ec10a7e0d7b053fbb084c0b7a9d36 Mon Sep 17 00:00:00 2001
-From: David Howells <dhowells@redhat.com>
-Date: Mon, 24 Sep 2012 20:51:59 +0100
-Subject: [PATCH 26/26] MODSIGN: Extend the policy on signature check failure
-
-Extend the policy on handling various sorts of signature check failure such as
-not having the requisite key available or being in FIPS mode.
-
-If the key specified is not known (ENOKEY) permit the module to be loaded in
-non-enforcing mode, otherwise reject it.
-
-If in FIPS mode, any loading failure shall cause a panic.
-
-Also print a warning if we try and fail to find a module signing key:
-
- Request for unknown module key 'Magrathea: Glacier signing key: 5dd0839552bd6af498253f8af1e65da3472941c6' err -11
-
-This contains the identity field and the key ID from the signature as well as
-the error code. The error codes are the raw return from keyring_search() and
-may be translated to -ENOKEY.
-
-Signed-off-by: David Howells <dhowells@redhat.com>
----
- kernel/Makefile | 2 +-
- kernel/module.c | 9 ++++++++-
- kernel/module_signing.c | 3 +++
- 3 files changed, 12 insertions(+), 2 deletions(-)
-
-diff --git a/kernel/Makefile b/kernel/Makefile
-index 63f8386..111a845 100644
---- a/kernel/Makefile
-+++ b/kernel/Makefile
-@@ -177,7 +177,7 @@ x509.genkey:
- @echo >>x509.genkey "x509_extensions = myexts"
- @echo >>x509.genkey
- @echo >>x509.genkey "[ req_distinguished_name ]"
-- @echo >>x509.genkey "O = Magarathea"
-+ @echo >>x509.genkey "O = Magrathea"
- @echo >>x509.genkey "CN = Glacier signing key"
- @echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2"
- @echo >>x509.genkey
-diff --git a/kernel/module.c b/kernel/module.c
-index ab69599..de16959 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
-@@ -2470,7 +2471,13 @@ found_marker:
- sig = p + markerlen;
- /* Truncate module up to signature. */
- *len = p - mod;
-- return mod_verify_sig(mod, *len, sig, end - sig, &info->sig_ok);
-+ err = mod_verify_sig(mod, *len, sig, end - sig, &info->sig_ok);
-+ if (err < 0 && fips_enabled)
-+ panic("Module verification failed with error %d in FIPS mode\n",
-+ err);
-+ if (err == -ENOKEY && !sig_enforce)
-+ err = 0;
-+ return err;
- }
- #else /* !CONFIG_MODULE_SIG */
- static int module_sig_check(struct load_info *info,
-diff --git a/kernel/module_signing.c b/kernel/module_signing.c
-index 83eb505..2beea56 100644
---- a/kernel/module_signing.c
-+++ b/kernel/module_signing.c
-@@ -159,6 +159,9 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
-
- 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)) {
---
-1.7.11.4
-
-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>
----
-
- 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.11.7
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
+
diff --git a/freed-ora/current/f18/secure-boot-20120924.patch b/freed-ora/current/f18/secure-boot-20121026.patch
index 54825efe6..b0bddd943 100644
--- a/freed-ora/current/f18/secure-boot-20120924.patch
+++ b/freed-ora/current/f18/secure-boot-20121026.patch
@@ -711,3 +711,694 @@ index de16959..7d4c50a 100644
--
1.7.11.4
+From 945f3829d0d376c5e0c790b57c4fa9e875d602d3 Mon Sep 17 00:00:00 2001
+From: Dave Howells <dhowells@redhat.com>
+Date: Tue, 23 Oct 2012 09:30:54 -0400
+Subject: [PATCH 1/2] Add EFI signature data types, such as are used for
+ containing hashes, keys and certificates for
+ cryptographic verification.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ include/linux/efi.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 8670eb1..836c797 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -312,6 +312,12 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+ #define EFI_FILE_SYSTEM_GUID \
+ EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
++#define EFI_CERT_SHA256_GUID \
++ EFI_GUID( 0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 )
++
++#define EFI_CERT_X509_GUID \
++ EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
++
+ typedef struct {
+ efi_guid_t guid;
+ u64 table;
+@@ -447,6 +453,20 @@ typedef struct {
+
+ #define EFI_INVALID_TABLE_ADDR (~0UL)
+
++typedef struct {
++ efi_guid_t signature_owner;
++ u8 signature_data[];
++} efi_signature_data_t;
++
++typedef struct {
++ efi_guid_t signature_type;
++ u32 signature_list_size;
++ u32 signature_header_size;
++ u32 signature_size;
++ u8 signature_header[];
++ /* efi_signature_data_t signatures[][] */
++} efi_signature_list_t;
++
+ /*
+ * All runtime access to EFI goes through this structure:
+ */
+--
+1.7.12.1
+
+
+From 5934634101936bc4ee4636df7269e00c4979911c Mon Sep 17 00:00:00 2001
+From: Dave Howells <dhowells@redhat.com>
+Date: Tue, 23 Oct 2012 09:36:28 -0400
+Subject: [PATCH 2/2] Add an EFI signature blob parser and key loader. X.509
+ certificates are loaded into the specified keyring as
+ asymmetric type keys.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ crypto/asymmetric_keys/Kconfig | 7 +++
+ crypto/asymmetric_keys/Makefile | 1 +
+ crypto/asymmetric_keys/efi_parser.c | 107 ++++++++++++++++++++++++++++++++++++
+ include/linux/efi.h | 4 ++
+ 4 files changed, 119 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/efi_parser.c
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 6d2c2ea..eb53fc3 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -35,4 +35,11 @@ config X509_CERTIFICATE_PARSER
+ data and provides the ability to instantiate a crypto key from a
+ public key packet found inside the certificate.
+
++config EFI_SIGNATURE_LIST_PARSER
++ bool "EFI signature list parser"
++ select X509_CERTIFICATE_PARSER
++ help
++ This option provides support for parsing EFI signature lists for
++ X.509 certificates and turning them into keys.
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 0727204..cd8388e 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -8,6 +8,7 @@ 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
++obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o
+
+ #
+ # X.509 Certificate handling
+diff --git a/crypto/asymmetric_keys/efi_parser.c b/crypto/asymmetric_keys/efi_parser.c
+new file mode 100644
+index 0000000..59b859a
+--- /dev/null
++++ b/crypto/asymmetric_keys/efi_parser.c
+@@ -0,0 +1,107 @@
++/* EFI signature/key/certificate list 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) "EFI: "fmt
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/err.h>
++#include <linux/efi.h>
++#include <keys/asymmetric-type.h>
++
++static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID;
++
++/**
++ * parse_efi_signature_list - Parse an EFI signature list for certificates
++ * @data: The data blob to parse
++ * @size: The size of the data blob
++ * @keyring: The keyring to add extracted keys to
++ */
++int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring)
++{
++ unsigned offs = 0;
++ size_t lsize, esize, hsize, elsize;
++
++ pr_devel("-->%s(,%zu)\n", __func__, size);
++
++ while (size > 0) {
++ efi_signature_list_t list;
++ const efi_signature_data_t *elem;
++ key_ref_t key;
++
++ if (size < sizeof(list))
++ return -EBADMSG;
++
++ memcpy(&list, data, sizeof(list));
++ pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
++ offs,
++ list.signature_type.b, list.signature_list_size,
++ list.signature_header_size, list.signature_size);
++
++ lsize = list.signature_list_size;
++ hsize = list.signature_header_size;
++ esize = list.signature_size;
++ elsize = lsize - sizeof(list) - hsize;
++
++ if (lsize > size) {
++ pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
++ __func__, offs);
++ return -EBADMSG;
++ }
++ if (lsize < sizeof(list) ||
++ lsize - sizeof(list) < hsize ||
++ esize < sizeof(*elem) ||
++ elsize < esize ||
++ elsize % esize != 0) {
++ pr_devel("- bad size combo @%x\n", offs);
++ continue;
++ }
++
++ if (efi_guidcmp(list.signature_type, efi_cert_x509_guid) != 0) {
++ data += lsize;
++ size -= lsize;
++ offs += lsize;
++ continue;
++ }
++
++ data += sizeof(list) + hsize;
++ size -= sizeof(list) + hsize;
++ offs += sizeof(list) + hsize;
++
++ for (; elsize > 0; elsize -= esize) {
++ elem = data;
++
++ pr_devel("ELEM[%04x]\n", offs);
++
++ key = key_create_or_update(
++ make_key_ref(keyring, 1),
++ "asymmetric",
++ NULL,
++ &elem->signature_data,
++ esize - sizeof(*elem),
++ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW,
++ KEY_ALLOC_NOT_IN_QUOTA);
++
++ if (IS_ERR(key))
++ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
++ PTR_ERR(key));
++ else
++ pr_notice("Loaded cert '%s'\n",
++ key_ref_to_ptr(key)->description);
++
++ data += esize;
++ size -= esize;
++ offs += esize;
++ }
++ }
++
++ return 0;
++}
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 836c797..9cc3250 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -536,6 +536,10 @@ extern int efi_set_rtc_mmss(unsigned long nowtime);
+ extern void efi_reserve_boot_services(void);
+ extern struct efi_memory_map memmap;
+
++struct key;
++extern int __init parse_efi_signature_list(const void *data, size_t size,
++ struct key *keyring);
++
+ /**
+ * efi_range_is_wc - check the WC bit on an address range
+ * @start: starting kvirt address
+--
+1.7.12.1
+
+From 84d11d541cc039e8561d06deab5f9b700f12f246 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 12:29:49 -0400
+Subject: [PATCH 1/3] EFI: Add in-kernel variable to determine if Secure Boot
+ is enabled
+
+There are a few cases where in-kernel functions may need to know if
+Secure Boot is enabled. The added capability check cannot be used as the
+kernel can't drop it's own capabilites, so we add a global variable
+similar to efi_enabled so they can determine if Secure Boot is enabled.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ arch/x86/kernel/setup.c | 4 +++-
+ arch/x86/platform/efi/efi.c | 2 ++
+ include/linux/efi.h | 3 +++
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 51f6970..d5b9548 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -961,8 +961,10 @@ void __init setup_arch(char **cmdline_p)
+
+ io_delay_init();
+
+- if (boot_params.secure_boot)
++ if (boot_params.secure_boot) {
+ secureboot_enable();
++ secure_boot_enabled = 1;
++ }
+
+ /*
+ * Parse the ACPI tables for possible boot-time SMP configuration.
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index aded2a9..e57320b 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -54,6 +54,8 @@
+ int efi_enabled;
+ EXPORT_SYMBOL(efi_enabled);
+
++int secure_boot_enabled;
++
+ struct efi __read_mostly efi = {
+ .mps = EFI_INVALID_TABLE_ADDR,
+ .acpi = EFI_INVALID_TABLE_ADDR,
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 9cc3250..ff72468 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -573,11 +573,14 @@ extern int __init efi_setup_pcdp_console(char *);
+ # ifdef CONFIG_X86
+ extern int efi_enabled;
+ extern bool efi_64bit;
++ extern int secure_boot_enabled;
+ # else
+ # define efi_enabled 1
++# define secure_boot_enabled 0
+ # endif
+ #else
+ # define efi_enabled 0
++# define secure_boot_enabled 0
+ #endif
+
+ /*
+--
+1.7.12.1
+
+
+From 2a5f33b264daffd717b509bc5ac3cdc060b5573e Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 12:36:24 -0400
+Subject: [PATCH 2/3] MODSIGN: Add module certificate blacklist keyring
+
+This adds an additional keyring that is used to store certificates that
+are blacklisted. This keyring is searched first when loading signed modules
+and if the module's certificate is found, it will refuse to load. This is
+useful in cases where third party certificates are used for module signing.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ init/Kconfig | 8 ++++++++
+ kernel/modsign_pubkey.c | 17 +++++++++++++++++
+ kernel/module-internal.h | 3 +++
+ kernel/module_signing.c | 14 +++++++++++++-
+ 4 files changed, 41 insertions(+), 1 deletion(-)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index 6fdd6e3..7a9bf00 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1602,6 +1602,14 @@ config MODULE_SIG_FORCE
+ Reject unsigned modules or signed modules for which we don't have a
+ key. Without this, such modules will simply taint the kernel.
+
++config MODULE_SIG_BLACKLIST
++ bool "Support for blacklisting module signature certificates"
++ depends on MODULE_SIG
++ help
++ This adds support for keeping a blacklist of certificates that
++ should not pass module signature verification. If a module is
++ signed with something in this keyring, the load will be rejected.
++
+ choice
+ prompt "Which hash algorithm should modules be signed with?"
+ depends on MODULE_SIG
+diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
+index 4646eb2..6d70783 100644
+--- a/kernel/modsign_pubkey.c
++++ b/kernel/modsign_pubkey.c
+@@ -17,6 +17,9 @@
+ #include "module-internal.h"
+
+ struct key *modsign_keyring;
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++struct key *modsign_blacklist;
++#endif
+
+ extern __initdata const u8 modsign_certificate_list[];
+ extern __initdata const u8 modsign_certificate_list_end[];
+@@ -52,6 +55,20 @@ static __init int module_verify_init(void)
+ if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
+ panic("Can't instantiate module signing keyring\n");
+
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++ modsign_blacklist = key_alloc(&key_type_keyring, ".modsign_blacklist",
++ 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_blacklist))
++ panic("Can't allocate module signing blacklist keyring\n");
++
++ if (key_instantiate_and_link(modsign_blacklist, NULL, 0, NULL, NULL) < 0)
++ panic("Can't instantiate module signing blacklist keyring\n");
++#endif
++
+ return 0;
+ }
+
+diff --git a/kernel/module-internal.h b/kernel/module-internal.h
+index 24f9247..51a8380 100644
+--- a/kernel/module-internal.h
++++ b/kernel/module-internal.h
+@@ -10,5 +10,8 @@
+ */
+
+ extern struct key *modsign_keyring;
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++extern struct key *modsign_blacklist;
++#endif
+
+ extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index ea1b1df..602aa24 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -132,7 +132,7 @@ static int mod_extract_mpi_array(struct public_key_signature *pks,
+ 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;
++ key_ref_t key, blacklist;
+ size_t i;
+ char *id, *q;
+
+@@ -157,6 +157,18 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
+
+ pr_debug("Look up: \"%s\"\n", id);
+
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++ blacklist = keyring_search(make_key_ref(modsign_blacklist, 1),
++ &key_type_asymmetric, id);
++ if (!IS_ERR(blacklist)) {
++ /* module is signed with a cert in the blacklist. reject */
++ pr_err("Module key '%s' is in blacklist\n", id);
++ key_ref_put(blacklist);
++ kfree(id);
++ return ERR_PTR(-EKEYREJECTED);
++ }
++#endif
++
+ key = keyring_search(make_key_ref(modsign_keyring, 1),
+ &key_type_asymmetric, id);
+ if (IS_ERR(key))
+--
+1.7.12.1
+
+
+
+From ddd5e2e1b775fb19aeec7fb842e707fc35347bc0 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 12:42:16 -0400
+Subject: [PATCH] MODSIGN: Import certificates from UEFI Secure Boot
+
+Secure Boot stores a list of allowed certificates in the 'db' variable.
+This imports those certificates into the module signing keyring. This
+allows for a third party signing certificate to be used in conjunction
+with signed modules. By importing the public certificate into the 'db'
+variable, a user can allow a module signed with that certificate to
+load.
+
+In the opposite case, Secure Boot maintains a list of disallowed
+certificates in the 'dbx' variable. We load those certificates into
+the newly introduced module blacklist keyring and forbid any module
+signed with those from loading.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ include/linux/efi.h | 3 ++
+ init/Kconfig | 9 ++++++
+ kernel/Makefile | 3 ++
+ kernel/modsign_uefi.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 99 insertions(+)
+ create mode 100644 kernel/modsign_uefi.c
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index ff72468..509755e 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -318,6 +318,9 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+ #define EFI_CERT_X509_GUID \
+ EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
+
++#define EFI_IMAGE_SECURITY_DATABASE_GUID \
++ EFI_GUID( 0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
++
+ typedef struct {
+ efi_guid_t guid;
+ u64 table;
+diff --git a/init/Kconfig b/init/Kconfig
+index 7a9bf00..9c4c529 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1610,6 +1610,15 @@ config MODULE_SIG_BLACKLIST
+ should not pass module signature verification. If a module is
+ signed with something in this keyring, the load will be rejected.
+
++config MODULE_SIG_UEFI
++ bool "Allow modules signed with certs stored in UEFI"
++ depends on MODULE_SIG && MODULE_SIG_BLACKLIST && EFI
++ select EFI_SIGNATURE_LIST_PARSER
++ help
++ This will import certificates stored in UEFI and allow modules
++ signed with those to be loaded. It will also disallow loading
++ of modules stored in the UEFI dbx variable.
++
+ choice
+ prompt "Which hash algorithm should modules be signed with?"
+ depends on MODULE_SIG
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 0dfeca4..ff1468f 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -55,6 +55,7 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += module.o
+ obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
++obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+@@ -113,6 +114,8 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+
+ $(obj)/configs.o: $(obj)/config_data.h
+
++$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
++
+ # config_data.h contains the same information as ikconfig.h but gzipped.
+ # Info from config_data can be extracted from /proc/config*
+ targets += config_data.gz
+diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
+new file mode 100644
+index 0000000..049669d
+--- /dev/null
++++ b/kernel/modsign_uefi.c
+@@ -0,0 +1,84 @@
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/cred.h>
++#include <linux/err.h>
++#include <linux/efi.h>
++#include <keys/asymmetric-type.h>
++#include "module-internal.h"
++
++static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
++{
++ efi_status_t status;
++ unsigned long lsize = 4;
++ unsigned long tmpdb[4];
++ void *db = NULL;
++
++ status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
++ if (status != EFI_BUFFER_TOO_SMALL) {
++ pr_err("Couldn't get size: 0x%lx\n", status);
++ return NULL;
++ }
++
++ db = kmalloc(lsize, GFP_KERNEL);
++ if (!db) {
++ pr_err("Couldn't allocate memory for uefi cert list\n");
++ goto out;
++ }
++
++ status = efi.get_variable(name, guid, NULL, &lsize, db);
++ if (status != EFI_SUCCESS) {
++ kfree(db);
++ db = NULL;
++ pr_err("Error reading db var: 0x%lx\n", status);
++ }
++out:
++ *size = lsize;
++ return db;
++}
++
++/*
++ * * Load the certs contained in the UEFI databases
++ * */
++static int __init load_uefi_certs(void)
++{
++ efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
++ void *db = NULL, *dbx = NULL;
++ unsigned long dbsize = 0, dbxsize = 0;
++ int rc = 0;
++
++ /* Check if SB is enabled and just return if not */
++ if (!secure_boot_enabled)
++ return 0;
++
++ db = get_cert_list(L"db", &secure_var, &dbsize);
++ if (!db) {
++ pr_err("Couldn't get db list\n");
++ rc = -1;
++ goto err;
++ }
++
++ /* Get dbx. It might not exist, so it isn't an error if we can't
++ * get it.
++ */
++ dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
++ if (!dbx) {
++ pr_err("Couldn't get dbx list\n");
++ }
++
++ rc = parse_efi_signature_list(db, dbsize, modsign_keyring);
++ if (rc)
++ pr_err("Couldn't parse db signatures: %d\n", rc);
++
++ if (dbx) {
++ rc = parse_efi_signature_list(dbx, dbxsize,
++ modsign_blacklist);
++ if (rc)
++ pr_err("Couldn't parse dbx signatures: %d\n", rc);
++ }
++
++err:
++ kfree(db);
++ kfree(dbx);
++ return rc;
++}
++late_initcall(load_uefi_certs);
+--
+1.7.12.1
+
+
+From 924e09f1b267c407ca037171bc6f8f90b09265d6 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 14:02:09 -0400
+Subject: [PATCH] hibernate: Disable in a Secure Boot environment
+
+There is currently no way to verify the resume image when returning
+from hibernate. This might compromise the secure boot trust model,
+so until we can work with signed hibernate images we disable it in
+a Secure Boot environment.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ kernel/power/hibernate.c | 14 +++++++++++++-
+ kernel/power/main.c | 4 +++-
+ kernel/power/user.c | 3 +++
+ 3 files changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index b26f5f1..f04343b 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -632,6 +632,10 @@ int hibernate(void)
+ {
+ int error;
+
++ if (!capable(CAP_COMPROMISE_KERNEL)) {
++ return -EPERM;
++ }
++
+ lock_system_sleep();
+ /* The snapshot device should not be opened while we're running */
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+@@ -723,7 +727,7 @@ static int software_resume(void)
+ /*
+ * If the user said "noresume".. bail out early.
+ */
+- if (noresume)
++ if (noresume || !capable(CAP_COMPROMISE_KERNEL))
+ return 0;
+
+ /*
+@@ -889,6 +893,11 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+ int i;
+ char *start = buf;
+
++ if (!capable(CAP_COMPROMISE_KERNEL)) {
++ buf += sprintf(buf, "[%s]\n", "disabled");
++ return buf-start;
++ }
++
+ for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+ if (!hibernation_modes[i])
+ continue;
+@@ -923,6 +932,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+ char *p;
+ int mode = HIBERNATION_INVALID;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+
+diff --git a/kernel/power/main.c b/kernel/power/main.c
+index f458238..72580c1 100644
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -301,7 +301,9 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ }
+ #endif
+ #ifdef CONFIG_HIBERNATION
+- s += sprintf(s, "%s\n", "disk");
++ if (capable(CAP_COMPROMISE_KERNEL)) {
++ s += sprintf(s, "%s\n", "disk");
++ }
+ #else
+ if (s != buf)
+ /* convert the last space to a newline */
+diff --git a/kernel/power/user.c b/kernel/power/user.c
+index 4ed81e7..b11a0f4 100644
+--- a/kernel/power/user.c
++++ b/kernel/power/user.c
+@@ -48,6 +48,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
+ struct snapshot_data *data;
+ int error;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ lock_system_sleep();
+
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+--
+1.7.12.1
+
OpenPOWER on IntegriCloud