diff options
Diffstat (limited to 'freed-ora/current/f18/modsign-upstream-3.7.patch')
-rw-r--r-- | freed-ora/current/f18/modsign-upstream-3.7.patch | 10963 |
1 files changed, 10963 insertions, 0 deletions
diff --git a/freed-ora/current/f18/modsign-upstream-3.7.patch b/freed-ora/current/f18/modsign-upstream-3.7.patch new file mode 100644 index 000000000..4ed27c8a5 --- /dev/null +++ b/freed-ora/current/f18/modsign-upstream-3.7.patch @@ -0,0 +1,10963 @@ +From 9d501208ff48eb3ecc0d1ac8d897c38e99d18161 Mon Sep 17 00:00:00 2001 +From: Rusty Russell <rusty@rustcorp.com.au> +Date: Wed, 26 Sep 2012 10:09:40 +0100 +Subject: [PATCH 01/37] module: signature checking hook + +We do a very simple search for a particular string appended to the module +(which is cache-hot and about to be SHA'd anyway). There's both a config +option and a boot parameter which control whether we accept or fail with +unsigned modules and modules that are signed with an unknown key. + +If module signing is enabled, the kernel will be tainted if a module is +loaded that is unsigned or has a signature for which we don't have the +key. + +(Useful feedback and tweaks by David Howells <dhowells@redhat.com>) + +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + Documentation/kernel-parameters.txt | 6 +++ + include/linux/module.h | 8 ++++ + init/Kconfig | 14 ++++++ + kernel/Makefile | 1 + + kernel/module-internal.h | 13 ++++++ + kernel/module.c | 93 ++++++++++++++++++++++++++++++++++++- + kernel/module_signing.c | 23 +++++++++ + 7 files changed, 157 insertions(+), 1 deletion(-) + create mode 100644 kernel/module-internal.h + create mode 100644 kernel/module_signing.c + +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index ad7e2e5..9b2b8d3 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. + log everything. Information is printed at KERN_DEBUG + so loglevel=8 may also need to be specified. + ++ module.sig_enforce ++ [KNL] When CONFIG_MODULE_SIG is set, this means that ++ modules without (valid) signatures will fail to load. ++ Note that if CONFIG_MODULE_SIG_ENFORCE is set, that ++ is always true, so this option does nothing. ++ + mousedev.tap_time= + [MOUSE] Maximum time between finger touching and + leaving touchpad surface for touch to be considered +diff --git a/include/linux/module.h b/include/linux/module.h +index fbcafe2..7760c6d 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -21,6 +21,9 @@ + #include <linux/percpu.h> + #include <asm/module.h> + ++/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ ++#define MODULE_SIG_STRING "~Module signature appended~\n" ++ + /* Not Yet Implemented */ + #define MODULE_SUPPORTED_DEVICE(name) + +@@ -260,6 +263,11 @@ struct module + const unsigned long *unused_gpl_crcs; + #endif + ++#ifdef CONFIG_MODULE_SIG ++ /* Signature was verified. */ ++ bool sig_ok; ++#endif ++ + /* symbols that will be GPL-only in the near future. */ + const struct kernel_symbol *gpl_future_syms; + const unsigned long *gpl_future_crcs; +diff --git a/init/Kconfig b/init/Kconfig +index af6c7f8..7452e19 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL + the version). With this option, such a "srcversion" field + will be created for all modules. If unsure, say N. + ++config MODULE_SIG ++ bool "Module signature verification" ++ depends on MODULES ++ help ++ Check modules for valid signatures upon load: the signature ++ is simply appended to the module. For more information see ++ Documentation/module-signing.txt. ++ ++config MODULE_SIG_FORCE ++ bool "Require modules to be validly signed" ++ depends on MODULE_SIG ++ help ++ Reject unsigned modules or signed modules for which we don't have a ++ key. Without this, such modules will simply taint the kernel. + endif # MODULES + + config INIT_ALL_POSSIBLE +diff --git a/kernel/Makefile b/kernel/Makefile +index c0cc67a..08ba8a6 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -55,6 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o + obj-$(CONFIG_PROVE_LOCKING) += spinlock.o + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += module.o ++obj-$(CONFIG_MODULE_SIG) += module_signing.o + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +diff --git a/kernel/module-internal.h b/kernel/module-internal.h +new file mode 100644 +index 0000000..033c17f +--- /dev/null ++++ b/kernel/module-internal.h +@@ -0,0 +1,13 @@ ++/* Module internals ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++extern int mod_verify_sig(const void *mod, unsigned long modlen, ++ const void *sig, unsigned long siglen); +diff --git a/kernel/module.c b/kernel/module.c +index 9ad9ee9..7efb415 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -58,6 +58,7 @@ + #include <linux/jump_label.h> + #include <linux/pfn.h> + #include <linux/bsearch.h> ++#include "module-internal.h" + + #define CREATE_TRACE_POINTS + #include <trace/events/module.h> +@@ -102,6 +103,43 @@ static LIST_HEAD(modules); + struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ + #endif /* CONFIG_KGDB_KDB */ + ++#ifdef CONFIG_MODULE_SIG ++#ifdef CONFIG_MODULE_SIG_FORCE ++static bool sig_enforce = true; ++#else ++static bool sig_enforce = false; ++ ++static int param_set_bool_enable_only(const char *val, ++ const struct kernel_param *kp) ++{ ++ int err; ++ bool test; ++ struct kernel_param dummy_kp = *kp; ++ ++ dummy_kp.arg = &test; ++ ++ err = param_set_bool(val, &dummy_kp); ++ if (err) ++ return err; ++ ++ /* Don't let them unset it once it's set! */ ++ if (!test && sig_enforce) ++ return -EROFS; ++ ++ if (test) ++ sig_enforce = true; ++ return 0; ++} ++ ++static const struct kernel_param_ops param_ops_bool_enable_only = { ++ .set = param_set_bool_enable_only, ++ .get = param_get_bool, ++}; ++#define param_check_bool_enable_only param_check_bool ++ ++module_param(sig_enforce, bool_enable_only, 0644); ++#endif /* !CONFIG_MODULE_SIG_FORCE */ ++#endif /* CONFIG_MODULE_SIG */ + + /* Block module loading/unloading? */ + int modules_disabled = 0; +@@ -136,6 +174,7 @@ struct load_info { + unsigned long symoffs, stroffs; + struct _ddebug *debug; + unsigned int num_debug; ++ bool sig_ok; + struct { + unsigned int sym, str, mod, vers, info, pcpu; + } index; +@@ -2399,7 +2438,49 @@ static inline void kmemleak_load_module(const struct module *mod, + } + #endif + +-/* Sets info->hdr and info->len. */ ++#ifdef CONFIG_MODULE_SIG ++static int module_sig_check(struct load_info *info, ++ const void *mod, unsigned long *len) ++{ ++ int err = -ENOKEY; ++ const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; ++ const void *p = mod, *end = mod + *len; ++ ++ /* Poor man's memmem. */ ++ while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) { ++ if (p + markerlen > end) ++ break; ++ ++ if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) { ++ const void *sig = p + markerlen; ++ /* Truncate module up to signature. */ ++ *len = p - mod; ++ err = mod_verify_sig(mod, *len, sig, end - sig); ++ break; ++ } ++ p++; ++ } ++ ++ if (!err) { ++ info->sig_ok = true; ++ return 0; ++ } ++ ++ /* Not having a signature is only an error if we're strict. */ ++ if (err == -ENOKEY && !sig_enforce) ++ err = 0; ++ ++ return err; ++} ++#else /* !CONFIG_MODULE_SIG */ ++static int module_sig_check(struct load_info *info, ++ void *mod, unsigned long *len) ++{ ++ return 0; ++} ++#endif /* !CONFIG_MODULE_SIG */ ++ ++/* Sets info->hdr, info->len and info->sig_ok. */ + static int copy_and_check(struct load_info *info, + const void __user *umod, unsigned long len, + const char __user *uargs) +@@ -2419,6 +2500,10 @@ static int copy_and_check(struct load_info *info, + goto free_hdr; + } + ++ err = module_sig_check(info, hdr, &len); ++ if (err) ++ goto free_hdr; ++ + /* Sanity checks against insmoding binaries or wrong arch, + weird elf version */ + if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 +@@ -2890,6 +2975,12 @@ static struct module *load_module(void __user *umod, + goto free_copy; + } + ++#ifdef CONFIG_MODULE_SIG ++ mod->sig_ok = info.sig_ok; ++ if (!mod->sig_ok) ++ add_taint_module(mod, TAINT_FORCED_MODULE); ++#endif ++ + /* Now module is in final location, initialize linked lists, etc. */ + err = module_unload_init(mod); + if (err) +diff --git a/kernel/module_signing.c b/kernel/module_signing.c +new file mode 100644 +index 0000000..499728a +--- /dev/null ++++ b/kernel/module_signing.c +@@ -0,0 +1,23 @@ ++/* Module signature checker ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/err.h> ++#include "module-internal.h" ++ ++/* ++ * Verify the signature on a module. ++ */ ++int mod_verify_sig(const void *mod, unsigned long modlen, ++ const void *sig, unsigned long siglen) ++{ ++ return -ENOKEY; ++} +-- +1.7.12.1 + + +From 82400c211d81ea36338fb8266b5c41710101a013 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 13 Sep 2012 13:06:29 +0100 +Subject: [PATCH 02/37] KEYS: Add payload preparsing opportunity prior to key + instantiate or update + +Give the key type the opportunity to preparse the payload prior to the +instantiation and update routines being called. This is done with the +provision of two new key type operations: + + int (*preparse)(struct key_preparsed_payload *prep); + void (*free_preparse)(struct key_preparsed_payload *prep); + +If the first operation is present, then it is called before key creation (in +the add/update case) or before the key semaphore is taken (in the update and +instantiate cases). The second operation is called to clean up if the first +was called. + +preparse() is given the opportunity to fill in the following structure: + + struct key_preparsed_payload { + char *description; + void *type_data[2]; + void *payload; + const void *data; + size_t datalen; + size_t quotalen; + }; + +Before the preparser is called, the first three fields will have been cleared, +the payload pointer and size will be stored in data and datalen and the default +quota size from the key_type struct will be stored into quotalen. + +The preparser may parse the payload in any way it likes and may store data in +the type_data[] and payload fields for use by the instantiate() and update() +ops. + +The preparser may also propose a description for the key by attaching it as a +string to the description field. This can be used by passing a NULL or "" +description to the add_key() system call or the key_create_or_update() +function. This cannot work with request_key() as that required the description +to tell the upcall about the key to be created. + +This, for example permits keys that store PGP public keys to generate their own +name from the user ID and public key fingerprint in the key. + +The instantiate() and update() operations are then modified to look like this: + + int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); + int (*update)(struct key *key, struct key_preparsed_payload *prep); + +and the new payload data is passed in *prep, whether or not it was preparsed. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + Documentation/security/keys.txt | 50 +++++++++++++- + fs/cifs/cifs_spnego.c | 6 +- + fs/cifs/cifsacl.c | 8 +-- + include/keys/user-type.h | 6 +- + include/linux/key-type.h | 35 +++++++++- + net/ceph/crypto.c | 9 +-- + net/dns_resolver/dns_key.c | 6 +- + net/rxrpc/ar-key.c | 40 +++++------ + security/keys/encrypted-keys/encrypted.c | 16 +++-- + security/keys/key.c | 114 ++++++++++++++++++++++--------- + security/keys/keyctl.c | 18 +++-- + security/keys/keyring.c | 6 +- + security/keys/request_key_auth.c | 8 +-- + security/keys/trusted.c | 16 +++-- + security/keys/user_defined.c | 14 ++-- + 15 files changed, 250 insertions(+), 102 deletions(-) + +diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt +index aa0dbd7..7d9ca92 100644 +--- a/Documentation/security/keys.txt ++++ b/Documentation/security/keys.txt +@@ -412,6 +412,10 @@ The main syscalls are: + to the keyring. In this case, an error will be generated if the process + does not have permission to write to the keyring. + ++ If the key type supports it, if the description is NULL or an empty ++ string, the key type will try and generate a description from the content ++ of the payload. ++ + The payload is optional, and the pointer can be NULL if not required by + the type. The payload is plen in size, and plen can be zero for an empty + payload. +@@ -1114,12 +1118,53 @@ The structure has a number of fields, some of which are mandatory: + it should return 0. + + +- (*) int (*instantiate)(struct key *key, const void *data, size_t datalen); ++ (*) int (*preparse)(struct key_preparsed_payload *prep); ++ ++ This optional method permits the key type to attempt to parse payload ++ before a key is created (add key) or the key semaphore is taken (update or ++ instantiate key). The structure pointed to by prep looks like: ++ ++ struct key_preparsed_payload { ++ char *description; ++ void *type_data[2]; ++ void *payload; ++ const void *data; ++ size_t datalen; ++ size_t quotalen; ++ }; ++ ++ Before calling the method, the caller will fill in data and datalen with ++ the payload blob parameters; quotalen will be filled in with the default ++ quota size from the key type and the rest will be cleared. ++ ++ If a description can be proposed from the payload contents, that should be ++ attached as a string to the description field. This will be used for the ++ key description if the caller of add_key() passes NULL or "". ++ ++ The method can attach anything it likes to type_data[] and payload. These ++ are merely passed along to the instantiate() or update() operations. ++ ++ The method should return 0 if success ful or a negative error code ++ otherwise. ++ ++ ++ (*) void (*free_preparse)(struct key_preparsed_payload *prep); ++ ++ This method is only required if the preparse() method is provided, ++ otherwise it is unused. It cleans up anything attached to the ++ description, type_data and payload fields of the key_preparsed_payload ++ struct as filled in by the preparse() method. ++ ++ ++ (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); + + This method is called to attach a payload to a key during construction. + The payload attached need not bear any relation to the data passed to this + function. + ++ The prep->data and prep->datalen fields will define the original payload ++ blob. If preparse() was supplied then other fields may be filled in also. ++ + If the amount of data attached to the key differs from the size in + keytype->def_datalen, then key_payload_reserve() should be called. + +@@ -1135,6 +1180,9 @@ The structure has a number of fields, some of which are mandatory: + If this type of key can be updated, then this method should be provided. + It is called to update a key's payload from the blob of data provided. + ++ The prep->data and prep->datalen fields will define the original payload ++ blob. If preparse() was supplied then other fields may be filled in also. ++ + key_payload_reserve() should be called if the data length might change + before any changes are actually made. Note that if this succeeds, the type + is committed to changing the key because it's already been altered, so all +diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c +index e622863..086f381 100644 +--- a/fs/cifs/cifs_spnego.c ++++ b/fs/cifs/cifs_spnego.c +@@ -31,18 +31,18 @@ + + /* create a new cifs key */ + static int +-cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen) ++cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep) + { + char *payload; + int ret; + + ret = -ENOMEM; +- payload = kmalloc(datalen, GFP_KERNEL); ++ payload = kmalloc(prep->datalen, GFP_KERNEL); + if (!payload) + goto error; + + /* attach the data */ +- memcpy(payload, data, datalen); ++ memcpy(payload, prep->data, prep->datalen); + key->payload.data = payload; + ret = 0; + +diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c +index 05f4dc2..f3c60e2 100644 +--- a/fs/cifs/cifsacl.c ++++ b/fs/cifs/cifsacl.c +@@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = { + }; + + static int +-cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) ++cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) + { + char *payload; + +- payload = kmalloc(datalen, GFP_KERNEL); ++ payload = kmalloc(prep->datalen, GFP_KERNEL); + if (!payload) + return -ENOMEM; + +- memcpy(payload, data, datalen); ++ memcpy(payload, prep->data, prep->datalen); + key->payload.data = payload; +- key->datalen = datalen; ++ key->datalen = prep->datalen; + return 0; + } + +diff --git a/include/keys/user-type.h b/include/keys/user-type.h +index bc9ec1d..5e452c8 100644 +--- a/include/keys/user-type.h ++++ b/include/keys/user-type.h +@@ -35,8 +35,10 @@ struct user_key_payload { + extern struct key_type key_type_user; + extern struct key_type key_type_logon; + +-extern int user_instantiate(struct key *key, const void *data, size_t datalen); +-extern int user_update(struct key *key, const void *data, size_t datalen); ++struct key_preparsed_payload; ++ ++extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep); ++extern int user_update(struct key *key, struct key_preparsed_payload *prep); + extern int user_match(const struct key *key, const void *criterion); + extern void user_revoke(struct key *key); + extern void user_destroy(struct key *key); +diff --git a/include/linux/key-type.h b/include/linux/key-type.h +index f0c651c..518a53a 100644 +--- a/include/linux/key-type.h ++++ b/include/linux/key-type.h +@@ -26,6 +26,27 @@ struct key_construction { + struct key *authkey;/* authorisation for key being constructed */ + }; + ++/* ++ * Pre-parsed payload, used by key add, update and instantiate. ++ * ++ * This struct will be cleared and data and datalen will be set with the data ++ * and length parameters from the caller and quotalen will be set from ++ * def_datalen from the key type. Then if the preparse() op is provided by the ++ * key type, that will be called. Then the struct will be passed to the ++ * instantiate() or the update() op. ++ * ++ * If the preparse() op is given, the free_preparse() op will be called to ++ * clear the contents. ++ */ ++struct key_preparsed_payload { ++ char *description; /* Proposed key description (or NULL) */ ++ void *type_data[2]; /* Private key-type data */ ++ void *payload; /* Proposed payload */ ++ const void *data; /* Raw data */ ++ size_t datalen; /* Raw datalen */ ++ size_t quotalen; /* Quota length for proposed payload */ ++}; ++ + typedef int (*request_key_actor_t)(struct key_construction *key, + const char *op, void *aux); + +@@ -45,18 +66,28 @@ struct key_type { + /* vet a description */ + int (*vet_description)(const char *description); + ++ /* Preparse the data blob from userspace that is to be the payload, ++ * generating a proposed description and payload that will be handed to ++ * the instantiate() and update() ops. ++ */ ++ int (*preparse)(struct key_preparsed_payload *prep); ++ ++ /* Free a preparse data structure. ++ */ ++ void (*free_preparse)(struct key_preparsed_payload *prep); ++ + /* instantiate a key of this type + * - this method should call key_payload_reserve() to determine if the + * user's quota will hold the payload + */ +- int (*instantiate)(struct key *key, const void *data, size_t datalen); ++ int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); + + /* update a key of this type (optional) + * - this method should call key_payload_reserve() to recalculate the + * quota consumption + * - the key must be locked against read when modifying + */ +- int (*update)(struct key *key, const void *data, size_t datalen); ++ int (*update)(struct key *key, struct key_preparsed_payload *prep); + + /* match a key against a description */ + int (*match)(const struct key *key, const void *desc); +diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c +index 9da7fdd..af14cb4 100644 +--- a/net/ceph/crypto.c ++++ b/net/ceph/crypto.c +@@ -423,14 +423,15 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, + } + } + +-int ceph_key_instantiate(struct key *key, const void *data, size_t datalen) ++int ceph_key_instantiate(struct key *key, struct key_preparsed_payload *prep) + { + struct ceph_crypto_key *ckey; ++ size_t datalen = prep->datalen; + int ret; + void *p; + + ret = -EINVAL; +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + goto err; + + ret = key_payload_reserve(key, datalen); +@@ -443,8 +444,8 @@ int ceph_key_instantiate(struct key *key, const void *data, size_t datalen) + goto err; + + /* TODO ceph_crypto_key_decode should really take const input */ +- p = (void *)data; +- ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen); ++ p = (void *)prep->data; ++ ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen); + if (ret < 0) + goto err_ckey; + +diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c +index d9507dd..859ab8b 100644 +--- a/net/dns_resolver/dns_key.c ++++ b/net/dns_resolver/dns_key.c +@@ -59,13 +59,13 @@ const struct cred *dns_resolver_cache; + * "ip1,ip2,...#foo=bar" + */ + static int +-dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) ++dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) + { + struct user_key_payload *upayload; + unsigned long derrno; + int ret; +- size_t result_len = 0; +- const char *data = _data, *end, *opt; ++ size_t datalen = prep->datalen, result_len = 0; ++ const char *data = prep->data, *end, *opt; + + kenter("%%%d,%s,'%*.*s',%zu", + key->serial, key->description, +diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c +index 8b1f9f4..106c5a6 100644 +--- a/net/rxrpc/ar-key.c ++++ b/net/rxrpc/ar-key.c +@@ -26,8 +26,8 @@ + #include "ar-internal.h" + + static int rxrpc_vet_description_s(const char *); +-static int rxrpc_instantiate(struct key *, const void *, size_t); +-static int rxrpc_instantiate_s(struct key *, const void *, size_t); ++static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *); ++static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *); + static void rxrpc_destroy(struct key *); + static void rxrpc_destroy_s(struct key *); + static void rxrpc_describe(const struct key *, struct seq_file *); +@@ -678,7 +678,7 @@ error: + * + * if no data is provided, then a no-security key is made + */ +-static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) ++static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep) + { + const struct rxrpc_key_data_v1 *v1; + struct rxrpc_key_token *token, **pp; +@@ -686,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) + u32 kver; + int ret; + +- _enter("{%x},,%zu", key_serial(key), datalen); ++ _enter("{%x},,%zu", key_serial(key), prep->datalen); + + /* handle a no-security key */ +- if (!data && datalen == 0) ++ if (!prep->data && prep->datalen == 0) + return 0; + + /* determine if the XDR payload format is being used */ +- if (datalen > 7 * 4) { +- ret = rxrpc_instantiate_xdr(key, data, datalen); ++ if (prep->datalen > 7 * 4) { ++ ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen); + if (ret != -EPROTO) + return ret; + } + + /* get the key interface version number */ + ret = -EINVAL; +- if (datalen <= 4 || !data) ++ if (prep->datalen <= 4 || !prep->data) + goto error; +- memcpy(&kver, data, sizeof(kver)); +- data += sizeof(kver); +- datalen -= sizeof(kver); ++ memcpy(&kver, prep->data, sizeof(kver)); ++ prep->data += sizeof(kver); ++ prep->datalen -= sizeof(kver); + + _debug("KEY I/F VERSION: %u", kver); + +@@ -715,11 +715,11 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) + + /* deal with a version 1 key */ + ret = -EINVAL; +- if (datalen < sizeof(*v1)) ++ if (prep->datalen < sizeof(*v1)) + goto error; + +- v1 = data; +- if (datalen != sizeof(*v1) + v1->ticket_length) ++ v1 = prep->data; ++ if (prep->datalen != sizeof(*v1) + v1->ticket_length) + goto error; + + _debug("SCIX: %u", v1->security_index); +@@ -784,17 +784,17 @@ error: + * instantiate a server secret key + * data should be a pointer to the 8-byte secret key + */ +-static int rxrpc_instantiate_s(struct key *key, const void *data, +- size_t datalen) ++static int rxrpc_instantiate_s(struct key *key, ++ struct key_preparsed_payload *prep) + { + struct crypto_blkcipher *ci; + +- _enter("{%x},,%zu", key_serial(key), datalen); ++ _enter("{%x},,%zu", key_serial(key), prep->datalen); + +- if (datalen != 8) ++ if (prep->datalen != 8) + return -EINVAL; + +- memcpy(&key->type_data, data, 8); ++ memcpy(&key->type_data, prep->data, 8); + + ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(ci)) { +@@ -802,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data, + return PTR_ERR(ci); + } + +- if (crypto_blkcipher_setkey(ci, data, 8) < 0) ++ if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) + BUG(); + + key->payload.data = ci; +diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c +index 2d1bb8a..9e1e005 100644 +--- a/security/keys/encrypted-keys/encrypted.c ++++ b/security/keys/encrypted-keys/encrypted.c +@@ -773,8 +773,8 @@ static int encrypted_init(struct encrypted_key_payload *epayload, + * + * On success, return 0. Otherwise return errno. + */ +-static int encrypted_instantiate(struct key *key, const void *data, +- size_t datalen) ++static int encrypted_instantiate(struct key *key, ++ struct key_preparsed_payload *prep) + { + struct encrypted_key_payload *epayload = NULL; + char *datablob = NULL; +@@ -782,16 +782,17 @@ static int encrypted_instantiate(struct key *key, const void *data, + char *master_desc = NULL; + char *decrypted_datalen = NULL; + char *hex_encoded_iv = NULL; ++ size_t datalen = prep->datalen; + int ret; + +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + return -EINVAL; + + datablob = kmalloc(datalen + 1, GFP_KERNEL); + if (!datablob) + return -ENOMEM; + datablob[datalen] = 0; +- memcpy(datablob, data, datalen); ++ memcpy(datablob, prep->data, datalen); + ret = datablob_parse(datablob, &format, &master_desc, + &decrypted_datalen, &hex_encoded_iv); + if (ret < 0) +@@ -834,16 +835,17 @@ static void encrypted_rcu_free(struct rcu_head *rcu) + * + * On success, return 0. Otherwise return errno. + */ +-static int encrypted_update(struct key *key, const void *data, size_t datalen) ++static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) + { + struct encrypted_key_payload *epayload = key->payload.data; + struct encrypted_key_payload *new_epayload; + char *buf; + char *new_master_desc = NULL; + const char *format = NULL; ++ size_t datalen = prep->datalen; + int ret = 0; + +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + return -EINVAL; + + buf = kmalloc(datalen + 1, GFP_KERNEL); +@@ -851,7 +853,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) + return -ENOMEM; + + buf[datalen] = 0; +- memcpy(buf, data, datalen); ++ memcpy(buf, prep->data, datalen); + ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); + if (ret < 0) + goto out; +diff --git a/security/keys/key.c b/security/keys/key.c +index 50d96d4..1d039af 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve); + * key_construction_mutex. + */ + static int __key_instantiate_and_link(struct key *key, +- const void *data, +- size_t datalen, ++ struct key_preparsed_payload *prep, + struct key *keyring, + struct key *authkey, + unsigned long *_prealloc) +@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key, + /* can't instantiate twice */ + if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { + /* instantiate the key */ +- ret = key->type->instantiate(key, data, datalen); ++ ret = key->type->instantiate(key, prep); + + if (ret == 0) { + /* mark the key as being instantiated */ +@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key, + struct key *keyring, + struct key *authkey) + { ++ struct key_preparsed_payload prep; + unsigned long prealloc; + int ret; + ++ memset(&prep, 0, sizeof(prep)); ++ prep.data = data; ++ prep.datalen = datalen; ++ prep.quotalen = key->type->def_datalen; ++ if (key->type->preparse) { ++ ret = key->type->preparse(&prep); ++ if (ret < 0) ++ goto error; ++ } ++ + if (keyring) { + ret = __key_link_begin(keyring, key->type, key->description, + &prealloc); + if (ret < 0) +- return ret; ++ goto error_free_preparse; + } + +- ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey, ++ ret = __key_instantiate_and_link(key, &prep, keyring, authkey, + &prealloc); + + if (keyring) + __key_link_end(keyring, key->type, prealloc); + ++error_free_preparse: ++ if (key->type->preparse) ++ key->type->free_preparse(&prep); ++error: + return ret; + } + +@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype) + * if we get an error. + */ + static inline key_ref_t __key_update(key_ref_t key_ref, +- const void *payload, size_t plen) ++ struct key_preparsed_payload *prep) + { + struct key *key = key_ref_to_ptr(key_ref); + int ret; +@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref, + + down_write(&key->sem); + +- ret = key->type->update(key, payload, plen); ++ ret = key->type->update(key, prep); + if (ret == 0) + /* updating a negative key instantiates it */ + clear_bit(KEY_FLAG_NEGATIVE, &key->flags); +@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + unsigned long flags) + { + unsigned long prealloc; ++ struct key_preparsed_payload prep; + const struct cred *cred = current_cred(); + struct key_type *ktype; + struct key *keyring, *key = NULL; +@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + } + + key_ref = ERR_PTR(-EINVAL); +- if (!ktype->match || !ktype->instantiate) +- goto error_2; ++ if (!ktype->match || !ktype->instantiate || ++ (!description && !ktype->preparse)) ++ goto error_put_type; + + keyring = key_ref_to_ptr(keyring_ref); + +@@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + + key_ref = ERR_PTR(-ENOTDIR); + if (keyring->type != &key_type_keyring) +- goto error_2; ++ goto error_put_type; ++ ++ memset(&prep, 0, sizeof(prep)); ++ prep.data = payload; ++ prep.datalen = plen; ++ prep.quotalen = ktype->def_datalen; ++ if (ktype->preparse) { ++ ret = ktype->preparse(&prep); ++ if (ret < 0) { ++ key_ref = ERR_PTR(ret); ++ goto error_put_type; ++ } ++ if (!description) ++ description = prep.description; ++ key_ref = ERR_PTR(-EINVAL); ++ if (!description) ++ goto error_free_prep; ++ } + + ret = __key_link_begin(keyring, ktype, description, &prealloc); +- if (ret < 0) +- goto error_2; ++ if (ret < 0) { ++ key_ref = ERR_PTR(ret); ++ goto error_free_prep; ++ } + + /* if we're going to allocate a new key, we're going to have + * to modify the keyring */ + ret = key_permission(keyring_ref, KEY_WRITE); + if (ret < 0) { + key_ref = ERR_PTR(ret); +- goto error_3; ++ goto error_link_end; + } + + /* if it's possible to update this type of key, search for an existing +@@ -840,25 +875,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + perm, flags); + if (IS_ERR(key)) { + key_ref = ERR_CAST(key); +- goto error_3; ++ goto error_link_end; + } + + /* instantiate it and link it into the target keyring */ +- ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL, +- &prealloc); ++ ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc); + if (ret < 0) { + key_put(key); + key_ref = ERR_PTR(ret); +- goto error_3; ++ goto error_link_end; + } + + key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); + +- error_3: ++error_link_end: + __key_link_end(keyring, ktype, prealloc); +- error_2: ++error_free_prep: ++ if (ktype->preparse) ++ ktype->free_preparse(&prep); ++error_put_type: + key_type_put(ktype); +- error: ++error: + return key_ref; + + found_matching_key: +@@ -866,10 +903,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + * - we can drop the locks first as we have the key pinned + */ + __key_link_end(keyring, ktype, prealloc); +- key_type_put(ktype); + +- key_ref = __key_update(key_ref, payload, plen); +- goto error; ++ key_ref = __key_update(key_ref, &prep); ++ goto error_free_prep; + } + EXPORT_SYMBOL(key_create_or_update); + +@@ -888,6 +924,7 @@ EXPORT_SYMBOL(key_create_or_update); + */ + int key_update(key_ref_t key_ref, const void *payload, size_t plen) + { ++ struct key_preparsed_payload prep; + struct key *key = key_ref_to_ptr(key_ref); + int ret; + +@@ -900,18 +937,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) + + /* attempt to update it if supported */ + ret = -EOPNOTSUPP; +- if (key->type->update) { +- down_write(&key->sem); +- +- ret = key->type->update(key, payload, plen); +- if (ret == 0) +- /* updating a negative key instantiates it */ +- clear_bit(KEY_FLAG_NEGATIVE, &key->flags); ++ if (!key->type->update) ++ goto error; + +- up_write(&key->sem); ++ memset(&prep, 0, sizeof(prep)); ++ prep.data = payload; ++ prep.datalen = plen; ++ prep.quotalen = key->type->def_datalen; ++ if (key->type->preparse) { ++ ret = key->type->preparse(&prep); ++ if (ret < 0) ++ goto error; + } + +- error: ++ down_write(&key->sem); ++ ++ ret = key->type->update(key, &prep); ++ if (ret == 0) ++ /* updating a negative key instantiates it */ ++ clear_bit(KEY_FLAG_NEGATIVE, &key->flags); ++ ++ up_write(&key->sem); ++ ++ if (key->type->preparse) ++ key->type->free_preparse(&prep); ++error: + return ret; + } + EXPORT_SYMBOL(key_update); +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index 3364fbf..505d40b 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -46,6 +46,9 @@ static int key_get_type_from_user(char *type, + * Extract the description of a new key from userspace and either add it as a + * new key to the specified keyring or update a matching key in that keyring. + * ++ * If the description is NULL or an empty string, the key type is asked to ++ * generate one from the payload. ++ * + * The keyring must be writable so that we can attach the key to it. + * + * If successful, the new key's serial number is returned, otherwise an error +@@ -72,10 +75,17 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, + if (ret < 0) + goto error; + +- description = strndup_user(_description, PAGE_SIZE); +- if (IS_ERR(description)) { +- ret = PTR_ERR(description); +- goto error; ++ description = NULL; ++ if (_description) { ++ description = strndup_user(_description, PAGE_SIZE); ++ if (IS_ERR(description)) { ++ ret = PTR_ERR(description); ++ goto error; ++ } ++ if (!*description) { ++ kfree(description); ++ description = NULL; ++ } + } + + /* pull the payload in if one was supplied */ +diff --git a/security/keys/keyring.c b/security/keys/keyring.c +index 81e7852..f04d8cf 100644 +--- a/security/keys/keyring.c ++++ b/security/keys/keyring.c +@@ -66,7 +66,7 @@ static inline unsigned keyring_hash(const char *desc) + * operations. + */ + static int keyring_instantiate(struct key *keyring, +- const void *data, size_t datalen); ++ struct key_preparsed_payload *prep); + static int keyring_match(const struct key *keyring, const void *criterion); + static void keyring_revoke(struct key *keyring); + static void keyring_destroy(struct key *keyring); +@@ -121,12 +121,12 @@ static void keyring_publish_name(struct key *keyring) + * Returns 0 on success, -EINVAL if given any data. + */ + static int keyring_instantiate(struct key *keyring, +- const void *data, size_t datalen) ++ struct key_preparsed_payload *prep) + { + int ret; + + ret = -EINVAL; +- if (datalen == 0) { ++ if (prep->datalen == 0) { + /* make the keyring available by name if it has one */ + keyring_publish_name(keyring); + ret = 0; +diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c +index 60d4e3f..85730d5 100644 +--- a/security/keys/request_key_auth.c ++++ b/security/keys/request_key_auth.c +@@ -19,7 +19,8 @@ + #include <asm/uaccess.h> + #include "internal.h" + +-static int request_key_auth_instantiate(struct key *, const void *, size_t); ++static int request_key_auth_instantiate(struct key *, ++ struct key_preparsed_payload *); + static void request_key_auth_describe(const struct key *, struct seq_file *); + static void request_key_auth_revoke(struct key *); + static void request_key_auth_destroy(struct key *); +@@ -42,10 +43,9 @@ struct key_type key_type_request_key_auth = { + * Instantiate a request-key authorisation key. + */ + static int request_key_auth_instantiate(struct key *key, +- const void *data, +- size_t datalen) ++ struct key_preparsed_payload *prep) + { +- key->payload.data = (struct request_key_auth *) data; ++ key->payload.data = (struct request_key_auth *)prep->data; + return 0; + } + +diff --git a/security/keys/trusted.c b/security/keys/trusted.c +index 2d5d041..42036c7 100644 +--- a/security/keys/trusted.c ++++ b/security/keys/trusted.c +@@ -927,22 +927,23 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key) + * + * On success, return 0. Otherwise return errno. + */ +-static int trusted_instantiate(struct key *key, const void *data, +- size_t datalen) ++static int trusted_instantiate(struct key *key, ++ struct key_preparsed_payload *prep) + { + struct trusted_key_payload *payload = NULL; + struct trusted_key_options *options = NULL; ++ size_t datalen = prep->datalen; + char *datablob; + int ret = 0; + int key_cmd; + +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + return -EINVAL; + + datablob = kmalloc(datalen + 1, GFP_KERNEL); + if (!datablob) + return -ENOMEM; +- memcpy(datablob, data, datalen); ++ memcpy(datablob, prep->data, datalen); + datablob[datalen] = '\0'; + + options = trusted_options_alloc(); +@@ -1011,17 +1012,18 @@ static void trusted_rcu_free(struct rcu_head *rcu) + /* + * trusted_update - reseal an existing key with new PCR values + */ +-static int trusted_update(struct key *key, const void *data, size_t datalen) ++static int trusted_update(struct key *key, struct key_preparsed_payload *prep) + { + struct trusted_key_payload *p = key->payload.data; + struct trusted_key_payload *new_p; + struct trusted_key_options *new_o; ++ size_t datalen = prep->datalen; + char *datablob; + int ret = 0; + + if (!p->migratable) + return -EPERM; +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + return -EINVAL; + + datablob = kmalloc(datalen + 1, GFP_KERNEL); +@@ -1038,7 +1040,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen) + goto out; + } + +- memcpy(datablob, data, datalen); ++ memcpy(datablob, prep->data, datalen); + datablob[datalen] = '\0'; + ret = datablob_parse(datablob, new_p, new_o); + if (ret != Opt_update) { +diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c +index c7660a2..55dc889 100644 +--- a/security/keys/user_defined.c ++++ b/security/keys/user_defined.c +@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon); + /* + * instantiate a user defined key + */ +-int user_instantiate(struct key *key, const void *data, size_t datalen) ++int user_instantiate(struct key *key, struct key_preparsed_payload *prep) + { + struct user_key_payload *upayload; ++ size_t datalen = prep->datalen; + int ret; + + ret = -EINVAL; +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + goto error; + + ret = key_payload_reserve(key, datalen); +@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen) + + /* attach the data */ + upayload->datalen = datalen; +- memcpy(upayload->data, data, datalen); ++ memcpy(upayload->data, prep->data, datalen); + rcu_assign_keypointer(key, upayload); + ret = 0; + +@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate); + * update a user defined key + * - the key's semaphore is write-locked + */ +-int user_update(struct key *key, const void *data, size_t datalen) ++int user_update(struct key *key, struct key_preparsed_payload *prep) + { + struct user_key_payload *upayload, *zap; ++ size_t datalen = prep->datalen; + int ret; + + ret = -EINVAL; +- if (datalen <= 0 || datalen > 32767 || !data) ++ if (datalen <= 0 || datalen > 32767 || !prep->data) + goto error; + + /* construct a replacement payload */ +@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen) + goto error; + + upayload->datalen = datalen; +- memcpy(upayload->data, data, datalen); ++ memcpy(upayload->data, prep->data, datalen); + + /* check the quota and attach the new data */ + zap = upayload; +-- +1.7.12.1 + + +From 162ce9c1b0f28d36598975f8931f216245b7e778 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 13 Sep 2012 13:09:33 +0100 +Subject: [PATCH 03/37] MPILIB: Provide count_leading/trailing_zeros() based + on arch functions + +Provide count_leading/trailing_zeros() macros based on extant arch bit scanning +functions rather than reimplementing from scratch in MPILIB. + +Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x). + +Also move the definition to asm-generic as other people may be interested in +using it. + +Signed-off-by: David Howells <dhowells@redhat.com> +Cc: David S. Miller <davem@davemloft.net> +Cc: Dmitry Kasatkin <dmitry.kasatkin@intel.com> +Cc: Arnd Bergmann <arnd@arndb.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + include/asm-generic/bitops/count_zeros.h | 57 +++++++++++++ + lib/mpi/longlong.h | 138 +------------------------------ + lib/mpi/mpi-bit.c | 2 +- + lib/mpi/mpi-pow.c | 4 +- + 4 files changed, 62 insertions(+), 139 deletions(-) + create mode 100644 include/asm-generic/bitops/count_zeros.h + +diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h +new file mode 100644 +index 0000000..97520d2 +--- /dev/null ++++ b/include/asm-generic/bitops/count_zeros.h +@@ -0,0 +1,57 @@ ++/* Count leading and trailing zeros functions ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ ++#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ ++ ++#include <asm/bitops.h> ++ ++/** ++ * count_leading_zeros - Count the number of zeros from the MSB back ++ * @x: The value ++ * ++ * Count the number of leading zeros from the MSB going towards the LSB in @x. ++ * ++ * If the MSB of @x is set, the result is 0. ++ * If only the LSB of @x is set, then the result is BITS_PER_LONG-1. ++ * If @x is 0 then the result is COUNT_LEADING_ZEROS_0. ++ */ ++static inline int count_leading_zeros(unsigned long x) ++{ ++ if (sizeof(x) == 4) ++ return BITS_PER_LONG - fls(x); ++ else ++ return BITS_PER_LONG - fls64(x); ++} ++ ++#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG ++ ++/** ++ * count_trailing_zeros - Count the number of zeros from the LSB forwards ++ * @x: The value ++ * ++ * Count the number of trailing zeros from the LSB going towards the MSB in @x. ++ * ++ * If the LSB of @x is set, the result is 0. ++ * If only the MSB of @x is set, then the result is BITS_PER_LONG-1. ++ * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0. ++ */ ++static inline int count_trailing_zeros(unsigned long x) ++{ ++#define COUNT_TRAILING_ZEROS_0 (-1) ++ ++ if (sizeof(x) == 4) ++ return ffs(x); ++ else ++ return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0; ++} ++ ++#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */ +diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h +index 29f9862..678ce4f 100644 +--- a/lib/mpi/longlong.h ++++ b/lib/mpi/longlong.h +@@ -19,6 +19,8 @@ + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. */ + ++#include <asm-generic/bitops/count_zeros.h> ++ + /* You have to define the following before including this file: + * + * UWtype -- An unsigned type, default type for operations (typically a "word") +@@ -146,12 +148,6 @@ do { \ + : "1" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "r" ((USItype)(d))) +- +-#define count_leading_zeros(count, x) \ +- __asm__ ("clz %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x))) +-#define COUNT_LEADING_ZEROS_0 32 + #endif /* __a29k__ */ + + #if defined(__alpha) && W_TYPE_SIZE == 64 +@@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd(); + : "1" ((USItype)(nh)), \ + "0" ((USItype)(nl)), \ + "g" ((USItype)(d))) +-#define count_leading_zeros(count, x) \ +- __asm__ ("bsch/1 %1,%0" \ +- : "=g" (count) \ +- : "g" ((USItype)(x)), \ +- "0" ((USItype)0)) + #endif + + /*************************************** +@@ -354,27 +345,6 @@ do { USItype __r; \ + } while (0) + extern USItype __udiv_qrnnd(); + #endif /* LONGLONG_STANDALONE */ +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __tmp; \ +- __asm__ ( \ +- "ldi 1,%0\n" \ +- "extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ +- "extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n" \ +- "ldo 16(%0),%0 ; Yes. Perform add.\n" \ +- "extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ +- "extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n" \ +- "ldo 8(%0),%0 ; Yes. Perform add.\n" \ +- "extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ +- "extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n" \ +- "ldo 4(%0),%0 ; Yes. Perform add.\n" \ +- "extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ +- "extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n" \ +- "ldo 2(%0),%0 ; Yes. Perform add.\n" \ +- "extru %1,30,1,%1 ; Extract bit 1.\n" \ +- "sub %0,%1,%0 ; Subtract it. " \ +- : "=r" (count), "=r" (__tmp) : "1" (x)); \ +-} while (0) + #endif /* hppa */ + + /*************************************** +@@ -457,15 +427,6 @@ do { \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "rm" ((USItype)(d))) +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __cbtmp; \ +- __asm__ ("bsrl %1,%0" \ +- : "=r" (__cbtmp) : "rm" ((USItype)(x))); \ +- (count) = __cbtmp ^ 31; \ +-} while (0) +-#define count_trailing_zeros(count, x) \ +- __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) + #ifndef UMUL_TIME + #define UMUL_TIME 40 + #endif +@@ -536,15 +497,6 @@ do { \ + "dI" ((USItype)(d))); \ + (r) = __rq.__i.__l; (q) = __rq.__i.__h; \ + } while (0) +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __cbtmp; \ +- __asm__ ("scanbit %1,%0" \ +- : "=r" (__cbtmp) \ +- : "r" ((USItype)(x))); \ +- (count) = __cbtmp ^ 31; \ +-} while (0) +-#define COUNT_LEADING_ZEROS_0 (-32) /* sic */ + #if defined(__i960mx) /* what is the proper symbol to test??? */ + #define rshift_rhlc(r, h, l, c) \ + do { \ +@@ -603,11 +555,6 @@ do { \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "dmi" ((USItype)(d))) +-#define count_leading_zeros(count, x) \ +- __asm__ ("bfffo %1{%b2:%b2},%0" \ +- : "=d" ((USItype)(count)) \ +- : "od" ((USItype)(x)), "n" (0)) +-#define COUNT_LEADING_ZEROS_0 32 + #else /* not mc68020 */ + #define umul_ppmm(xh, xl, a, b) \ + do { USItype __umul_tmp1, __umul_tmp2; \ +@@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \ + "rJ" ((USItype)(bh)), \ + "rJ" ((USItype)(al)), \ + "rJ" ((USItype)(bl))) +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __cbtmp; \ +- __asm__ ("ff1 %0,%1" \ +- : "=r" (__cbtmp) \ +- : "r" ((USItype)(x))); \ +- (count) = __cbtmp ^ 31; \ +-} while (0) +-#define COUNT_LEADING_ZEROS_0 63 /* sic */ + #if defined(__m88110__) + #define umul_ppmm(wh, wl, u, v) \ + do { \ +@@ -779,12 +717,6 @@ do { \ + : "0" (__xx.__ll), \ + "g" ((USItype)(d))); \ + (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) +-#define count_trailing_zeros(count, x) \ +-do { \ +- __asm__("ffsd %2,%0" \ +- : "=r"((USItype) (count)) \ +- : "0"((USItype) 0), "r"((USItype) (x))); \ +- } while (0) + #endif /* __ns32000__ */ + + /*************************************** +@@ -855,11 +787,6 @@ do { \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + } while (0) +-#define count_leading_zeros(count, x) \ +- __asm__ ("{cntlz|cntlzw} %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x))) +-#define COUNT_LEADING_ZEROS_0 32 + #if defined(_ARCH_PPC) + #define umul_ppmm(ph, pl, m0, m1) \ + do { \ +@@ -1001,19 +928,6 @@ do { \ + } while (0) + #define UMUL_TIME 20 + #define UDIV_TIME 200 +-#define count_leading_zeros(count, x) \ +-do { \ +- if ((x) >= 0x10000) \ +- __asm__ ("clz %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x) >> 16)); \ +- else { \ +- __asm__ ("clz %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x))); \ +- (count) += 16; \ +- } \ +-} while (0) + #endif /* RT/ROMP */ + + /*************************************** +@@ -1142,13 +1056,6 @@ do { \ + "rI" ((USItype)(d)) \ + : "%g1" __AND_CLOBBER_CC) + #define UDIV_TIME 37 +-#define count_leading_zeros(count, x) \ +- __asm__ ("scan %1,0,%0" \ +- : "=r" ((USItype)(x)) \ +- : "r" ((USItype)(count))) +-/* Early sparclites return 63 for an argument of 0, but they warn that future +- implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 +- undefined. */ + #endif /* __sparclite__ */ + #endif /* __sparc_v8__ */ + /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */ +@@ -1454,47 +1361,6 @@ do { \ + #define udiv_qrnnd __udiv_qrnnd_c + #endif + +-#undef count_leading_zeros +-#if !defined(count_leading_zeros) +- extern +-#ifdef __STDC__ +- const +-#endif +- unsigned char __clz_tab[]; +-#define count_leading_zeros(count, x) \ +-do { \ +- UWtype __xr = (x); \ +- UWtype __a; \ +- \ +- if (W_TYPE_SIZE <= 32) { \ +- __a = __xr < ((UWtype) 1 << 2*__BITS4) \ +- ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \ +- : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ +- } \ +- else { \ +- for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ +- if (((__xr >> __a) & 0xff) != 0) \ +- break; \ +- } \ +- \ +- (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ +-} while (0) +- /* This version gives a well-defined value for zero. */ +-#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +-#endif +- +-#if !defined(count_trailing_zeros) +-/* Define count_trailing_zeros using count_leading_zeros. The latter might be +- defined in asm, but if it is not, the C version above is good enough. */ +-#define count_trailing_zeros(count, x) \ +-do { \ +- UWtype __ctz_x = (x); \ +- UWtype __ctz_c; \ +- count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \ +- (count) = W_TYPE_SIZE - 1 - __ctz_c; \ +-} while (0) +-#endif +- + #ifndef UDIV_NEEDS_NORMALIZATION + #define UDIV_NEEDS_NORMALIZATION 0 + #endif +diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c +index 5687248..503537e 100644 +--- a/lib/mpi/mpi-bit.c ++++ b/lib/mpi/mpi-bit.c +@@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a) + if (a->nlimbs) { + mpi_limb_t alimb = a->d[a->nlimbs - 1]; + if (alimb) +- count_leading_zeros(n, alimb); ++ n = count_leading_zeros(alimb); + else + n = BITS_PER_MPI_LIMB; + n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB; +diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c +index 67f3e79..5464c87 100644 +--- a/lib/mpi/mpi-pow.c ++++ b/lib/mpi/mpi-pow.c +@@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) + mp = mp_marker = mpi_alloc_limb_space(msize); + if (!mp) + goto enomem; +- count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); ++ mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]); + if (mod_shift_cnt) + mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); + else +@@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) + + i = esize - 1; + e = ep[i]; +- count_leading_zeros(c, e); ++ c = count_leading_zeros(e); + e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ + c = BITS_PER_MPI_LIMB - 1 - c; + +-- +1.7.12.1 + + +From ef184bcab1e58dafae2f02ae30824365bec1d27a Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 13 Sep 2012 15:17:21 +0100 +Subject: [PATCH 04/37] KEYS: Document asymmetric key type + +In-source documentation for the asymmetric key type. This will be located in: + + Documentation/crypto/asymmetric-keys.txt + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + Documentation/crypto/asymmetric-keys.txt | 312 +++++++++++++++++++++++++++++++ + 1 file changed, 312 insertions(+) + create mode 100644 Documentation/crypto/asymmetric-keys.txt + +diff --git a/Documentation/crypto/asymmetric-keys.txt b/Documentation/crypto/asymmetric-keys.txt +new file mode 100644 +index 0000000..b767590 +--- /dev/null ++++ b/Documentation/crypto/asymmetric-keys.txt +@@ -0,0 +1,312 @@ ++ ============================================= ++ ASYMMETRIC / PUBLIC-KEY CRYPTOGRAPHY KEY TYPE ++ ============================================= ++ ++Contents: ++ ++ - Overview. ++ - Key identification. ++ - Accessing asymmetric keys. ++ - Signature verification. ++ - Asymmetric key subtypes. ++ - Instantiation data parsers. ++ ++ ++======== ++OVERVIEW ++======== ++ ++The "asymmetric" key type is designed to be a container for the keys used in ++public-key cryptography, without imposing any particular restrictions on the ++form or mechanism of the cryptography or form of the key. ++ ++The asymmetric key is given a subtype that defines what sort of data is ++associated with the key and provides operations to describe and destroy it. ++However, no requirement is made that the key data actually be stored in the ++key. ++ ++A completely in-kernel key retention and operation subtype can be defined, but ++it would also be possible to provide access to cryptographic hardware (such as ++a TPM) that might be used to both retain the relevant key and perform ++operations using that key. In such a case, the asymmetric key would then ++merely be an interface to the TPM driver. ++ ++Also provided is the concept of a data parser. Data parsers are responsible ++for extracting information from the blobs of data passed to the instantiation ++function. The first data parser that recognises the blob gets to set the ++subtype of the key and define the operations that can be done on that key. ++ ++A data parser may interpret the data blob as containing the bits representing a ++key, or it may interpret it as a reference to a key held somewhere else in the ++system (for example, a TPM). ++ ++ ++================== ++KEY IDENTIFICATION ++================== ++ ++If a key is added with an empty name, the instantiation data parsers are given ++the opportunity to pre-parse a key and to determine the description the key ++should be given from the content of the key. ++ ++This can then be used to refer to the key, either by complete match or by ++partial match. The key type may also use other criteria to refer to a key. ++ ++The asymmetric key type's match function can then perform a wider range of ++comparisons than just the straightforward comparison of the description with ++the criterion string: ++ ++ (1) If the criterion string is of the form "id:<hexdigits>" then the match ++ function will examine a key's fingerprint to see if the hex digits given ++ after the "id:" match the tail. For instance: ++ ++ keyctl search @s asymmetric id:5acc2142 ++ ++ will match a key with fingerprint: ++ ++ 1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142 ++ ++ (2) If the criterion string is of the form "<subtype>:<hexdigits>" then the ++ match will match the ID as in (1), but with the added restriction that ++ only keys of the specified subtype (e.g. tpm) will be matched. For ++ instance: ++ ++ keyctl search @s asymmetric tpm:5acc2142 ++ ++Looking in /proc/keys, the last 8 hex digits of the key fingerprint are ++displayed, along with the subtype: ++ ++ 1a39e171 I----- 1 perm 3f010000 0 0 asymmetri modsign.0: DSA 5acc2142 [] ++ ++ ++========================= ++ACCESSING ASYMMETRIC KEYS ++========================= ++ ++For general access to asymmetric keys from within the kernel, the following ++inclusion is required: ++ ++ #include <crypto/public_key.h> ++ ++This gives access to functions for dealing with asymmetric / public keys. ++Three enums are defined there for representing public-key cryptography ++algorithms: ++ ++ enum pkey_algo ++ ++digest algorithms used by those: ++ ++ enum pkey_hash_algo ++ ++and key identifier representations: ++ ++ enum pkey_id_type ++ ++Note that the key type representation types are required because key ++identifiers from different standards aren't necessarily compatible. For ++instance, PGP generates key identifiers by hashing the key data plus some ++PGP-specific metadata, whereas X.509 has arbitrary certificate identifiers. ++ ++The operations defined upon a key are: ++ ++ (1) Signature verification. ++ ++Other operations are possible (such as encryption) with the same key data ++required for verification, but not currently supported, and others ++(eg. decryption and signature generation) require extra key data. ++ ++ ++SIGNATURE VERIFICATION ++---------------------- ++ ++An operation is provided to perform cryptographic signature verification, using ++an asymmetric key to provide or to provide access to the public key. ++ ++ int verify_signature(const struct key *key, ++ const struct public_key_signature *sig); ++ ++The caller must have already obtained the key from some source and can then use ++it to check the signature. The caller must have parsed the signature and ++transferred the relevant bits to the structure pointed to by sig. ++ ++ struct public_key_signature { ++ u8 *digest; ++ u8 digest_size; ++ enum pkey_hash_algo pkey_hash_algo : 8; ++ u8 nr_mpi; ++ union { ++ MPI mpi[2]; ++ ... ++ }; ++ }; ++ ++The algorithm used must be noted in sig->pkey_hash_algo, and all the MPIs that ++make up the actual signature must be stored in sig->mpi[] and the count of MPIs ++placed in sig->nr_mpi. ++ ++In addition, the data must have been digested by the caller and the resulting ++hash must be pointed to by sig->digest and the size of the hash be placed in ++sig->digest_size. ++ ++The function will return 0 upon success or -EKEYREJECTED if the signature ++doesn't match. ++ ++The function may also return -ENOTSUPP if an unsupported public-key algorithm ++or public-key/hash algorithm combination is specified or the key doesn't ++support the operation; -EBADMSG or -ERANGE if some of the parameters have weird ++data; or -ENOMEM if an allocation can't be performed. -EINVAL can be returned ++if the key argument is the wrong type or is incompletely set up. ++ ++ ++======================= ++ASYMMETRIC KEY SUBTYPES ++======================= ++ ++Asymmetric keys have a subtype that defines the set of operations that can be ++performed on that key and that determines what data is attached as the key ++payload. The payload format is entirely at the whim of the subtype. ++ ++The subtype is selected by the key data parser and the parser must initialise ++the data required for it. The asymmetric key retains a reference on the ++subtype module. ++ ++The subtype definition structure can be found in: ++ ++ #include <keys/asymmetric-subtype.h> ++ ++and looks like the following: ++ ++ struct asymmetric_key_subtype { ++ struct module *owner; ++ const char *name; ++ ++ void (*describe)(const struct key *key, struct seq_file *m); ++ void (*destroy)(void *payload); ++ int (*verify_signature)(const struct key *key, ++ const struct public_key_signature *sig); ++ }; ++ ++Asymmetric keys point to this with their type_data[0] member. ++ ++The owner and name fields should be set to the owning module and the name of ++the subtype. Currently, the name is only used for print statements. ++ ++There are a number of operations defined by the subtype: ++ ++ (1) describe(). ++ ++ Mandatory. This allows the subtype to display something in /proc/keys ++ against the key. For instance the name of the public key algorithm type ++ could be displayed. The key type will display the tail of the key ++ identity string after this. ++ ++ (2) destroy(). ++ ++ Mandatory. This should free the memory associated with the key. The ++ asymmetric key will look after freeing the fingerprint and releasing the ++ reference on the subtype module. ++ ++ (3) verify_signature(). ++ ++ Optional. These are the entry points for the key usage operations. ++ Currently there is only the one defined. If not set, the caller will be ++ given -ENOTSUPP. The subtype may do anything it likes to implement an ++ operation, including offloading to hardware. ++ ++ ++========================== ++INSTANTIATION DATA PARSERS ++========================== ++ ++The asymmetric key type doesn't generally want to store or to deal with a raw ++blob of data that holds the key data. It would have to parse it and error ++check it each time it wanted to use it. Further, the contents of the blob may ++have various checks that can be performed on it (eg. self-signatures, validity ++dates) and may contain useful data about the key (identifiers, capabilities). ++ ++Also, the blob may represent a pointer to some hardware containing the key ++rather than the key itself. ++ ++Examples of blob formats for which parsers could be implemented include: ++ ++ - OpenPGP packet stream [RFC 4880]. ++ - X.509 ASN.1 stream. ++ - Pointer to TPM key. ++ - Pointer to UEFI key. ++ ++During key instantiation each parser in the list is tried until one doesn't ++return -EBADMSG. ++ ++The parser definition structure can be found in: ++ ++ #include <keys/asymmetric-parser.h> ++ ++and looks like the following: ++ ++ struct asymmetric_key_parser { ++ struct module *owner; ++ const char *name; ++ ++ int (*parse)(struct key_preparsed_payload *prep); ++ }; ++ ++The owner and name fields should be set to the owning module and the name of ++the parser. ++ ++There is currently only a single operation defined by the parser, and it is ++mandatory: ++ ++ (1) parse(). ++ ++ This is called to preparse the key from the key creation and update paths. ++ In particular, it is called during the key creation _before_ a key is ++ allocated, and as such, is permitted to provide the key's description in ++ the case that the caller declines to do so. ++ ++ The caller passes a pointer to the following struct with all of the fields ++ cleared, except for data, datalen and quotalen [see ++ Documentation/security/keys.txt]. ++ ++ struct key_preparsed_payload { ++ char *description; ++ void *type_data[2]; ++ void *payload; ++ const void *data; ++ size_t datalen; ++ size_t quotalen; ++ }; ++ ++ The instantiation data is in a blob pointed to by data and is datalen in ++ size. The parse() function is not permitted to change these two values at ++ all, and shouldn't change any of the other values _unless_ they are ++ recognise the blob format and will not return -EBADMSG to indicate it is ++ not theirs. ++ ++ If the parser is happy with the blob, it should propose a description for ++ the key and attach it to ->description, ->type_data[0] should be set to ++ point to the subtype to be used, ->payload should be set to point to the ++ initialised data for that subtype, ->type_data[1] should point to a hex ++ fingerprint and quotalen should be updated to indicate how much quota this ++ key should account for. ++ ++ When clearing up, the data attached to ->type_data[1] and ->description ++ will be kfree()'d and the data attached to ->payload will be passed to the ++ subtype's ->destroy() method to be disposed of. A module reference for ++ the subtype pointed to by ->type_data[0] will be put. ++ ++ ++ If the data format is not recognised, -EBADMSG should be returned. If it ++ is recognised, but the key cannot for some reason be set up, some other ++ negative error code should be returned. On success, 0 should be returned. ++ ++ The key's fingerprint string may be partially matched upon. For a ++ public-key algorithm such as RSA and DSA this will likely be a printable ++ hex version of the key's fingerprint. ++ ++Functions are provided to register and unregister parsers: ++ ++ int register_asymmetric_key_parser(struct asymmetric_key_parser *parser); ++ void unregister_asymmetric_key_parser(struct asymmetric_key_parser *subtype); ++ ++Parsers may not have the same name. The names are otherwise only used for ++displaying in debugging messages. +-- +1.7.12.1 + + +From 0e450d75d1067b6f45f1f6b58a530a5d95144373 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 13 Sep 2012 15:17:21 +0100 +Subject: [PATCH 05/37] KEYS: Implement asymmetric key type + +Create a key type that can be used to represent an asymmetric key type for use +in appropriate cryptographic operations, such as encryption, decryption, +signature generation and signature verification. + +The key type is "asymmetric" and can provide access to a variety of +cryptographic algorithms. + +Possibly, this would be better as "public_key" - but that has the disadvantage +that "public key" is an overloaded term. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/Kconfig | 1 + + crypto/Makefile | 1 + + crypto/asymmetric_keys/Kconfig | 13 +++ + crypto/asymmetric_keys/Makefile | 7 ++ + crypto/asymmetric_keys/asymmetric_keys.h | 15 +++ + crypto/asymmetric_keys/asymmetric_type.c | 156 +++++++++++++++++++++++++++++++ + include/keys/asymmetric-subtype.h | 55 +++++++++++ + include/keys/asymmetric-type.h | 25 +++++ + 8 files changed, 273 insertions(+) + create mode 100644 crypto/asymmetric_keys/Kconfig + create mode 100644 crypto/asymmetric_keys/Makefile + create mode 100644 crypto/asymmetric_keys/asymmetric_keys.h + create mode 100644 crypto/asymmetric_keys/asymmetric_type.c + create mode 100644 include/keys/asymmetric-subtype.h + create mode 100644 include/keys/asymmetric-type.h + +diff --git a/crypto/Kconfig b/crypto/Kconfig +index a323805..1ca0b24 100644 +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1043,5 +1043,6 @@ config CRYPTO_USER_API_SKCIPHER + key cipher algorithms. + + source "drivers/crypto/Kconfig" ++source crypto/asymmetric_keys/Kconfig + + endif # if CRYPTO +diff --git a/crypto/Makefile b/crypto/Makefile +index 30f33d6..ced472e 100644 +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -96,3 +96,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o + # + obj-$(CONFIG_XOR_BLOCKS) += xor.o + obj-$(CONFIG_ASYNC_CORE) += async_tx/ ++obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ +diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig +new file mode 100644 +index 0000000..cad29b3 +--- /dev/null ++++ b/crypto/asymmetric_keys/Kconfig +@@ -0,0 +1,13 @@ ++menuconfig ASYMMETRIC_KEY_TYPE ++ tristate "Asymmetric (public-key cryptographic) key type" ++ depends on KEYS ++ help ++ This option provides support for a key type that holds the data for ++ the asymmetric keys used for public key cryptographic operations such ++ as encryption, decryption, signature generation and signature ++ verification. ++ ++if ASYMMETRIC_KEY_TYPE ++ ++ ++endif # ASYMMETRIC_KEY_TYPE +diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile +new file mode 100644 +index 0000000..b725bcc +--- /dev/null ++++ b/crypto/asymmetric_keys/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for asymmetric cryptographic keys ++# ++ ++obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o ++ ++asymmetric_keys-y := asymmetric_type.o +diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h +new file mode 100644 +index 0000000..515b634 +--- /dev/null ++++ b/crypto/asymmetric_keys/asymmetric_keys.h +@@ -0,0 +1,15 @@ ++/* Internal definitions for asymmetric key type ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++static inline const char *asymmetric_key_id(const struct key *key) ++{ ++ return key->type_data.p[1]; ++} +diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c +new file mode 100644 +index 0000000..bfb0424 +--- /dev/null ++++ b/crypto/asymmetric_keys/asymmetric_type.c +@@ -0,0 +1,156 @@ ++/* Asymmetric public-key cryptography key type ++ * ++ * See Documentation/security/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++#include <keys/asymmetric-subtype.h> ++#include <linux/seq_file.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include "asymmetric_keys.h" ++ ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Match asymmetric keys on (part of) their name ++ * We have some shorthand methods for matching keys. We allow: ++ * ++ * "<desc>" - request a key by description ++ * "id:<id>" - request a key matching the ID ++ * "<subtype>:<id>" - request a key of a subtype ++ */ ++static int asymmetric_key_match(const struct key *key, const void *description) ++{ ++ const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); ++ const char *spec = description; ++ const char *id, *kid; ++ ptrdiff_t speclen; ++ size_t idlen, kidlen; ++ ++ if (!subtype || !spec || !*spec) ++ return 0; ++ ++ /* See if the full key description matches as is */ ++ if (key->description && strcmp(key->description, description) == 0) ++ return 1; ++ ++ /* All tests from here on break the criterion description into a ++ * specifier, a colon and then an identifier. ++ */ ++ id = strchr(spec, ':'); ++ if (!id) ++ return 0; ++ ++ speclen = id - spec; ++ id++; ++ ++ /* Anything after here requires a partial match on the ID string */ ++ kid = asymmetric_key_id(key); ++ if (!kid) ++ return 0; ++ ++ idlen = strlen(id); ++ kidlen = strlen(kid); ++ if (idlen > kidlen) ++ return 0; ++ ++ kid += kidlen - idlen; ++ if (strcasecmp(id, kid) != 0) ++ return 0; ++ ++ if (speclen == 2 && ++ memcmp(spec, "id", 2) == 0) ++ return 1; ++ ++ if (speclen == subtype->name_len && ++ memcmp(spec, subtype->name, speclen) == 0) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * Describe the asymmetric key ++ */ ++static void asymmetric_key_describe(const struct key *key, struct seq_file *m) ++{ ++ const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); ++ const char *kid = asymmetric_key_id(key); ++ size_t n; ++ ++ seq_puts(m, key->description); ++ ++ if (subtype) { ++ seq_puts(m, ": "); ++ subtype->describe(key, m); ++ ++ if (kid) { ++ seq_putc(m, ' '); ++ n = strlen(kid); ++ if (n <= 8) ++ seq_puts(m, kid); ++ else ++ seq_puts(m, kid + n - 8); ++ } ++ ++ seq_puts(m, " ["); ++ /* put something here to indicate the key's capabilities */ ++ seq_putc(m, ']'); ++ } ++} ++ ++/* ++ * Instantiate a asymmetric_key defined key. The key was preparsed, so we just ++ * have to transfer the data here. ++ */ ++static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep) ++{ ++ return -EOPNOTSUPP; ++} ++ ++/* ++ * dispose of the data dangling from the corpse of a asymmetric key ++ */ ++static void asymmetric_key_destroy(struct key *key) ++{ ++ struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); ++ if (subtype) { ++ subtype->destroy(key->payload.data); ++ module_put(subtype->owner); ++ key->type_data.p[0] = NULL; ++ } ++ kfree(key->type_data.p[1]); ++ key->type_data.p[1] = NULL; ++} ++ ++struct key_type key_type_asymmetric = { ++ .name = "asymmetric", ++ .instantiate = asymmetric_key_instantiate, ++ .match = asymmetric_key_match, ++ .destroy = asymmetric_key_destroy, ++ .describe = asymmetric_key_describe, ++}; ++EXPORT_SYMBOL_GPL(key_type_asymmetric); ++ ++/* ++ * Module stuff ++ */ ++static int __init asymmetric_key_init(void) ++{ ++ return register_key_type(&key_type_asymmetric); ++} ++ ++static void __exit asymmetric_key_cleanup(void) ++{ ++ unregister_key_type(&key_type_asymmetric); ++} ++ ++module_init(asymmetric_key_init); ++module_exit(asymmetric_key_cleanup); +diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h +new file mode 100644 +index 0000000..4b840e8 +--- /dev/null ++++ b/include/keys/asymmetric-subtype.h +@@ -0,0 +1,55 @@ ++/* Asymmetric public-key cryptography key subtype ++ * ++ * See Documentation/security/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _KEYS_ASYMMETRIC_SUBTYPE_H ++#define _KEYS_ASYMMETRIC_SUBTYPE_H ++ ++#include <linux/seq_file.h> ++#include <keys/asymmetric-type.h> ++ ++struct public_key_signature; ++ ++/* ++ * Keys of this type declare a subtype that indicates the handlers and ++ * capabilities. ++ */ ++struct asymmetric_key_subtype { ++ struct module *owner; ++ const char *name; ++ unsigned short name_len; /* length of name */ ++ ++ /* Describe a key of this subtype for /proc/keys */ ++ void (*describe)(const struct key *key, struct seq_file *m); ++ ++ /* Destroy a key of this subtype */ ++ void (*destroy)(void *payload); ++ ++ /* Verify the signature on a key of this subtype (optional) */ ++ int (*verify_signature)(const struct key *key, ++ const struct public_key_signature *sig); ++}; ++ ++/** ++ * asymmetric_key_subtype - Get the subtype from an asymmetric key ++ * @key: The key of interest. ++ * ++ * Retrieves and returns the subtype pointer of the asymmetric key from the ++ * type-specific data attached to the key. ++ */ ++static inline ++struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key) ++{ ++ return key->type_data.p[0]; ++} ++ ++#endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */ +diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h +new file mode 100644 +index 0000000..7dd4734 +--- /dev/null ++++ b/include/keys/asymmetric-type.h +@@ -0,0 +1,25 @@ ++/* Asymmetric Public-key cryptography key type interface ++ * ++ * See Documentation/security/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _KEYS_ASYMMETRIC_TYPE_H ++#define _KEYS_ASYMMETRIC_TYPE_H ++ ++#include <linux/key-type.h> ++ ++extern struct key_type key_type_asymmetric; ++ ++/* ++ * The payload is at the discretion of the subtype. ++ */ ++ ++#endif /* _KEYS_ASYMMETRIC_TYPE_H */ +-- +1.7.12.1 + + +From 6ec62201b26995d57fbd457469314bfc5653f2a0 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 13 Sep 2012 15:17:32 +0100 +Subject: [PATCH 06/37] KEYS: Asymmetric key pluggable data parsers + +The instantiation data passed to the asymmetric key type are expected to be +formatted in some way, and there are several possible standard ways to format +the data. + +The two obvious standards are OpenPGP keys and X.509 certificates. The latter +is especially useful when dealing with UEFI, and the former might be useful +when dealing with, say, eCryptfs. + +Further, it might be desirable to provide formatted blobs that indicate +hardware is to be accessed to retrieve the keys or that the keys live +unretrievably in a hardware store, but that the keys can be used by means of +the hardware. + +From userspace, the keys can be loaded using the keyctl command, for example, +an X.509 binary certificate: + + keyctl padd asymmetric foo @s <dhowells.pem + +or a PGP key: + + keyctl padd asymmetric bar @s <dhowells.pub + +or a pointer into the contents of the TPM: + + keyctl add asymmetric zebra "TPM:04982390582905f8" @s + +Inside the kernel, pluggable parsers register themselves and then get to +examine the payload data to see if they can handle it. If they can, they get +to: + + (1) Propose a name for the key, to be used it the name is "" or NULL. + + (2) Specify the key subtype. + + (3) Provide the data for the subtype. + +The key type asks the parser to do its stuff before a key is allocated and thus +before the name is set. If successful, the parser stores the suggested data +into the key_preparsed_payload struct, which will be either used (if the key is +successfully created and instantiated or updated) or discarded. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/asymmetric_type.c | 120 ++++++++++++++++++++++++++++++- + include/keys/asymmetric-parser.h | 37 ++++++++++ + 2 files changed, 156 insertions(+), 1 deletion(-) + create mode 100644 include/keys/asymmetric-parser.h + +diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c +index bfb0424..cf80765 100644 +--- a/crypto/asymmetric_keys/asymmetric_type.c ++++ b/crypto/asymmetric_keys/asymmetric_type.c +@@ -11,6 +11,7 @@ + * 2 of the Licence, or (at your option) any later version. + */ + #include <keys/asymmetric-subtype.h> ++#include <keys/asymmetric-parser.h> + #include <linux/seq_file.h> + #include <linux/module.h> + #include <linux/slab.h> +@@ -18,6 +19,9 @@ + + MODULE_LICENSE("GPL"); + ++static LIST_HEAD(asymmetric_key_parsers); ++static DECLARE_RWSEM(asymmetric_key_parsers_sem); ++ + /* + * Match asymmetric keys on (part of) their name + * We have some shorthand methods for matching keys. We allow: +@@ -107,12 +111,79 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m) + } + + /* ++ * Preparse a asymmetric payload to get format the contents appropriately for the ++ * internal payload to cut down on the number of scans of the data performed. ++ * ++ * We also generate a proposed description from the contents of the key that ++ * can be used to name the key if the user doesn't want to provide one. ++ */ ++static int asymmetric_key_preparse(struct key_preparsed_payload *prep) ++{ ++ struct asymmetric_key_parser *parser; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (prep->datalen == 0) ++ return -EINVAL; ++ ++ down_read(&asymmetric_key_parsers_sem); ++ ++ ret = -EBADMSG; ++ list_for_each_entry(parser, &asymmetric_key_parsers, link) { ++ pr_debug("Trying parser '%s'\n", parser->name); ++ ++ ret = parser->parse(prep); ++ if (ret != -EBADMSG) { ++ pr_debug("Parser recognised the format (ret %d)\n", ++ ret); ++ break; ++ } ++ } ++ ++ up_read(&asymmetric_key_parsers_sem); ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; ++} ++ ++/* ++ * Clean up the preparse data ++ */ ++static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) ++{ ++ struct asymmetric_key_subtype *subtype = prep->type_data[0]; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (subtype) { ++ subtype->destroy(prep->payload); ++ module_put(subtype->owner); ++ } ++ kfree(prep->type_data[1]); ++ kfree(prep->description); ++} ++ ++/* + * Instantiate a asymmetric_key defined key. The key was preparsed, so we just + * have to transfer the data here. + */ + static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep) + { +- return -EOPNOTSUPP; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ ret = key_payload_reserve(key, prep->quotalen); ++ if (ret == 0) { ++ key->type_data.p[0] = prep->type_data[0]; ++ key->type_data.p[1] = prep->type_data[1]; ++ key->payload.data = prep->payload; ++ prep->type_data[0] = NULL; ++ prep->type_data[1] = NULL; ++ prep->payload = NULL; ++ } ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; + } + + /* +@@ -132,6 +203,8 @@ static void asymmetric_key_destroy(struct key *key) + + struct key_type key_type_asymmetric = { + .name = "asymmetric", ++ .preparse = asymmetric_key_preparse, ++ .free_preparse = asymmetric_key_free_preparse, + .instantiate = asymmetric_key_instantiate, + .match = asymmetric_key_match, + .destroy = asymmetric_key_destroy, +@@ -139,6 +212,51 @@ struct key_type key_type_asymmetric = { + }; + EXPORT_SYMBOL_GPL(key_type_asymmetric); + ++/** ++ * register_asymmetric_key_parser - Register a asymmetric key blob parser ++ * @parser: The parser to register ++ */ ++int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) ++{ ++ struct asymmetric_key_parser *cursor; ++ int ret; ++ ++ down_write(&asymmetric_key_parsers_sem); ++ ++ list_for_each_entry(cursor, &asymmetric_key_parsers, link) { ++ if (strcmp(cursor->name, parser->name) == 0) { ++ pr_err("Asymmetric key parser '%s' already registered\n", ++ parser->name); ++ ret = -EEXIST; ++ goto out; ++ } ++ } ++ ++ list_add_tail(&parser->link, &asymmetric_key_parsers); ++ ++ pr_notice("Asymmetric key parser '%s' registered\n", parser->name); ++ ret = 0; ++ ++out: ++ up_write(&asymmetric_key_parsers_sem); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); ++ ++/** ++ * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser ++ * @parser: The parser to unregister ++ */ ++void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) ++{ ++ down_write(&asymmetric_key_parsers_sem); ++ list_del(&parser->link); ++ up_write(&asymmetric_key_parsers_sem); ++ ++ pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); ++} ++EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); ++ + /* + * Module stuff + */ +diff --git a/include/keys/asymmetric-parser.h b/include/keys/asymmetric-parser.h +new file mode 100644 +index 0000000..09b3b48 +--- /dev/null ++++ b/include/keys/asymmetric-parser.h +@@ -0,0 +1,37 @@ ++/* Asymmetric public-key cryptography data parser ++ * ++ * See Documentation/crypto/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _KEYS_ASYMMETRIC_PARSER_H ++#define _KEYS_ASYMMETRIC_PARSER_H ++ ++/* ++ * Key data parser. Called during key instantiation. ++ */ ++struct asymmetric_key_parser { ++ struct list_head link; ++ struct module *owner; ++ const char *name; ++ ++ /* Attempt to parse a key from the data blob passed to add_key() or ++ * keyctl_instantiate(). Should also generate a proposed description ++ * that the caller can optionally use for the key. ++ * ++ * Return EBADMSG if not recognised. ++ */ ++ int (*parse)(struct key_preparsed_payload *prep); ++}; ++ ++extern int register_asymmetric_key_parser(struct asymmetric_key_parser *); ++extern void unregister_asymmetric_key_parser(struct asymmetric_key_parser *); ++ ++#endif /* _KEYS_ASYMMETRIC_PARSER_H */ +-- +1.7.12.1 + + +From 390ad626607322c6e4da8a2e6d2a4094e78b919a Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:24:55 +0100 +Subject: [PATCH 07/37] KEYS: Asymmetric public-key algorithm crypto key + subtype + +Add a subtype for supporting asymmetric public-key encryption algorithms such +as DSA (FIPS-186) and RSA (PKCS#1 / RFC1337). + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/Kconfig | 8 +++ + crypto/asymmetric_keys/Makefile | 2 + + crypto/asymmetric_keys/public_key.c | 108 ++++++++++++++++++++++++++++++++++++ + crypto/asymmetric_keys/public_key.h | 28 ++++++++++ + include/crypto/public_key.h | 104 ++++++++++++++++++++++++++++++++++ + 5 files changed, 250 insertions(+) + create mode 100644 crypto/asymmetric_keys/public_key.c + create mode 100644 crypto/asymmetric_keys/public_key.h + create mode 100644 include/crypto/public_key.h + +diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig +index cad29b3..bbfccaa 100644 +--- a/crypto/asymmetric_keys/Kconfig ++++ b/crypto/asymmetric_keys/Kconfig +@@ -9,5 +9,13 @@ menuconfig ASYMMETRIC_KEY_TYPE + + if ASYMMETRIC_KEY_TYPE + ++config ASYMMETRIC_PUBLIC_KEY_SUBTYPE ++ tristate "Asymmetric public-key crypto algorithm subtype" ++ select MPILIB ++ help ++ This option provides support for asymmetric public key type handling. ++ If signature generation and/or verification are to be used, ++ appropriate hash algorithms (such as SHA-1) must be available. ++ ENOPKG will be reported if the requisite algorithm is unavailable. + + endif # ASYMMETRIC_KEY_TYPE +diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile +index b725bcc..5ed46ee 100644 +--- a/crypto/asymmetric_keys/Makefile ++++ b/crypto/asymmetric_keys/Makefile +@@ -5,3 +5,5 @@ + obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o + + asymmetric_keys-y := asymmetric_type.o ++ ++obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o +diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c +new file mode 100644 +index 0000000..cb2e291 +--- /dev/null ++++ b/crypto/asymmetric_keys/public_key.c +@@ -0,0 +1,108 @@ ++/* In-software asymmetric public-key crypto subtype ++ * ++ * See Documentation/crypto/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "PKEY: "fmt ++#include <linux/module.h> ++#include <linux/export.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/seq_file.h> ++#include <keys/asymmetric-subtype.h> ++#include "public_key.h" ++ ++MODULE_LICENSE("GPL"); ++ ++const char *const pkey_algo[PKEY_ALGO__LAST] = { ++ [PKEY_ALGO_DSA] = "DSA", ++ [PKEY_ALGO_RSA] = "RSA", ++}; ++EXPORT_SYMBOL_GPL(pkey_algo); ++ ++const char *const pkey_hash_algo[PKEY_HASH__LAST] = { ++ [PKEY_HASH_MD4] = "md4", ++ [PKEY_HASH_MD5] = "md5", ++ [PKEY_HASH_SHA1] = "sha1", ++ [PKEY_HASH_RIPE_MD_160] = "rmd160", ++ [PKEY_HASH_SHA256] = "sha256", ++ [PKEY_HASH_SHA384] = "sha384", ++ [PKEY_HASH_SHA512] = "sha512", ++ [PKEY_HASH_SHA224] = "sha224", ++}; ++EXPORT_SYMBOL_GPL(pkey_hash_algo); ++ ++const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { ++ [PKEY_ID_PGP] = "PGP", ++ [PKEY_ID_X509] = "X509", ++}; ++EXPORT_SYMBOL_GPL(pkey_id_type); ++ ++/* ++ * Provide a part of a description of the key for /proc/keys. ++ */ ++static void public_key_describe(const struct key *asymmetric_key, ++ struct seq_file *m) ++{ ++ struct public_key *key = asymmetric_key->payload.data; ++ ++ if (key) ++ seq_printf(m, "%s.%s", ++ pkey_id_type[key->id_type], key->algo->name); ++} ++ ++/* ++ * Destroy a public key algorithm key. ++ */ ++void public_key_destroy(void *payload) ++{ ++ struct public_key *key = payload; ++ int i; ++ ++ if (key) { ++ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) ++ mpi_free(key->mpi[i]); ++ kfree(key); ++ } ++} ++EXPORT_SYMBOL_GPL(public_key_destroy); ++ ++/* ++ * Verify a signature using a public key. ++ */ ++static int public_key_verify_signature(const struct key *key, ++ const struct public_key_signature *sig) ++{ ++ const struct public_key *pk = key->payload.data; ++ ++ if (!pk->algo->verify_signature) ++ return -ENOTSUPP; ++ ++ if (sig->nr_mpi != pk->algo->n_sig_mpi) { ++ pr_debug("Signature has %u MPI not %u\n", ++ sig->nr_mpi, pk->algo->n_sig_mpi); ++ return -EINVAL; ++ } ++ ++ return pk->algo->verify_signature(pk, sig); ++} ++ ++/* ++ * Public key algorithm asymmetric key subtype ++ */ ++struct asymmetric_key_subtype public_key_subtype = { ++ .owner = THIS_MODULE, ++ .name = "public_key", ++ .describe = public_key_describe, ++ .destroy = public_key_destroy, ++ .verify_signature = public_key_verify_signature, ++}; ++EXPORT_SYMBOL_GPL(public_key_subtype); +diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h +new file mode 100644 +index 0000000..1f86aad +--- /dev/null ++++ b/crypto/asymmetric_keys/public_key.h +@@ -0,0 +1,28 @@ ++/* Public key algorithm internals ++ * ++ * See Documentation/crypto/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <crypto/public_key.h> ++ ++extern struct asymmetric_key_subtype public_key_subtype; ++ ++/* ++ * Public key algorithm definition. ++ */ ++struct public_key_algorithm { ++ const char *name; ++ u8 n_pub_mpi; /* Number of MPIs in public key */ ++ u8 n_sec_mpi; /* Number of MPIs in secret key */ ++ u8 n_sig_mpi; /* Number of MPIs in a signature */ ++ int (*verify_signature)(const struct public_key *key, ++ const struct public_key_signature *sig); ++}; +diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h +new file mode 100644 +index 0000000..4b8b6c1 +--- /dev/null ++++ b/include/crypto/public_key.h +@@ -0,0 +1,104 @@ ++/* Asymmetric public-key algorithm definitions ++ * ++ * See Documentation/crypto/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_PUBLIC_KEY_H ++#define _LINUX_PUBLIC_KEY_H ++ ++#include <linux/mpi.h> ++ ++enum pkey_algo { ++ PKEY_ALGO_DSA, ++ PKEY_ALGO_RSA, ++ PKEY_ALGO__LAST ++}; ++ ++extern const char *const pkey_algo[PKEY_ALGO__LAST]; ++ ++enum pkey_hash_algo { ++ PKEY_HASH_MD4, ++ PKEY_HASH_MD5, ++ PKEY_HASH_SHA1, ++ PKEY_HASH_RIPE_MD_160, ++ PKEY_HASH_SHA256, ++ PKEY_HASH_SHA384, ++ PKEY_HASH_SHA512, ++ PKEY_HASH_SHA224, ++ PKEY_HASH__LAST ++}; ++ ++extern const char *const pkey_hash_algo[PKEY_HASH__LAST]; ++ ++enum pkey_id_type { ++ PKEY_ID_PGP, /* OpenPGP generated key ID */ ++ PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ ++ PKEY_ID_TYPE__LAST ++}; ++ ++extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST]; ++ ++/* ++ * Cryptographic data for the public-key subtype of the asymmetric key type. ++ * ++ * Note that this may include private part of the key as well as the public ++ * part. ++ */ ++struct public_key { ++ const struct public_key_algorithm *algo; ++ u8 capabilities; ++#define PKEY_CAN_ENCRYPT 0x01 ++#define PKEY_CAN_DECRYPT 0x02 ++#define PKEY_CAN_SIGN 0x04 ++#define PKEY_CAN_VERIFY 0x08 ++ enum pkey_id_type id_type : 8; ++ union { ++ MPI mpi[5]; ++ struct { ++ MPI p; /* DSA prime */ ++ MPI q; /* DSA group order */ ++ MPI g; /* DSA group generator */ ++ MPI y; /* DSA public-key value = g^x mod p */ ++ MPI x; /* DSA secret exponent (if present) */ ++ } dsa; ++ struct { ++ MPI n; /* RSA public modulus */ ++ MPI e; /* RSA public encryption exponent */ ++ MPI d; /* RSA secret encryption exponent (if present) */ ++ MPI p; /* RSA secret prime (if present) */ ++ MPI q; /* RSA secret prime (if present) */ ++ } rsa; ++ }; ++}; ++ ++extern void public_key_destroy(void *payload); ++ ++/* ++ * Public key cryptography signature data ++ */ ++struct public_key_signature { ++ u8 *digest; ++ u8 digest_size; /* Number of bytes in digest */ ++ u8 nr_mpi; /* Occupancy of mpi[] */ ++ enum pkey_hash_algo pkey_hash_algo : 8; ++ union { ++ MPI mpi[2]; ++ struct { ++ MPI s; /* m^d mod n */ ++ } rsa; ++ struct { ++ MPI r; ++ MPI s; ++ } dsa; ++ }; ++}; ++ ++#endif /* _LINUX_PUBLIC_KEY_H */ +-- +1.7.12.1 + + +From 13d9a26663043faaa37dbe6c2f214ceef5f00b05 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:25:04 +0100 +Subject: [PATCH 08/37] KEYS: Provide signature verification with an + asymmetric key + +Provide signature verification using an asymmetric-type key to indicate the +public key to be used. + +The API is a single function that can be found in crypto/public_key.h: + + int verify_signature(const struct key *key, + const struct public_key_signature *sig) + +The first argument is the appropriate key to be used and the second argument +is the parsed signature data: + + struct public_key_signature { + u8 *digest; + u16 digest_size; + enum pkey_hash_algo pkey_hash_algo : 8; + union { + MPI mpi[2]; + struct { + MPI s; /* m^d mod n */ + } rsa; + struct { + MPI r; + MPI s; + } dsa; + }; + }; + +This should be filled in prior to calling the function. The hash algorithm +should already have been called and the hash finalised and the output should +be in a buffer pointed to by the 'digest' member. + +Any extra data to be added to the hash by the hash format (eg. PGP) should +have been added by the caller prior to finalising the hash. + +It is assumed that the signature is made up of a number of MPI values. If an +algorithm becomes available for which this is not the case, the above structure +will have to change. + +It is also assumed that it will have been checked that the signature algorithm +matches the key algorithm. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/Makefile | 2 +- + crypto/asymmetric_keys/signature.c | 49 ++++++++++++++++++++++++++++++++++++++ + include/crypto/public_key.h | 4 ++++ + 3 files changed, 54 insertions(+), 1 deletion(-) + create mode 100644 crypto/asymmetric_keys/signature.c + +diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile +index 5ed46ee..8dcdf0c 100644 +--- a/crypto/asymmetric_keys/Makefile ++++ b/crypto/asymmetric_keys/Makefile +@@ -4,6 +4,6 @@ + + obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o + +-asymmetric_keys-y := asymmetric_type.o ++asymmetric_keys-y := asymmetric_type.o signature.o + + obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o +diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c +new file mode 100644 +index 0000000..50b3f88 +--- /dev/null ++++ b/crypto/asymmetric_keys/signature.c +@@ -0,0 +1,49 @@ ++/* Signature verification with an asymmetric key ++ * ++ * See Documentation/security/asymmetric-keys.txt ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <keys/asymmetric-subtype.h> ++#include <linux/module.h> ++#include <linux/err.h> ++#include <crypto/public_key.h> ++#include "asymmetric_keys.h" ++ ++/** ++ * verify_signature - Initiate the use of an asymmetric key to verify a signature ++ * @key: The asymmetric key to verify against ++ * @sig: The signature to check ++ * ++ * Returns 0 if successful or else an error. ++ */ ++int verify_signature(const struct key *key, ++ const struct public_key_signature *sig) ++{ ++ const struct asymmetric_key_subtype *subtype; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (key->type != &key_type_asymmetric) ++ return -EINVAL; ++ subtype = asymmetric_key_subtype(key); ++ if (!subtype || ++ !key->payload.data) ++ return -EINVAL; ++ if (!subtype->verify_signature) ++ return -ENOTSUPP; ++ ++ ret = subtype->verify_signature(key, sig); ++ ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(verify_signature); +diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h +index 4b8b6c1..f5b0224 100644 +--- a/include/crypto/public_key.h ++++ b/include/crypto/public_key.h +@@ -101,4 +101,8 @@ struct public_key_signature { + }; + }; + ++struct key; ++extern int verify_signature(const struct key *key, ++ const struct public_key_signature *sig); ++ + #endif /* _LINUX_PUBLIC_KEY_H */ +-- +1.7.12.1 + + +From 3d379de76f21782c611b7d409d7374b82bc90220 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:25:22 +0100 +Subject: [PATCH 09/37] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA + signature verification + +Reinstate and export mpi_cmp() and mpi_cmp_ui() from the MPI library for use by +RSA signature verification as per RFC3447 section 5.2.2 step 1. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + lib/mpi/Makefile | 1 + + lib/mpi/mpi-cmp.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 71 insertions(+) + create mode 100644 lib/mpi/mpi-cmp.c + +diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile +index 45ca90a..019a68c 100644 +--- a/lib/mpi/Makefile ++++ b/lib/mpi/Makefile +@@ -14,6 +14,7 @@ mpi-y = \ + generic_mpih-add1.o \ + mpicoder.o \ + mpi-bit.o \ ++ mpi-cmp.o \ + mpih-cmp.o \ + mpih-div.o \ + mpih-mul.o \ +diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c +new file mode 100644 +index 0000000..1871e7b +--- /dev/null ++++ b/lib/mpi/mpi-cmp.c +@@ -0,0 +1,70 @@ ++/* mpi-cmp.c - MPI functions ++ * Copyright (C) 1998, 1999 Free Software Foundation, Inc. ++ * ++ * This file is part of GnuPG. ++ * ++ * GnuPG is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuPG is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ++ */ ++ ++#include "mpi-internal.h" ++ ++int mpi_cmp_ui(MPI u, unsigned long v) ++{ ++ mpi_limb_t limb = v; ++ ++ mpi_normalize(u); ++ if (!u->nlimbs && !limb) ++ return 0; ++ if (u->sign) ++ return -1; ++ if (u->nlimbs > 1) ++ return 1; ++ ++ if (u->d[0] == limb) ++ return 0; ++ else if (u->d[0] > limb) ++ return 1; ++ else ++ return -1; ++} ++EXPORT_SYMBOL_GPL(mpi_cmp_ui); ++ ++int mpi_cmp(MPI u, MPI v) ++{ ++ mpi_size_t usize, vsize; ++ int cmp; ++ ++ mpi_normalize(u); ++ mpi_normalize(v); ++ usize = u->nlimbs; ++ vsize = v->nlimbs; ++ if (!u->sign && v->sign) ++ return 1; ++ if (u->sign && !v->sign) ++ return -1; ++ if (usize != vsize && !u->sign && !v->sign) ++ return usize - vsize; ++ if (usize != vsize && u->sign && v->sign) ++ return vsize + usize; ++ if (!usize) ++ return 0; ++ cmp = mpihelp_cmp(u->d, v->d, usize); ++ if (!cmp) ++ return 0; ++ if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0)) ++ return 1; ++ return -1; ++} ++EXPORT_SYMBOL_GPL(mpi_cmp); +-- +1.7.12.1 + + +From b872c7db2ce34b5f051d1c38216843a1f796aa86 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:25:40 +0100 +Subject: [PATCH 10/37] RSA: Implement signature verification algorithm + [PKCS#1 / RFC3447] + +Implement RSA public key cryptography [PKCS#1 / RFC3447]. At this time, only +the signature verification algorithm is supported. This uses the asymmetric +public key subtype to hold its key data. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/Kconfig | 7 + + crypto/asymmetric_keys/Makefile | 1 + + crypto/asymmetric_keys/public_key.h | 2 + + crypto/asymmetric_keys/rsa.c | 269 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 279 insertions(+) + create mode 100644 crypto/asymmetric_keys/rsa.c + +diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig +index bbfccaa..561759d 100644 +--- a/crypto/asymmetric_keys/Kconfig ++++ b/crypto/asymmetric_keys/Kconfig +@@ -18,4 +18,11 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE + appropriate hash algorithms (such as SHA-1) must be available. + ENOPKG will be reported if the requisite algorithm is unavailable. + ++config PUBLIC_KEY_ALGO_RSA ++ tristate "RSA public-key algorithm" ++ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE ++ select MPILIB_EXTRA ++ help ++ This option enables support for the RSA algorithm (PKCS#1, RFC3447). ++ + endif # ASYMMETRIC_KEY_TYPE +diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile +index 8dcdf0c..7c92691 100644 +--- a/crypto/asymmetric_keys/Makefile ++++ b/crypto/asymmetric_keys/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o + asymmetric_keys-y := asymmetric_type.o signature.o + + obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o ++obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o +diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h +index 1f86aad..5e5e356 100644 +--- a/crypto/asymmetric_keys/public_key.h ++++ b/crypto/asymmetric_keys/public_key.h +@@ -26,3 +26,5 @@ struct public_key_algorithm { + int (*verify_signature)(const struct public_key *key, + const struct public_key_signature *sig); + }; ++ ++extern const struct public_key_algorithm RSA_public_key_algorithm; +diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c +new file mode 100644 +index 0000000..9b31ee2 +--- /dev/null ++++ b/crypto/asymmetric_keys/rsa.c +@@ -0,0 +1,269 @@ ++/* RSA asymmetric public-key algorithm [RFC3447] ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "RSA: "fmt ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include "public_key.h" ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("RSA Public Key Algorithm"); ++ ++#define kenter(FMT, ...) \ ++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) ++#define kleave(FMT, ...) \ ++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) ++ ++/* ++ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. ++ */ ++static const u8 RSA_digest_info_MD5[] = { ++ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, ++ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ ++ 0x05, 0x00, 0x04, 0x10 ++}; ++ ++static const u8 RSA_digest_info_SHA1[] = { ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x0E, 0x03, 0x02, 0x1A, ++ 0x05, 0x00, 0x04, 0x14 ++}; ++ ++static const u8 RSA_digest_info_RIPE_MD_160[] = { ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x24, 0x03, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x14 ++}; ++ ++static const u8 RSA_digest_info_SHA224[] = { ++ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, ++ 0x05, 0x00, 0x04, 0x1C ++}; ++ ++static const u8 RSA_digest_info_SHA256[] = { ++ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x20 ++}; ++ ++static const u8 RSA_digest_info_SHA384[] = { ++ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, ++ 0x05, 0x00, 0x04, 0x30 ++}; ++ ++static const u8 RSA_digest_info_SHA512[] = { ++ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x05, 0x00, 0x04, 0x40 ++}; ++ ++static const struct { ++ const u8 *data; ++ size_t size; ++} RSA_ASN1_templates[PKEY_HASH__LAST] = { ++#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } ++ [PKEY_HASH_MD5] = _(MD5), ++ [PKEY_HASH_SHA1] = _(SHA1), ++ [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), ++ [PKEY_HASH_SHA256] = _(SHA256), ++ [PKEY_HASH_SHA384] = _(SHA384), ++ [PKEY_HASH_SHA512] = _(SHA512), ++ [PKEY_HASH_SHA224] = _(SHA224), ++#undef _ ++}; ++ ++/* ++ * RSAVP1() function [RFC3447 sec 5.2.2] ++ */ ++static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) ++{ ++ MPI m; ++ int ret; ++ ++ /* (1) Validate 0 <= s < n */ ++ if (mpi_cmp_ui(s, 0) < 0) { ++ kleave(" = -EBADMSG [s < 0]"); ++ return -EBADMSG; ++ } ++ if (mpi_cmp(s, key->rsa.n) >= 0) { ++ kleave(" = -EBADMSG [s >= n]"); ++ return -EBADMSG; ++ } ++ ++ m = mpi_alloc(0); ++ if (!m) ++ return -ENOMEM; ++ ++ /* (2) m = s^e mod n */ ++ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); ++ if (ret < 0) { ++ mpi_free(m); ++ return ret; ++ } ++ ++ *_m = m; ++ return 0; ++} ++ ++/* ++ * Integer to Octet String conversion [RFC3447 sec 4.1] ++ */ ++static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) ++{ ++ unsigned X_size, x_size; ++ int X_sign; ++ u8 *X; ++ ++ /* Make sure the string is the right length. The number should begin ++ * with { 0x00, 0x01, ... } so we have to account for 15 leading zero ++ * bits not being reported by MPI. ++ */ ++ x_size = mpi_get_nbits(x); ++ pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); ++ if (x_size != xLen * 8 - 15) ++ return -ERANGE; ++ ++ X = mpi_get_buffer(x, &X_size, &X_sign); ++ if (!X) ++ return -ENOMEM; ++ if (X_sign < 0) { ++ kfree(X); ++ return -EBADMSG; ++ } ++ if (X_size != xLen - 1) { ++ kfree(X); ++ return -EBADMSG; ++ } ++ ++ *_X = X; ++ return 0; ++} ++ ++/* ++ * Perform the RSA signature verification. ++ * @H: Value of hash of data and metadata ++ * @EM: The computed signature value ++ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) ++ * @hash_size: The size of H ++ * @asn1_template: The DigestInfo ASN.1 template ++ * @asn1_size: Size of asm1_template[] ++ */ ++static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, ++ const u8 *asn1_template, size_t asn1_size) ++{ ++ unsigned PS_end, T_offset, i; ++ ++ kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); ++ ++ if (k < 2 + 1 + asn1_size + hash_size) ++ return -EBADMSG; ++ ++ /* Decode the EMSA-PKCS1-v1_5 */ ++ if (EM[1] != 0x01) { ++ kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); ++ return -EBADMSG; ++ } ++ ++ T_offset = k - (asn1_size + hash_size); ++ PS_end = T_offset - 1; ++ if (EM[PS_end] != 0x00) { ++ kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); ++ return -EBADMSG; ++ } ++ ++ for (i = 2; i < PS_end; i++) { ++ if (EM[i] != 0xff) { ++ kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); ++ return -EBADMSG; ++ } ++ } ++ ++ if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { ++ kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); ++ return -EBADMSG; ++ } ++ ++ if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { ++ kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); ++ return -EKEYREJECTED; ++ } ++ ++ kleave(" = 0"); ++ return 0; ++} ++ ++/* ++ * Perform the verification step [RFC3447 sec 8.2.2]. ++ */ ++static int RSA_verify_signature(const struct public_key *key, ++ const struct public_key_signature *sig) ++{ ++ size_t tsize; ++ int ret; ++ ++ /* Variables as per RFC3447 sec 8.2.2 */ ++ const u8 *H = sig->digest; ++ u8 *EM = NULL; ++ MPI m = NULL; ++ size_t k; ++ ++ kenter(""); ++ ++ if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) ++ return -ENOTSUPP; ++ ++ /* (1) Check the signature size against the public key modulus size */ ++ k = (mpi_get_nbits(key->rsa.n) + 7) / 8; ++ ++ tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; ++ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); ++ if (tsize != k) { ++ ret = -EBADMSG; ++ goto error; ++ } ++ ++ /* (2b) Apply the RSAVP1 verification primitive to the public key */ ++ ret = RSAVP1(key, sig->rsa.s, &m); ++ if (ret < 0) ++ goto error; ++ ++ /* (2c) Convert the message representative (m) to an encoded message ++ * (EM) of length k octets. ++ * ++ * NOTE! The leading zero byte is suppressed by MPI, so we pass a ++ * pointer to the _preceding_ byte to RSA_verify()! ++ */ ++ ret = RSA_I2OSP(m, k, &EM); ++ if (ret < 0) ++ goto error; ++ ++ ret = RSA_verify(H, EM - 1, k, sig->digest_size, ++ RSA_ASN1_templates[sig->pkey_hash_algo].data, ++ RSA_ASN1_templates[sig->pkey_hash_algo].size); ++ ++error: ++ kfree(EM); ++ mpi_free(m); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++const struct public_key_algorithm RSA_public_key_algorithm = { ++ .name = "RSA", ++ .n_pub_mpi = 2, ++ .n_sec_mpi = 3, ++ .n_sig_mpi = 1, ++ .verify_signature = RSA_verify_signature, ++}; ++EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); +-- +1.7.12.1 + + +From 362af238a35e095094b3f5a228cf2c0f60c10cd9 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:28:05 +0100 +Subject: [PATCH 11/37] RSA: Fix signature verification for shorter signatures + +gpg can produce a signature file where length of signature is less than the +modulus size because the amount of space an MPI takes up is kept as low as +possible by discarding leading zeros. This regularly happens for several +modules during the build. + +Fix it by relaxing check in RSA verification code. + +Thanks to Tomas Mraz and Miloslav Trmac for help. + +Signed-off-by: Milan Broz <mbroz@redhat.com> +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/rsa.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c +index 9b31ee2..4a6a069 100644 +--- a/crypto/asymmetric_keys/rsa.c ++++ b/crypto/asymmetric_keys/rsa.c +@@ -224,15 +224,23 @@ static int RSA_verify_signature(const struct public_key *key, + return -ENOTSUPP; + + /* (1) Check the signature size against the public key modulus size */ +- k = (mpi_get_nbits(key->rsa.n) + 7) / 8; ++ k = mpi_get_nbits(key->rsa.n); ++ tsize = mpi_get_nbits(sig->rsa.s); + +- tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; ++ /* According to RFC 4880 sec 3.2, length of MPI is computed starting ++ * from most significant bit. So the RFC 3447 sec 8.2.2 size check ++ * must be relaxed to conform with shorter signatures - so we fail here ++ * only if signature length is longer than modulus size. ++ */ + pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); +- if (tsize != k) { ++ if (k < tsize) { + ret = -EBADMSG; + goto error; + } + ++ /* Round up and convert to octets */ ++ k = (k + 7) / 8; ++ + /* (2b) Apply the RSAVP1 verification primitive to the public key */ + ret = RSAVP1(key, sig->rsa.s, &m); + if (ret < 0) +-- +1.7.12.1 + + +From 81451f08c7db892e06144cf3bc89746e68269624 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:30:46 +0100 +Subject: [PATCH 12/37] X.509: Implement simple static OID registry + +Implement a simple static OID registry that allows the mapping of an encoded +OID to an enum value for ease of use. + +The OID registry index enum appears in the: + + linux/oid_registry.h + +header file. A script generates the registry from lines in the header file +that look like: + + <sp*>OID_foo,<sp*>/*<sp*>1.2.3.4<sp*>*/ + +The actual OID is taken to be represented by the numbers with interpolated +dots in the comment. + +All other lines in the header are ignored. + +The registry is queries by calling: + + OID look_up_oid(const void *data, size_t datasize); + +This returns a number from the registry enum representing the OID if found or +OID__NR if not. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + include/linux/oid_registry.h | 90 +++++++++++++++++++ + lib/.gitignore | 2 +- + lib/Kconfig | 5 ++ + lib/Makefile | 16 ++++ + lib/build_OID_registry | 209 +++++++++++++++++++++++++++++++++++++++++++ + lib/oid_registry.c | 89 ++++++++++++++++++ + 6 files changed, 410 insertions(+), 1 deletion(-) + create mode 100644 include/linux/oid_registry.h + create mode 100755 lib/build_OID_registry + create mode 100644 lib/oid_registry.c + +diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h +new file mode 100644 +index 0000000..5928546 +--- /dev/null ++++ b/include/linux/oid_registry.h +@@ -0,0 +1,90 @@ ++/* ASN.1 Object identifier (OID) registry ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_OID_REGISTRY_H ++#define _LINUX_OID_REGISTRY_H ++ ++#include <linux/types.h> ++ ++/* ++ * OIDs are turned into these values if possible, or OID__NR if not held here. ++ * ++ * NOTE! Do not mess with the format of each line as this is read by ++ * build_OID_registry.pl to generate the data for look_up_OID(). ++ */ ++enum OID { ++ OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */ ++ OID_id_dsa, /* 1.2.840.10040.4.1 */ ++ OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */ ++ OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */ ++ ++ /* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */ ++ OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */ ++ OID_md2WithRSAEncryption, /* 1.2.840.113549.1.1.2 */ ++ OID_md3WithRSAEncryption, /* 1.2.840.113549.1.1.3 */ ++ OID_md4WithRSAEncryption, /* 1.2.840.113549.1.1.4 */ ++ OID_sha1WithRSAEncryption, /* 1.2.840.113549.1.1.5 */ ++ OID_sha256WithRSAEncryption, /* 1.2.840.113549.1.1.11 */ ++ OID_sha384WithRSAEncryption, /* 1.2.840.113549.1.1.12 */ ++ OID_sha512WithRSAEncryption, /* 1.2.840.113549.1.1.13 */ ++ OID_sha224WithRSAEncryption, /* 1.2.840.113549.1.1.14 */ ++ /* PKCS#7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)} */ ++ OID_data, /* 1.2.840.113549.1.7.1 */ ++ OID_signed_data, /* 1.2.840.113549.1.7.2 */ ++ /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */ ++ OID_email_address, /* 1.2.840.113549.1.9.1 */ ++ OID_content_type, /* 1.2.840.113549.1.9.3 */ ++ OID_messageDigest, /* 1.2.840.113549.1.9.4 */ ++ OID_signingTime, /* 1.2.840.113549.1.9.5 */ ++ OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */ ++ OID_smimeAuthenticatedAttrs, /* 1.2.840.113549.1.9.16.2.11 */ ++ ++ /* {iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2)} */ ++ OID_md2, /* 1.2.840.113549.2.2 */ ++ OID_md4, /* 1.2.840.113549.2.4 */ ++ OID_md5, /* 1.2.840.113549.2.5 */ ++ ++ OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ ++ OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ ++ OID_sha1, /* 1.3.14.3.2.26 */ ++ ++ /* Distinguished Name attribute IDs [RFC 2256] */ ++ OID_commonName, /* 2.5.4.3 */ ++ OID_surname, /* 2.5.4.4 */ ++ OID_countryName, /* 2.5.4.6 */ ++ OID_locality, /* 2.5.4.7 */ ++ OID_stateOrProvinceName, /* 2.5.4.8 */ ++ OID_organizationName, /* 2.5.4.10 */ ++ OID_organizationUnitName, /* 2.5.4.11 */ ++ OID_title, /* 2.5.4.12 */ ++ OID_description, /* 2.5.4.13 */ ++ OID_name, /* 2.5.4.41 */ ++ OID_givenName, /* 2.5.4.42 */ ++ OID_initials, /* 2.5.4.43 */ ++ OID_generationalQualifier, /* 2.5.4.44 */ ++ ++ /* Certificate extension IDs */ ++ OID_subjectKeyIdentifier, /* 2.5.29.14 */ ++ OID_keyUsage, /* 2.5.29.15 */ ++ OID_subjectAltName, /* 2.5.29.17 */ ++ OID_issuerAltName, /* 2.5.29.18 */ ++ OID_basicConstraints, /* 2.5.29.19 */ ++ OID_crlDistributionPoints, /* 2.5.29.31 */ ++ OID_certPolicies, /* 2.5.29.32 */ ++ OID_authorityKeyIdentifier, /* 2.5.29.35 */ ++ OID_extKeyUsage, /* 2.5.29.37 */ ++ ++ OID__NR ++}; ++ ++extern enum OID look_up_OID(const void *data, size_t datasize); ++ ++#endif /* _LINUX_OID_REGISTRY_H */ +diff --git a/lib/.gitignore b/lib/.gitignore +index 3bef1ea..09aae85 100644 +--- a/lib/.gitignore ++++ b/lib/.gitignore +@@ -3,4 +3,4 @@ + # + gen_crc32table + crc32table.h +- ++oid_registry_data.c +diff --git a/lib/Kconfig b/lib/Kconfig +index bb94c1b..4b31a46 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -396,4 +396,9 @@ config SIGNATURE + config LIBFDT + bool + ++config OID_REGISTRY ++ tristate ++ help ++ Enable fast lookup object identifier registry. ++ + endmenu +diff --git a/lib/Makefile b/lib/Makefile +index 42d283e..b042896 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -150,3 +150,19 @@ quiet_cmd_crc32 = GEN $@ + + $(obj)/crc32table.h: $(obj)/gen_crc32table + $(call cmd,crc32) ++ ++# ++# Build a fast OID lookip registry from include/linux/oid_registry.h ++# ++obj-$(CONFIG_OID_REGISTRY) += oid_registry.o ++ ++$(obj)/oid_registry.c: $(obj)/oid_registry_data.c ++ ++$(obj)/oid_registry_data.c: $(srctree)/include/linux/oid_registry.h \ ++ $(src)/build_OID_registry ++ $(call cmd,build_OID_registry) ++ ++quiet_cmd_build_OID_registry = GEN $@ ++ cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@ ++ ++clean-files += oid_registry_data.c +diff --git a/lib/build_OID_registry b/lib/build_OID_registry +new file mode 100755 +index 0000000..dfbdaab +--- /dev/null ++++ b/lib/build_OID_registry +@@ -0,0 +1,209 @@ ++#!/usr/bin/perl -w ++# ++# Build a static ASN.1 Object Identified (OID) registry ++# ++# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++# Written by David Howells (dhowells@redhat.com) ++# ++# This program is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public Licence ++# as published by the Free Software Foundation; either version ++# 2 of the Licence, or (at your option) any later version. ++# ++ ++use strict; ++ ++my @names = (); ++my @oids = (); ++ ++if ($#ARGV != 1) { ++ print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n"; ++ exit(2); ++} ++ ++# ++# Open the file to read from ++# ++open IN_FILE, "<$ARGV[0]" || die; ++while (<IN_FILE>) { ++ chomp; ++ if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) { ++ push @names, $1; ++ push @oids, $2; ++ } ++} ++close IN_FILE || die; ++ ++# ++# Open the files to write into ++# ++open C_FILE, ">$ARGV[1]" or die; ++print C_FILE "/*\n"; ++print C_FILE " * Automatically generated by ", $0, ". Do not edit\n"; ++print C_FILE " */\n"; ++ ++# ++# Split the data up into separate lists and also determine the lengths of the ++# encoded data arrays. ++# ++my @indices = (); ++my @lengths = (); ++my $total_length = 0; ++ ++print "Compiling ", $#names + 1, " OIDs\n"; ++ ++for (my $i = 0; $i <= $#names; $i++) { ++ my $name = $names[$i]; ++ my $oid = $oids[$i]; ++ ++ my @components = split(/[.]/, $oid); ++ ++ # Determine the encoded length of this OID ++ my $size = $#components; ++ for (my $loop = 2; $loop <= $#components; $loop++) { ++ my $c = $components[$loop]; ++ ++ # We will base128 encode the number ++ my $tmp = ($c == 0) ? 0 : int(log($c)/log(2)); ++ $tmp = int($tmp / 7); ++ $size += $tmp; ++ } ++ push @lengths, $size; ++ push @indices, $total_length; ++ $total_length += $size; ++} ++ ++# ++# Emit the look-up-by-OID index table ++# ++print C_FILE "\n"; ++if ($total_length <= 255) { ++ print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n"; ++} else { ++ print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n"; ++} ++for (my $i = 0; $i <= $#names; $i++) { ++ print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n" ++} ++print C_FILE "\t[OID__NR] = ", $total_length, "\n"; ++print C_FILE "};\n"; ++ ++# ++# Encode the OIDs ++# ++my @encoded_oids = (); ++ ++for (my $i = 0; $i <= $#names; $i++) { ++ my @octets = (); ++ ++ my @components = split(/[.]/, $oids[$i]); ++ ++ push @octets, $components[0] * 40 + $components[1]; ++ ++ for (my $loop = 2; $loop <= $#components; $loop++) { ++ my $c = $components[$loop]; ++ ++ # Base128 encode the number ++ my $tmp = ($c == 0) ? 0 : int(log($c)/log(2)); ++ $tmp = int($tmp / 7); ++ ++ for (; $tmp > 0; $tmp--) { ++ push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80; ++ } ++ push @octets, $c & 0x7f; ++ } ++ ++ push @encoded_oids, \@octets; ++} ++ ++# ++# Create a hash value for each OID ++# ++my @hash_values = (); ++for (my $i = 0; $i <= $#names; $i++) { ++ my @octets = @{$encoded_oids[$i]}; ++ ++ my $hash = $#octets; ++ foreach (@octets) { ++ $hash += $_ * 33; ++ } ++ ++ $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash); ++ ++ push @hash_values, $hash & 0xff; ++} ++ ++# ++# Emit the OID data ++# ++print C_FILE "\n"; ++print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n"; ++for (my $i = 0; $i <= $#names; $i++) { ++ my @octets = @{$encoded_oids[$i]}; ++ print C_FILE "\t"; ++ print C_FILE $_, ", " foreach (@octets); ++ print C_FILE "\t// ", $names[$i]; ++ print C_FILE "\n"; ++} ++print C_FILE "};\n"; ++ ++# ++# Build the search index table (ordered by length then hash then content) ++# ++my @index_table = ( 0 .. $#names ); ++ ++@index_table = sort { ++ my @octets_a = @{$encoded_oids[$a]}; ++ my @octets_b = @{$encoded_oids[$b]}; ++ ++ return $hash_values[$a] <=> $hash_values[$b] ++ if ($hash_values[$a] != $hash_values[$b]); ++ return $#octets_a <=> $#octets_b ++ if ($#octets_a != $#octets_b); ++ for (my $i = $#octets_a; $i >= 0; $i--) { ++ return $octets_a[$i] <=> $octets_b[$i] ++ if ($octets_a[$i] != $octets_b[$i]); ++ } ++ return 0; ++ ++} @index_table; ++ ++# ++# Emit the search index and hash value table ++# ++print C_FILE "\n"; ++print C_FILE "static const struct {\n"; ++print C_FILE "\tunsigned char hash;\n"; ++if ($#names <= 255) { ++ print C_FILE "\tenum OID oid : 8;\n"; ++} else { ++ print C_FILE "\tenum OID oid : 16;\n"; ++} ++print C_FILE "} oid_search_table[OID__NR] = {\n"; ++for (my $i = 0; $i <= $#names; $i++) { ++ my @octets = @{$encoded_oids[$index_table[$i]]}; ++ printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ", ++ $i, ++ $hash_values[$index_table[$i]], ++ $names[$index_table[$i]]); ++ printf C_FILE "%02x", $_ foreach (@octets); ++ print C_FILE "\n"; ++} ++print C_FILE "};\n"; ++ ++# ++# Emit the OID debugging name table ++# ++#print C_FILE "\n"; ++#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n"; ++# ++#for (my $i = 0; $i <= $#names; $i++) { ++# print C_FILE "\t\"", $names[$i], "\",\n" ++#} ++#print C_FILE "\t\"Unknown-OID\"\n"; ++#print C_FILE "};\n"; ++ ++# ++# Polish off ++# ++close C_FILE or die; +diff --git a/lib/oid_registry.c b/lib/oid_registry.c +new file mode 100644 +index 0000000..33cfd17 +--- /dev/null ++++ b/lib/oid_registry.c +@@ -0,0 +1,89 @@ ++/* ASN.1 Object identifier (OID) registry ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/export.h> ++#include <linux/oid_registry.h> ++#include "oid_registry_data.c" ++ ++/** ++ * look_up_OID - Find an OID registration for the specified data ++ * @data: Binary representation of the OID ++ * @datasize: Size of the binary representation ++ */ ++enum OID look_up_OID(const void *data, size_t datasize) ++{ ++ const unsigned char *octets = data; ++ enum OID oid; ++ unsigned char xhash; ++ unsigned i, j, k, hash; ++ size_t len; ++ ++ /* Hash the OID data */ ++ hash = datasize - 1; ++ ++ for (i = 0; i < datasize; i++) ++ hash += octets[i] * 33; ++ hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash; ++ hash &= 0xff; ++ ++ /* Binary search the OID registry. OIDs are stored in ascending order ++ * of hash value then ascending order of size and then in ascending ++ * order of reverse value. ++ */ ++ i = 0; ++ k = OID__NR; ++ while (i < k) { ++ j = (i + k) / 2; ++ ++ xhash = oid_search_table[j].hash; ++ if (xhash > hash) { ++ k = j; ++ continue; ++ } ++ if (xhash < hash) { ++ i = j + 1; ++ continue; ++ } ++ ++ oid = oid_search_table[j].oid; ++ len = oid_index[oid + 1] - oid_index[oid]; ++ if (len > datasize) { ++ k = j; ++ continue; ++ } ++ if (len < datasize) { ++ i = j + 1; ++ continue; ++ } ++ ++ /* Variation is most likely to be at the tail end of the ++ * OID, so do the comparison in reverse. ++ */ ++ while (len > 0) { ++ unsigned char a = oid_data[oid_index[oid] + --len]; ++ unsigned char b = octets[len]; ++ if (a > b) { ++ k = j; ++ goto next; ++ } ++ if (a < b) { ++ i = j + 1; ++ goto next; ++ } ++ } ++ return oid; ++ next: ++ ; ++ } ++ ++ return OID__NR; ++} ++EXPORT_SYMBOL_GPL(look_up_OID); +-- +1.7.12.1 + + +From 3e1b30d7c67fd5419d4f6eb5d10b557dda4bc4fd Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:30:51 +0100 +Subject: [PATCH 13/37] X.509: Add utility functions to render OIDs as strings + +Add a pair of utility functions to render OIDs as strings. The first takes an +encoded OID and turns it into a "a.b.c.d" form string: + + int sprint_oid(const void *data, size_t datasize, + char *buffer, size_t bufsize); + +The second takes an OID enum index and calls the first on the data held +therein: + + int sprint_OID(enum OID oid, char *buffer, size_t bufsize); + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + include/linux/oid_registry.h | 2 ++ + lib/oid_registry.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 83 insertions(+) + +diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h +index 5928546..6926db7 100644 +--- a/include/linux/oid_registry.h ++++ b/include/linux/oid_registry.h +@@ -86,5 +86,7 @@ enum OID { + }; + + extern enum OID look_up_OID(const void *data, size_t datasize); ++extern int sprint_oid(const void *, size_t, char *, size_t); ++extern int sprint_OID(enum OID, char *, size_t); + + #endif /* _LINUX_OID_REGISTRY_H */ +diff --git a/lib/oid_registry.c b/lib/oid_registry.c +index 33cfd17..d8de11f 100644 +--- a/lib/oid_registry.c ++++ b/lib/oid_registry.c +@@ -11,6 +11,9 @@ + + #include <linux/export.h> + #include <linux/oid_registry.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/bug.h> + #include "oid_registry_data.c" + + /** +@@ -87,3 +90,81 @@ enum OID look_up_OID(const void *data, size_t datasize) + return OID__NR; + } + EXPORT_SYMBOL_GPL(look_up_OID); ++ ++/* ++ * sprint_OID - Print an Object Identifier into a buffer ++ * @data: The encoded OID to print ++ * @datasize: The size of the encoded OID ++ * @buffer: The buffer to render into ++ * @bufsize: The size of the buffer ++ * ++ * The OID is rendered into the buffer in "a.b.c.d" format and the number of ++ * bytes is returned. -EBADMSG is returned if the data could not be intepreted ++ * and -ENOBUFS if the buffer was too small. ++ */ ++int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize) ++{ ++ const unsigned char *v = data, *end = v + datasize; ++ unsigned long num; ++ unsigned char n; ++ size_t ret; ++ int count; ++ ++ if (v >= end) ++ return -EBADMSG; ++ ++ n = *v++; ++ ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40); ++ buffer += count; ++ bufsize -= count; ++ if (bufsize == 0) ++ return -ENOBUFS; ++ ++ while (v < end) { ++ num = 0; ++ n = *v++; ++ if (!(n & 0x80)) { ++ num = n; ++ } else { ++ num = n & 0x7f; ++ do { ++ if (v >= end) ++ return -EBADMSG; ++ n = *v++; ++ num <<= 7; ++ num |= n & 0x7f; ++ } while (n & 0x80); ++ } ++ ret += count = snprintf(buffer, bufsize, ".%lu", num); ++ buffer += count; ++ bufsize -= count; ++ if (bufsize == 0) ++ return -ENOBUFS; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(sprint_oid); ++ ++/** ++ * sprint_OID - Print an Object Identifier into a buffer ++ * @oid: The OID to print ++ * @buffer: The buffer to render into ++ * @bufsize: The size of the buffer ++ * ++ * The OID is rendered into the buffer in "a.b.c.d" format and the number of ++ * bytes is returned. ++ */ ++int sprint_OID(enum OID oid, char *buffer, size_t bufsize) ++{ ++ int ret; ++ ++ BUG_ON(oid >= OID__NR); ++ ++ ret = sprint_oid(oid_data + oid_index[oid], ++ oid_index[oid + 1] - oid_index[oid], ++ buffer, bufsize); ++ BUG_ON(ret == -EBADMSG); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(sprint_OID); +-- +1.7.12.1 + + +From 978cd19071f71ae6a0e622bb2521f88ea633a326 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 21 Sep 2012 23:31:13 +0100 +Subject: [PATCH 14/37] X.509: Add simple ASN.1 grammar compiler + +Add a simple ASN.1 grammar compiler. This produces a bytecode output that can +be fed to a decoder to inform the decoder how to interpret the ASN.1 stream it +is trying to parse. + +Action functions can be specified in the grammar by interpolating: + + ({ foo }) + +after a type, for example: + + SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING ({ do_key_data }) + } + +The decoder is expected to call these after matching this type and parsing the +contents if it is a constructed type. + +The grammar compiler does not currently support the SET type (though it does +support SET OF) as I can't see a good way of tracking which members have been +encountered yet without using up extra stack space. + +Currently, the grammar compiler will fail if more than 256 bytes of bytecode +would be produced or more than 256 actions have been specified as it uses +8-bit jump values and action indices to keep space usage down. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + include/linux/asn1.h | 67 ++ + include/linux/asn1_ber_bytecode.h | 87 +++ + init/Kconfig | 8 + + scripts/.gitignore | 1 + + scripts/Makefile | 2 + + scripts/Makefile.build | 11 + + scripts/asn1_compiler.c | 1545 +++++++++++++++++++++++++++++++++++++ + 7 files changed, 1721 insertions(+) + create mode 100644 include/linux/asn1.h + create mode 100644 include/linux/asn1_ber_bytecode.h + create mode 100644 scripts/asn1_compiler.c + +diff --git a/include/linux/asn1.h b/include/linux/asn1.h +new file mode 100644 +index 0000000..5c3f4e4 +--- /dev/null ++++ b/include/linux/asn1.h +@@ -0,0 +1,67 @@ ++/* ASN.1 BER/DER/CER encoding definitions ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_ASN1_H ++#define _LINUX_ASN1_H ++ ++/* Class */ ++enum asn1_class { ++ ASN1_UNIV = 0, /* Universal */ ++ ASN1_APPL = 1, /* Application */ ++ ASN1_CONT = 2, /* Context */ ++ ASN1_PRIV = 3 /* Private */ ++}; ++#define ASN1_CLASS_BITS 0xc0 ++ ++ ++enum asn1_method { ++ ASN1_PRIM = 0, /* Primitive */ ++ ASN1_CONS = 1 /* Constructed */ ++}; ++#define ASN1_CONS_BIT 0x20 ++ ++/* Tag */ ++enum asn1_tag { ++ ASN1_EOC = 0, /* End Of Contents or N/A */ ++ ASN1_BOOL = 1, /* Boolean */ ++ ASN1_INT = 2, /* Integer */ ++ ASN1_BTS = 3, /* Bit String */ ++ ASN1_OTS = 4, /* Octet String */ ++ ASN1_NULL = 5, /* Null */ ++ ASN1_OID = 6, /* Object Identifier */ ++ ASN1_ODE = 7, /* Object Description */ ++ ASN1_EXT = 8, /* External */ ++ ASN1_REAL = 9, /* Real float */ ++ ASN1_ENUM = 10, /* Enumerated */ ++ ASN1_EPDV = 11, /* Embedded PDV */ ++ ASN1_UTF8STR = 12, /* UTF8 String */ ++ ASN1_RELOID = 13, /* Relative OID */ ++ /* 14 - Reserved */ ++ /* 15 - Reserved */ ++ ASN1_SEQ = 16, /* Sequence and Sequence of */ ++ ASN1_SET = 17, /* Set and Set of */ ++ ASN1_NUMSTR = 18, /* Numerical String */ ++ ASN1_PRNSTR = 19, /* Printable String */ ++ ASN1_TEXSTR = 20, /* T61 String / Teletext String */ ++ ASN1_VIDSTR = 21, /* Videotex String */ ++ ASN1_IA5STR = 22, /* IA5 String */ ++ ASN1_UNITIM = 23, /* Universal Time */ ++ ASN1_GENTIM = 24, /* General Time */ ++ ASN1_GRASTR = 25, /* Graphic String */ ++ ASN1_VISSTR = 26, /* Visible String */ ++ ASN1_GENSTR = 27, /* General String */ ++ ASN1_UNISTR = 28, /* Universal String */ ++ ASN1_CHRSTR = 29, /* Character String */ ++ ASN1_BMPSTR = 30, /* BMP String */ ++ ASN1_LONG_TAG = 31 /* Long form tag */ ++}; ++ ++#endif /* _LINUX_ASN1_H */ +diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h +new file mode 100644 +index 0000000..945d44a +--- /dev/null ++++ b/include/linux/asn1_ber_bytecode.h +@@ -0,0 +1,87 @@ ++/* ASN.1 BER/DER/CER parsing state machine internal definitions ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_ASN1_BER_BYTECODE_H ++#define _LINUX_ASN1_BER_BYTECODE_H ++ ++#ifdef __KERNEL__ ++#include <linux/types.h> ++#endif ++#include <linux/asn1.h> ++ ++typedef int (*asn1_action_t)(void *context, ++ size_t hdrlen, /* In case of ANY type */ ++ unsigned char tag, /* In case of ANY type */ ++ const void *value, size_t vlen); ++ ++struct asn1_decoder { ++ const unsigned char *machine; ++ size_t machlen; ++ const asn1_action_t *actions; ++}; ++ ++enum asn1_opcode { ++ /* The tag-matching ops come first and the odd-numbered slots ++ * are for OR_SKIP ops. ++ */ ++#define ASN1_OP_MATCH__SKIP 0x01 ++#define ASN1_OP_MATCH__ACT 0x02 ++#define ASN1_OP_MATCH__JUMP 0x04 ++#define ASN1_OP_MATCH__ANY 0x08 ++#define ASN1_OP_MATCH__COND 0x10 ++ ++ ASN1_OP_MATCH = 0x00, ++ ASN1_OP_MATCH_OR_SKIP = 0x01, ++ ASN1_OP_MATCH_ACT = 0x02, ++ ASN1_OP_MATCH_ACT_OR_SKIP = 0x03, ++ ASN1_OP_MATCH_JUMP = 0x04, ++ ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, ++ ASN1_OP_MATCH_ANY = 0x08, ++ ASN1_OP_MATCH_ANY_ACT = 0x0a, ++ /* Everything before here matches unconditionally */ ++ ++ ASN1_OP_COND_MATCH_OR_SKIP = 0x11, ++ ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, ++ ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, ++ ASN1_OP_COND_MATCH_ANY = 0x18, ++ ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, ++ ++ /* Everything before here will want a tag from the data */ ++#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT ++ ++ /* These are here to help fill up space */ ++ ASN1_OP_COND_FAIL = 0x1b, ++ ASN1_OP_COMPLETE = 0x1c, ++ ASN1_OP_ACT = 0x1d, ++ ASN1_OP_RETURN = 0x1e, ++ ++ /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ ++ ASN1_OP_END_SEQ = 0x20, ++ ASN1_OP_END_SET = 0x21, ++ ASN1_OP_END_SEQ_OF = 0x22, ++ ASN1_OP_END_SET_OF = 0x23, ++ ASN1_OP_END_SEQ_ACT = 0x24, ++ ASN1_OP_END_SET_ACT = 0x25, ++ ASN1_OP_END_SEQ_OF_ACT = 0x26, ++ ASN1_OP_END_SET_OF_ACT = 0x27, ++#define ASN1_OP_END__SET 0x01 ++#define ASN1_OP_END__OF 0x02 ++#define ASN1_OP_END__ACT 0x04 ++ ++ ASN1_OP__NR ++}; ++ ++#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG) ++#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG) ++#define _jump_target(N) (N) ++#define _action(N) (N) ++ ++#endif /* _LINUX_ASN1_BER_BYTECODE_H */ +diff --git a/init/Kconfig b/init/Kconfig +index 7452e19..fa8ccad 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1626,4 +1626,12 @@ config PADATA + depends on SMP + bool + ++config ASN1 ++ tristate ++ help ++ Build a simple ASN.1 grammar compiler that produces a bytecode output ++ that can be interpreted by the ASN.1 stream decoder and used to ++ inform it as to what tags are to be expected in a stream and what ++ functions to call on what tags. ++ + source "kernel/Kconfig.locks" +diff --git a/scripts/.gitignore b/scripts/.gitignore +index 65f362d..fb070fa 100644 +--- a/scripts/.gitignore ++++ b/scripts/.gitignore +@@ -10,3 +10,4 @@ ihex2fw + recordmcount + docproc + sortextable ++asn1_compiler +diff --git a/scripts/Makefile b/scripts/Makefile +index a55b006..01e7adb 100644 +--- a/scripts/Makefile ++++ b/scripts/Makefile +@@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash + hostprogs-$(CONFIG_IKCONFIG) += bin2c + hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount + hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable ++hostprogs-$(CONFIG_ASN1) += asn1_compiler + + HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include ++HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include + + always := $(hostprogs-y) $(hostprogs-m) + +diff --git a/scripts/Makefile.build b/scripts/Makefile.build +index ff1720d..0e801c3 100644 +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@ + $(obj)/%.lds: $(src)/%.lds.S FORCE + $(call if_changed_dep,cpp_lds_S) + ++# ASN.1 grammar ++# --------------------------------------------------------------------------- ++quiet_cmd_asn1_compiler = ASN.1 $@ ++ cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ ++ $(subst .h,.c,$@) $(subst .c,.h,$@) ++ ++.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h ++ ++$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler ++ $(call cmd,asn1_compiler) ++ + # Build the compiled-in targets + # --------------------------------------------------------------------------- + +diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c +new file mode 100644 +index 0000000..db0e5cd +--- /dev/null ++++ b/scripts/asn1_compiler.c +@@ -0,0 +1,1545 @@ ++/* Simplified ASN.1 notation parser ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdint.h> ++#include <string.h> ++#include <ctype.h> ++#include <unistd.h> ++#include <fcntl.h> ++#include <sys/stat.h> ++#include <linux/asn1_ber_bytecode.h> ++ ++enum token_type { ++ DIRECTIVE_ABSENT, ++ DIRECTIVE_ALL, ++ DIRECTIVE_ANY, ++ DIRECTIVE_APPLICATION, ++ DIRECTIVE_AUTOMATIC, ++ DIRECTIVE_BEGIN, ++ DIRECTIVE_BIT, ++ DIRECTIVE_BMPString, ++ DIRECTIVE_BOOLEAN, ++ DIRECTIVE_BY, ++ DIRECTIVE_CHARACTER, ++ DIRECTIVE_CHOICE, ++ DIRECTIVE_CLASS, ++ DIRECTIVE_COMPONENT, ++ DIRECTIVE_COMPONENTS, ++ DIRECTIVE_CONSTRAINED, ++ DIRECTIVE_CONTAINING, ++ DIRECTIVE_DEFAULT, ++ DIRECTIVE_DEFINED, ++ DIRECTIVE_DEFINITIONS, ++ DIRECTIVE_EMBEDDED, ++ DIRECTIVE_ENCODED, ++ DIRECTIVE_ENCODING_CONTROL, ++ DIRECTIVE_END, ++ DIRECTIVE_ENUMERATED, ++ DIRECTIVE_EXCEPT, ++ DIRECTIVE_EXPLICIT, ++ DIRECTIVE_EXPORTS, ++ DIRECTIVE_EXTENSIBILITY, ++ DIRECTIVE_EXTERNAL, ++ DIRECTIVE_FALSE, ++ DIRECTIVE_FROM, ++ DIRECTIVE_GeneralString, ++ DIRECTIVE_GeneralizedTime, ++ DIRECTIVE_GraphicString, ++ DIRECTIVE_IA5String, ++ DIRECTIVE_IDENTIFIER, ++ DIRECTIVE_IMPLICIT, ++ DIRECTIVE_IMPLIED, ++ DIRECTIVE_IMPORTS, ++ DIRECTIVE_INCLUDES, ++ DIRECTIVE_INSTANCE, ++ DIRECTIVE_INSTRUCTIONS, ++ DIRECTIVE_INTEGER, ++ DIRECTIVE_INTERSECTION, ++ DIRECTIVE_ISO646String, ++ DIRECTIVE_MAX, ++ DIRECTIVE_MIN, ++ DIRECTIVE_MINUS_INFINITY, ++ DIRECTIVE_NULL, ++ DIRECTIVE_NumericString, ++ DIRECTIVE_OBJECT, ++ DIRECTIVE_OCTET, ++ DIRECTIVE_OF, ++ DIRECTIVE_OPTIONAL, ++ DIRECTIVE_ObjectDescriptor, ++ DIRECTIVE_PATTERN, ++ DIRECTIVE_PDV, ++ DIRECTIVE_PLUS_INFINITY, ++ DIRECTIVE_PRESENT, ++ DIRECTIVE_PRIVATE, ++ DIRECTIVE_PrintableString, ++ DIRECTIVE_REAL, ++ DIRECTIVE_RELATIVE_OID, ++ DIRECTIVE_SEQUENCE, ++ DIRECTIVE_SET, ++ DIRECTIVE_SIZE, ++ DIRECTIVE_STRING, ++ DIRECTIVE_SYNTAX, ++ DIRECTIVE_T61String, ++ DIRECTIVE_TAGS, ++ DIRECTIVE_TRUE, ++ DIRECTIVE_TeletexString, ++ DIRECTIVE_UNION, ++ DIRECTIVE_UNIQUE, ++ DIRECTIVE_UNIVERSAL, ++ DIRECTIVE_UTCTime, ++ DIRECTIVE_UTF8String, ++ DIRECTIVE_UniversalString, ++ DIRECTIVE_VideotexString, ++ DIRECTIVE_VisibleString, ++ DIRECTIVE_WITH, ++ NR__DIRECTIVES, ++ TOKEN_ASSIGNMENT = NR__DIRECTIVES, ++ TOKEN_OPEN_CURLY, ++ TOKEN_CLOSE_CURLY, ++ TOKEN_OPEN_SQUARE, ++ TOKEN_CLOSE_SQUARE, ++ TOKEN_OPEN_ACTION, ++ TOKEN_CLOSE_ACTION, ++ TOKEN_COMMA, ++ TOKEN_NUMBER, ++ TOKEN_TYPE_NAME, ++ TOKEN_ELEMENT_NAME, ++ NR__TOKENS ++}; ++ ++static const unsigned char token_to_tag[NR__TOKENS] = { ++ /* EOC goes first */ ++ [DIRECTIVE_BOOLEAN] = ASN1_BOOL, ++ [DIRECTIVE_INTEGER] = ASN1_INT, ++ [DIRECTIVE_BIT] = ASN1_BTS, ++ [DIRECTIVE_OCTET] = ASN1_OTS, ++ [DIRECTIVE_NULL] = ASN1_NULL, ++ [DIRECTIVE_OBJECT] = ASN1_OID, ++ [DIRECTIVE_ObjectDescriptor] = ASN1_ODE, ++ [DIRECTIVE_EXTERNAL] = ASN1_EXT, ++ [DIRECTIVE_REAL] = ASN1_REAL, ++ [DIRECTIVE_ENUMERATED] = ASN1_ENUM, ++ [DIRECTIVE_EMBEDDED] = 0, ++ [DIRECTIVE_UTF8String] = ASN1_UTF8STR, ++ [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID, ++ /* 14 */ ++ /* 15 */ ++ [DIRECTIVE_SEQUENCE] = ASN1_SEQ, ++ [DIRECTIVE_SET] = ASN1_SET, ++ [DIRECTIVE_NumericString] = ASN1_NUMSTR, ++ [DIRECTIVE_PrintableString] = ASN1_PRNSTR, ++ [DIRECTIVE_T61String] = ASN1_TEXSTR, ++ [DIRECTIVE_TeletexString] = ASN1_TEXSTR, ++ [DIRECTIVE_VideotexString] = ASN1_VIDSTR, ++ [DIRECTIVE_IA5String] = ASN1_IA5STR, ++ [DIRECTIVE_UTCTime] = ASN1_UNITIM, ++ [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM, ++ [DIRECTIVE_GraphicString] = ASN1_GRASTR, ++ [DIRECTIVE_VisibleString] = ASN1_VISSTR, ++ [DIRECTIVE_GeneralString] = ASN1_GENSTR, ++ [DIRECTIVE_UniversalString] = ASN1_UNITIM, ++ [DIRECTIVE_CHARACTER] = ASN1_CHRSTR, ++ [DIRECTIVE_BMPString] = ASN1_BMPSTR, ++}; ++ ++static const char asn1_classes[4][5] = { ++ [ASN1_UNIV] = "UNIV", ++ [ASN1_APPL] = "APPL", ++ [ASN1_CONT] = "CONT", ++ [ASN1_PRIV] = "PRIV" ++}; ++ ++static const char asn1_methods[2][5] = { ++ [ASN1_UNIV] = "PRIM", ++ [ASN1_APPL] = "CONS" ++}; ++ ++static const char *const asn1_universal_tags[32] = { ++ "EOC", ++ "BOOL", ++ "INT", ++ "BTS", ++ "OTS", ++ "NULL", ++ "OID", ++ "ODE", ++ "EXT", ++ "REAL", ++ "ENUM", ++ "EPDV", ++ "UTF8STR", ++ "RELOID", ++ NULL, /* 14 */ ++ NULL, /* 15 */ ++ "SEQ", ++ "SET", ++ "NUMSTR", ++ "PRNSTR", ++ "TEXSTR", ++ "VIDSTR", ++ "IA5STR", ++ "UNITIM", ++ "GENTIM", ++ "GRASTR", ++ "VISSTR", ++ "GENSTR", ++ "UNISTR", ++ "CHRSTR", ++ "BMPSTR", ++ NULL /* 31 */ ++}; ++ ++static const char *filename; ++static const char *grammar_name; ++static const char *outputname; ++static const char *headername; ++ ++static const char *const directives[NR__DIRECTIVES] = { ++#define _(X) [DIRECTIVE_##X] = #X ++ _(ABSENT), ++ _(ALL), ++ _(ANY), ++ _(APPLICATION), ++ _(AUTOMATIC), ++ _(BEGIN), ++ _(BIT), ++ _(BMPString), ++ _(BOOLEAN), ++ _(BY), ++ _(CHARACTER), ++ _(CHOICE), ++ _(CLASS), ++ _(COMPONENT), ++ _(COMPONENTS), ++ _(CONSTRAINED), ++ _(CONTAINING), ++ _(DEFAULT), ++ _(DEFINED), ++ _(DEFINITIONS), ++ _(EMBEDDED), ++ _(ENCODED), ++ [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL", ++ _(END), ++ _(ENUMERATED), ++ _(EXCEPT), ++ _(EXPLICIT), ++ _(EXPORTS), ++ _(EXTENSIBILITY), ++ _(EXTERNAL), ++ _(FALSE), ++ _(FROM), ++ _(GeneralString), ++ _(GeneralizedTime), ++ _(GraphicString), ++ _(IA5String), ++ _(IDENTIFIER), ++ _(IMPLICIT), ++ _(IMPLIED), ++ _(IMPORTS), ++ _(INCLUDES), ++ _(INSTANCE), ++ _(INSTRUCTIONS), ++ _(INTEGER), ++ _(INTERSECTION), ++ _(ISO646String), ++ _(MAX), ++ _(MIN), ++ [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY", ++ [DIRECTIVE_NULL] = "NULL", ++ _(NumericString), ++ _(OBJECT), ++ _(OCTET), ++ _(OF), ++ _(OPTIONAL), ++ _(ObjectDescriptor), ++ _(PATTERN), ++ _(PDV), ++ [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY", ++ _(PRESENT), ++ _(PRIVATE), ++ _(PrintableString), ++ _(REAL), ++ [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID", ++ _(SEQUENCE), ++ _(SET), ++ _(SIZE), ++ _(STRING), ++ _(SYNTAX), ++ _(T61String), ++ _(TAGS), ++ _(TRUE), ++ _(TeletexString), ++ _(UNION), ++ _(UNIQUE), ++ _(UNIVERSAL), ++ _(UTCTime), ++ _(UTF8String), ++ _(UniversalString), ++ _(VideotexString), ++ _(VisibleString), ++ _(WITH) ++}; ++ ++struct action { ++ struct action *next; ++ unsigned char index; ++ char name[]; ++}; ++ ++static struct action *action_list; ++static unsigned nr_actions; ++ ++struct token { ++ unsigned short line; ++ enum token_type token_type : 8; ++ unsigned char size; ++ struct action *action; ++ const char *value; ++ struct type *type; ++}; ++ ++static struct token *token_list; ++static unsigned nr_tokens; ++ ++static int directive_compare(const void *_key, const void *_pdir) ++{ ++ const struct token *token = _key; ++ const char *const *pdir = _pdir, *dir = *pdir; ++ size_t dlen, clen; ++ int val; ++ ++ dlen = strlen(dir); ++ clen = (dlen < token->size) ? dlen : token->size; ++ ++ //printf("cmp(%*.*s,%s) = ", ++ // (int)token->size, (int)token->size, token->value, ++ // dir); ++ ++ val = memcmp(token->value, dir, clen); ++ if (val != 0) { ++ //printf("%d [cmp]\n", val); ++ return val; ++ } ++ ++ if (dlen == token->size) { ++ //printf("0\n"); ++ return 0; ++ } ++ //printf("%d\n", (int)dlen - (int)token->size); ++ return dlen - token->size; /* shorter -> negative */ ++} ++ ++/* ++ * Tokenise an ASN.1 grammar ++ */ ++static void tokenise(char *buffer, char *end) ++{ ++ struct token *tokens; ++ char *line, *nl, *p, *q; ++ unsigned tix, lineno; ++ ++ /* Assume we're going to have half as many tokens as we have ++ * characters ++ */ ++ token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); ++ if (!tokens) { ++ perror(NULL); ++ exit(1); ++ } ++ tix = 0; ++ ++ lineno = 0; ++ while (buffer < end) { ++ /* First of all, break out a line */ ++ lineno++; ++ line = buffer; ++ nl = memchr(line, '\n', end - buffer); ++ if (!nl) { ++ buffer = nl = end; ++ } else { ++ buffer = nl + 1; ++ *nl = '\0'; ++ } ++ ++ /* Remove "--" comments */ ++ p = line; ++ next_comment: ++ while ((p = memchr(p, '-', nl - p))) { ++ if (p[1] == '-') { ++ /* Found a comment; see if there's a terminator */ ++ q = p + 2; ++ while ((q = memchr(q, '-', nl - q))) { ++ if (q[1] == '-') { ++ /* There is - excise the comment */ ++ q += 2; ++ memmove(p, q, nl - q); ++ goto next_comment; ++ } ++ q++; ++ } ++ *p = '\0'; ++ nl = p; ++ break; ++ } else { ++ p++; ++ } ++ } ++ ++ p = line; ++ while (p < nl) { ++ /* Skip white space */ ++ while (p < nl && isspace(*p)) ++ *(p++) = 0; ++ if (p >= nl) ++ break; ++ ++ tokens[tix].line = lineno; ++ tokens[tix].value = p; ++ ++ /* Handle string tokens */ ++ if (isalpha(*p)) { ++ const char **dir; ++ ++ /* Can be a directive, type name or element ++ * name. Find the end of the name. ++ */ ++ q = p + 1; ++ while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) ++ q++; ++ tokens[tix].size = q - p; ++ p = q; ++ ++ /* If it begins with a lowercase letter then ++ * it's an element name ++ */ ++ if (islower(tokens[tix].value[0])) { ++ tokens[tix++].token_type = TOKEN_ELEMENT_NAME; ++ continue; ++ } ++ ++ /* Otherwise we need to search the directive ++ * table ++ */ ++ dir = bsearch(&tokens[tix], directives, ++ sizeof(directives) / sizeof(directives[1]), ++ sizeof(directives[1]), ++ directive_compare); ++ if (dir) { ++ tokens[tix++].token_type = dir - directives; ++ continue; ++ } ++ ++ tokens[tix++].token_type = TOKEN_TYPE_NAME; ++ continue; ++ } ++ ++ /* Handle numbers */ ++ if (isdigit(*p)) { ++ /* Find the end of the number */ ++ q = p + 1; ++ while (q < nl && (isdigit(*q))) ++ q++; ++ tokens[tix].size = q - p; ++ p = q; ++ tokens[tix++].token_type = TOKEN_NUMBER; ++ continue; ++ } ++ ++ if (nl - p >= 3) { ++ if (memcmp(p, "::=", 3) == 0) { ++ p += 3; ++ tokens[tix].size = 3; ++ tokens[tix++].token_type = TOKEN_ASSIGNMENT; ++ continue; ++ } ++ } ++ ++ if (nl - p >= 2) { ++ if (memcmp(p, "({", 2) == 0) { ++ p += 2; ++ tokens[tix].size = 2; ++ tokens[tix++].token_type = TOKEN_OPEN_ACTION; ++ continue; ++ } ++ if (memcmp(p, "})", 2) == 0) { ++ p += 2; ++ tokens[tix].size = 2; ++ tokens[tix++].token_type = TOKEN_CLOSE_ACTION; ++ continue; ++ } ++ } ++ ++ if (nl - p >= 1) { ++ tokens[tix].size = 1; ++ switch (*p) { ++ case '{': ++ p += 1; ++ tokens[tix++].token_type = TOKEN_OPEN_CURLY; ++ continue; ++ case '}': ++ p += 1; ++ tokens[tix++].token_type = TOKEN_CLOSE_CURLY; ++ continue; ++ case '[': ++ p += 1; ++ tokens[tix++].token_type = TOKEN_OPEN_SQUARE; ++ continue; ++ case ']': ++ p += 1; ++ tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; ++ continue; ++ case ',': ++ p += 1; ++ tokens[tix++].token_type = TOKEN_COMMA; ++ continue; ++ default: ++ break; ++ } ++ } ++ ++ fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", ++ filename, lineno, *p); ++ exit(1); ++ } ++ } ++ ++ nr_tokens = tix; ++ printf("Extracted %u tokens\n", nr_tokens); ++ ++#if 0 ++ { ++ int n; ++ for (n = 0; n < nr_tokens; n++) ++ printf("Token %3u: '%*.*s'\n", ++ n, ++ (int)token_list[n].size, (int)token_list[n].size, ++ token_list[n].value); ++ } ++#endif ++} ++ ++static void build_type_list(void); ++static void parse(void); ++static void render(FILE *out, FILE *hdr); ++ ++/* ++ * ++ */ ++int main(int argc, char **argv) ++{ ++ struct stat st; ++ ssize_t readlen; ++ FILE *out, *hdr; ++ char *buffer, *p; ++ int fd; ++ ++ if (argc != 4) { ++ fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", ++ argv[0]); ++ exit(2); ++ } ++ ++ filename = argv[1]; ++ outputname = argv[2]; ++ headername = argv[3]; ++ ++ fd = open(filename, O_RDONLY); ++ if (fd < 0) { ++ perror(filename); ++ exit(1); ++ } ++ ++ if (fstat(fd, &st) < 0) { ++ perror(filename); ++ exit(1); ++ } ++ ++ if (!(buffer = malloc(st.st_size + 1))) { ++ perror(NULL); ++ exit(1); ++ } ++ ++ if ((readlen = read(fd, buffer, st.st_size)) < 0) { ++ perror(filename); ++ exit(1); ++ } ++ ++ if (close(fd) < 0) { ++ perror(filename); ++ exit(1); ++ } ++ ++ if (readlen != st.st_size) { ++ fprintf(stderr, "%s: Short read\n", filename); ++ exit(1); ++ } ++ ++ p = strrchr(argv[1], '/'); ++ p = p ? p + 1 : argv[1]; ++ grammar_name = strdup(p); ++ if (!p) { ++ perror(NULL); ++ exit(1); ++ } ++ p = strchr(grammar_name, '.'); ++ if (p) ++ *p = '\0'; ++ ++ buffer[readlen] = 0; ++ tokenise(buffer, buffer + readlen); ++ build_type_list(); ++ parse(); ++ ++ out = fopen(outputname, "w"); ++ if (!out) { ++ perror(outputname); ++ exit(1); ++ } ++ ++ hdr = fopen(headername, "w"); ++ if (!out) { ++ perror(headername); ++ exit(1); ++ } ++ ++ render(out, hdr); ++ ++ if (fclose(out) < 0) { ++ perror(outputname); ++ exit(1); ++ } ++ ++ if (fclose(hdr) < 0) { ++ perror(headername); ++ exit(1); ++ } ++ ++ return 0; ++} ++ ++enum compound { ++ NOT_COMPOUND, ++ SET, ++ SET_OF, ++ SEQUENCE, ++ SEQUENCE_OF, ++ CHOICE, ++ ANY, ++ TYPE_REF, ++ TAG_OVERRIDE ++}; ++ ++struct element { ++ struct type *type_def; ++ struct token *name; ++ struct token *type; ++ struct action *action; ++ struct element *children; ++ struct element *next; ++ struct element *render_next; ++ struct element *list_next; ++ uint8_t n_elements; ++ enum compound compound : 8; ++ enum asn1_class class : 8; ++ enum asn1_method method : 8; ++ uint8_t tag; ++ unsigned entry_index; ++ unsigned flags; ++#define ELEMENT_IMPLICIT 0x0001 ++#define ELEMENT_EXPLICIT 0x0002 ++#define ELEMENT_MARKED 0x0004 ++#define ELEMENT_RENDERED 0x0008 ++#define ELEMENT_SKIPPABLE 0x0010 ++#define ELEMENT_CONDITIONAL 0x0020 ++}; ++ ++struct type { ++ struct token *name; ++ struct token *def; ++ struct element *element; ++ unsigned ref_count; ++ unsigned flags; ++#define TYPE_STOP_MARKER 0x0001 ++#define TYPE_BEGIN 0x0002 ++}; ++ ++static struct type *type_list; ++static struct type **type_index; ++static unsigned nr_types; ++ ++static int type_index_compare(const void *_a, const void *_b) ++{ ++ const struct type *const *a = _a, *const *b = _b; ++ ++ if ((*a)->name->size != (*b)->name->size) ++ return (*a)->name->size - (*b)->name->size; ++ else ++ return memcmp((*a)->name->value, (*b)->name->value, ++ (*a)->name->size); ++} ++ ++static int type_finder(const void *_key, const void *_ti) ++{ ++ const struct token *token = _key; ++ const struct type *const *ti = _ti; ++ const struct type *type = *ti; ++ ++ if (token->size != type->name->size) ++ return token->size - type->name->size; ++ else ++ return memcmp(token->value, type->name->value, ++ token->size); ++} ++ ++/* ++ * Build up a list of types and a sorted index to that list. ++ */ ++static void build_type_list(void) ++{ ++ struct type *types; ++ unsigned nr, t, n; ++ ++ nr = 0; ++ for (n = 0; n < nr_tokens - 1; n++) ++ if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && ++ token_list[n + 1].token_type == TOKEN_ASSIGNMENT) ++ nr++; ++ ++ if (nr == 0) { ++ fprintf(stderr, "%s: No defined types\n", filename); ++ exit(1); ++ } ++ ++ nr_types = nr; ++ types = type_list = calloc(nr + 1, sizeof(type_list[0])); ++ if (!type_list) { ++ perror(NULL); ++ exit(1); ++ } ++ type_index = calloc(nr, sizeof(type_index[0])); ++ if (!type_index) { ++ perror(NULL); ++ exit(1); ++ } ++ ++ t = 0; ++ types[t].flags |= TYPE_BEGIN; ++ for (n = 0; n < nr_tokens - 1; n++) { ++ if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && ++ token_list[n + 1].token_type == TOKEN_ASSIGNMENT) { ++ types[t].name = &token_list[n]; ++ type_index[t] = &types[t]; ++ t++; ++ } ++ } ++ types[t].name = &token_list[n + 1]; ++ types[t].flags |= TYPE_STOP_MARKER; ++ ++ qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); ++ ++ printf("Extracted %u types\n", nr_types); ++#if 0 ++ for (n = 0; n < nr_types; n++) { ++ struct type *type = type_index[n]; ++ printf("- %*.*s\n", ++ (int)type->name->size, ++ (int)type->name->size, ++ type->name->value); ++ } ++#endif ++} ++ ++static struct element *parse_type(struct token **_cursor, struct token *stop, ++ struct token *name); ++ ++/* ++ * Parse the token stream ++ */ ++static void parse(void) ++{ ++ struct token *cursor; ++ struct type *type; ++ ++ /* Parse one type definition statement at a time */ ++ type = type_list; ++ do { ++ cursor = type->name; ++ ++ if (cursor[0].token_type != TOKEN_TYPE_NAME || ++ cursor[1].token_type != TOKEN_ASSIGNMENT) ++ abort(); ++ cursor += 2; ++ ++ type->element = parse_type(&cursor, type[1].name, NULL); ++ type->element->type_def = type; ++ ++ if (cursor != type[1].name) { ++ fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ ++ } while (type++, !(type->flags & TYPE_STOP_MARKER)); ++ ++ printf("Extracted %u actions\n", nr_actions); ++} ++ ++static struct element *element_list; ++ ++static struct element *alloc_elem(struct token *type) ++{ ++ struct element *e = calloc(1, sizeof(*e)); ++ if (!e) { ++ perror(NULL); ++ exit(1); ++ } ++ e->list_next = element_list; ++ element_list = e; ++ return e; ++} ++ ++static struct element *parse_compound(struct token **_cursor, struct token *end, ++ int alternates); ++ ++/* ++ * Parse one type definition statement ++ */ ++static struct element *parse_type(struct token **_cursor, struct token *end, ++ struct token *name) ++{ ++ struct element *top, *element; ++ struct action *action, **ppaction; ++ struct token *cursor = *_cursor; ++ struct type **ref; ++ char *p; ++ int labelled = 0, implicit = 0; ++ ++ top = element = alloc_elem(cursor); ++ element->class = ASN1_UNIV; ++ element->method = ASN1_PRIM; ++ element->tag = token_to_tag[cursor->token_type]; ++ element->name = name; ++ ++ /* Extract the tag value if one given */ ++ if (cursor->token_type == TOKEN_OPEN_SQUARE) { ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ switch (cursor->token_type) { ++ case DIRECTIVE_UNIVERSAL: ++ element->class = ASN1_UNIV; ++ cursor++; ++ break; ++ case DIRECTIVE_APPLICATION: ++ element->class = ASN1_APPL; ++ cursor++; ++ break; ++ case TOKEN_NUMBER: ++ element->class = ASN1_CONT; ++ break; ++ case DIRECTIVE_PRIVATE: ++ element->class = ASN1_PRIV; ++ cursor++; ++ break; ++ default: ++ fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != TOKEN_NUMBER) { ++ fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ ++ element->tag &= ~0x1f; ++ element->tag |= strtoul(cursor->value, &p, 10); ++ if (p - cursor->value != cursor->size) ++ abort(); ++ cursor++; ++ ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != TOKEN_CLOSE_SQUARE) { ++ fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ labelled = 1; ++ } ++ ++ /* Handle implicit and explicit markers */ ++ if (cursor->token_type == DIRECTIVE_IMPLICIT) { ++ element->flags |= ELEMENT_IMPLICIT; ++ implicit = 1; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ } else if (cursor->token_type == DIRECTIVE_EXPLICIT) { ++ element->flags |= ELEMENT_EXPLICIT; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ } ++ ++ if (labelled) { ++ if (!implicit) ++ element->method |= ASN1_CONS; ++ element->compound = implicit ? TAG_OVERRIDE : SEQUENCE; ++ element->children = alloc_elem(cursor); ++ element = element->children; ++ element->class = ASN1_UNIV; ++ element->method = ASN1_PRIM; ++ element->tag = token_to_tag[cursor->token_type]; ++ element->name = name; ++ } ++ ++ /* Extract the type we're expecting here */ ++ element->type = cursor; ++ switch (cursor->token_type) { ++ case DIRECTIVE_ANY: ++ element->compound = ANY; ++ cursor++; ++ break; ++ ++ case DIRECTIVE_NULL: ++ case DIRECTIVE_BOOLEAN: ++ case DIRECTIVE_ENUMERATED: ++ case DIRECTIVE_INTEGER: ++ element->compound = NOT_COMPOUND; ++ cursor++; ++ break; ++ ++ case DIRECTIVE_EXTERNAL: ++ element->method = ASN1_CONS; ++ ++ case DIRECTIVE_BMPString: ++ case DIRECTIVE_GeneralString: ++ case DIRECTIVE_GraphicString: ++ case DIRECTIVE_IA5String: ++ case DIRECTIVE_ISO646String: ++ case DIRECTIVE_NumericString: ++ case DIRECTIVE_PrintableString: ++ case DIRECTIVE_T61String: ++ case DIRECTIVE_TeletexString: ++ case DIRECTIVE_UniversalString: ++ case DIRECTIVE_UTF8String: ++ case DIRECTIVE_VideotexString: ++ case DIRECTIVE_VisibleString: ++ case DIRECTIVE_ObjectDescriptor: ++ case DIRECTIVE_GeneralizedTime: ++ case DIRECTIVE_UTCTime: ++ element->compound = NOT_COMPOUND; ++ cursor++; ++ break; ++ ++ case DIRECTIVE_BIT: ++ case DIRECTIVE_OCTET: ++ element->compound = NOT_COMPOUND; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != DIRECTIVE_STRING) ++ goto parse_error; ++ cursor++; ++ break; ++ ++ case DIRECTIVE_OBJECT: ++ element->compound = NOT_COMPOUND; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != DIRECTIVE_IDENTIFIER) ++ goto parse_error; ++ cursor++; ++ break; ++ ++ case TOKEN_TYPE_NAME: ++ element->compound = TYPE_REF; ++ ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), ++ type_finder); ++ if (!ref) { ++ fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ cursor->type = *ref; ++ (*ref)->ref_count++; ++ cursor++; ++ break; ++ ++ case DIRECTIVE_CHOICE: ++ element->compound = CHOICE; ++ cursor++; ++ element->children = parse_compound(&cursor, end, 1); ++ break; ++ ++ case DIRECTIVE_SEQUENCE: ++ element->compound = SEQUENCE; ++ element->method = ASN1_CONS; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type == DIRECTIVE_OF) { ++ element->compound = SEQUENCE_OF; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ element->children = parse_type(&cursor, end, NULL); ++ } else { ++ element->children = parse_compound(&cursor, end, 0); ++ } ++ break; ++ ++ case DIRECTIVE_SET: ++ element->compound = SET; ++ element->method = ASN1_CONS; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type == DIRECTIVE_OF) { ++ element->compound = SET_OF; ++ cursor++; ++ if (cursor >= end) ++ goto parse_error; ++ element->children = parse_type(&cursor, end, NULL); ++ } else { ++ element->children = parse_compound(&cursor, end, 1); ++ } ++ break; ++ ++ default: ++ fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ ++ /* Handle elements that are optional */ ++ if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL || ++ cursor->token_type == DIRECTIVE_DEFAULT) ++ ) { ++ cursor++; ++ top->flags |= ELEMENT_SKIPPABLE; ++ } ++ ++ if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) { ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != TOKEN_ELEMENT_NAME) { ++ fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ ++ action = malloc(sizeof(struct action) + cursor->size + 1); ++ if (!action) { ++ perror(NULL); ++ exit(1); ++ } ++ action->index = 0; ++ memcpy(action->name, cursor->value, cursor->size); ++ action->name[cursor->size] = 0; ++ ++ for (ppaction = &action_list; ++ *ppaction; ++ ppaction = &(*ppaction)->next ++ ) { ++ int cmp = strcmp(action->name, (*ppaction)->name); ++ if (cmp == 0) { ++ free(action); ++ action = *ppaction; ++ goto found; ++ } ++ if (cmp < 0) { ++ action->next = *ppaction; ++ *ppaction = action; ++ nr_actions++; ++ goto found; ++ } ++ } ++ action->next = NULL; ++ *ppaction = action; ++ nr_actions++; ++ found: ++ ++ element->action = action; ++ cursor->action = action; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != TOKEN_CLOSE_ACTION) { ++ fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ cursor++; ++ } ++ ++ *_cursor = cursor; ++ return top; ++ ++parse_error: ++ fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ ++overrun_error: ++ fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); ++ exit(1); ++} ++ ++/* ++ * Parse a compound type list ++ */ ++static struct element *parse_compound(struct token **_cursor, struct token *end, ++ int alternates) ++{ ++ struct element *children, **child_p = &children, *element; ++ struct token *cursor = *_cursor, *name; ++ ++ if (cursor->token_type != TOKEN_OPEN_CURLY) { ++ fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ ++ if (cursor->token_type == TOKEN_OPEN_CURLY) { ++ fprintf(stderr, "%s:%d: Empty compound\n", ++ filename, cursor->line); ++ exit(1); ++ } ++ ++ for (;;) { ++ name = NULL; ++ if (cursor->token_type == TOKEN_ELEMENT_NAME) { ++ name = cursor; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ } ++ ++ element = parse_type(&cursor, end, name); ++ if (alternates) ++ element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL; ++ ++ *child_p = element; ++ child_p = &element->next; ++ ++ if (cursor >= end) ++ goto overrun_error; ++ if (cursor->token_type != TOKEN_COMMA) ++ break; ++ cursor++; ++ if (cursor >= end) ++ goto overrun_error; ++ } ++ ++ children->flags &= ~ELEMENT_CONDITIONAL; ++ ++ if (cursor->token_type != TOKEN_CLOSE_CURLY) { ++ fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", ++ filename, cursor->line, ++ (int)cursor->size, (int)cursor->size, cursor->value); ++ exit(1); ++ } ++ cursor++; ++ ++ *_cursor = cursor; ++ return children; ++ ++overrun_error: ++ fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); ++ exit(1); ++} ++ ++static void render_element(FILE *out, struct element *e, struct element *tag); ++static void render_out_of_line_list(FILE *out); ++ ++static int nr_entries; ++static int render_depth = 1; ++static struct element *render_list, **render_list_p = &render_list; ++ ++__attribute__((format(printf, 2, 3))) ++static void render_opcode(FILE *out, const char *fmt, ...) ++{ ++ va_list va; ++ ++ if (out) { ++ fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, ""); ++ va_start(va, fmt); ++ vfprintf(out, fmt, va); ++ va_end(va); ++ } ++ nr_entries++; ++} ++ ++__attribute__((format(printf, 2, 3))) ++static void render_more(FILE *out, const char *fmt, ...) ++{ ++ va_list va; ++ ++ if (out) { ++ va_start(va, fmt); ++ vfprintf(out, fmt, va); ++ va_end(va); ++ } ++} ++ ++/* ++ * Render the grammar into a state machine definition. ++ */ ++static void render(FILE *out, FILE *hdr) ++{ ++ struct element *e; ++ struct action *action; ++ struct type *root; ++ int index; ++ ++ fprintf(hdr, "/*\n"); ++ fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n"); ++ fprintf(hdr, " *\n"); ++ fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name); ++ fprintf(hdr, " */\n"); ++ fprintf(hdr, "#include <linux/asn1_decoder.h>\n"); ++ fprintf(hdr, "\n"); ++ fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name); ++ if (ferror(hdr)) { ++ perror(headername); ++ exit(1); ++ } ++ ++ fprintf(out, "/*\n"); ++ fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n"); ++ fprintf(out, " *\n"); ++ fprintf(out, " * ASN.1 parser for %s\n", grammar_name); ++ fprintf(out, " */\n"); ++ fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n"); ++ fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name); ++ fprintf(out, "\n"); ++ if (ferror(out)) { ++ perror(outputname); ++ exit(1); ++ } ++ ++ /* Tabulate the action functions we might have to call */ ++ fprintf(hdr, "\n"); ++ index = 0; ++ for (action = action_list; action; action = action->next) { ++ action->index = index++; ++ fprintf(hdr, ++ "extern int %s(void *, size_t, unsigned char," ++ " const void *, size_t);\n", ++ action->name); ++ } ++ fprintf(hdr, "\n"); ++ ++ fprintf(out, "enum %s_actions {\n", grammar_name); ++ for (action = action_list; action; action = action->next) ++ fprintf(out, "\tACT_%s = %u,\n", ++ action->name, action->index); ++ fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions); ++ fprintf(out, "};\n"); ++ ++ fprintf(out, "\n"); ++ fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n", ++ grammar_name, grammar_name); ++ for (action = action_list; action; action = action->next) ++ fprintf(out, "\t[%4u] = %s,\n", action->index, action->name); ++ fprintf(out, "};\n"); ++ ++ if (ferror(out)) { ++ perror(outputname); ++ exit(1); ++ } ++ ++ /* We do two passes - the first one calculates all the offsets */ ++ printf("Pass 1\n"); ++ nr_entries = 0; ++ root = &type_list[0]; ++ render_element(NULL, root->element, NULL); ++ render_opcode(NULL, "ASN1_OP_COMPLETE,\n"); ++ render_out_of_line_list(NULL); ++ ++ for (e = element_list; e; e = e->list_next) ++ e->flags &= ~ELEMENT_RENDERED; ++ ++ /* And then we actually render */ ++ printf("Pass 2\n"); ++ fprintf(out, "\n"); ++ fprintf(out, "static const unsigned char %s_machine[] = {\n", ++ grammar_name); ++ ++ nr_entries = 0; ++ root = &type_list[0]; ++ render_element(out, root->element, NULL); ++ render_opcode(out, "ASN1_OP_COMPLETE,\n"); ++ render_out_of_line_list(out); ++ ++ fprintf(out, "};\n"); ++ ++ fprintf(out, "\n"); ++ fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name); ++ fprintf(out, "\t.machine = %s_machine,\n", grammar_name); ++ fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name); ++ fprintf(out, "\t.actions = %s_action_table,\n", grammar_name); ++ fprintf(out, "};\n"); ++} ++ ++/* ++ * Render the out-of-line elements ++ */ ++static void render_out_of_line_list(FILE *out) ++{ ++ struct element *e, *ce; ++ const char *act; ++ int entry; ++ ++ while ((e = render_list)) { ++ render_list = e->render_next; ++ if (!render_list) ++ render_list_p = &render_list; ++ ++ render_more(out, "\n"); ++ e->entry_index = entry = nr_entries; ++ render_depth++; ++ for (ce = e->children; ce; ce = ce->next) ++ render_element(out, ce, NULL); ++ render_depth--; ++ ++ act = e->action ? "_ACT" : ""; ++ switch (e->compound) { ++ case SEQUENCE: ++ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); ++ break; ++ case SEQUENCE_OF: ++ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); ++ render_opcode(out, "_jump_target(%u),\n", entry); ++ break; ++ case SET: ++ render_opcode(out, "ASN1_OP_END_SET%s,\n", act); ++ break; ++ case SET_OF: ++ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); ++ render_opcode(out, "_jump_target(%u),\n", entry); ++ break; ++ } ++ if (e->action) ++ render_opcode(out, "_action(ACT_%s),\n", ++ e->action->name); ++ render_opcode(out, "ASN1_OP_RETURN,\n"); ++ } ++} ++ ++/* ++ * Render an element. ++ */ ++static void render_element(FILE *out, struct element *e, struct element *tag) ++{ ++ struct element *ec; ++ const char *cond, *act; ++ int entry, skippable = 0, outofline = 0; ++ ++ if (e->flags & ELEMENT_SKIPPABLE || ++ (tag && tag->flags & ELEMENT_SKIPPABLE)) ++ skippable = 1; ++ ++ if ((e->type_def && e->type_def->ref_count > 1) || ++ skippable) ++ outofline = 1; ++ ++ if (e->type_def && out) { ++ render_more(out, "\t// %*.*s\n", ++ (int)e->type_def->name->size, (int)e->type_def->name->size, ++ e->type_def->name->value); ++ } ++ ++ /* Render the operation */ ++ cond = (e->flags & ELEMENT_CONDITIONAL || ++ (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; ++ act = e->action ? "_ACT" : ""; ++ switch (e->compound) { ++ case ANY: ++ render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); ++ if (e->name) ++ render_more(out, "\t\t// %*.*s", ++ (int)e->name->size, (int)e->name->size, ++ e->name->value); ++ render_more(out, "\n"); ++ goto dont_render_tag; ++ ++ case TAG_OVERRIDE: ++ render_element(out, e->children, e); ++ return; ++ ++ case SEQUENCE: ++ case SEQUENCE_OF: ++ case SET: ++ case SET_OF: ++ render_opcode(out, "ASN1_OP_%sMATCH%s%s,", ++ cond, ++ outofline ? "_JUMP" : "", ++ skippable ? "_OR_SKIP" : ""); ++ break; ++ ++ case CHOICE: ++ goto dont_render_tag; ++ ++ case TYPE_REF: ++ if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) ++ goto dont_render_tag; ++ default: ++ render_opcode(out, "ASN1_OP_%sMATCH%s%s,", ++ cond, act, ++ skippable ? "_OR_SKIP" : ""); ++ break; ++ } ++ ++ if (e->name) ++ render_more(out, "\t\t// %*.*s", ++ (int)e->name->size, (int)e->name->size, ++ e->name->value); ++ render_more(out, "\n"); ++ ++ /* Render the tag */ ++ if (!tag) ++ tag = e; ++ if (tag->class == ASN1_UNIV && ++ tag->tag != 14 && ++ tag->tag != 15 && ++ tag->tag != 31) ++ render_opcode(out, "_tag(%s, %s, %s),\n", ++ asn1_classes[tag->class], ++ asn1_methods[tag->method | e->method], ++ asn1_universal_tags[tag->tag]); ++ else ++ render_opcode(out, "_tagn(%s, %s, %2u),\n", ++ asn1_classes[tag->class], ++ asn1_methods[tag->method | e->method], ++ tag->tag); ++ tag = NULL; ++dont_render_tag: ++ ++ /* Deal with compound types */ ++ switch (e->compound) { ++ case TYPE_REF: ++ render_element(out, e->type->type->element, tag); ++ if (e->action) ++ render_opcode(out, "ASN1_OP_ACT,\n"); ++ break; ++ ++ case SEQUENCE: ++ if (outofline) { ++ /* Render out-of-line for multiple use or ++ * skipability */ ++ render_opcode(out, "_jump_target(%u),", e->entry_index); ++ if (e->type_def && e->type_def->name) ++ render_more(out, "\t\t// --> %*.*s", ++ (int)e->type_def->name->size, ++ (int)e->type_def->name->size, ++ e->type_def->name->value); ++ render_more(out, "\n"); ++ if (!(e->flags & ELEMENT_RENDERED)) { ++ e->flags |= ELEMENT_RENDERED; ++ *render_list_p = e; ++ render_list_p = &e->render_next; ++ } ++ return; ++ } else { ++ /* Render inline for single use */ ++ render_depth++; ++ for (ec = e->children; ec; ec = ec->next) ++ render_element(out, ec, NULL); ++ render_depth--; ++ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); ++ } ++ break; ++ ++ case SEQUENCE_OF: ++ case SET_OF: ++ if (outofline) { ++ /* Render out-of-line for multiple use or ++ * skipability */ ++ render_opcode(out, "_jump_target(%u),", e->entry_index); ++ if (e->type_def && e->type_def->name) ++ render_more(out, "\t\t// --> %*.*s", ++ (int)e->type_def->name->size, ++ (int)e->type_def->name->size, ++ e->type_def->name->value); ++ render_more(out, "\n"); ++ if (!(e->flags & ELEMENT_RENDERED)) { ++ e->flags |= ELEMENT_RENDERED; ++ *render_list_p = e; ++ render_list_p = &e->render_next; ++ } ++ return; ++ } else { ++ /* Render inline for single use */ ++ entry = nr_entries; ++ render_depth++; ++ render_element(out, e->children, NULL); ++ render_depth--; ++ if (e->compound == SEQUENCE_OF) ++ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); ++ else ++ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); ++ render_opcode(out, "_jump_target(%u),\n", entry); ++ } ++ break; ++ ++ case SET: ++ /* I can't think of a nice way to do SET support without having ++ * a stack of bitmasks to make sure no element is repeated. ++ * The bitmask has also to be checked that no non-optional ++ * elements are left out whilst not preventing optional ++ * elements from being left out. ++ */ ++ fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); ++ exit(1); ++ ++ case CHOICE: ++ for (ec = e->children; ec; ec = ec->next) ++ render_element(out, ec, NULL); ++ if (!skippable) ++ render_opcode(out, "ASN1_OP_COND_FAIL,\n"); ++ if (e->action) ++ render_opcode(out, "ASN1_OP_ACT,\n"); ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (e->action) ++ render_opcode(out, "_action(ACT_%s),\n", e->action->name); ++} +-- +1.7.12.1 + + +From 650c728e4b8d58d72b19973e97c3c765178e81b8 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Mon, 24 Sep 2012 17:11:16 +0100 +Subject: [PATCH 15/37] X.509: Add an ASN.1 decoder + +Add an ASN.1 BER/DER/CER decoder. This uses the bytecode from the ASN.1 +compiler in the previous patch to inform it as to what to expect to find in the +encoded byte stream. The output from the compiler also tells it what functions +to call on what tags, thus allowing the caller to retrieve information. + +The decoder is called as follows: + + int asn1_decoder(const struct asn1_decoder *decoder, + void *context, + const unsigned char *data, + size_t datalen); + +The decoder argument points to the bytecode from the ASN.1 compiler. context +is the caller's context and is passed to the action functions. data and +datalen define the byte stream to be decoded. + +Note that the decoder is currently limited to datalen being less than 64K. +This reduces the amount of stack space used by the decoder because ASN.1 is a +nested construct. Similarly, the decoder is limited to a maximum of 10 levels +of constructed data outside of a leaf node also in an effort to keep stack +usage down. + +These restrictions can be raised if necessary. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + include/linux/asn1_decoder.h | 24 +++ + lib/Makefile | 2 + + lib/asn1_decoder.c | 477 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 503 insertions(+) + create mode 100644 include/linux/asn1_decoder.h + create mode 100644 lib/asn1_decoder.c + +diff --git a/include/linux/asn1_decoder.h b/include/linux/asn1_decoder.h +new file mode 100644 +index 0000000..fa2ff5b +--- /dev/null ++++ b/include/linux/asn1_decoder.h +@@ -0,0 +1,24 @@ ++/* ASN.1 decoder ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_ASN1_DECODER_H ++#define _LINUX_ASN1_DECODER_H ++ ++#include <linux/asn1.h> ++ ++struct asn1_decoder; ++ ++extern int asn1_ber_decoder(const struct asn1_decoder *decoder, ++ void *context, ++ const unsigned char *data, ++ size_t datalen); ++ ++#endif /* _LINUX_ASN1_DECODER_H */ +diff --git a/lib/Makefile b/lib/Makefile +index b042896..ca856b6 100644 +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -140,6 +140,8 @@ $(foreach file, $(libfdt_files), \ + $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt)) + lib-$(CONFIG_LIBFDT) += $(libfdt_files) + ++obj-$(CONFIG_ASN1) += asn1_decoder.o ++ + hostprogs-y := gen_crc32table + clean-files := crc32table.h + +diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c +new file mode 100644 +index 0000000..2e4196d +--- /dev/null ++++ b/lib/asn1_decoder.c +@@ -0,0 +1,477 @@ ++/* Decoder for ASN.1 BER/DER/CER encoded bytestream ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/export.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/asn1_decoder.h> ++#include <linux/asn1_ber_bytecode.h> ++ ++static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { ++ /* OPC TAG JMP ACT */ ++ [ASN1_OP_MATCH] = 1 + 1, ++ [ASN1_OP_MATCH_OR_SKIP] = 1 + 1, ++ [ASN1_OP_MATCH_ACT] = 1 + 1 + 1, ++ [ASN1_OP_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, ++ [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, ++ [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, ++ [ASN1_OP_MATCH_ANY] = 1, ++ [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, ++ [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, ++ [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, ++ [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, ++ [ASN1_OP_COND_MATCH_ANY] = 1, ++ [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, ++ [ASN1_OP_COND_FAIL] = 1, ++ [ASN1_OP_COMPLETE] = 1, ++ [ASN1_OP_ACT] = 1 + 1, ++ [ASN1_OP_RETURN] = 1, ++ [ASN1_OP_END_SEQ] = 1, ++ [ASN1_OP_END_SEQ_OF] = 1 + 1, ++ [ASN1_OP_END_SET] = 1, ++ [ASN1_OP_END_SET_OF] = 1 + 1, ++ [ASN1_OP_END_SEQ_ACT] = 1 + 1, ++ [ASN1_OP_END_SEQ_OF_ACT] = 1 + 1 + 1, ++ [ASN1_OP_END_SET_ACT] = 1 + 1, ++ [ASN1_OP_END_SET_OF_ACT] = 1 + 1 + 1, ++}; ++ ++/* ++ * Find the length of an indefinite length object ++ */ ++static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, ++ const char **_errmsg, size_t *_err_dp) ++{ ++ unsigned char tag, tmp; ++ size_t dp = 0, len, n; ++ int indef_level = 1; ++ ++next_tag: ++ if (unlikely(datalen - dp < 2)) { ++ if (datalen == dp) ++ goto missing_eoc; ++ goto data_overrun_error; ++ } ++ ++ /* Extract a tag from the data */ ++ tag = data[dp++]; ++ if (tag == 0) { ++ /* It appears to be an EOC. */ ++ if (data[dp++] != 0) ++ goto invalid_eoc; ++ if (--indef_level <= 0) ++ return dp; ++ goto next_tag; ++ } ++ ++ if (unlikely((tag & 0x1f) == 0x1f)) { ++ do { ++ if (unlikely(datalen - dp < 2)) ++ goto data_overrun_error; ++ tmp = data[dp++]; ++ } while (tmp & 0x80); ++ } ++ ++ /* Extract the length */ ++ len = data[dp++]; ++ if (len < 0x7f) { ++ dp += len; ++ goto next_tag; ++ } ++ ++ if (unlikely(len == 0x80)) { ++ /* Indefinite length */ ++ if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5)) ++ goto indefinite_len_primitive; ++ indef_level++; ++ goto next_tag; ++ } ++ ++ n = len - 0x80; ++ if (unlikely(n > sizeof(size_t) - 1)) ++ goto length_too_long; ++ if (unlikely(n > datalen - dp)) ++ goto data_overrun_error; ++ for (len = 0; n > 0; n--) { ++ len <<= 8; ++ len |= data[dp++]; ++ } ++ dp += len; ++ goto next_tag; ++ ++length_too_long: ++ *_errmsg = "Unsupported length"; ++ goto error; ++indefinite_len_primitive: ++ *_errmsg = "Indefinite len primitive not permitted"; ++ goto error; ++invalid_eoc: ++ *_errmsg = "Invalid length EOC"; ++ goto error; ++data_overrun_error: ++ *_errmsg = "Data overrun error"; ++ goto error; ++missing_eoc: ++ *_errmsg = "Missing EOC in indefinite len cons"; ++error: ++ *_err_dp = dp; ++ return -1; ++} ++ ++/** ++ * asn1_ber_decoder - Decoder BER/DER/CER ASN.1 according to pattern ++ * @decoder: The decoder definition (produced by asn1_compiler) ++ * @context: The caller's context (to be passed to the action functions) ++ * @data: The encoded data ++ * @datasize: The size of the encoded data ++ * ++ * Decode BER/DER/CER encoded ASN.1 data according to a bytecode pattern ++ * produced by asn1_compiler. Action functions are called on marked tags to ++ * allow the caller to retrieve significant data. ++ * ++ * LIMITATIONS: ++ * ++ * To keep down the amount of stack used by this function, the following limits ++ * have been imposed: ++ * ++ * (1) This won't handle datalen > 65535 without increasing the size of the ++ * cons stack elements and length_too_long checking. ++ * ++ * (2) The stack of constructed types is 10 deep. If the depth of non-leaf ++ * constructed types exceeds this, the decode will fail. ++ * ++ * (3) The SET type (not the SET OF type) isn't really supported as tracking ++ * what members of the set have been seen is a pain. ++ */ ++int asn1_ber_decoder(const struct asn1_decoder *decoder, ++ void *context, ++ const unsigned char *data, ++ size_t datalen) ++{ ++ const unsigned char *machine = decoder->machine; ++ const asn1_action_t *actions = decoder->actions; ++ size_t machlen = decoder->machlen; ++ enum asn1_opcode op; ++ unsigned char tag = 0, csp = 0, jsp = 0, optag = 0, hdr = 0; ++ const char *errmsg; ++ size_t pc = 0, dp = 0, tdp = 0, len = 0; ++ int ret; ++ ++ unsigned char flags = 0; ++#define FLAG_INDEFINITE_LENGTH 0x01 ++#define FLAG_MATCHED 0x02 ++#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag ++ * - ie. whether or not we are going to parse ++ * a compound type. ++ */ ++ ++#define NR_CONS_STACK 10 ++ unsigned short cons_dp_stack[NR_CONS_STACK]; ++ unsigned short cons_datalen_stack[NR_CONS_STACK]; ++ unsigned char cons_hdrlen_stack[NR_CONS_STACK]; ++#define NR_JUMP_STACK 10 ++ unsigned char jump_stack[NR_JUMP_STACK]; ++ ++ if (datalen > 65535) ++ return -EMSGSIZE; ++ ++next_op: ++ pr_debug("next_op: pc=\e[32m%zu\e[m/%zu dp=\e[33m%zu\e[m/%zu C=%d J=%d\n", ++ pc, machlen, dp, datalen, csp, jsp); ++ if (unlikely(pc >= machlen)) ++ goto machine_overrun_error; ++ op = machine[pc]; ++ if (unlikely(pc + asn1_op_lengths[op] > machlen)) ++ goto machine_overrun_error; ++ ++ /* If this command is meant to match a tag, then do that before ++ * evaluating the command. ++ */ ++ if (op <= ASN1_OP__MATCHES_TAG) { ++ unsigned char tmp; ++ ++ /* Skip conditional matches if possible */ ++ if ((op & ASN1_OP_MATCH__COND && ++ flags & FLAG_MATCHED) || ++ dp == datalen) { ++ pc += asn1_op_lengths[op]; ++ goto next_op; ++ } ++ ++ flags = 0; ++ hdr = 2; ++ ++ /* Extract a tag from the data */ ++ if (unlikely(dp >= datalen - 1)) ++ goto data_overrun_error; ++ tag = data[dp++]; ++ if (unlikely((tag & 0x1f) == 0x1f)) ++ goto long_tag_not_supported; ++ ++ if (op & ASN1_OP_MATCH__ANY) { ++ pr_debug("- any %02x\n", tag); ++ } else { ++ /* Extract the tag from the machine ++ * - Either CONS or PRIM are permitted in the data if ++ * CONS is not set in the op stream, otherwise CONS ++ * is mandatory. ++ */ ++ optag = machine[pc + 1]; ++ flags |= optag & FLAG_CONS; ++ ++ /* Determine whether the tag matched */ ++ tmp = optag ^ tag; ++ tmp &= ~(optag & ASN1_CONS_BIT); ++ pr_debug("- match? %02x %02x %02x\n", tag, optag, tmp); ++ if (tmp != 0) { ++ /* All odd-numbered tags are MATCH_OR_SKIP. */ ++ if (op & ASN1_OP_MATCH__SKIP) { ++ pc += asn1_op_lengths[op]; ++ dp--; ++ goto next_op; ++ } ++ goto tag_mismatch; ++ } ++ } ++ flags |= FLAG_MATCHED; ++ ++ len = data[dp++]; ++ if (len > 0x7f) { ++ if (unlikely(len == 0x80)) { ++ /* Indefinite length */ ++ if (unlikely(!(tag & ASN1_CONS_BIT))) ++ goto indefinite_len_primitive; ++ flags |= FLAG_INDEFINITE_LENGTH; ++ if (unlikely(2 > datalen - dp)) ++ goto data_overrun_error; ++ } else { ++ int n = len - 0x80; ++ if (unlikely(n > 2)) ++ goto length_too_long; ++ if (unlikely(dp >= datalen - n)) ++ goto data_overrun_error; ++ hdr += n; ++ for (len = 0; n > 0; n--) { ++ len <<= 8; ++ len |= data[dp++]; ++ } ++ if (unlikely(len > datalen - dp)) ++ goto data_overrun_error; ++ } ++ } ++ ++ if (flags & FLAG_CONS) { ++ /* For expected compound forms, we stack the positions ++ * of the start and end of the data. ++ */ ++ if (unlikely(csp >= NR_CONS_STACK)) ++ goto cons_stack_overflow; ++ cons_dp_stack[csp] = dp; ++ cons_hdrlen_stack[csp] = hdr; ++ if (!(flags & FLAG_INDEFINITE_LENGTH)) { ++ cons_datalen_stack[csp] = datalen; ++ datalen = dp + len; ++ } else { ++ cons_datalen_stack[csp] = 0; ++ } ++ csp++; ++ } ++ ++ pr_debug("- TAG: %02x %zu%s\n", ++ tag, len, flags & FLAG_CONS ? " CONS" : ""); ++ tdp = dp; ++ } ++ ++ /* Decide how to handle the operation */ ++ switch (op) { ++ case ASN1_OP_MATCH_ANY_ACT: ++ case ASN1_OP_COND_MATCH_ANY_ACT: ++ ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); ++ if (ret < 0) ++ return ret; ++ goto skip_data; ++ ++ case ASN1_OP_MATCH_ACT: ++ case ASN1_OP_MATCH_ACT_OR_SKIP: ++ case ASN1_OP_COND_MATCH_ACT_OR_SKIP: ++ ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len); ++ if (ret < 0) ++ return ret; ++ goto skip_data; ++ ++ case ASN1_OP_MATCH: ++ case ASN1_OP_MATCH_OR_SKIP: ++ case ASN1_OP_MATCH_ANY: ++ case ASN1_OP_COND_MATCH_OR_SKIP: ++ case ASN1_OP_COND_MATCH_ANY: ++ skip_data: ++ if (!(flags & FLAG_CONS)) { ++ if (flags & FLAG_INDEFINITE_LENGTH) { ++ len = asn1_find_indefinite_length( ++ data + dp, datalen - dp, &errmsg, &dp); ++ if (len < 0) ++ goto error; ++ } ++ pr_debug("- LEAF: %zu\n", len); ++ dp += len; ++ } ++ pc += asn1_op_lengths[op]; ++ goto next_op; ++ ++ case ASN1_OP_MATCH_JUMP: ++ case ASN1_OP_MATCH_JUMP_OR_SKIP: ++ case ASN1_OP_COND_MATCH_JUMP_OR_SKIP: ++ pr_debug("- MATCH_JUMP\n"); ++ if (unlikely(jsp == NR_JUMP_STACK)) ++ goto jump_stack_overflow; ++ jump_stack[jsp++] = pc + asn1_op_lengths[op]; ++ pc = machine[pc + 2]; ++ goto next_op; ++ ++ case ASN1_OP_COND_FAIL: ++ if (unlikely(!(flags & FLAG_MATCHED))) ++ goto tag_mismatch; ++ pc += asn1_op_lengths[op]; ++ goto next_op; ++ ++ case ASN1_OP_COMPLETE: ++ if (unlikely(jsp != 0 || csp != 0)) { ++ pr_err("ASN.1 decoder error: Stacks not empty at completion (%u, %u)\n", ++ jsp, csp); ++ return -EBADMSG; ++ } ++ return 0; ++ ++ case ASN1_OP_END_SET: ++ case ASN1_OP_END_SET_ACT: ++ if (unlikely(!(flags & FLAG_MATCHED))) ++ goto tag_mismatch; ++ case ASN1_OP_END_SEQ: ++ case ASN1_OP_END_SET_OF: ++ case ASN1_OP_END_SEQ_OF: ++ case ASN1_OP_END_SEQ_ACT: ++ case ASN1_OP_END_SET_OF_ACT: ++ case ASN1_OP_END_SEQ_OF_ACT: ++ if (unlikely(csp <= 0)) ++ goto cons_stack_underflow; ++ csp--; ++ tdp = cons_dp_stack[csp]; ++ hdr = cons_hdrlen_stack[csp]; ++ len = datalen; ++ datalen = cons_datalen_stack[csp]; ++ pr_debug("- end cons t=%zu dp=%zu l=%zu/%zu\n", ++ tdp, dp, len, datalen); ++ if (datalen == 0) { ++ /* Indefinite length - check for the EOC. */ ++ datalen = len; ++ if (unlikely(datalen - dp < 2)) ++ goto data_overrun_error; ++ if (data[dp++] != 0) { ++ if (op & ASN1_OP_END__OF) { ++ dp--; ++ csp++; ++ pc = machine[pc + 1]; ++ pr_debug("- continue\n"); ++ goto next_op; ++ } ++ goto missing_eoc; ++ } ++ if (data[dp++] != 0) ++ goto invalid_eoc; ++ len = dp - tdp - 2; ++ } else { ++ if (dp < len && (op & ASN1_OP_END__OF)) { ++ datalen = len; ++ csp++; ++ pc = machine[pc + 1]; ++ pr_debug("- continue\n"); ++ goto next_op; ++ } ++ if (dp != len) ++ goto cons_length_error; ++ len -= tdp; ++ pr_debug("- cons len l=%zu d=%zu\n", len, dp - tdp); ++ } ++ ++ if (op & ASN1_OP_END__ACT) { ++ unsigned char act; ++ if (op & ASN1_OP_END__OF) ++ act = machine[pc + 2]; ++ else ++ act = machine[pc + 1]; ++ ret = actions[act](context, hdr, 0, data + tdp, len); ++ } ++ pc += asn1_op_lengths[op]; ++ goto next_op; ++ ++ case ASN1_OP_ACT: ++ ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); ++ pc += asn1_op_lengths[op]; ++ goto next_op; ++ ++ case ASN1_OP_RETURN: ++ if (unlikely(jsp <= 0)) ++ goto jump_stack_underflow; ++ pc = jump_stack[--jsp]; ++ goto next_op; ++ ++ default: ++ break; ++ } ++ ++ /* Shouldn't reach here */ ++ pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op); ++ return -EBADMSG; ++ ++data_overrun_error: ++ errmsg = "Data overrun error"; ++ goto error; ++machine_overrun_error: ++ errmsg = "Machine overrun error"; ++ goto error; ++jump_stack_underflow: ++ errmsg = "Jump stack underflow"; ++ goto error; ++jump_stack_overflow: ++ errmsg = "Jump stack overflow"; ++ goto error; ++cons_stack_underflow: ++ errmsg = "Cons stack underflow"; ++ goto error; ++cons_stack_overflow: ++ errmsg = "Cons stack overflow"; ++ goto error; ++cons_length_error: ++ errmsg = "Cons length error"; ++ goto error; ++missing_eoc: ++ errmsg = "Missing EOC in indefinite len cons"; ++ goto error; ++invalid_eoc: ++ errmsg = "Invalid length EOC"; ++ goto error; ++length_too_long: ++ errmsg = "Unsupported length"; ++ goto error; ++indefinite_len_primitive: ++ errmsg = "Indefinite len primitive not permitted"; ++ goto error; ++tag_mismatch: ++ errmsg = "Unexpected tag"; ++ goto error; ++long_tag_not_supported: ++ errmsg = "Long tag not supported"; ++error: ++ pr_debug("\nASN1: %s [m=%zu d=%zu ot=%02x t=%02x l=%zu]\n", ++ errmsg, pc, dp, optag, tag, len); ++ return -EBADMSG; ++} ++EXPORT_SYMBOL_GPL(asn1_ber_decoder); +-- +1.7.12.1 + + +From 686b0b5e3549b711c0bcc405d833697ff5e2344d Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Mon, 24 Sep 2012 17:11:27 +0100 +Subject: [PATCH 16/37] MPILIB: Provide a function to read raw data into an + MPI + +Provide a function to read raw data of a predetermined size into an MPI rather +than expecting the size to be encoded within the data. The data is assumed to +represent an unsigned integer, and the resulting MPI will be positive. + +The function looks like this: + + MPI mpi_read_raw_data(const void *, size_t); + +This is useful for reading ASN.1 integer primitives where the length is encoded +in the ASN.1 metadata. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + include/linux/mpi.h | 1 + + lib/mpi/mpicoder.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+) + +diff --git a/include/linux/mpi.h b/include/linux/mpi.h +index d02cca6..5af1b81 100644 +--- a/include/linux/mpi.h ++++ b/include/linux/mpi.h +@@ -76,6 +76,7 @@ void mpi_swap(MPI a, MPI b); + + /*-- mpicoder.c --*/ + MPI do_encode_md(const void *sha_buffer, unsigned nbits); ++MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes); + MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread); + int mpi_fromstr(MPI val, const char *str); + u32 mpi_get_keyid(MPI a, u32 *keyid); +diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c +index f0fa659..3962b7f 100644 +--- a/lib/mpi/mpicoder.c ++++ b/lib/mpi/mpicoder.c +@@ -18,10 +18,65 @@ + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + ++#include <linux/bitops.h> ++#include <asm-generic/bitops/count_zeros.h> + #include "mpi-internal.h" + + #define MAX_EXTERN_MPI_BITS 16384 + ++/** ++ * mpi_read_raw_data - Read a raw byte stream as a positive integer ++ * @xbuffer: The data to read ++ * @nbytes: The amount of data to read ++ */ ++MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes) ++{ ++ const uint8_t *buffer = xbuffer; ++ int i, j; ++ unsigned nbits, nlimbs; ++ mpi_limb_t a; ++ MPI val = NULL; ++ ++ while (nbytes >= 0 && buffer[0] == 0) { ++ buffer++; ++ nbytes--; ++ } ++ ++ nbits = nbytes * 8; ++ if (nbits > MAX_EXTERN_MPI_BITS) { ++ pr_info("MPI: mpi too large (%u bits)\n", nbits); ++ return NULL; ++ } ++ if (nbytes > 0) ++ nbits -= count_leading_zeros(buffer[0]); ++ else ++ nbits = 0; ++ ++ nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; ++ val = mpi_alloc(nlimbs); ++ if (!val) ++ return NULL; ++ val->nbits = nbits; ++ val->sign = 0; ++ val->nlimbs = nlimbs; ++ ++ if (nbytes > 0) { ++ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; ++ i %= BYTES_PER_MPI_LIMB; ++ for (j = nlimbs; j > 0; j--) { ++ a = 0; ++ for (; i < BYTES_PER_MPI_LIMB; i++) { ++ a <<= 8; ++ a |= *buffer++; ++ } ++ i = 0; ++ val->d[j - 1] = a; ++ } ++ } ++ return val; ++} ++EXPORT_SYMBOL_GPL(mpi_read_raw_data); ++ + MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) + { + const uint8_t *buffer = xbuffer; +-- +1.7.12.1 + + +From c6ca1b7770b65d0639fb84a7afead457ff22c8d4 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Mon, 24 Sep 2012 17:11:48 +0100 +Subject: [PATCH 17/37] X.509: Add a crypto key parser for binary (DER) X.509 + certificates + +Add a crypto key parser for binary (DER) encoded X.509 certificates. The +certificate is parsed and, if possible, the signature is verified. + +An X.509 key can be added like this: + + # keyctl padd crypto bar @s </tmp/x509.cert + 15768135 + +and displayed like this: + + # cat /proc/keys + 00f09a47 I--Q--- 1 perm 39390000 0 0 asymmetri bar: X509.RSA e9fd6d08 [] + +Note that this only works with binary certificates. PEM encoded certificates +are ignored by the parser. + +Note also that the X.509 key ID is not congruent with the PGP key ID, but for +the moment, they will match. + +If a NULL or "" name is given to add_key(), then the parser will generate a key +description from the CertificateSerialNumber and Name fields of the +TBSCertificate: + + 00aefc4e I--Q--- 1 perm 39390000 0 0 asymmetri bfbc0cd76d050ea4:/C=GB/L=Cambridge/O=Red Hat/CN=kernel key: X509.RSA 0c688c7b [] + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/.gitignore | 1 + + crypto/asymmetric_keys/Kconfig | 10 + + crypto/asymmetric_keys/Makefile | 17 + + crypto/asymmetric_keys/x509.asn1 | 60 ++++ + crypto/asymmetric_keys/x509_cert_parser.c | 497 ++++++++++++++++++++++++++++++ + crypto/asymmetric_keys/x509_parser.h | 36 +++ + crypto/asymmetric_keys/x509_public_key.c | 207 +++++++++++++ + crypto/asymmetric_keys/x509_rsakey.asn1 | 4 + + 8 files changed, 832 insertions(+) + create mode 100644 crypto/asymmetric_keys/.gitignore + create mode 100644 crypto/asymmetric_keys/x509.asn1 + create mode 100644 crypto/asymmetric_keys/x509_cert_parser.c + create mode 100644 crypto/asymmetric_keys/x509_parser.h + create mode 100644 crypto/asymmetric_keys/x509_public_key.c + create mode 100644 crypto/asymmetric_keys/x509_rsakey.asn1 + +diff --git a/crypto/asymmetric_keys/.gitignore b/crypto/asymmetric_keys/.gitignore +new file mode 100644 +index 0000000..ee32837 +--- /dev/null ++++ b/crypto/asymmetric_keys/.gitignore +@@ -0,0 +1 @@ ++*-asn1.[ch] +diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig +index 561759d..6d2c2ea 100644 +--- a/crypto/asymmetric_keys/Kconfig ++++ b/crypto/asymmetric_keys/Kconfig +@@ -25,4 +25,14 @@ config PUBLIC_KEY_ALGO_RSA + help + This option enables support for the RSA algorithm (PKCS#1, RFC3447). + ++config X509_CERTIFICATE_PARSER ++ tristate "X.509 certificate parser" ++ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE ++ select ASN1 ++ select OID_REGISTRY ++ help ++ This option procides support for parsing X.509 format blobs for key ++ data and provides the ability to instantiate a crypto key from a ++ public key packet found inside the certificate. ++ + endif # ASYMMETRIC_KEY_TYPE +diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile +index 7c92691..0727204 100644 +--- a/crypto/asymmetric_keys/Makefile ++++ b/crypto/asymmetric_keys/Makefile +@@ -8,3 +8,20 @@ asymmetric_keys-y := asymmetric_type.o signature.o + + obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o + obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o ++ ++# ++# X.509 Certificate handling ++# ++obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o ++x509_key_parser-y := \ ++ x509-asn1.o \ ++ x509_rsakey-asn1.o \ ++ x509_cert_parser.o \ ++ x509_public_key.o ++ ++$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h ++$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h ++$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h ++ ++clean-files += x509-asn1.c x509-asn1.h ++clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h +diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1 +new file mode 100644 +index 0000000..bf32b3d +--- /dev/null ++++ b/crypto/asymmetric_keys/x509.asn1 +@@ -0,0 +1,60 @@ ++Certificate ::= SEQUENCE { ++ tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }), ++ signatureAlgorithm AlgorithmIdentifier, ++ signature BIT STRING ({ x509_note_signature }) ++ } ++ ++TBSCertificate ::= SEQUENCE { ++ version [ 0 ] Version DEFAULT, ++ serialNumber CertificateSerialNumber, ++ signature AlgorithmIdentifier ({ x509_note_pkey_algo }), ++ issuer Name ({ x509_note_issuer }), ++ validity Validity, ++ subject Name ({ x509_note_subject }), ++ subjectPublicKeyInfo SubjectPublicKeyInfo, ++ issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, ++ subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, ++ extensions [ 3 ] Extensions OPTIONAL ++ } ++ ++Version ::= INTEGER ++CertificateSerialNumber ::= INTEGER ++ ++AlgorithmIdentifier ::= SEQUENCE { ++ algorithm OBJECT IDENTIFIER ({ x509_note_OID }), ++ parameters ANY OPTIONAL ++} ++ ++Name ::= SEQUENCE OF RelativeDistinguishedName ++ ++RelativeDistinguishedName ::= SET OF AttributeValueAssertion ++ ++AttributeValueAssertion ::= SEQUENCE { ++ attributeType OBJECT IDENTIFIER ({ x509_note_OID }), ++ attributeValue ANY ({ x509_extract_name_segment }) ++ } ++ ++Validity ::= SEQUENCE { ++ notBefore Time ({ x509_note_not_before }), ++ notAfter Time ({ x509_note_not_after }) ++ } ++ ++Time ::= CHOICE { ++ utcTime UTCTime, ++ generalTime GeneralizedTime ++ } ++ ++SubjectPublicKeyInfo ::= SEQUENCE { ++ algorithm AlgorithmIdentifier, ++ subjectPublicKey BIT STRING ({ x509_extract_key_data }) ++ } ++ ++UniqueIdentifier ::= BIT STRING ++ ++Extensions ::= SEQUENCE OF Extension ++ ++Extension ::= SEQUENCE { ++ extnid OBJECT IDENTIFIER ({ x509_note_OID }), ++ critical BOOLEAN DEFAULT, ++ extnValue OCTET STRING ({ x509_process_extension }) ++ } +diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c +new file mode 100644 +index 0000000..8fcac94 +--- /dev/null ++++ b/crypto/asymmetric_keys/x509_cert_parser.c +@@ -0,0 +1,497 @@ ++/* X.509 certificate parser ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "X.509: "fmt ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/err.h> ++#include <linux/oid_registry.h> ++#include "public_key.h" ++#include "x509_parser.h" ++#include "x509-asn1.h" ++#include "x509_rsakey-asn1.h" ++ ++struct x509_parse_context { ++ struct x509_certificate *cert; /* Certificate being constructed */ ++ unsigned long data; /* Start of data */ ++ const void *cert_start; /* Start of cert content */ ++ const void *key; /* Key data */ ++ size_t key_size; /* Size of key data */ ++ enum OID last_oid; /* Last OID encountered */ ++ enum OID algo_oid; /* Algorithm OID */ ++ unsigned char nr_mpi; /* Number of MPIs stored */ ++ u8 o_size; /* Size of organizationName (O) */ ++ u8 cn_size; /* Size of commonName (CN) */ ++ u8 email_size; /* Size of emailAddress */ ++ u16 o_offset; /* Offset of organizationName (O) */ ++ u16 cn_offset; /* Offset of commonName (CN) */ ++ u16 email_offset; /* Offset of emailAddress */ ++}; ++ ++/* ++ * Free an X.509 certificate ++ */ ++void x509_free_certificate(struct x509_certificate *cert) ++{ ++ if (cert) { ++ public_key_destroy(cert->pub); ++ kfree(cert->issuer); ++ kfree(cert->subject); ++ kfree(cert->fingerprint); ++ kfree(cert->authority); ++ kfree(cert); ++ } ++} ++ ++/* ++ * Parse an X.509 certificate ++ */ ++struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) ++{ ++ struct x509_certificate *cert; ++ struct x509_parse_context *ctx; ++ long ret; ++ ++ ret = -ENOMEM; ++ cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); ++ if (!cert) ++ goto error_no_cert; ++ cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); ++ if (!cert->pub) ++ goto error_no_ctx; ++ ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); ++ if (!ctx) ++ goto error_no_ctx; ++ ++ ctx->cert = cert; ++ ctx->data = (unsigned long)data; ++ ++ /* Attempt to decode the certificate */ ++ ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); ++ if (ret < 0) ++ goto error_decode; ++ ++ /* Decode the public key */ ++ ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, ++ ctx->key, ctx->key_size); ++ if (ret < 0) ++ goto error_decode; ++ ++ kfree(ctx); ++ return cert; ++ ++error_decode: ++ kfree(ctx); ++error_no_ctx: ++ x509_free_certificate(cert); ++error_no_cert: ++ return ERR_PTR(ret); ++} ++ ++/* ++ * Note an OID when we find one for later processing when we know how ++ * to interpret it. ++ */ ++int x509_note_OID(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ ++ ctx->last_oid = look_up_OID(value, vlen); ++ if (ctx->last_oid == OID__NR) { ++ char buffer[50]; ++ sprint_oid(value, vlen, buffer, sizeof(buffer)); ++ pr_debug("Unknown OID: [%zu] %s\n", ++ (unsigned long)value - ctx->data, buffer); ++ } ++ return 0; ++} ++ ++/* ++ * Save the position of the TBS data so that we can check the signature over it ++ * later. ++ */ ++int x509_note_tbs_certificate(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ ++ pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n", ++ hdrlen, tag, (unsigned long)value - ctx->data, vlen); ++ ++ ctx->cert->tbs = value - hdrlen; ++ ctx->cert->tbs_size = vlen + hdrlen; ++ return 0; ++} ++ ++/* ++ * Record the public key algorithm ++ */ ++int x509_note_pkey_algo(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ ++ pr_debug("PubKey Algo: %u\n", ctx->last_oid); ++ ++ switch (ctx->last_oid) { ++ case OID_md2WithRSAEncryption: ++ case OID_md3WithRSAEncryption: ++ default: ++ return -ENOPKG; /* Unsupported combination */ ++ ++ case OID_md4WithRSAEncryption: ++ ctx->cert->sig_hash_algo = PKEY_HASH_MD5; ++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ break; ++ ++ case OID_sha1WithRSAEncryption: ++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA1; ++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ break; ++ ++ case OID_sha256WithRSAEncryption: ++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA256; ++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ break; ++ ++ case OID_sha384WithRSAEncryption: ++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA384; ++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ break; ++ ++ case OID_sha512WithRSAEncryption: ++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA512; ++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ break; ++ ++ case OID_sha224WithRSAEncryption: ++ ctx->cert->sig_hash_algo = PKEY_HASH_SHA224; ++ ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ break; ++ } ++ ++ ctx->algo_oid = ctx->last_oid; ++ return 0; ++} ++ ++/* ++ * Note the whereabouts and type of the signature. ++ */ ++int x509_note_signature(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ ++ pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen); ++ ++ if (ctx->last_oid != ctx->algo_oid) { ++ pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n", ++ ctx->algo_oid, ctx->last_oid); ++ return -EINVAL; ++ } ++ ++ ctx->cert->sig = value; ++ ctx->cert->sig_size = vlen; ++ return 0; ++} ++ ++/* ++ * Note some of the name segments from which we'll fabricate a name. ++ */ ++int x509_extract_name_segment(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ ++ switch (ctx->last_oid) { ++ case OID_commonName: ++ ctx->cn_size = vlen; ++ ctx->cn_offset = (unsigned long)value - ctx->data; ++ break; ++ case OID_organizationName: ++ ctx->o_size = vlen; ++ ctx->o_offset = (unsigned long)value - ctx->data; ++ break; ++ case OID_email_address: ++ ctx->email_size = vlen; ++ ctx->email_offset = (unsigned long)value - ctx->data; ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Fabricate and save the issuer and subject names ++ */ ++static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen, ++ unsigned char tag, ++ char **_name, size_t vlen) ++{ ++ const void *name, *data = (const void *)ctx->data; ++ size_t namesize; ++ char *buffer; ++ ++ if (*_name) ++ return -EINVAL; ++ ++ /* Empty name string if no material */ ++ if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) { ++ buffer = kmalloc(1, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ buffer[0] = 0; ++ goto done; ++ } ++ ++ if (ctx->cn_size && ctx->o_size) { ++ /* Consider combining O and CN, but use only the CN if it is ++ * prefixed by the O, or a significant portion thereof. ++ */ ++ namesize = ctx->cn_size; ++ name = data + ctx->cn_offset; ++ if (ctx->cn_size >= ctx->o_size && ++ memcmp(data + ctx->cn_offset, data + ctx->o_offset, ++ ctx->o_size) == 0) ++ goto single_component; ++ if (ctx->cn_size >= 7 && ++ ctx->o_size >= 7 && ++ memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0) ++ goto single_component; ++ ++ buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1, ++ GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ++ data + ctx->o_offset, ctx->o_size); ++ buffer[ctx->o_size + 0] = ':'; ++ buffer[ctx->o_size + 1] = ' '; ++ memcpy(buffer + ctx->o_size + 2, ++ data + ctx->cn_offset, ctx->cn_size); ++ buffer[ctx->o_size + 2 + ctx->cn_size] = 0; ++ goto done; ++ ++ } else if (ctx->cn_size) { ++ namesize = ctx->cn_size; ++ name = data + ctx->cn_offset; ++ } else if (ctx->o_size) { ++ namesize = ctx->o_size; ++ name = data + ctx->o_offset; ++ } else { ++ namesize = ctx->email_size; ++ name = data + ctx->email_offset; ++ } ++ ++single_component: ++ buffer = kmalloc(namesize + 1, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ memcpy(buffer, name, namesize); ++ buffer[namesize] = 0; ++ ++done: ++ *_name = buffer; ++ ctx->cn_size = 0; ++ ctx->o_size = 0; ++ ctx->email_size = 0; ++ return 0; ++} ++ ++int x509_note_issuer(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); ++} ++ ++int x509_note_subject(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); ++} ++ ++/* ++ * Extract the data for the public key algorithm ++ */ ++int x509_extract_key_data(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ ++ if (ctx->last_oid != OID_rsaEncryption) ++ return -ENOPKG; ++ ++ /* There seems to be an extraneous 0 byte on the front of the data */ ++ ctx->cert->pkey_algo = PKEY_ALGO_RSA; ++ ctx->key = value + 1; ++ ctx->key_size = vlen - 1; ++ return 0; ++} ++ ++/* ++ * Extract a RSA public key value ++ */ ++int rsa_extract_mpi(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ MPI mpi; ++ ++ if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { ++ pr_err("Too many public key MPIs in certificate\n"); ++ return -EBADMSG; ++ } ++ ++ mpi = mpi_read_raw_data(value, vlen); ++ if (!mpi) ++ return -ENOMEM; ++ ++ ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; ++ return 0; ++} ++ ++/* ++ * Process certificate extensions that are used to qualify the certificate. ++ */ ++int x509_process_extension(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ const unsigned char *v = value; ++ char *f; ++ int i; ++ ++ pr_debug("Extension: %u\n", ctx->last_oid); ++ ++ if (ctx->last_oid == OID_subjectKeyIdentifier) { ++ /* Get hold of the key fingerprint */ ++ if (vlen < 3) ++ return -EBADMSG; ++ if (v[0] != ASN1_OTS || v[1] != vlen - 2) ++ return -EBADMSG; ++ v += 2; ++ vlen -= 2; ++ ++ f = kmalloc(vlen * 2 + 1, GFP_KERNEL); ++ if (!f) ++ return -ENOMEM; ++ for (i = 0; i < vlen; i++) ++ sprintf(f + i * 2, "%02x", v[i]); ++ pr_debug("fingerprint %s\n", f); ++ ctx->cert->fingerprint = f; ++ return 0; ++ } ++ ++ if (ctx->last_oid == OID_authorityKeyIdentifier) { ++ /* Get hold of the CA key fingerprint */ ++ if (vlen < 5) ++ return -EBADMSG; ++ if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)) || ++ v[1] != vlen - 2 || ++ v[2] != (ASN1_CONT << 6) || ++ v[3] != vlen - 4) ++ return -EBADMSG; ++ v += 4; ++ vlen -= 4; ++ ++ f = kmalloc(vlen * 2 + 1, GFP_KERNEL); ++ if (!f) ++ return -ENOMEM; ++ for (i = 0; i < vlen; i++) ++ sprintf(f + i * 2, "%02x", v[i]); ++ pr_debug("authority %s\n", f); ++ ctx->cert->authority = f; ++ return 0; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Record a certificate time. ++ */ ++static int x509_note_time(time_t *_time, size_t hdrlen, ++ unsigned char tag, ++ const unsigned char *value, size_t vlen) ++{ ++ unsigned YY, MM, DD, hh, mm, ss; ++ const unsigned char *p = value; ++ ++#define dec2bin(X) ((X) - '0') ++#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) ++ ++ if (tag == ASN1_UNITIM) { ++ /* UTCTime: YYMMDDHHMMSSZ */ ++ if (vlen != 13) ++ goto unsupported_time; ++ YY = DD2bin(p); ++ if (YY > 50) ++ YY += 1900; ++ else ++ YY += 2000; ++ } else if (tag == ASN1_GENTIM) { ++ /* GenTime: YYYYMMDDHHMMSSZ */ ++ if (vlen != 15) ++ goto unsupported_time; ++ YY = DD2bin(p) * 100 + DD2bin(p); ++ } else { ++ goto unsupported_time; ++ } ++ ++ MM = DD2bin(p); ++ DD = DD2bin(p); ++ hh = DD2bin(p); ++ mm = DD2bin(p); ++ ss = DD2bin(p); ++ ++ if (*p != 'Z') ++ goto unsupported_time; ++ ++ *_time = mktime(YY, MM, DD, hh, mm, ss); ++ return 0; ++ ++unsupported_time: ++ pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", ++ tag, (int)vlen, (int)vlen, value); ++ return -EBADMSG; ++} ++ ++int x509_note_not_before(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); ++} ++ ++int x509_note_not_after(void *context, size_t hdrlen, ++ unsigned char tag, ++ const void *value, size_t vlen) ++{ ++ struct x509_parse_context *ctx = context; ++ return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); ++} +diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h +new file mode 100644 +index 0000000..635053f +--- /dev/null ++++ b/crypto/asymmetric_keys/x509_parser.h +@@ -0,0 +1,36 @@ ++/* X.509 certificate parser internal definitions ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <crypto/public_key.h> ++ ++struct x509_certificate { ++ struct x509_certificate *next; ++ struct public_key *pub; /* Public key details */ ++ char *issuer; /* Name of certificate issuer */ ++ char *subject; /* Name of certificate subject */ ++ char *fingerprint; /* Key fingerprint as hex */ ++ char *authority; /* Authority key fingerprint as hex */ ++ time_t valid_from; ++ time_t valid_to; ++ enum pkey_algo pkey_algo : 8; /* Public key algorithm */ ++ enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */ ++ enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */ ++ const void *tbs; /* Signed data */ ++ size_t tbs_size; /* Size of signed data */ ++ const void *sig; /* Signature data */ ++ size_t sig_size; /* Size of sigature */ ++}; ++ ++/* ++ * x509_cert_parser.c ++ */ ++extern void x509_free_certificate(struct x509_certificate *cert); ++extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +new file mode 100644 +index 0000000..716917c +--- /dev/null ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -0,0 +1,207 @@ ++/* Instantiate a public key crypto key from an X.509 Certificate ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "X.509: "fmt ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/err.h> ++#include <linux/mpi.h> ++#include <linux/asn1_decoder.h> ++#include <keys/asymmetric-subtype.h> ++#include <keys/asymmetric-parser.h> ++#include <crypto/hash.h> ++#include "asymmetric_keys.h" ++#include "public_key.h" ++#include "x509_parser.h" ++ ++static const ++struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = { ++ [PKEY_ALGO_DSA] = NULL, ++#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ ++ defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) ++ [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, ++#endif ++}; ++ ++/* ++ * Check the signature on a certificate using the provided public key ++ */ ++static int x509_check_signature(const struct public_key *pub, ++ const struct x509_certificate *cert) ++{ ++ struct public_key_signature *sig; ++ struct crypto_shash *tfm; ++ struct shash_desc *desc; ++ size_t digest_size, desc_size; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ /* Allocate the hashing algorithm we're going to need and find out how ++ * big the hash operational data will be. ++ */ ++ tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0); ++ if (IS_ERR(tfm)) ++ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); ++ ++ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); ++ digest_size = crypto_shash_digestsize(tfm); ++ ++ /* We allocate the hash operational data storage on the end of our ++ * context data. ++ */ ++ ret = -ENOMEM; ++ sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); ++ if (!sig) ++ goto error_no_sig; ++ ++ sig->pkey_hash_algo = cert->sig_hash_algo; ++ sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; ++ sig->digest_size = digest_size; ++ ++ desc = (void *)sig + sizeof(*sig); ++ desc->tfm = tfm; ++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ ++ ret = crypto_shash_init(desc); ++ if (ret < 0) ++ goto error; ++ ++ ret = -ENOMEM; ++ sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); ++ if (!sig->rsa.s) ++ goto error; ++ ++ ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); ++ if (ret < 0) ++ goto error_mpi; ++ ++ ret = pub->algo->verify_signature(pub, sig); ++ ++ pr_debug("Cert Verification: %d\n", ret); ++ ++error_mpi: ++ mpi_free(sig->rsa.s); ++error: ++ kfree(sig); ++error_no_sig: ++ crypto_free_shash(tfm); ++ ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; ++} ++ ++/* ++ * Attempt to parse a data blob for a key as an X509 certificate. ++ */ ++static int x509_key_preparse(struct key_preparsed_payload *prep) ++{ ++ struct x509_certificate *cert; ++ time_t now; ++ size_t srlen, sulen; ++ char *desc = NULL; ++ int ret; ++ ++ cert = x509_cert_parse(prep->data, prep->datalen); ++ if (IS_ERR(cert)) ++ return PTR_ERR(cert); ++ ++ pr_devel("Cert Issuer: %s\n", cert->issuer); ++ pr_devel("Cert Subject: %s\n", cert->subject); ++ pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); ++ pr_devel("Cert Valid: %lu - %lu\n", cert->valid_from, cert->valid_to); ++ pr_devel("Cert Signature: %s + %s\n", ++ pkey_algo[cert->sig_pkey_algo], ++ pkey_hash_algo[cert->sig_hash_algo]); ++ ++ if (!cert->fingerprint || !cert->authority) { ++ pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", ++ cert->subject); ++ ret = -EKEYREJECTED; ++ goto error_free_cert; ++ } ++ ++ now = CURRENT_TIME.tv_sec; ++ if (now < cert->valid_from) { ++ pr_warn("Cert %s is not yet valid\n", cert->fingerprint); ++ ret = -EKEYREJECTED; ++ goto error_free_cert; ++ } ++ if (now >= cert->valid_to) { ++ pr_warn("Cert %s has expired\n", cert->fingerprint); ++ ret = -EKEYEXPIRED; ++ goto error_free_cert; ++ } ++ ++ cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo]; ++ cert->pub->id_type = PKEY_ID_X509; ++ ++ /* Check the signature on the key */ ++ if (strcmp(cert->fingerprint, cert->authority) == 0) { ++ ret = x509_check_signature(cert->pub, cert); ++ if (ret < 0) ++ goto error_free_cert; ++ } ++ ++ /* Propose a description */ ++ sulen = strlen(cert->subject); ++ srlen = strlen(cert->fingerprint); ++ ret = -ENOMEM; ++ desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); ++ if (!desc) ++ goto error_free_cert; ++ memcpy(desc, cert->subject, sulen); ++ desc[sulen] = ':'; ++ desc[sulen + 1] = ' '; ++ memcpy(desc + sulen + 2, cert->fingerprint, srlen); ++ desc[sulen + 2 + srlen] = 0; ++ ++ /* We're pinning the module by being linked against it */ ++ __module_get(public_key_subtype.owner); ++ prep->type_data[0] = &public_key_subtype; ++ prep->type_data[1] = cert->fingerprint; ++ prep->payload = cert->pub; ++ prep->description = desc; ++ prep->quotalen = 100; ++ ++ /* We've finished with the certificate */ ++ cert->pub = NULL; ++ cert->fingerprint = NULL; ++ desc = NULL; ++ ret = 0; ++ ++error_free_cert: ++ x509_free_certificate(cert); ++ return ret; ++} ++ ++static struct asymmetric_key_parser x509_key_parser = { ++ .owner = THIS_MODULE, ++ .name = "x509", ++ .parse = x509_key_preparse, ++}; ++ ++/* ++ * Module stuff ++ */ ++static int __init x509_key_init(void) ++{ ++ return register_asymmetric_key_parser(&x509_key_parser); ++} ++ ++static void __exit x509_key_exit(void) ++{ ++ unregister_asymmetric_key_parser(&x509_key_parser); ++} ++ ++module_init(x509_key_init); ++module_exit(x509_key_exit); +diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1 +new file mode 100644 +index 0000000..4ec7cc6 +--- /dev/null ++++ b/crypto/asymmetric_keys/x509_rsakey.asn1 +@@ -0,0 +1,4 @@ ++RSAPublicKey ::= SEQUENCE { ++ modulus INTEGER ({ rsa_extract_mpi }), -- n ++ publicExponent INTEGER ({ rsa_extract_mpi }) -- e ++ } +-- +1.7.12.1 + + +From a4c3000ab42b11536ffc8eb9c1d03a746b424bda Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:09:50 +0100 +Subject: [PATCH 18/37] MODSIGN: Add FIPS policy + +If we're in FIPS mode, we should panic if we fail to verify the signature on a +module or we're asked to load an unsigned module in signature enforcing mode. +Possibly FIPS mode should automatically enable enforcing mode. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + kernel/module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/module.c b/kernel/module.c +index 7efb415..3e8b1a7 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -58,6 +58,7 @@ + #include <linux/jump_label.h> + #include <linux/pfn.h> + #include <linux/bsearch.h> ++#include <linux/fips.h> + #include "module-internal.h" + + #define CREATE_TRACE_POINTS +@@ -2467,6 +2468,9 @@ static int module_sig_check(struct load_info *info, + } + + /* Not having a signature is only an error if we're strict. */ ++ if (err < 0 && fips_enabled) ++ panic("Module verification failed with error %d in FIPS mode\n", ++ err); + if (err == -ENOKEY && !sig_enforce) + err = 0; + +-- +1.7.12.1 + + +From 86342ab6db2c5b10b08bd9d1064b1779070c2a82 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:09:50 +0100 +Subject: [PATCH 19/37] MODSIGN: Provide gitignore and make clean rules for + extra files + +Provide gitignore and make clean rules for extra files to hide and clean up the +extra files produced by module signing stuff once it is added. Also add a +clean up rule for the module content extractor program used to extract the data +to be signed. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + .gitignore | 14 ++++++++++++++ + Makefile | 1 + + 2 files changed, 15 insertions(+) + +diff --git a/.gitignore b/.gitignore +index 57af07c..0f2f40f 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,6 +14,10 @@ + *.o.* + *.a + *.s ++*.ko.unsigned ++*.ko.stripped ++*.ko.stripped.dig ++*.ko.stripped.sig + *.ko + *.so + *.so.dbg +@@ -84,3 +88,13 @@ GTAGS + *.orig + *~ + \#*# ++ ++# ++# Leavings from module signing ++# ++extra_certificates ++signing_key.priv ++signing_key.x509 ++signing_key.x509.keyid ++signing_key.x509.signer ++x509.genkey +diff --git a/Makefile b/Makefile +index 6cdadf4..b4f9eb5 100644 +--- a/Makefile ++++ b/Makefile +@@ -1239,6 +1239,7 @@ clean: $(clean-dirs) + $(call cmd,rmfiles) + @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ + \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ ++ -o -name '*.ko.*' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ + -o -name '*.symtypes' -o -name 'modules.order' \ + -o -name modules.builtin -o -name '.tmp_*.o.*' \ +-- +1.7.12.1 + + +From c631aa86c295b87aa09188d9313cccf41e5db23f Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:09:50 +0100 +Subject: [PATCH 20/37] MODSIGN: Provide Kconfig options + +Provide kernel configuration options for module signing. + +The following configuration options are added: + + CONFIG_MODULE_SIG_SHA1 + CONFIG_MODULE_SIG_SHA224 + CONFIG_MODULE_SIG_SHA256 + CONFIG_MODULE_SIG_SHA384 + CONFIG_MODULE_SIG_SHA512 + +These select the cryptographic hash used to digest the data prior to signing. +Additionally, the crypto module selected will be built into the kernel as it +won't be possible to load it as a module without incurring a circular +dependency when the kernel tries to check its signature. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + init/Kconfig | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/init/Kconfig b/init/Kconfig +index fa8ccad..00d4579 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1593,12 +1593,50 @@ config MODULE_SIG + is simply appended to the module. For more information see + Documentation/module-signing.txt. + ++ !!!WARNING!!! If you enable this option, you MUST make sure that the ++ module DOES NOT get stripped after being signed. This includes the ++ debuginfo strip done by some packagers (such as rpmbuild) and ++ inclusion into an initramfs that wants the module size reduced. ++ + config MODULE_SIG_FORCE + bool "Require modules to be validly signed" + depends on MODULE_SIG + help + Reject unsigned modules or signed modules for which we don't have a + key. Without this, such modules will simply taint the kernel. ++ ++choice ++ prompt "Which hash algorithm should modules be signed with?" ++ depends on MODULE_SIG ++ help ++ This determines which sort of hashing algorithm will be used during ++ signature generation. This algorithm _must_ be built into the kernel ++ directly so that signature verification can take place. It is not ++ possible to load a signed module containing the algorithm to check ++ the signature on that module. ++ ++config MODULE_SIG_SHA1 ++ bool "Sign modules with SHA-1" ++ select CRYPTO_SHA1 ++ ++config MODULE_SIG_SHA224 ++ bool "Sign modules with SHA-224" ++ select CRYPTO_SHA256 ++ ++config MODULE_SIG_SHA256 ++ bool "Sign modules with SHA-256" ++ select CRYPTO_SHA256 ++ ++config MODULE_SIG_SHA384 ++ bool "Sign modules with SHA-384" ++ select CRYPTO_SHA512 ++ ++config MODULE_SIG_SHA512 ++ bool "Sign modules with SHA-512" ++ select CRYPTO_SHA512 ++ ++endchoice ++ + endif # MODULES + + config INIT_ALL_POSSIBLE +-- +1.7.12.1 + + +From 84d1788d1ea47ecfe2d30d0c2081055d7e89441d Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:09:51 +0100 +Subject: [PATCH 21/37] MODSIGN: Automatically generate module signing keys if + missing + +Automatically generate keys for module signing if they're absent so that +allyesconfig doesn't break. The builder should consider generating their own +key and certificate, however, so that the keys are appropriately named. + +The private key for the module signer should be placed in signing_key.priv +(unencrypted!) and the public key in an X.509 certificate as signing_key.x509. + +If a transient key is desired for signing the modules, a config file for +'openssl req' can be placed in x509.genkey, looking something like the +following: + + [ req ] + default_bits = 4096 + distinguished_name = req_distinguished_name + prompt = no + x509_extensions = myexts + + [ req_distinguished_name ] + O = Magarathea + CN = Glacier signing key + emailAddress = slartibartfast@magrathea.h2g2 + + [ myexts ] + basicConstraints=critical,CA:FALSE + keyUsage=digitalSignature + subjectKeyIdentifier=hash + authorityKeyIdentifier=hash + +The build process will use this to configure: + + openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \ + -x509 -config x509.genkey \ + -outform DER -out signing_key.x509 \ + -keyout signing_key.priv + +to generate the key. + +Note that it is required that the X.509 certificate have a subjectKeyIdentifier +and an authorityKeyIdentifier. Without those, the certificate will be +rejected. These can be used to check the validity of a certificate. + +Note that 'make distclean' will remove signing_key.{priv,x509} and x509.genkey, +whether or not they were generated automatically. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + kernel/Makefile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/kernel/Makefile b/kernel/Makefile +index 08ba8a6..58c6f11 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -132,3 +132,52 @@ quiet_cmd_timeconst = TIMEC $@ + targets += timeconst.h + $(obj)/timeconst.h: $(src)/timeconst.pl FORCE + $(call if_changed,timeconst) ++ ++ifeq ($(CONFIG_MODULE_SIG),y) ++ ++############################################################################### ++# ++# If module signing is requested, say by allyesconfig, but a key has not been ++# supplied, then one will need to be generated to make sure the build does not ++# fail and that the kernel may be used afterwards. ++# ++############################################################################### ++signing_key.priv signing_key.x509: x509.genkey ++ @echo "###" ++ @echo "### Now generating an X.509 key pair to be used for signing modules." ++ @echo "###" ++ @echo "### If this takes a long time, you might wish to run rngd in the" ++ @echo "### background to keep the supply of entropy topped up. It" ++ @echo "### needs to be run as root, and should use a hardware random" ++ @echo "### number generator if one is available, eg:" ++ @echo "###" ++ @echo "### rngd -r /dev/hwrandom" ++ @echo "###" ++ openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \ ++ -x509 -config x509.genkey \ ++ -outform DER -out signing_key.x509 \ ++ -keyout signing_key.priv ++ @echo "###" ++ @echo "### Key pair generated." ++ @echo "###" ++ ++x509.genkey: ++ @echo Generating X.509 key generation config ++ @echo >x509.genkey "[ req ]" ++ @echo >>x509.genkey "default_bits = 4096" ++ @echo >>x509.genkey "distinguished_name = req_distinguished_name" ++ @echo >>x509.genkey "prompt = no" ++ @echo >>x509.genkey "x509_extensions = myexts" ++ @echo >>x509.genkey ++ @echo >>x509.genkey "[ req_distinguished_name ]" ++ @echo >>x509.genkey "O = Magrathea" ++ @echo >>x509.genkey "CN = Glacier signing key" ++ @echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2" ++ @echo >>x509.genkey ++ @echo >>x509.genkey "[ myexts ]" ++ @echo >>x509.genkey "basicConstraints=critical,CA:FALSE" ++ @echo >>x509.genkey "keyUsage=digitalSignature" ++ @echo >>x509.genkey "subjectKeyIdentifier=hash" ++ @echo >>x509.genkey "authorityKeyIdentifier=keyid" ++endif ++CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey +-- +1.7.12.1 + + +From 51da59e56f0666efe97c376830dffefdfcecd21f Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:09:51 +0100 +Subject: [PATCH 22/37] MODSIGN: Provide module signing public keys to the + kernel + +Include a PGP keyring containing the public keys required to perform module +verification in the kernel image during build and create a special keyring +during boot which is then populated with keys of crypto type holding the public +keys found in the PGP keyring. + +These can be seen by root: + +[root@andromeda ~]# cat /proc/keys +07ad4ee0 I----- 1 perm 3f010000 0 0 crypto modsign.0: RSA 87b9b3bd [] +15c7f8c3 I----- 1 perm 1f030000 0 0 keyring .module_sign: 1/4 +... + +It is probably worth permitting root to invalidate these keys, resulting in +their removal and preventing further modules from being loaded with that key. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + kernel/Makefile | 11 ++++- + kernel/modsign_pubkey.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++ + kernel/module-internal.h | 2 + + 3 files changed, 124 insertions(+), 2 deletions(-) + create mode 100644 kernel/modsign_pubkey.c + +diff --git a/kernel/Makefile b/kernel/Makefile +index 58c6f11..111a845 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -55,7 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o + obj-$(CONFIG_PROVE_LOCKING) += spinlock.o + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += module.o +-obj-$(CONFIG_MODULE_SIG) += module_signing.o ++obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +@@ -134,6 +134,13 @@ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE + $(call if_changed,timeconst) + + ifeq ($(CONFIG_MODULE_SIG),y) ++# ++# Pull the signing certificate and any extra certificates into the kernel ++# ++extra_certificates: ++ touch $@ ++ ++kernel/modsign_pubkey.o: signing_key.x509 extra_certificates + + ############################################################################### + # +@@ -180,4 +187,4 @@ x509.genkey: + @echo >>x509.genkey "subjectKeyIdentifier=hash" + @echo >>x509.genkey "authorityKeyIdentifier=keyid" + endif +-CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey ++CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates +diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c +new file mode 100644 +index 0000000..4646eb2 +--- /dev/null ++++ b/kernel/modsign_pubkey.c +@@ -0,0 +1,113 @@ ++/* Public keys for module signature verification ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/cred.h> ++#include <linux/err.h> ++#include <keys/asymmetric-type.h> ++#include "module-internal.h" ++ ++struct key *modsign_keyring; ++ ++extern __initdata const u8 modsign_certificate_list[]; ++extern __initdata const u8 modsign_certificate_list_end[]; ++asm(".section .init.data,\"aw\"\n" ++ "modsign_certificate_list:\n" ++ ".incbin \"signing_key.x509\"\n" ++ ".incbin \"extra_certificates\"\n" ++ "modsign_certificate_list_end:" ++ ); ++ ++/* ++ * We need to make sure ccache doesn't cache the .o file as it doesn't notice ++ * if modsign.pub changes. ++ */ ++static __initdata const char annoy_ccache[] = __TIME__ "foo"; ++ ++/* ++ * Load the compiled-in keys ++ */ ++static __init int module_verify_init(void) ++{ ++ pr_notice("Initialise module verification\n"); ++ ++ modsign_keyring = key_alloc(&key_type_keyring, ".module_sign", ++ KUIDT_INIT(0), KGIDT_INIT(0), ++ current_cred(), ++ (KEY_POS_ALL & ~KEY_POS_SETATTR) | ++ KEY_USR_VIEW | KEY_USR_READ, ++ KEY_ALLOC_NOT_IN_QUOTA); ++ if (IS_ERR(modsign_keyring)) ++ panic("Can't allocate module signing keyring\n"); ++ ++ if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0) ++ panic("Can't instantiate module signing keyring\n"); ++ ++ return 0; ++} ++ ++/* ++ * Must be initialised before we try and load the keys into the keyring. ++ */ ++device_initcall(module_verify_init); ++ ++/* ++ * Load the compiled-in keys ++ */ ++static __init int load_module_signing_keys(void) ++{ ++ key_ref_t key; ++ const u8 *p, *end; ++ size_t plen; ++ ++ pr_notice("Loading module verification certificates\n"); ++ ++ end = modsign_certificate_list_end; ++ p = modsign_certificate_list; ++ while (p < end) { ++ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more ++ * than 256 bytes in size. ++ */ ++ if (end - p < 4) ++ goto dodgy_cert; ++ if (p[0] != 0x30 && ++ p[1] != 0x82) ++ goto dodgy_cert; ++ plen = (p[2] << 8) | p[3]; ++ plen += 4; ++ if (plen > end - p) ++ goto dodgy_cert; ++ ++ key = key_create_or_update(make_key_ref(modsign_keyring, 1), ++ "asymmetric", ++ NULL, ++ p, ++ plen, ++ (KEY_POS_ALL & ~KEY_POS_SETATTR) | ++ KEY_USR_VIEW, ++ KEY_ALLOC_NOT_IN_QUOTA); ++ if (IS_ERR(key)) ++ pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n", ++ PTR_ERR(key)); ++ else ++ pr_notice("MODSIGN: Loaded cert '%s'\n", ++ key_ref_to_ptr(key)->description); ++ p += plen; ++ } ++ ++ return 0; ++ ++dodgy_cert: ++ pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n"); ++ return 0; ++} ++late_initcall(load_module_signing_keys); +diff --git a/kernel/module-internal.h b/kernel/module-internal.h +index 033c17f..6114a13 100644 +--- a/kernel/module-internal.h ++++ b/kernel/module-internal.h +@@ -9,5 +9,7 @@ + * 2 of the Licence, or (at your option) any later version. + */ + ++extern struct key *modsign_keyring; ++ + extern int mod_verify_sig(const void *mod, unsigned long modlen, + const void *sig, unsigned long siglen); +-- +1.7.12.1 + + +From 81a8def438b252dac4aa9c7eda39ad517bfe51ac Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:11:03 +0100 +Subject: [PATCH 23/37] MODSIGN: Implement module signature checking + +Check the signature on the module against the keys compiled into the kernel or +available in a hardware key store. + +Currently, only RSA keys are supported - though that's easy enough to change, +and the signature is expected to contain raw components (so not a PGP or +PKCS#7 formatted blob). + +The signature blob is expected to consist of the following pieces in order: + + (1) The binary identifier for the key. This is expected to match the + SubjectKeyIdentifier from an X.509 certificate. Only X.509 type + identifiers are currently supported. + + (2) The signature data, consisting of a series of MPIs in which each is in + the format of a 2-byte BE word sizes followed by the content data. + + (3) A 12 byte information block of the form: + + struct module_signature { + enum pkey_algo algo : 8; + enum pkey_hash_algo hash : 8; + enum pkey_id_type id_type : 8; + u8 __pad; + __be32 id_length; + __be32 sig_length; + }; + + The three enums are defined in crypto/public_key.h. + + 'algo' contains the public-key algorithm identifier (0->DSA, 1->RSA). + + 'hash' contains the digest algorithm identifier (0->MD4, 1->MD5, 2->SHA1, + etc.). + + 'id_type' contains the public-key identifier type (0->PGP, 1->X.509). + + '__pad' should be 0. + + 'id_length' should contain in the binary identifier length in BE form. + + 'sig_length' should contain in the signature data length in BE form. + + The lengths are in BE order rather than CPU order to make dealing with + cross-compilation easier. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (minor Kconfig fix) +--- + init/Kconfig | 8 ++ + kernel/module_signing.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 229 insertions(+), 1 deletion(-) + +diff --git a/init/Kconfig b/init/Kconfig +index 00d4579..abc6e63 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1588,6 +1588,14 @@ config MODULE_SRCVERSION_ALL + config MODULE_SIG + bool "Module signature verification" + depends on MODULES ++ select KEYS ++ select CRYPTO ++ select ASYMMETRIC_KEY_TYPE ++ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE ++ select PUBLIC_KEY_ALGO_RSA ++ select ASN1 ++ select OID_REGISTRY ++ select X509_CERTIFICATE_PARSER + help + Check modules for valid signatures upon load: the signature + is simply appended to the module. For more information see +diff --git a/kernel/module_signing.c b/kernel/module_signing.c +index 499728a..6b09f69 100644 +--- a/kernel/module_signing.c ++++ b/kernel/module_signing.c +@@ -11,13 +11,233 @@ + + #include <linux/kernel.h> + #include <linux/err.h> ++#include <crypto/public_key.h> ++#include <crypto/hash.h> ++#include <keys/asymmetric-type.h> + #include "module-internal.h" + + /* ++ * Module signature information block. ++ * ++ * The constituents of the signature section are, in order: ++ * ++ * - Signer's name ++ * - Key identifier ++ * - Signature data ++ * - Information block ++ */ ++struct module_signature { ++ enum pkey_algo algo : 8; /* Public-key crypto algorithm */ ++ enum pkey_hash_algo hash : 8; /* Digest algorithm */ ++ enum pkey_id_type id_type : 8; /* Key identifier type */ ++ u8 signer_len; /* Length of signer's name */ ++ u8 key_id_len; /* Length of key identifier */ ++ u8 __pad[3]; ++ __be32 sig_len; /* Length of signature data */ ++}; ++ ++/* ++ * Digest the module contents. ++ */ ++static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash, ++ const void *mod, ++ unsigned long modlen) ++{ ++ struct public_key_signature *pks; ++ struct crypto_shash *tfm; ++ struct shash_desc *desc; ++ size_t digest_size, desc_size; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ /* Allocate the hashing algorithm we're going to need and find out how ++ * big the hash operational data will be. ++ */ ++ tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0); ++ if (IS_ERR(tfm)) ++ return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); ++ ++ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); ++ digest_size = crypto_shash_digestsize(tfm); ++ ++ /* We allocate the hash operational data storage on the end of our ++ * context data and the digest output buffer on the end of that. ++ */ ++ ret = -ENOMEM; ++ pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); ++ if (!pks) ++ goto error_no_pks; ++ ++ pks->pkey_hash_algo = hash; ++ pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; ++ pks->digest_size = digest_size; ++ ++ desc = (void *)pks + sizeof(*pks); ++ desc->tfm = tfm; ++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ ++ ret = crypto_shash_init(desc); ++ if (ret < 0) ++ goto error; ++ ++ ret = crypto_shash_finup(desc, mod, modlen, pks->digest); ++ if (ret < 0) ++ goto error; ++ ++ crypto_free_shash(tfm); ++ pr_devel("<==%s() = ok\n", __func__); ++ return pks; ++ ++error: ++ kfree(pks); ++error_no_pks: ++ crypto_free_shash(tfm); ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ERR_PTR(ret); ++} ++ ++/* ++ * Extract an MPI array from the signature data. This represents the actual ++ * signature. Each raw MPI is prefaced by a BE 2-byte value indicating the ++ * size of the MPI in bytes. ++ * ++ * RSA signatures only have one MPI, so currently we only read one. ++ */ ++static int mod_extract_mpi_array(struct public_key_signature *pks, ++ const void *data, size_t len) ++{ ++ size_t nbytes; ++ MPI mpi; ++ ++ if (len < 3) ++ return -EBADMSG; ++ nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1]; ++ data += 2; ++ len -= 2; ++ if (len != nbytes) ++ return -EBADMSG; ++ ++ mpi = mpi_read_raw_data(data, nbytes); ++ if (!mpi) ++ return -ENOMEM; ++ pks->mpi[0] = mpi; ++ pks->nr_mpi = 1; ++ return 0; ++} ++ ++/* ++ * Request an asymmetric key. ++ */ ++static struct key *request_asymmetric_key(const char *signer, size_t signer_len, ++ const u8 *key_id, size_t key_id_len) ++{ ++ key_ref_t key; ++ size_t i; ++ char *id, *q; ++ ++ pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len); ++ ++ /* Construct an identifier. */ ++ id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL); ++ if (!id) ++ return ERR_PTR(-ENOKEY); ++ ++ memcpy(id, signer, signer_len); ++ ++ q = id + signer_len; ++ *q++ = ':'; ++ *q++ = ' '; ++ for (i = 0; i < key_id_len; i++) { ++ *q++ = hex_asc[*key_id >> 4]; ++ *q++ = hex_asc[*key_id++ & 0x0f]; ++ } ++ ++ *q = 0; ++ ++ pr_debug("Look up: \"%s\"\n", id); ++ ++ key = keyring_search(make_key_ref(modsign_keyring, 1), ++ &key_type_asymmetric, id); ++ if (IS_ERR(key)) ++ pr_warn("Request for unknown module key '%s' err %ld\n", ++ id, PTR_ERR(key)); ++ kfree(id); ++ ++ if (IS_ERR(key)) { ++ switch (PTR_ERR(key)) { ++ /* Hide some search errors */ ++ case -EACCES: ++ case -ENOTDIR: ++ case -EAGAIN: ++ return ERR_PTR(-ENOKEY); ++ default: ++ return ERR_CAST(key); ++ } ++ } ++ ++ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); ++ return key_ref_to_ptr(key); ++} ++ ++/* + * Verify the signature on a module. + */ + int mod_verify_sig(const void *mod, unsigned long modlen, + const void *sig, unsigned long siglen) + { +- return -ENOKEY; ++ struct public_key_signature *pks; ++ struct module_signature ms; ++ struct key *key; ++ size_t sig_len; ++ int ret; ++ ++ pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen); ++ ++ if (siglen <= sizeof(ms)) ++ return -EBADMSG; ++ ++ memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms)); ++ siglen -= sizeof(ms); ++ ++ sig_len = be32_to_cpu(ms.sig_len); ++ if (sig_len >= siglen || ++ siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len) ++ return -EBADMSG; ++ ++ /* For the moment, only support RSA and X.509 identifiers */ ++ if (ms.algo != PKEY_ALGO_RSA || ++ ms.id_type != PKEY_ID_X509) ++ return -ENOPKG; ++ ++ if (ms.hash >= PKEY_HASH__LAST || ++ !pkey_hash_algo[ms.hash]) ++ return -ENOPKG; ++ ++ key = request_asymmetric_key(sig, ms.signer_len, ++ sig + ms.signer_len, ms.key_id_len); ++ if (IS_ERR(key)) ++ return PTR_ERR(key); ++ ++ pks = mod_make_digest(ms.hash, mod, modlen); ++ if (IS_ERR(pks)) { ++ ret = PTR_ERR(pks); ++ goto error_put_key; ++ } ++ ++ ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len, ++ sig_len); ++ if (ret < 0) ++ goto error_free_pks; ++ ++ ret = verify_signature(key, pks); ++ pr_devel("verify_signature() = %d\n", ret); ++ ++error_free_pks: ++ mpi_free(pks->rsa.s); ++ kfree(pks); ++error_put_key: ++ key_put(key); ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; + } +-- +1.7.12.1 + + +From 952f5922dd45a25f7896843df02aec2250c41f42 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:11:06 +0100 +Subject: [PATCH 24/37] MODSIGN: Provide a script for generating a key ID from + an X.509 cert + +Provide a script to parse an X.509 certificate and certain pieces of +information from it in order to generate a key identifier to be included within +a module signature. + +The script takes the Subject Name and extracts (if present) the +organizationName (O), the commonName (CN) and the emailAddress and fabricates +the signer's name from them: + + (1) If both O and CN exist, then the name will be "O: CN", unless: + + (a) CN is prefixed by O, in which case only CN is used. + + (b) CN and O share at least the first 7 characters, in which case only CN + is used. + + (2) Otherwise, CN is used if present. + + (3) Otherwise, O is used if present. + + (4) Otherwise the emailAddress is used, if present. + + (5) Otherwise a blank name is used. + +The script emits a binary encoded identifier in the following form: + + - 2 BE bytes indicating the length of the signer's name. + + - 2 BE bytes indicating the length of the subject key identifier. + + - The characters of the signer's name. + + - The bytes of the subject key identifier. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + scripts/x509keyid | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 268 insertions(+) + create mode 100755 scripts/x509keyid + +diff --git a/scripts/x509keyid b/scripts/x509keyid +new file mode 100755 +index 0000000..c8e91a4 +--- /dev/null ++++ b/scripts/x509keyid +@@ -0,0 +1,268 @@ ++#!/usr/bin/perl -w ++# ++# Generate an identifier from an X.509 certificate that can be placed in a ++# module signature to indentify the key to use. ++# ++# Format: ++# ++# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id> ++# ++# We read the DER-encoded X509 certificate and parse it to extract the Subject ++# name and Subject Key Identifier. The provide the data we need to build the ++# certificate identifier. ++# ++# The signer's name part of the identifier is fabricated from the commonName, ++# the organizationName or the emailAddress components of the X.509 subject ++# name and written to the second named file. ++# ++# The subject key ID to select which of that signer's certificates we're ++# intending to use to sign the module is written to the third named file. ++# ++use strict; ++ ++my $raw_data; ++ ++die "Need three filenames\n" if ($#ARGV != 2); ++ ++my $src = $ARGV[0]; ++ ++open(FD, "<$src") || die $src; ++binmode FD; ++my @st = stat(FD); ++die $src if (!@st); ++read(FD, $raw_data, $st[7]) || die $src; ++close(FD); ++ ++my $UNIV = 0 << 6; ++my $APPL = 1 << 6; ++my $CONT = 2 << 6; ++my $PRIV = 3 << 6; ++ ++my $CONS = 0x20; ++ ++my $BOOLEAN = 0x01; ++my $INTEGER = 0x02; ++my $BIT_STRING = 0x03; ++my $OCTET_STRING = 0x04; ++my $NULL = 0x05; ++my $OBJ_ID = 0x06; ++my $UTF8String = 0x0c; ++my $SEQUENCE = 0x10; ++my $SET = 0x11; ++my $UTCTime = 0x17; ++my $GeneralizedTime = 0x18; ++ ++my %OIDs = ( ++ pack("CCC", 85, 4, 3) => "commonName", ++ pack("CCC", 85, 4, 6) => "countryName", ++ pack("CCC", 85, 4, 10) => "organizationName", ++ pack("CCC", 85, 4, 11) => "organizationUnitName", ++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", ++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", ++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", ++ pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", ++ pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", ++ pack("CCC", 85, 29, 19) => "basicConstraints" ++); ++ ++############################################################################### ++# ++# Extract an ASN.1 element from a string and return information about it. ++# ++############################################################################### ++sub asn1_extract($$@) ++{ ++ my ($cursor, $expected_tag, $optional) = @_; ++ ++ return [ -1 ] ++ if ($cursor->[1] == 0 && $optional); ++ ++ die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" ++ if ($cursor->[1] < 2); ++ ++ my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); ++ ++ if ($expected_tag != -1 && $tag != $expected_tag) { ++ return [ -1 ] ++ if ($optional); ++ die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, ++ " not ", $expected_tag, ")\n"; ++ } ++ ++ $cursor->[0] += 2; ++ $cursor->[1] -= 2; ++ ++ die $src, ": ", $cursor->[0], ": ASN.1 long tag\n" ++ if (($tag & 0x1f) == 0x1f); ++ die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n" ++ if ($len == 0x80); ++ ++ if ($len > 0x80) { ++ my $l = $len - 0x80; ++ die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" ++ if ($cursor->[1] < $l); ++ ++ if ($l == 0x1) { ++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); ++ } elsif ($l = 0x2) { ++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); ++ } elsif ($l = 0x3) { ++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; ++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); ++ } elsif ($l = 0x4) { ++ $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); ++ } else { ++ die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; ++ } ++ ++ $cursor->[0] += $l; ++ $cursor->[1] -= $l; ++ } ++ ++ die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" ++ if ($cursor->[1] < $len); ++ ++ my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; ++ $cursor->[0] += $len; ++ $cursor->[1] -= $len; ++ ++ return $ret; ++} ++ ++############################################################################### ++# ++# Retrieve the data referred to by a cursor ++# ++############################################################################### ++sub asn1_retrieve($) ++{ ++ my ($cursor) = @_; ++ my ($offset, $len, $data) = @$cursor; ++ return substr($$data, $offset, $len); ++} ++ ++############################################################################### ++# ++# Roughly parse the X.509 certificate ++# ++############################################################################### ++my $cursor = [ 0, length($raw_data), \$raw_data ]; ++ ++my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); ++my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); ++my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); ++my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); ++my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); ++my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); ++my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); ++ ++my $subject_key_id = (); ++my $authority_key_id = (); ++ ++# ++# Parse the extension list ++# ++if ($extension_list->[0] != -1) { ++ my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); ++ ++ while ($extensions->[1]->[1] > 0) { ++ my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); ++ my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); ++ my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); ++ my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); ++ ++ my $raw_oid = asn1_retrieve($x_oid->[1]); ++ next if (!exists($OIDs{$raw_oid})); ++ my $x_type = $OIDs{$raw_oid}; ++ ++ my $raw_value = asn1_retrieve($x_val->[1]); ++ ++ if ($x_type eq "subjectKeyIdentifier") { ++ my $vcursor = [ 0, length($raw_value), \$raw_value ]; ++ ++ $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); ++ } ++ } ++} ++ ++############################################################################### ++# ++# Determine what we're going to use as the signer's name. In order of ++# preference, take one of: commonName, organizationName or emailAddress. ++# ++############################################################################### ++my $org = ""; ++my $cn = ""; ++my $email = ""; ++ ++while ($subject->[1]->[1] > 0) { ++ my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); ++ my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); ++ my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); ++ my $n_val = asn1_extract($attr->[1], -1); ++ ++ my $raw_oid = asn1_retrieve($n_oid->[1]); ++ next if (!exists($OIDs{$raw_oid})); ++ my $n_type = $OIDs{$raw_oid}; ++ ++ my $raw_value = asn1_retrieve($n_val->[1]); ++ ++ if ($n_type eq "organizationName") { ++ $org = $raw_value; ++ } elsif ($n_type eq "commonName") { ++ $cn = $raw_value; ++ } elsif ($n_type eq "emailAddress") { ++ $email = $raw_value; ++ } ++} ++ ++my $id_name = $email; ++ ++if ($org && $cn) { ++ # Don't use the organizationName if the commonName repeats it ++ if (length($org) <= length($cn) && ++ substr($cn, 0, length($org)) eq $org) { ++ $id_name = $cn; ++ goto got_id_name; ++ } ++ ++ # Or a signifcant chunk of it ++ if (length($org) >= 7 && ++ length($cn) >= 7 && ++ substr($cn, 0, 7) eq substr($org, 0, 7)) { ++ $id_name = $cn; ++ goto got_id_name; ++ } ++ ++ $id_name = $org . ": " . $cn; ++} elsif ($org) { ++ $id_name = $org; ++} elsif ($cn) { ++ $id_name = $cn; ++} ++ ++got_id_name: ++ ++############################################################################### ++# ++# Output the signer's name and the key identifier that we're going to include ++# in module signatures. ++# ++############################################################################### ++die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" ++ if (!$subject_key_id); ++ ++my $id_key_id = asn1_retrieve($subject_key_id->[1]); ++ ++open(OUTFD, ">$ARGV[1]") || die $ARGV[1]; ++print OUTFD $id_name; ++close OUTFD || die $ARGV[1]; ++ ++open(OUTFD, ">$ARGV[2]") || die $ARGV[2]; ++print OUTFD $id_key_id; ++close OUTFD || die $ARGV[2]; +-- +1.7.12.1 + + +From 52a1f2ba9612d689f1a5ed6c1a03bd784f34bf1c Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 26 Sep 2012 10:11:06 +0100 +Subject: [PATCH 25/37] MODSIGN: Sign modules during the build process + +If CONFIG_MODULE_SIG is set, then this patch will cause all modules files to +to have signatures added. The following steps will occur: + + (1) The module will be linked to foo.ko.unsigned instead of foo.ko + + (2) The module will be stripped using both "strip -x -g" and "eu-strip" to + ensure minimal size for inclusion in an initramfs. + + (3) The signature will be generated on the stripped module. + + (4) The signature will be appended to the module, along with some information + about the signature and a magic string that indicates the presence of the + signature. + +Step (3) requires private and public keys to be available. By default these +are expected to be found in files: + + signing_key.priv + signing_key.x509 + +in the base directory of the build. The first is the private key in PEM form +and the second is the X.509 certificate in DER form as can be generated from +openssl: + + openssl req \ + -new -x509 -outform PEM -out signing_key.x509 \ + -keyout signing_key.priv -nodes \ + -subj "/CN=H2G2/O=Magrathea/CN=Slartibartfast" + +If the secret key is not found then signing will be skipped and the unsigned +module from (1) will just be copied to foo.ko. + +If signing occurs, lines like the following will be seen: + + LD [M] fs/foo/foo.ko.unsigned + STRIP [M] fs/foo/foo.ko.stripped + SIGN [M] fs/foo/foo.ko + +will appear in the build log. If the signature step will be skipped and the +following will be seen: + + LD [M] fs/foo/foo.ko.unsigned + STRIP [M] fs/foo/foo.ko.stripped + NO SIGN [M] fs/foo/foo.ko + +NOTE! After the signature step, the signed module _must_not_ be passed through +strip. The unstripped, unsigned module is still available at the name on the +LD [M] line. This restriction may affect packaging tools (such as rpmbuild) +and initramfs composition tools. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + scripts/Makefile.modpost | 77 ++++++++++++++++++++++++++++++- + scripts/sign-file | 115 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 191 insertions(+), 1 deletion(-) + create mode 100644 scripts/sign-file + +diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost +index 08dce14..2a4d1a1 100644 +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -14,7 +14,8 @@ + # 3) create one <module>.mod.c file pr. module + # 4) create one Module.symvers file with CRC for all exported symbols + # 5) compile all <module>.mod.c files +-# 6) final link of the module to a <module.ko> file ++# 6) final link of the module to a <module.ko> (or <module.unsigned>) file ++# 7) signs the modules to a <module.ko> file + + # Step 3 is used to place certain information in the module's ELF + # section, including information such as: +@@ -32,6 +33,8 @@ + # Step 4 is solely used to allow module versioning in external modules, + # where the CRC of each module is retrieved from the Module.symvers file. + ++# Step 7 is dependent on CONFIG_MODULE_SIG being enabled. ++ + # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined + # symbols in the final module linking stage + # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. +@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE + targets += $(modules:.ko=.mod.o) + + # Step 6), final link of the modules ++ifneq ($(CONFIG_MODULE_SIG),y) + quiet_cmd_ld_ko_o = LD [M] $@ + cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ +@@ -125,7 +129,78 @@ $(modules): %.ko :%.o %.mod.o FORCE + $(call if_changed,ld_ko_o) + + targets += $(modules) ++else ++quiet_cmd_ld_ko_unsigned_o = LD [M] $@ ++ cmd_ld_ko_unsigned_o = \ ++ $(LD) -r $(LDFLAGS) \ ++ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ ++ -o $@ $(filter-out FORCE,$^) \ ++ $(if $(AFTER_LINK),; $(AFTER_LINK)) ++ ++$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE ++ $(call if_changed,ld_ko_unsigned_o) ++ ++targets += $(modules:.ko=.ko.unsigned) ++ ++# Step 7), sign the modules ++MODSECKEY = ./signing_key.priv ++MODPUBKEY = ./signing_key.x509 ++ ++ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) ++ifeq ($(KBUILD_SRC),) ++ # no O= is being used ++ SCRIPTS_DIR := scripts ++else ++ SCRIPTS_DIR := $(KBUILD_SRC)/scripts ++endif ++SIGN_MODULES := 1 ++else ++SIGN_MODULES := 0 ++endif ++ ++# only sign if it's an in-tree module ++ifneq ($(KBUILD_EXTMOD),) ++SIGN_MODULES := 0 ++endif + ++# We strip the module as best we can - note that using both strip and eu-strip ++# results in a smaller module than using either alone. ++EU_STRIP = $(shell which eu-strip || echo true) ++ ++quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@ ++ cmd_sign_ko_stripped_ko_unsigned = \ ++ cp $< $@ && \ ++ strip -x -g $@ && \ ++ $(EU_STRIP) $@ ++ ++ifeq ($(SIGN_MODULES),1) ++ ++quiet_cmd_genkeyid = GENKEYID $@ ++ cmd_genkeyid = \ ++ perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid ++ ++%.signer %.keyid: % ++ $(call if_changed,genkeyid) ++ ++KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid ++quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@ ++ cmd_sign_ko_ko_stripped = \ ++ sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@ ++else ++KEYRING_DEP := ++quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@ ++ cmd_sign_ko_ko_unsigned = \ ++ cp $< $@ ++endif ++ ++$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE ++ $(call if_changed,sign_ko_ko_stripped) ++ ++$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE ++ $(call if_changed,sign_ko_stripped_ko_unsigned) ++ ++targets += $(modules) ++endif + + # Add FORCE to the prequisites of a target to force it to be always rebuilt. + # --------------------------------------------------------------------------- +diff --git a/scripts/sign-file b/scripts/sign-file +new file mode 100644 +index 0000000..e58e34e +--- /dev/null ++++ b/scripts/sign-file +@@ -0,0 +1,115 @@ ++#!/bin/sh ++# ++# Sign a module file using the given key. ++# ++# Format: sign-file <key> <x509> <src-file> <dst-file> ++# ++ ++scripts=`dirname $0` ++ ++CONFIG_MODULE_SIG_SHA512=y ++if [ -r .config ] ++then ++ . ./.config ++fi ++ ++key="$1" ++x509="$2" ++src="$3" ++dst="$4" ++ ++if [ ! -r "$key" ] ++then ++ echo "Can't read private key" >&2 ++ exit 2 ++fi ++ ++if [ ! -r "$x509" ] ++then ++ echo "Can't read X.509 certificate" >&2 ++ exit 2 ++fi ++if [ ! -r "$x509.signer" ] ++then ++ echo "Can't read Signer name" >&2 ++ exit 2; ++fi ++if [ ! -r "$x509.keyid" ] ++then ++ echo "Can't read Key identifier" >&2 ++ exit 2; ++fi ++ ++# ++# Signature parameters ++# ++algo=1 # Public-key crypto algorithm: RSA ++hash= # Digest algorithm ++id_type=1 # Identifier type: X.509 ++ ++# ++# Digest the data ++# ++dgst= ++if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ] ++then ++ prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14" ++ dgst=-sha1 ++ hash=2 ++elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ] ++then ++ prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C" ++ dgst=-sha224 ++ hash=7 ++elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ] ++then ++ prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20" ++ dgst=-sha256 ++ hash=4 ++elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ] ++then ++ prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30" ++ dgst=-sha384 ++ hash=5 ++elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ] ++then ++ prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40" ++ dgst=-sha512 ++ hash=6 ++else ++ echo "$0: Can't determine hash algorithm" >&2 ++ exit 2 ++fi ++ ++( ++perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $? ++openssl dgst $dgst -binary $src || exit $? ++) >$src.dig || exit $? ++ ++# ++# Generate the binary signature, which will be just the integer that comprises ++# the signature with no metadata attached. ++# ++openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $? ++signerlen=`stat -c %s $x509.signer` ++keyidlen=`stat -c %s $x509.keyid` ++siglen=`stat -c %s $src.sig` ++ ++# ++# Build the signed binary ++# ++( ++ cat $src || exit $? ++ echo '~Module signature appended~' || exit $? ++ cat $x509.signer $x509.keyid || exit $? ++ ++ # Preface each signature integer with a 2-byte BE length ++ perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $? ++ cat $src.sig || exit $? ++ ++ # Generate the information block ++ perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $? ++) >$dst~ || exit $? ++ ++# Permit in-place signing ++mv $dst~ $dst || exit $? +-- +1.7.12.1 + + +From 1e9ce85a6c40e2c0ba6c589605ceb565b1c83784 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 28 Sep 2012 11:16:57 +0100 +Subject: [PATCH 26/37] MODSIGN: Use the same digest for the autogen key sig + as for the module sig + +Use the same digest type for the autogenerated key signature as for the module +signature so that the hash algorithm is guaranteed to be present in the kernel. + +Without this, the X.509 certificate loader may reject the X.509 certificate so +generated because it was self-signed and the signature will be checked against +itself - but this won't work if the digest algorithm must be loaded as a +module. + +The symptom is that the key fails to load with the following message emitted +into the kernel log: + + MODSIGN: Problem loading in-kernel X.509 certificate (-65) + +the error in brackets being -ENOPKG. What you should see is something like: + + MODSIGN: Loaded cert 'Magarathea: Glacier signing key: 9588321144239a119d3406d4c4cf1fbae1836fa0' + +Note that this doesn't apply to certificates that are not self-signed as we +don't check those currently as they require the parent CA certificate to be +available. + +Reported-by: Rusty Russell <rusty@rustcorp.com.au> +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + kernel/Makefile | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/kernel/Makefile b/kernel/Makefile +index 111a845..a799029 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -149,6 +149,26 @@ kernel/modsign_pubkey.o: signing_key.x509 extra_certificates + # fail and that the kernel may be used afterwards. + # + ############################################################################### ++sign_key_with_hash := ++ifeq ($(CONFIG_MODULE_SIG_SHA1),y) ++sign_key_with_hash := -sha1 ++endif ++ifeq ($(CONFIG_MODULE_SIG_SHA224),y) ++sign_key_with_hash := -sha224 ++endif ++ifeq ($(CONFIG_MODULE_SIG_SHA256),y) ++sign_key_with_hash := -sha256 ++endif ++ifeq ($(CONFIG_MODULE_SIG_SHA384),y) ++sign_key_with_hash := -sha384 ++endif ++ifeq ($(CONFIG_MODULE_SIG_SHA512),y) ++sign_key_with_hash := -sha512 ++endif ++ifeq ($(sign_key_with_hash),) ++$(error Could not determine digest type to use from kernel config) ++endif ++ + signing_key.priv signing_key.x509: x509.genkey + @echo "###" + @echo "### Now generating an X.509 key pair to be used for signing modules." +@@ -160,7 +180,7 @@ signing_key.priv signing_key.x509: x509.genkey + @echo "###" + @echo "### rngd -r /dev/hwrandom" + @echo "###" +- openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \ ++ openssl req -new -nodes -utf8 $(sign_key_with_hash) -days 36500 -batch \ + -x509 -config x509.genkey \ + -outform DER -out signing_key.x509 \ + -keyout signing_key.priv +-- +1.7.12.1 + + +From 4c13d777ecee93ae75dae3184473003acff05a53 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 28 Sep 2012 11:16:57 +0100 +Subject: [PATCH 27/37] MODSIGN: Use utf8 strings in signer's name in + autogenerated X.509 certs + +Place an indication that the certificate should use utf8 strings into the +x509.genkey template generated by kernel/Makefile. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + kernel/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/Makefile b/kernel/Makefile +index a799029..e951adf 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -194,6 +194,7 @@ x509.genkey: + @echo >>x509.genkey "default_bits = 4096" + @echo >>x509.genkey "distinguished_name = req_distinguished_name" + @echo >>x509.genkey "prompt = no" ++ @echo >>x509.genkey "string_mask = utf8only" + @echo >>x509.genkey "x509_extensions = myexts" + @echo >>x509.genkey + @echo >>x509.genkey "[ req_distinguished_name ]" +-- +1.7.12.1 + + +From 836513a2dd15675d4ad5fefa585d1b866bec4995 Mon Sep 17 00:00:00 2001 +From: Rusty Russell <rusty@rustcorp.com.au> +Date: Tue, 2 Oct 2012 14:35:24 +0930 +Subject: [PATCH 28/37] MODSIGN: Make mrproper should remove generated files. + +It doesn't, because the clean targets don't include kernel/Makefile, and +because two files were missing from the list. + +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + Makefile | 5 ++++- + kernel/Makefile | 1 - + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Makefile b/Makefile +index b4f9eb5..e4292ea 100644 +--- a/Makefile ++++ b/Makefile +@@ -995,7 +995,10 @@ MRPROPER_DIRS += include/config usr/include include/generated \ + arch/*/include/generated + MRPROPER_FILES += .config .config.old .version .old_version \ + include/linux/version.h \ +- Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS ++ Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ ++ signing_key.priv signing_key.x509 x509.genkey \ ++ extra_certificates signing_key.x509.keyid \ ++ signing_key.x509.signer + + # clean - Delete most, but leave enough to build external modules + # +diff --git a/kernel/Makefile b/kernel/Makefile +index e951adf..d3611c8 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -208,4 +208,3 @@ x509.genkey: + @echo >>x509.genkey "subjectKeyIdentifier=hash" + @echo >>x509.genkey "authorityKeyIdentifier=keyid" + endif +-CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates +-- +1.7.12.1 + + +From 855c92bdf2fb006e4190650b809a6216579395d5 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Tue, 2 Oct 2012 14:36:16 +0100 +Subject: [PATCH 29/37] MODSIGN: Fix 32-bit overflow in X.509 certificate + validity date checking + +The current choice of lifetime for the autogenerated X.509 of 100 years, +putting the validTo date in 2112, causes problems on 32-bit systems where a +32-bit time_t wraps in 2106. 64-bit x86_64 systems seem to be unaffected. + +This can result in something like: + + Loading module verification certificates + X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired + MODSIGN: Problem loading in-kernel X.509 certificate (-127) + +Or: + + X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 is not yet valid + MODSIGN: Problem loading in-kernel X.509 certificate (-129) + +Instead of turning the dates into time_t values and comparing, turn the system +clock and the ASN.1 dates into tm structs and compare those piecemeal instead. + +Reported-by: Rusty Russell <rusty@rustcorp.com.au> +Signed-off-by: David Howells <dhowells@redhat.com> +Acked-by: Josh Boyer <jwboyer@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/x509_cert_parser.c | 25 +++++++++--------- + crypto/asymmetric_keys/x509_parser.h | 4 +-- + crypto/asymmetric_keys/x509_public_key.c | 42 +++++++++++++++++++++++++++---- + 3 files changed, 51 insertions(+), 20 deletions(-) + +diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c +index 8fcac94..db07e8c 100644 +--- a/crypto/asymmetric_keys/x509_cert_parser.c ++++ b/crypto/asymmetric_keys/x509_cert_parser.c +@@ -434,11 +434,10 @@ int x509_process_extension(void *context, size_t hdrlen, + /* + * Record a certificate time. + */ +-static int x509_note_time(time_t *_time, size_t hdrlen, ++static int x509_note_time(struct tm *tm, size_t hdrlen, + unsigned char tag, + const unsigned char *value, size_t vlen) + { +- unsigned YY, MM, DD, hh, mm, ss; + const unsigned char *p = value; + + #define dec2bin(X) ((X) - '0') +@@ -448,30 +447,30 @@ static int x509_note_time(time_t *_time, size_t hdrlen, + /* UTCTime: YYMMDDHHMMSSZ */ + if (vlen != 13) + goto unsupported_time; +- YY = DD2bin(p); +- if (YY > 50) +- YY += 1900; ++ tm->tm_year = DD2bin(p); ++ if (tm->tm_year >= 50) ++ tm->tm_year += 1900; + else +- YY += 2000; ++ tm->tm_year += 2000; + } else if (tag == ASN1_GENTIM) { + /* GenTime: YYYYMMDDHHMMSSZ */ + if (vlen != 15) + goto unsupported_time; +- YY = DD2bin(p) * 100 + DD2bin(p); ++ tm->tm_year = DD2bin(p) * 100 + DD2bin(p); + } else { + goto unsupported_time; + } + +- MM = DD2bin(p); +- DD = DD2bin(p); +- hh = DD2bin(p); +- mm = DD2bin(p); +- ss = DD2bin(p); ++ tm->tm_year -= 1900; ++ tm->tm_mon = DD2bin(p) - 1; ++ tm->tm_mday = DD2bin(p); ++ tm->tm_hour = DD2bin(p); ++ tm->tm_min = DD2bin(p); ++ tm->tm_sec = DD2bin(p); + + if (*p != 'Z') + goto unsupported_time; + +- *_time = mktime(YY, MM, DD, hh, mm, ss); + return 0; + + unsupported_time: +diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h +index 635053f..f86dc5f 100644 +--- a/crypto/asymmetric_keys/x509_parser.h ++++ b/crypto/asymmetric_keys/x509_parser.h +@@ -18,8 +18,8 @@ struct x509_certificate { + char *subject; /* Name of certificate subject */ + char *fingerprint; /* Key fingerprint as hex */ + char *authority; /* Authority key fingerprint as hex */ +- time_t valid_from; +- time_t valid_to; ++ struct tm valid_from; ++ struct tm valid_to; + enum pkey_algo pkey_algo : 8; /* Public key algorithm */ + enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */ + enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */ +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 716917c..5ab736d 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -106,7 +106,7 @@ error_no_sig: + static int x509_key_preparse(struct key_preparsed_payload *prep) + { + struct x509_certificate *cert; +- time_t now; ++ struct tm now; + size_t srlen, sulen; + char *desc = NULL; + int ret; +@@ -118,7 +118,14 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + pr_devel("Cert Issuer: %s\n", cert->issuer); + pr_devel("Cert Subject: %s\n", cert->subject); + pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); +- pr_devel("Cert Valid: %lu - %lu\n", cert->valid_from, cert->valid_to); ++ printk("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", ++ cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, ++ cert->valid_from.tm_mday, cert->valid_from.tm_hour, ++ cert->valid_from.tm_min, cert->valid_from.tm_sec); ++ printk("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", ++ cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, ++ cert->valid_to.tm_mday, cert->valid_to.tm_hour, ++ cert->valid_to.tm_min, cert->valid_to.tm_sec); + pr_devel("Cert Signature: %s + %s\n", + pkey_algo[cert->sig_pkey_algo], + pkey_hash_algo[cert->sig_hash_algo]); +@@ -130,13 +137,38 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + goto error_free_cert; + } + +- now = CURRENT_TIME.tv_sec; +- if (now < cert->valid_from) { ++ time_to_tm(CURRENT_TIME.tv_sec, 0, &now); ++ printk("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", ++ now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, ++ now.tm_hour, now.tm_min, now.tm_sec); ++ if (now.tm_year < cert->valid_from.tm_year || ++ (now.tm_year == cert->valid_from.tm_year && ++ (now.tm_mon < cert->valid_from.tm_mon || ++ (now.tm_mon == cert->valid_from.tm_mon && ++ (now.tm_mday < cert->valid_from.tm_mday || ++ (now.tm_mday == cert->valid_from.tm_mday && ++ (now.tm_hour < cert->valid_from.tm_hour || ++ (now.tm_hour == cert->valid_from.tm_hour && ++ (now.tm_min < cert->valid_from.tm_min || ++ (now.tm_min == cert->valid_from.tm_min && ++ (now.tm_sec < cert->valid_from.tm_sec ++ ))))))))))) { + pr_warn("Cert %s is not yet valid\n", cert->fingerprint); + ret = -EKEYREJECTED; + goto error_free_cert; + } +- if (now >= cert->valid_to) { ++ if (now.tm_year > cert->valid_to.tm_year || ++ (now.tm_year == cert->valid_to.tm_year && ++ (now.tm_mon > cert->valid_to.tm_mon || ++ (now.tm_mon == cert->valid_to.tm_mon && ++ (now.tm_mday > cert->valid_to.tm_mday || ++ (now.tm_mday == cert->valid_to.tm_mday && ++ (now.tm_hour > cert->valid_to.tm_hour || ++ (now.tm_hour == cert->valid_to.tm_hour && ++ (now.tm_min > cert->valid_to.tm_min || ++ (now.tm_min == cert->valid_to.tm_min && ++ (now.tm_sec > cert->valid_to.tm_sec ++ ))))))))))) { + pr_warn("Cert %s has expired\n", cert->fingerprint); + ret = -EKEYEXPIRED; + goto error_free_cert; +-- +1.7.12.1 + + +From f69bc56c32645bcc0b1a9ee88be662e8246398b4 Mon Sep 17 00:00:00 2001 +From: Randy Dunlap <rdunlap@xenotime.net> +Date: Wed, 3 Oct 2012 16:04:46 -0700 +Subject: [PATCH 30/37] asymmetric keys: fix printk format warning + +Fix printk format warning in x509_cert_parser.c: + +crypto/asymmetric_keys/x509_cert_parser.c: In function 'x509_note_OID': +crypto/asymmetric_keys/x509_cert_parser.c:113:3: warning: format '%zu' expects type 'size_t', but argument 2 has type 'long unsigned int' + +Builds cleanly on i386 and x86_64. + +Signed-off-by: Randy Dunlap <rdunlap@xenotime.net> +Cc: David Howells <dhowells@redhat.com> +Cc: Herbert Xu <herbert@gondor.apana.org.au> +Cc: linux-crypto@vger.kernel.org +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/x509_cert_parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c +index db07e8c..7fabc4c 100644 +--- a/crypto/asymmetric_keys/x509_cert_parser.c ++++ b/crypto/asymmetric_keys/x509_cert_parser.c +@@ -110,7 +110,7 @@ int x509_note_OID(void *context, size_t hdrlen, + if (ctx->last_oid == OID__NR) { + char buffer[50]; + sprint_oid(value, vlen, buffer, sizeof(buffer)); +- pr_debug("Unknown OID: [%zu] %s\n", ++ pr_debug("Unknown OID: [%lu] %s\n", + (unsigned long)value - ctx->data, buffer); + } + return 0; +-- +1.7.12.1 + + +From 81338d71c284b7d001004e4a03abfce2d2144087 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 4 Oct 2012 14:21:23 +0100 +Subject: [PATCH 31/37] X.509: Convert some printk calls to pr_devel + +Some debugging printk() calls should've been converted to pr_devel() calls. +Do that now. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + crypto/asymmetric_keys/x509_public_key.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 5ab736d..06007f0 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -118,11 +118,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + pr_devel("Cert Issuer: %s\n", cert->issuer); + pr_devel("Cert Subject: %s\n", cert->subject); + pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); +- printk("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", ++ pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", + cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, + cert->valid_from.tm_mday, cert->valid_from.tm_hour, + cert->valid_from.tm_min, cert->valid_from.tm_sec); +- printk("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", ++ pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", + cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, + cert->valid_to.tm_mday, cert->valid_to.tm_hour, + cert->valid_to.tm_min, cert->valid_to.tm_sec); +@@ -138,7 +138,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + } + + time_to_tm(CURRENT_TIME.tv_sec, 0, &now); +- printk("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", ++ pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", + now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec); + if (now.tm_year < cert->valid_from.tm_year || +-- +1.7.12.1 + + +From 1054ea17fe1bf8f2087197c453626153d4649ac5 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 4 Oct 2012 14:21:23 +0100 +Subject: [PATCH 32/37] X.509: Fix indefinite length element skip error + handling + +asn1_find_indefinite_length() returns an error indicator of -1, which the +caller asn1_ber_decoder() places in a size_t (which is usually unsigned) and +then checks to see whether it is less than 0 (which it can't be). This can +lead to the following warning: + + lib/asn1_decoder.c:320 asn1_ber_decoder() + warn: unsigned 'len' is never less than zero. + +Instead, asn1_find_indefinite_length() update the caller's idea of the data +cursor and length separately from returning the error code. + +Reported-by: Dan Carpenter <dan.carpenter@oracle.com> +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +--- + lib/asn1_decoder.c | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c +index 2e4196d..de2c8b5 100644 +--- a/lib/asn1_decoder.c ++++ b/lib/asn1_decoder.c +@@ -46,12 +46,18 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { + + /* + * Find the length of an indefinite length object ++ * @data: The data buffer ++ * @datalen: The end of the innermost containing element in the buffer ++ * @_dp: The data parse cursor (updated before returning) ++ * @_len: Where to return the size of the element. ++ * @_errmsg: Where to return a pointer to an error message on error + */ + static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, +- const char **_errmsg, size_t *_err_dp) ++ size_t *_dp, size_t *_len, ++ const char **_errmsg) + { + unsigned char tag, tmp; +- size_t dp = 0, len, n; ++ size_t dp = *_dp, len, n; + int indef_level = 1; + + next_tag: +@@ -67,8 +73,11 @@ next_tag: + /* It appears to be an EOC. */ + if (data[dp++] != 0) + goto invalid_eoc; +- if (--indef_level <= 0) +- return dp; ++ if (--indef_level <= 0) { ++ *_len = dp - *_dp; ++ *_dp = dp; ++ return 0; ++ } + goto next_tag; + } + +@@ -122,7 +131,7 @@ data_overrun_error: + missing_eoc: + *_errmsg = "Missing EOC in indefinite len cons"; + error: +- *_err_dp = dp; ++ *_dp = dp; + return -1; + } + +@@ -315,13 +324,14 @@ next_op: + skip_data: + if (!(flags & FLAG_CONS)) { + if (flags & FLAG_INDEFINITE_LENGTH) { +- len = asn1_find_indefinite_length( +- data + dp, datalen - dp, &errmsg, &dp); +- if (len < 0) ++ ret = asn1_find_indefinite_length( ++ data, datalen, &dp, &len, &errmsg); ++ if (ret < 0) + goto error; ++ } else { ++ dp += len; + } + pr_debug("- LEAF: %zu\n", len); +- dp += len; + } + pc += asn1_op_lengths[op]; + goto next_op; +-- +1.7.12.1 + + +From 4ae37452e7450971072481b98f6e1c29e5165c1e Mon Sep 17 00:00:00 2001 +From: Rusty Russell <rusty@rustcorp.com.au> +Date: Fri, 19 Oct 2012 11:53:15 +1030 +Subject: [PATCH 33/37] kbuild: sign the modules at install time + +Linus deleted the old code and put signing on the install command, +I fixed it to extract the keyid and signer-name within sign-file +and cleaned up that script now it always signs in-place. + +Some enthusiast should convert sign-key to perl and pull +x509keyid into it. + +Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + Makefile | 11 +++++++ + scripts/Makefile.modinst | 2 +- + scripts/Makefile.modpost | 77 +----------------------------------------------- + scripts/sign-file | 44 +++++++++++---------------- + scripts/x509keyid | 16 +++++----- + 5 files changed, 39 insertions(+), 111 deletions(-) + +diff --git a/Makefile b/Makefile +index e4292ea..1cc5de4 100644 +--- a/Makefile ++++ b/Makefile +@@ -714,6 +714,17 @@ endif # INSTALL_MOD_STRIP + export mod_strip_cmd + + ++ifeq ($(CONFIG_MODULE_SIG),y) ++MODSECKEY = ./signing_key.priv ++MODPUBKEY = ./signing_key.x509 ++export MODPUBKEY ++mod_sign_cmd = sh $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY) $(srctree)/scripts/x509keyid ++else ++mod_sign_cmd = true ++endif ++export mod_sign_cmd ++ ++ + ifeq ($(KBUILD_EXTMOD),) + core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ + +diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst +index efa5d94..38367bd 100644 +--- a/scripts/Makefile.modinst ++++ b/scripts/Makefile.modinst +@@ -17,7 +17,7 @@ __modinst: $(modules) + @: + + quiet_cmd_modules_install = INSTALL $@ +- cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ++ cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@) + + # Modules built outside the kernel source tree go into extra by default + INSTALL_MOD_DIR ?= extra +diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost +index 2a4d1a1..08dce14 100644 +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -14,8 +14,7 @@ + # 3) create one <module>.mod.c file pr. module + # 4) create one Module.symvers file with CRC for all exported symbols + # 5) compile all <module>.mod.c files +-# 6) final link of the module to a <module.ko> (or <module.unsigned>) file +-# 7) signs the modules to a <module.ko> file ++# 6) final link of the module to a <module.ko> file + + # Step 3 is used to place certain information in the module's ELF + # section, including information such as: +@@ -33,8 +32,6 @@ + # Step 4 is solely used to allow module versioning in external modules, + # where the CRC of each module is retrieved from the Module.symvers file. + +-# Step 7 is dependent on CONFIG_MODULE_SIG being enabled. +- + # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined + # symbols in the final module linking stage + # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. +@@ -119,7 +116,6 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE + targets += $(modules:.ko=.mod.o) + + # Step 6), final link of the modules +-ifneq ($(CONFIG_MODULE_SIG),y) + quiet_cmd_ld_ko_o = LD [M] $@ + cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ +@@ -129,78 +125,7 @@ $(modules): %.ko :%.o %.mod.o FORCE + $(call if_changed,ld_ko_o) + + targets += $(modules) +-else +-quiet_cmd_ld_ko_unsigned_o = LD [M] $@ +- cmd_ld_ko_unsigned_o = \ +- $(LD) -r $(LDFLAGS) \ +- $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ +- -o $@ $(filter-out FORCE,$^) \ +- $(if $(AFTER_LINK),; $(AFTER_LINK)) +- +-$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE +- $(call if_changed,ld_ko_unsigned_o) +- +-targets += $(modules:.ko=.ko.unsigned) +- +-# Step 7), sign the modules +-MODSECKEY = ./signing_key.priv +-MODPUBKEY = ./signing_key.x509 +- +-ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) +-ifeq ($(KBUILD_SRC),) +- # no O= is being used +- SCRIPTS_DIR := scripts +-else +- SCRIPTS_DIR := $(KBUILD_SRC)/scripts +-endif +-SIGN_MODULES := 1 +-else +-SIGN_MODULES := 0 +-endif +- +-# only sign if it's an in-tree module +-ifneq ($(KBUILD_EXTMOD),) +-SIGN_MODULES := 0 +-endif + +-# We strip the module as best we can - note that using both strip and eu-strip +-# results in a smaller module than using either alone. +-EU_STRIP = $(shell which eu-strip || echo true) +- +-quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@ +- cmd_sign_ko_stripped_ko_unsigned = \ +- cp $< $@ && \ +- strip -x -g $@ && \ +- $(EU_STRIP) $@ +- +-ifeq ($(SIGN_MODULES),1) +- +-quiet_cmd_genkeyid = GENKEYID $@ +- cmd_genkeyid = \ +- perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid +- +-%.signer %.keyid: % +- $(call if_changed,genkeyid) +- +-KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid +-quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@ +- cmd_sign_ko_ko_stripped = \ +- sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@ +-else +-KEYRING_DEP := +-quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@ +- cmd_sign_ko_ko_unsigned = \ +- cp $< $@ +-endif +- +-$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE +- $(call if_changed,sign_ko_ko_stripped) +- +-$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE +- $(call if_changed,sign_ko_stripped_ko_unsigned) +- +-targets += $(modules) +-endif + + # Add FORCE to the prequisites of a target to force it to be always rebuilt. + # --------------------------------------------------------------------------- +diff --git a/scripts/sign-file b/scripts/sign-file +index e58e34e..095a953 100644 +--- a/scripts/sign-file ++++ b/scripts/sign-file +@@ -1,8 +1,8 @@ +-#!/bin/sh ++#!/bin/bash + # + # Sign a module file using the given key. + # +-# Format: sign-file <key> <x509> <src-file> <dst-file> ++# Format: sign-file <key> <x509> <keyid-script> <module> + # + + scripts=`dirname $0` +@@ -15,8 +15,8 @@ fi + + key="$1" + x509="$2" +-src="$3" +-dst="$4" ++keyid_script="$3" ++mod="$4" + + if [ ! -r "$key" ] + then +@@ -29,16 +29,6 @@ then + echo "Can't read X.509 certificate" >&2 + exit 2 + fi +-if [ ! -r "$x509.signer" ] +-then +- echo "Can't read Signer name" >&2 +- exit 2; +-fi +-if [ ! -r "$x509.keyid" ] +-then +- echo "Can't read Key identifier" >&2 +- exit 2; +-fi + + # + # Signature parameters +@@ -83,33 +73,35 @@ fi + + ( + perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $? +-openssl dgst $dgst -binary $src || exit $? +-) >$src.dig || exit $? ++openssl dgst $dgst -binary $mod || exit $? ++) >$mod.dig || exit $? + + # + # Generate the binary signature, which will be just the integer that comprises + # the signature with no metadata attached. + # +-openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $? +-signerlen=`stat -c %s $x509.signer` +-keyidlen=`stat -c %s $x509.keyid` +-siglen=`stat -c %s $src.sig` ++openssl rsautl -sign -inkey $key -keyform PEM -in $mod.dig -out $mod.sig || exit $? ++ ++SIGNER="`perl $keyid_script $x509 signer-name`" ++KEYID="`perl $keyid_script $x509 keyid`" ++keyidlen=${#KEYID} ++siglen=${#SIGNER} + + # + # Build the signed binary + # + ( +- cat $src || exit $? ++ cat $mod || exit $? + echo '~Module signature appended~' || exit $? +- cat $x509.signer $x509.keyid || exit $? ++ echo -n "$SIGNER" || exit $? ++ echo -n "$KEYID" || exit $? + + # Preface each signature integer with a 2-byte BE length + perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $? +- cat $src.sig || exit $? ++ cat $mod.sig || exit $? + + # Generate the information block + perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $? +-) >$dst~ || exit $? ++) >$mod~ || exit $? + +-# Permit in-place signing +-mv $dst~ $dst || exit $? ++mv $mod~ $mod || exit $? +diff --git a/scripts/x509keyid b/scripts/x509keyid +index c8e91a4..4241ec6 100755 +--- a/scripts/x509keyid ++++ b/scripts/x509keyid +@@ -22,7 +22,7 @@ use strict; + + my $raw_data; + +-die "Need three filenames\n" if ($#ARGV != 2); ++die "Need a filename [keyid|signer-name]\n" if ($#ARGV != 1); + + my $src = $ARGV[0]; + +@@ -259,10 +259,10 @@ die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" + + my $id_key_id = asn1_retrieve($subject_key_id->[1]); + +-open(OUTFD, ">$ARGV[1]") || die $ARGV[1]; +-print OUTFD $id_name; +-close OUTFD || die $ARGV[1]; +- +-open(OUTFD, ">$ARGV[2]") || die $ARGV[2]; +-print OUTFD $id_key_id; +-close OUTFD || die $ARGV[2]; ++if ($ARGV[1] eq "signer-name") { ++ print $id_name; ++} elsif ($ARGV[1] eq "keyid") { ++ print $id_key_id; ++} else { ++ die "Unknown arg"; ++} +-- +1.7.12.1 + + +From 4aa23562520f07f4f27edb5c289bc289438005a0 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds <torvalds@linux-foundation.org> +Date: Fri, 19 Oct 2012 12:43:19 -0700 +Subject: [PATCH 34/37] kbuild: Fix module signature generation + +Rusty had clearly not actually tested his module signing changes that I +(trustingly) applied as commit e2a666d52b48 ("kbuild: sign the modules +at install time"). That commit had multiple bugs: + + - using "${#VARIABLE}" to get the number of characters in a shell + variable may look clever, but it's locale-dependent: it returns the + number of *characters*, not bytes. And we do need bytes. + + So don't use "${#..}" expansion, do the stupid "wc -c" thing instead + (where "c" stands for "bytes", not "characters", despite the letter. + + - Rusty had confused "siglen" and "signerlen", and his conversion + didn't set "signerlen" at all, and incorrectly set "siglen" to the + size of the signer, not the size of the signature. + +End result: the modified sign-file script did create something that +superficially *looked* like a signature, but didn't actually work at +all, and would fail the signature check. Oops. + +Tssk, tssk, Rusty. + +But Rusty was definitely right that this whole thing should be rewritten +in perl by somebody who has the perl-fu to do so. That is not me, +though - I'm just doing an emergency fix for the shell script. + +Cc: Rusty Russell <rusty@rustcorp.com.au> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + scripts/sign-file | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/scripts/sign-file b/scripts/sign-file +index 095a953..d014abd 100644 +--- a/scripts/sign-file ++++ b/scripts/sign-file +@@ -81,11 +81,12 @@ openssl dgst $dgst -binary $mod || exit $? + # the signature with no metadata attached. + # + openssl rsautl -sign -inkey $key -keyform PEM -in $mod.dig -out $mod.sig || exit $? ++siglen=`stat -c %s $mod.sig` + + SIGNER="`perl $keyid_script $x509 signer-name`" + KEYID="`perl $keyid_script $x509 keyid`" +-keyidlen=${#KEYID} +-siglen=${#SIGNER} ++keyidlen=$(echo -n "$KEYID" | wc -c) ++signerlen=$(echo -n "$SIGNER" | wc -c) + + # + # Build the signed binary +-- +1.7.12.1 + + +From f51b71db2cae9539acaa4d64a9e708d7aac1f879 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 19 Oct 2012 23:56:37 +0100 +Subject: [PATCH 35/37] MODSIGN: perlify sign-file and merge in x509keyid + +Turn sign-file into perl and merge in x509keyid. The latter doesn't +need to be a separate script as it doesn't actually need to work out the +SHA1 sum of the X.509 certificate itself, since it can get that from the +X.509 certificate. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + Makefile | 2 +- + scripts/sign-file | 477 +++++++++++++++++++++++++++++++++++++++++++++--------- + scripts/x509keyid | 268 ------------------------------ + 3 files changed, 400 insertions(+), 347 deletions(-) + mode change 100644 => 100755 scripts/sign-file + delete mode 100755 scripts/x509keyid + +diff --git a/Makefile b/Makefile +index 1cc5de4..f4f9cdb 100644 +--- a/Makefile ++++ b/Makefile +@@ -718,7 +718,7 @@ ifeq ($(CONFIG_MODULE_SIG),y) + MODSECKEY = ./signing_key.priv + MODPUBKEY = ./signing_key.x509 + export MODPUBKEY +-mod_sign_cmd = sh $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY) $(srctree)/scripts/x509keyid ++mod_sign_cmd = perl $(srctree)/scripts/sign-file $(MODSECKEY) $(MODPUBKEY) + else + mod_sign_cmd = true + endif +diff --git a/scripts/sign-file b/scripts/sign-file +old mode 100644 +new mode 100755 +index d014abd..d37d130 +--- a/scripts/sign-file ++++ b/scripts/sign-file +@@ -1,108 +1,429 @@ +-#!/bin/bash ++#!/usr/bin/perl -w + # + # Sign a module file using the given key. + # +-# Format: sign-file <key> <x509> <keyid-script> <module> ++# Format: + # ++# ./scripts/sign-file [-v] <key> <x509> <module> [<dest>] ++# ++# ++use strict; ++use FileHandle; ++use IPC::Open2; ++ ++my $verbose = 0; ++if ($#ARGV >= 0 && $ARGV[0] eq "-v") { ++ $verbose = 1; ++ shift; ++} ++ ++die "Format: ./scripts/sign-file [-v] <key> <x509> <module> [<dest>]\n" ++ if ($#ARGV != 2 && $#ARGV != 3); ++ ++my $private_key = $ARGV[0]; ++my $x509 = $ARGV[1]; ++my $module = $ARGV[2]; ++my $dest = ($#ARGV == 3) ? $ARGV[3] : $ARGV[2] . "~"; ++ ++die "Can't read private key\n" unless (-r $private_key); ++die "Can't read X.509 certificate\n" unless (-r $x509); ++die "Can't read module\n" unless (-r $module); ++ ++# ++# Read the kernel configuration ++# ++my %config = ( ++ CONFIG_MODULE_SIG_SHA512 => 1 ++ ); ++ ++if (-r ".config") { ++ open(FD, "<.config") || die ".config"; ++ while (<FD>) { ++ if ($_ =~ /^(CONFIG_.*)=[ym]/) { ++ $config{$1} = 1; ++ } ++ } ++ close(FD); ++} + +-scripts=`dirname $0` ++# ++# Function to read the contents of a file into a variable. ++# ++sub read_file($) ++{ ++ my ($file) = @_; ++ my $contents; ++ my $len; ++ ++ open(FD, "<$file") || die $file; ++ binmode FD; ++ my @st = stat(FD); ++ die $file if (!@st); ++ $len = read(FD, $contents, $st[7]) || die $file; ++ close(FD) || die $file; ++ die "$file: Wanted length ", $st[7], ", got ", $len, "\n" ++ if ($len != $st[7]); ++ return $contents; ++} ++ ++############################################################################### ++# ++# First of all, we have to parse the X.509 certificate to find certain details ++# about it. ++# ++# We read the DER-encoded X509 certificate and parse it to extract the Subject ++# name and Subject Key Identifier. Theis provides the data we need to build ++# the certificate identifier. ++# ++# The signer's name part of the identifier is fabricated from the commonName, ++# the organizationName or the emailAddress components of the X.509 subject ++# name. ++# ++# The subject key ID is used to select which of that signer's certificates ++# we're intending to use to sign the module. ++# ++############################################################################### ++my $x509_certificate = read_file($x509); + +-CONFIG_MODULE_SIG_SHA512=y +-if [ -r .config ] +-then +- . ./.config +-fi ++my $UNIV = 0 << 6; ++my $APPL = 1 << 6; ++my $CONT = 2 << 6; ++my $PRIV = 3 << 6; + +-key="$1" +-x509="$2" +-keyid_script="$3" +-mod="$4" ++my $CONS = 0x20; + +-if [ ! -r "$key" ] +-then +- echo "Can't read private key" >&2 +- exit 2 +-fi ++my $BOOLEAN = 0x01; ++my $INTEGER = 0x02; ++my $BIT_STRING = 0x03; ++my $OCTET_STRING = 0x04; ++my $NULL = 0x05; ++my $OBJ_ID = 0x06; ++my $UTF8String = 0x0c; ++my $SEQUENCE = 0x10; ++my $SET = 0x11; ++my $UTCTime = 0x17; ++my $GeneralizedTime = 0x18; + +-if [ ! -r "$x509" ] +-then +- echo "Can't read X.509 certificate" >&2 +- exit 2 +-fi ++my %OIDs = ( ++ pack("CCC", 85, 4, 3) => "commonName", ++ pack("CCC", 85, 4, 6) => "countryName", ++ pack("CCC", 85, 4, 10) => "organizationName", ++ pack("CCC", 85, 4, 11) => "organizationUnitName", ++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", ++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", ++ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", ++ pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", ++ pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", ++ pack("CCC", 85, 29, 19) => "basicConstraints" ++); ++ ++############################################################################### ++# ++# Extract an ASN.1 element from a string and return information about it. ++# ++############################################################################### ++sub asn1_extract($$@) ++{ ++ my ($cursor, $expected_tag, $optional) = @_; ++ ++ return [ -1 ] ++ if ($cursor->[1] == 0 && $optional); ++ ++ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" ++ if ($cursor->[1] < 2); ++ ++ my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); ++ ++ if ($expected_tag != -1 && $tag != $expected_tag) { ++ return [ -1 ] ++ if ($optional); ++ die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, ++ " not ", $expected_tag, ")\n"; ++ } ++ ++ $cursor->[0] += 2; ++ $cursor->[1] -= 2; ++ ++ die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n" ++ if (($tag & 0x1f) == 0x1f); ++ die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n" ++ if ($len == 0x80); ++ ++ if ($len > 0x80) { ++ my $l = $len - 0x80; ++ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" ++ if ($cursor->[1] < $l); ++ ++ if ($l == 0x1) { ++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); ++ } elsif ($l = 0x2) { ++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); ++ } elsif ($l = 0x3) { ++ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; ++ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); ++ } elsif ($l = 0x4) { ++ $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); ++ } else { ++ die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; ++ } ++ ++ $cursor->[0] += $l; ++ $cursor->[1] -= $l; ++ } ++ ++ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" ++ if ($cursor->[1] < $len); ++ ++ my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; ++ $cursor->[0] += $len; ++ $cursor->[1] -= $len; ++ ++ return $ret; ++} ++ ++############################################################################### ++# ++# Retrieve the data referred to by a cursor ++# ++############################################################################### ++sub asn1_retrieve($) ++{ ++ my ($cursor) = @_; ++ my ($offset, $len, $data) = @$cursor; ++ return substr($$data, $offset, $len); ++} ++ ++############################################################################### ++# ++# Roughly parse the X.509 certificate ++# ++############################################################################### ++my $cursor = [ 0, length($x509_certificate), \$x509_certificate ]; ++ ++my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); ++my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); ++my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); ++my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); ++my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); ++my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); ++my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); ++my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); ++ ++my $subject_key_id = (); ++my $authority_key_id = (); ++ ++# ++# Parse the extension list ++# ++if ($extension_list->[0] != -1) { ++ my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); ++ ++ while ($extensions->[1]->[1] > 0) { ++ my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); ++ my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); ++ my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); ++ my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); ++ ++ my $raw_oid = asn1_retrieve($x_oid->[1]); ++ next if (!exists($OIDs{$raw_oid})); ++ my $x_type = $OIDs{$raw_oid}; ++ ++ my $raw_value = asn1_retrieve($x_val->[1]); ++ ++ if ($x_type eq "subjectKeyIdentifier") { ++ my $vcursor = [ 0, length($raw_value), \$raw_value ]; ++ ++ $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); ++ } ++ } ++} ++ ++############################################################################### ++# ++# Determine what we're going to use as the signer's name. In order of ++# preference, take one of: commonName, organizationName or emailAddress. ++# ++############################################################################### ++my $org = ""; ++my $cn = ""; ++my $email = ""; ++ ++while ($subject->[1]->[1] > 0) { ++ my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); ++ my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); ++ my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); ++ my $n_val = asn1_extract($attr->[1], -1); ++ ++ my $raw_oid = asn1_retrieve($n_oid->[1]); ++ next if (!exists($OIDs{$raw_oid})); ++ my $n_type = $OIDs{$raw_oid}; ++ ++ my $raw_value = asn1_retrieve($n_val->[1]); ++ ++ if ($n_type eq "organizationName") { ++ $org = $raw_value; ++ } elsif ($n_type eq "commonName") { ++ $cn = $raw_value; ++ } elsif ($n_type eq "emailAddress") { ++ $email = $raw_value; ++ } ++} ++ ++my $signers_name = $email; ++ ++if ($org && $cn) { ++ # Don't use the organizationName if the commonName repeats it ++ if (length($org) <= length($cn) && ++ substr($cn, 0, length($org)) eq $org) { ++ $signers_name = $cn; ++ goto got_id_name; ++ } ++ ++ # Or a signifcant chunk of it ++ if (length($org) >= 7 && ++ length($cn) >= 7 && ++ substr($cn, 0, 7) eq substr($org, 0, 7)) { ++ $signers_name = $cn; ++ goto got_id_name; ++ } ++ ++ $signers_name = $org . ": " . $cn; ++} elsif ($org) { ++ $signers_name = $org; ++} elsif ($cn) { ++ $signers_name = $cn; ++} ++ ++got_id_name: ++ ++die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" ++ if (!$subject_key_id); ++ ++my $key_identifier = asn1_retrieve($subject_key_id->[1]); ++ ++############################################################################### ++# ++# Create and attach the module signature ++# ++############################################################################### + + # + # Signature parameters + # +-algo=1 # Public-key crypto algorithm: RSA +-hash= # Digest algorithm +-id_type=1 # Identifier type: X.509 ++my $algo = 1; # Public-key crypto algorithm: RSA ++my $hash = 0; # Digest algorithm ++my $id_type = 1; # Identifier type: X.509 + + # + # Digest the data + # +-dgst= +-if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ] +-then +- prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14" +- dgst=-sha1 +- hash=2 +-elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ] +-then +- prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C" +- dgst=-sha224 +- hash=7 +-elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ] +-then +- prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20" +- dgst=-sha256 +- hash=4 +-elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ] +-then +- prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30" +- dgst=-sha384 +- hash=5 +-elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ] +-then +- prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40" +- dgst=-sha512 +- hash=6 +-else +- echo "$0: Can't determine hash algorithm" >&2 +- exit 2 +-fi +- +-( +-perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $? +-openssl dgst $dgst -binary $mod || exit $? +-) >$mod.dig || exit $? ++my ($dgst, $prologue) = (); ++if (exists $config{"CONFIG_MODULE_SIG_SHA1"}) { ++ $prologue = pack("C*", ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x0E, 0x03, 0x02, 0x1A, ++ 0x05, 0x00, 0x04, 0x14); ++ $dgst = "-sha1"; ++ $hash = 2; ++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA224"}) { ++ $prologue = pack("C*", ++ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, ++ 0x05, 0x00, 0x04, 0x1C); ++ $dgst = "-sha224"; ++ $hash = 7; ++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA256"}) { ++ $prologue = pack("C*", ++ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x20); ++ $dgst = "-sha256"; ++ $hash = 4; ++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA384"}) { ++ $prologue = pack("C*", ++ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, ++ 0x05, 0x00, 0x04, 0x30); ++ $dgst = "-sha384"; ++ $hash = 5; ++} elsif (exists $config{"CONFIG_MODULE_SIG_SHA512"}) { ++ $prologue = pack("C*", ++ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x05, 0x00, 0x04, 0x40); ++ $dgst = "-sha512"; ++ $hash = 6; ++} else { ++ die "Can't determine hash algorithm"; ++} ++ ++# ++# Generate the digest and read from openssl's stdout ++# ++my $digest; ++$digest = readpipe("openssl dgst $dgst -binary $module") || die "openssl dgst"; + + # + # Generate the binary signature, which will be just the integer that comprises + # the signature with no metadata attached. + # +-openssl rsautl -sign -inkey $key -keyform PEM -in $mod.dig -out $mod.sig || exit $? +-siglen=`stat -c %s $mod.sig` ++my $pid; ++$pid = open2(*read_from, *write_to, ++ "openssl rsautl -sign -inkey $private_key -keyform PEM") || ++ die "openssl rsautl"; ++binmode write_to; ++print write_to $prologue . $digest || die "pipe to openssl rsautl"; ++close(write_to) || die "pipe to openssl rsautl"; ++ ++binmode read_from; ++my $signature; ++read(read_from, $signature, 4096) || die "pipe from openssl rsautl"; ++close(read_from) || die "pipe from openssl rsautl"; ++$signature = pack("n", length($signature)) . $signature, + +-SIGNER="`perl $keyid_script $x509 signer-name`" +-KEYID="`perl $keyid_script $x509 keyid`" +-keyidlen=$(echo -n "$KEYID" | wc -c) +-signerlen=$(echo -n "$SIGNER" | wc -c) ++waitpid($pid, 0) || die; ++die "openssl rsautl died: $?" if ($? >> 8); + + # + # Build the signed binary + # +-( +- cat $mod || exit $? +- echo '~Module signature appended~' || exit $? +- echo -n "$SIGNER" || exit $? +- echo -n "$KEYID" || exit $? ++my $unsigned_module = read_file($module); ++ ++my $magic_number = "~Module signature appended~\n"; ++ ++my $info = pack("CCCCCxxxN", ++ $algo, $hash, $id_type, ++ length($signers_name), ++ length($key_identifier), ++ length($signature)); + +- # Preface each signature integer with a 2-byte BE length +- perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $? +- cat $mod.sig || exit $? ++if ($verbose) { ++ print "Size of unsigned module: ", length($unsigned_module), "\n"; ++ print "Size of magic number : ", length($magic_number), "\n"; ++ print "Size of signer's name : ", length($signers_name), "\n"; ++ print "Size of key identifier : ", length($key_identifier), "\n"; ++ print "Size of signature : ", length($signature), "\n"; ++ print "Size of informaton : ", length($info), "\n"; ++ print "Signer's name : '", $signers_name, "'\n"; ++ print "Digest : $dgst\n"; ++} + +- # Generate the information block +- perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $? +-) >$mod~ || exit $? ++open(FD, ">$dest") || die $dest; ++binmode FD; ++print FD ++ $unsigned_module, ++ $magic_number, ++ $signers_name, ++ $key_identifier, ++ $signature, ++ $info ++ ; ++close FD || die $dest; + +-mv $mod~ $mod || exit $? ++if ($#ARGV != 3) { ++ rename($dest, $module) || die $module; ++} +diff --git a/scripts/x509keyid b/scripts/x509keyid +deleted file mode 100755 +index 4241ec6..0000000 +--- a/scripts/x509keyid ++++ /dev/null +@@ -1,268 +0,0 @@ +-#!/usr/bin/perl -w +-# +-# Generate an identifier from an X.509 certificate that can be placed in a +-# module signature to indentify the key to use. +-# +-# Format: +-# +-# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id> +-# +-# We read the DER-encoded X509 certificate and parse it to extract the Subject +-# name and Subject Key Identifier. The provide the data we need to build the +-# certificate identifier. +-# +-# The signer's name part of the identifier is fabricated from the commonName, +-# the organizationName or the emailAddress components of the X.509 subject +-# name and written to the second named file. +-# +-# The subject key ID to select which of that signer's certificates we're +-# intending to use to sign the module is written to the third named file. +-# +-use strict; +- +-my $raw_data; +- +-die "Need a filename [keyid|signer-name]\n" if ($#ARGV != 1); +- +-my $src = $ARGV[0]; +- +-open(FD, "<$src") || die $src; +-binmode FD; +-my @st = stat(FD); +-die $src if (!@st); +-read(FD, $raw_data, $st[7]) || die $src; +-close(FD); +- +-my $UNIV = 0 << 6; +-my $APPL = 1 << 6; +-my $CONT = 2 << 6; +-my $PRIV = 3 << 6; +- +-my $CONS = 0x20; +- +-my $BOOLEAN = 0x01; +-my $INTEGER = 0x02; +-my $BIT_STRING = 0x03; +-my $OCTET_STRING = 0x04; +-my $NULL = 0x05; +-my $OBJ_ID = 0x06; +-my $UTF8String = 0x0c; +-my $SEQUENCE = 0x10; +-my $SET = 0x11; +-my $UTCTime = 0x17; +-my $GeneralizedTime = 0x18; +- +-my %OIDs = ( +- pack("CCC", 85, 4, 3) => "commonName", +- pack("CCC", 85, 4, 6) => "countryName", +- pack("CCC", 85, 4, 10) => "organizationName", +- pack("CCC", 85, 4, 11) => "organizationUnitName", +- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", +- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", +- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", +- pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", +- pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", +- pack("CCC", 85, 29, 19) => "basicConstraints" +-); +- +-############################################################################### +-# +-# Extract an ASN.1 element from a string and return information about it. +-# +-############################################################################### +-sub asn1_extract($$@) +-{ +- my ($cursor, $expected_tag, $optional) = @_; +- +- return [ -1 ] +- if ($cursor->[1] == 0 && $optional); +- +- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" +- if ($cursor->[1] < 2); +- +- my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); +- +- if ($expected_tag != -1 && $tag != $expected_tag) { +- return [ -1 ] +- if ($optional); +- die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, +- " not ", $expected_tag, ")\n"; +- } +- +- $cursor->[0] += 2; +- $cursor->[1] -= 2; +- +- die $src, ": ", $cursor->[0], ": ASN.1 long tag\n" +- if (($tag & 0x1f) == 0x1f); +- die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n" +- if ($len == 0x80); +- +- if ($len > 0x80) { +- my $l = $len - 0x80; +- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" +- if ($cursor->[1] < $l); +- +- if ($l == 0x1) { +- $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); +- } elsif ($l = 0x2) { +- $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); +- } elsif ($l = 0x3) { +- $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; +- $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); +- } elsif ($l = 0x4) { +- $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); +- } else { +- die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; +- } +- +- $cursor->[0] += $l; +- $cursor->[1] -= $l; +- } +- +- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" +- if ($cursor->[1] < $len); +- +- my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; +- $cursor->[0] += $len; +- $cursor->[1] -= $len; +- +- return $ret; +-} +- +-############################################################################### +-# +-# Retrieve the data referred to by a cursor +-# +-############################################################################### +-sub asn1_retrieve($) +-{ +- my ($cursor) = @_; +- my ($offset, $len, $data) = @$cursor; +- return substr($$data, $offset, $len); +-} +- +-############################################################################### +-# +-# Roughly parse the X.509 certificate +-# +-############################################################################### +-my $cursor = [ 0, length($raw_data), \$raw_data ]; +- +-my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); +-my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); +-my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); +-my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); +-my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +-my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +-my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +-my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +-my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); +-my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); +-my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); +-my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); +- +-my $subject_key_id = (); +-my $authority_key_id = (); +- +-# +-# Parse the extension list +-# +-if ($extension_list->[0] != -1) { +- my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); +- +- while ($extensions->[1]->[1] > 0) { +- my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); +- my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); +- my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); +- my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); +- +- my $raw_oid = asn1_retrieve($x_oid->[1]); +- next if (!exists($OIDs{$raw_oid})); +- my $x_type = $OIDs{$raw_oid}; +- +- my $raw_value = asn1_retrieve($x_val->[1]); +- +- if ($x_type eq "subjectKeyIdentifier") { +- my $vcursor = [ 0, length($raw_value), \$raw_value ]; +- +- $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); +- } +- } +-} +- +-############################################################################### +-# +-# Determine what we're going to use as the signer's name. In order of +-# preference, take one of: commonName, organizationName or emailAddress. +-# +-############################################################################### +-my $org = ""; +-my $cn = ""; +-my $email = ""; +- +-while ($subject->[1]->[1] > 0) { +- my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); +- my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); +- my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); +- my $n_val = asn1_extract($attr->[1], -1); +- +- my $raw_oid = asn1_retrieve($n_oid->[1]); +- next if (!exists($OIDs{$raw_oid})); +- my $n_type = $OIDs{$raw_oid}; +- +- my $raw_value = asn1_retrieve($n_val->[1]); +- +- if ($n_type eq "organizationName") { +- $org = $raw_value; +- } elsif ($n_type eq "commonName") { +- $cn = $raw_value; +- } elsif ($n_type eq "emailAddress") { +- $email = $raw_value; +- } +-} +- +-my $id_name = $email; +- +-if ($org && $cn) { +- # Don't use the organizationName if the commonName repeats it +- if (length($org) <= length($cn) && +- substr($cn, 0, length($org)) eq $org) { +- $id_name = $cn; +- goto got_id_name; +- } +- +- # Or a signifcant chunk of it +- if (length($org) >= 7 && +- length($cn) >= 7 && +- substr($cn, 0, 7) eq substr($org, 0, 7)) { +- $id_name = $cn; +- goto got_id_name; +- } +- +- $id_name = $org . ": " . $cn; +-} elsif ($org) { +- $id_name = $org; +-} elsif ($cn) { +- $id_name = $cn; +-} +- +-got_id_name: +- +-############################################################################### +-# +-# Output the signer's name and the key identifier that we're going to include +-# in module signatures. +-# +-############################################################################### +-die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" +- if (!$subject_key_id); +- +-my $id_key_id = asn1_retrieve($subject_key_id->[1]); +- +-if ($ARGV[1] eq "signer-name") { +- print $id_name; +-} elsif ($ARGV[1] eq "keyid") { +- print $id_key_id; +-} else { +- die "Unknown arg"; +-} +-- +1.7.12.1 + + +From 02c76d9df8ff5387b9131799750895475f87c351 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 19 Oct 2012 23:56:45 +0100 +Subject: [PATCH 36/37] MODSIGN: Cleanup .gitignore + +The module build process no longer creates intermediate files for module +signing, so remove them from .gitignore. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + .gitignore | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/.gitignore b/.gitignore +index 0f2f40f..92bd0e4 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,10 +14,6 @@ + *.o.* + *.a + *.s +-*.ko.unsigned +-*.ko.stripped +-*.ko.stripped.dig +-*.ko.stripped.sig + *.ko + *.so + *.so.dbg +@@ -95,6 +91,4 @@ GTAGS + extra_certificates + signing_key.priv + signing_key.x509 +-signing_key.x509.keyid +-signing_key.x509.signer + x509.genkey +-- +1.7.12.1 + + +From fd08dfdc1a0022b48b7a5d4599cb4d46bf099882 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Sat, 20 Oct 2012 01:19:29 +0100 +Subject: [PATCH 37/37] MODSIGN: Move the magic string to the end of a module + and eliminate the search + +Emit the magic string that indicates a module has a signature after the +signature data instead of before it. This allows module_sig_check() to +be made simpler and faster by the elimination of the search for the +magic string. Instead we just need to do a single memcmp(). + +This works because at the end of the signature data there is the +fixed-length signature information block. This block then falls +immediately prior to the magic number. + +From the contents of the information block, it is trivial to calculate +the size of the signature data and thus the size of the actual module +data. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + kernel/module-internal.h | 3 +-- + kernel/module.c | 26 +++++++++----------------- + kernel/module_signing.c | 24 +++++++++++++++--------- + scripts/sign-file | 6 +++--- + 4 files changed, 28 insertions(+), 31 deletions(-) + +diff --git a/kernel/module-internal.h b/kernel/module-internal.h +index 6114a13..24f9247 100644 +--- a/kernel/module-internal.h ++++ b/kernel/module-internal.h +@@ -11,5 +11,4 @@ + + extern struct key *modsign_keyring; + +-extern int mod_verify_sig(const void *mod, unsigned long modlen, +- const void *sig, unsigned long siglen); ++extern int mod_verify_sig(const void *mod, unsigned long *_modlen); +diff --git a/kernel/module.c b/kernel/module.c +index 3e8b1a7..0cfcccc 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2441,25 +2441,17 @@ static inline void kmemleak_load_module(const struct module *mod, + + #ifdef CONFIG_MODULE_SIG + static int module_sig_check(struct load_info *info, +- const void *mod, unsigned long *len) ++ const void *mod, unsigned long *_len) + { + int err = -ENOKEY; +- const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; +- const void *p = mod, *end = mod + *len; +- +- /* Poor man's memmem. */ +- while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) { +- if (p + markerlen > end) +- break; +- +- if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) { +- const void *sig = p + markerlen; +- /* Truncate module up to signature. */ +- *len = p - mod; +- err = mod_verify_sig(mod, *len, sig, end - sig); +- break; +- } +- p++; ++ unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; ++ unsigned long len = *_len; ++ ++ if (len > markerlen && ++ memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { ++ /* We truncate the module to discard the signature */ ++ *_len -= markerlen; ++ err = mod_verify_sig(mod, _len); + } + + if (!err) { +diff --git a/kernel/module_signing.c b/kernel/module_signing.c +index 6b09f69..d492a23 100644 +--- a/kernel/module_signing.c ++++ b/kernel/module_signing.c +@@ -183,27 +183,33 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len, + /* + * Verify the signature on a module. + */ +-int mod_verify_sig(const void *mod, unsigned long modlen, +- const void *sig, unsigned long siglen) ++int mod_verify_sig(const void *mod, unsigned long *_modlen) + { + struct public_key_signature *pks; + struct module_signature ms; + struct key *key; +- size_t sig_len; ++ const void *sig; ++ size_t modlen = *_modlen, sig_len; + int ret; + +- pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen); ++ pr_devel("==>%s(,%lu)\n", __func__, modlen); + +- if (siglen <= sizeof(ms)) ++ if (modlen <= sizeof(ms)) + return -EBADMSG; + +- memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms)); +- siglen -= sizeof(ms); ++ memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); ++ modlen -= sizeof(ms); + + sig_len = be32_to_cpu(ms.sig_len); +- if (sig_len >= siglen || +- siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len) ++ if (sig_len >= modlen) + return -EBADMSG; ++ modlen -= sig_len; ++ if ((size_t)ms.signer_len + ms.key_id_len >= modlen) ++ return -EBADMSG; ++ modlen -= (size_t)ms.signer_len + ms.key_id_len; ++ ++ *_modlen = modlen; ++ sig = mod + modlen; + + /* For the moment, only support RSA and X.509 identifiers */ + if (ms.algo != PKEY_ALGO_RSA || +diff --git a/scripts/sign-file b/scripts/sign-file +index d37d130..87ca59d 100755 +--- a/scripts/sign-file ++++ b/scripts/sign-file +@@ -403,11 +403,11 @@ my $info = pack("CCCCCxxxN", + + if ($verbose) { + print "Size of unsigned module: ", length($unsigned_module), "\n"; +- print "Size of magic number : ", length($magic_number), "\n"; + print "Size of signer's name : ", length($signers_name), "\n"; + print "Size of key identifier : ", length($key_identifier), "\n"; + print "Size of signature : ", length($signature), "\n"; + print "Size of informaton : ", length($info), "\n"; ++ print "Size of magic number : ", length($magic_number), "\n"; + print "Signer's name : '", $signers_name, "'\n"; + print "Digest : $dgst\n"; + } +@@ -416,11 +416,11 @@ open(FD, ">$dest") || die $dest; + binmode FD; + print FD + $unsigned_module, +- $magic_number, + $signers_name, + $key_identifier, + $signature, +- $info ++ $info, ++ $magic_number + ; + close FD || die $dest; + +-- +1.7.12.1 + |