From be7ac52af682ed133aa613ed21c756d1459ff3aa Mon Sep 17 00:00:00 2001 From: Justin M. Forbes Date: Oct 15 2012 14:42:26 +0000 Subject: re-enable modsign and secure boot --- diff --git a/kernel.spec b/kernel.spec index ea4a8b5..cb52e45 100644 --- a/kernel.spec +++ b/kernel.spec @@ -1390,10 +1390,10 @@ ApplyPatch linux-2.6-crash-driver.patch ApplyPatch linux-2.6-e1000-ich9-montevina.patch # crypto/ -# ApplyPatch modsign-post-KS-jwb.patch +ApplyPatch modsign-post-KS-jwb.patch # secure boot -# ApplyPatch secure-boot-20120924.patch +ApplyPatch secure-boot-20120924.patch # Improved PCI support for UEFI ApplyPatch handle-efi-roms.patch @@ -2301,6 +2301,9 @@ fi # ||----w | # || || %changelog +* Mon Oct 15 2012 Justin M. Forbes +- re-enable modsign and secure boot + * Mon Oct 15 2012 Justin M. Forbes - 3.7.0-0.rc1.git0.1 - Linux 3.7-rc1 - Disable debugging options. diff --git a/modsign-post-KS-jwb.patch b/modsign-post-KS-jwb.patch index e8a86af..5900332 100644 --- a/modsign-post-KS-jwb.patch +++ b/modsign-post-KS-jwb.patch @@ -1,8791 +1,254 @@ -From 2cdfd353ac1a5b9f62398ef59b4a08b5b55ac089 Mon Sep 17 00:00:00 2001 -From: Rusty Russell -Date: Wed, 5 Sep 2012 12:32:17 +0930 -Subject: [PATCH 01/26] module: signature checking hook - -We do a very simple search for a particular string appended to the module -(which is cache-hot and about to be SHA'd anyway). There's both a config -option and a boot parameter which control whether we accept (and taint) or -fail with unsigned modules. - -Signed-off-by: Rusty Russell ---- - Documentation/kernel-parameters.txt | 6 +++ - include/linux/module.h | 8 ++++ - init/Kconfig | 14 ++++++ - kernel/module.c | 88 ++++++++++++++++++++++++++++++++++++- - 4 files changed, 115 insertions(+), 1 deletion(-) - -diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index ad7e2e5..9b2b8d3 100644 ---- a/Documentation/kernel-parameters.txt -+++ b/Documentation/kernel-parameters.txt -@@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. - log everything. Information is printed at KERN_DEBUG - so loglevel=8 may also need to be specified. - -+ module.sig_enforce -+ [KNL] When CONFIG_MODULE_SIG is set, this means that -+ modules without (valid) signatures will fail to load. -+ Note that if CONFIG_MODULE_SIG_ENFORCE is set, that -+ is always true, so this option does nothing. -+ - mousedev.tap_time= - [MOUSE] Maximum time between finger touching and - leaving touchpad surface for touch to be considered -diff --git a/include/linux/module.h b/include/linux/module.h -index fbcafe2..7760c6d 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -21,6 +21,9 @@ - #include - #include - -+/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ -+#define MODULE_SIG_STRING "~Module signature appended~\n" -+ - /* Not Yet Implemented */ - #define MODULE_SUPPORTED_DEVICE(name) - -@@ -260,6 +263,11 @@ struct module - const unsigned long *unused_gpl_crcs; - #endif - -+#ifdef CONFIG_MODULE_SIG -+ /* Signature was verified. */ -+ bool sig_ok; -+#endif -+ - /* symbols that will be GPL-only in the near future. */ - const struct kernel_symbol *gpl_future_syms; - const unsigned long *gpl_future_crcs; -diff --git a/init/Kconfig b/init/Kconfig -index af6c7f8..7452e19 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL - the version). With this option, such a "srcversion" field - will be created for all modules. If unsure, say N. - -+config MODULE_SIG -+ bool "Module signature verification" -+ depends on MODULES -+ help -+ Check modules for valid signatures upon load: the signature -+ is simply appended to the module. For more information see -+ Documentation/module-signing.txt. -+ -+config MODULE_SIG_FORCE -+ bool "Require modules to be validly signed" -+ depends on MODULE_SIG -+ help -+ Reject unsigned modules or signed modules for which we don't have a -+ key. Without this, such modules will simply taint the kernel. - endif # MODULES - - config INIT_ALL_POSSIBLE -diff --git a/kernel/module.c b/kernel/module.c -index 4edbd9c..5c6f65c 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -102,6 +102,43 @@ static LIST_HEAD(modules); - struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ - #endif /* CONFIG_KGDB_KDB */ - -+#ifdef CONFIG_MODULE_SIG -+#ifdef CONFIG_MODULE_SIG_FORCE -+static bool sig_enforce = true; -+#else -+static bool sig_enforce = false; -+ -+static int param_set_bool_enable_only(const char *val, -+ const struct kernel_param *kp) -+{ -+ int err; -+ bool test; -+ struct kernel_param dummy_kp = *kp; -+ -+ dummy_kp.arg = &test; -+ -+ err = param_set_bool(val, &dummy_kp); -+ if (err) -+ return err; -+ -+ /* Don't let them unset it once it's set! */ -+ if (!test && sig_enforce) -+ return -EROFS; -+ -+ if (test) -+ sig_enforce = true; -+ return 0; -+} -+ -+static const struct kernel_param_ops param_ops_bool_enable_only = { -+ .set = param_set_bool_enable_only, -+ .get = param_get_bool, -+}; -+#define param_check_bool_enable_only param_check_bool -+ -+module_param(sig_enforce, bool_enable_only, 0644); -+#endif /* !CONFIG_MODULE_SIG_FORCE */ -+#endif /* CONFIG_MODULE_SIG */ - - /* Block module loading/unloading? */ - int modules_disabled = 0; -@@ -136,6 +173,7 @@ struct load_info { - unsigned long symoffs, stroffs; - struct _ddebug *debug; - unsigned int num_debug; -+ bool sig_ok; - struct { - unsigned int sym, str, mod, vers, info, pcpu; - } index; -@@ -2399,7 +2437,45 @@ static inline void kmemleak_load_module(const struct module *mod, - } - #endif - --/* Sets info->hdr and info->len. */ -+#ifdef CONFIG_MODULE_SIG -+static int module_sig_check(struct load_info *info, -+ const void *mod, unsigned long *len) -+{ -+ int err = 0; -+ const unsigned long markerlen = strlen(MODULE_SIG_STRING); -+ const void *p = mod, *end = mod + *len; -+ -+ /* Poor man's memmem. */ -+ while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) { -+ if (p + markerlen > end) -+ break; -+ -+ if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) { -+ const void *sig = p + markerlen; -+ /* Truncate module up to signature. */ -+ *len = p - mod; -+ err = mod_verify_sig(mod, *len, -+ sig, end - sig, -+ &info->sig_ok); -+ break; -+ } -+ p++; -+ } -+ -+ /* Not having a signature is only an error if we're strict. */ -+ if (!err && !info->sig_ok && sig_enforce) -+ err = -EKEYREJECTED; -+ return err; -+} -+#else /* !CONFIG_MODULE_SIG */ -+static int module_sig_check(struct load_info *info, -+ void *mod, unsigned long *len) -+{ -+ return 0; -+} -+#endif /* !CONFIG_MODULE_SIG */ -+ -+/* Sets info->hdr, info->len and info->sig_ok. */ - static int copy_and_check(struct load_info *info, - const void __user *umod, unsigned long len, - const char __user *uargs) -@@ -2419,6 +2495,10 @@ static int copy_and_check(struct load_info *info, - goto free_hdr; - } - -+ err = module_sig_check(info, hdr, &len); -+ if (err) -+ goto free_hdr; -+ - /* Sanity checks against insmoding binaries or wrong arch, - weird elf version */ - if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 -@@ -2886,6 +2966,12 @@ static struct module *load_module(void __user *umod, - goto free_copy; - } - -+#ifdef CONFIG_MODULE_SIG -+ mod->sig_ok = info.sig_ok; -+ if (!mod->sig_ok) -+ add_taint_module(mod, TAINT_FORCED_MODULE); -+#endif -+ - /* Now module is in final location, initialize linked lists, etc. */ - err = module_unload_init(mod); - if (err) --- -1.7.11.4 - - -From d4f65b5d2497b2fd9c45f06b71deb4ab084a5b66 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Thu, 13 Sep 2012 13:06:29 +0100 -Subject: [PATCH 02/26] KEYS: Add payload preparsing opportunity prior to key - instantiate or update - -Give the key type the opportunity to preparse the payload prior to the -instantiation and update routines being called. This is done with the -provision of two new key type operations: - - int (*preparse)(struct key_preparsed_payload *prep); - void (*free_preparse)(struct key_preparsed_payload *prep); - -If the first operation is present, then it is called before key creation (in -the add/update case) or before the key semaphore is taken (in the update and -instantiate cases). The second operation is called to clean up if the first -was called. - -preparse() is given the opportunity to fill in the following structure: - - struct key_preparsed_payload { - char *description; - void *type_data[2]; - void *payload; - const void *data; - size_t datalen; - size_t quotalen; - }; - -Before the preparser is called, the first three fields will have been cleared, -the payload pointer and size will be stored in data and datalen and the default -quota size from the key_type struct will be stored into quotalen. - -The preparser may parse the payload in any way it likes and may store data in -the type_data[] and payload fields for use by the instantiate() and update() -ops. - -The preparser may also propose a description for the key by attaching it as a -string to the description field. This can be used by passing a NULL or "" -description to the add_key() system call or the key_create_or_update() -function. This cannot work with request_key() as that required the description -to tell the upcall about the key to be created. - -This, for example permits keys that store PGP public keys to generate their own -name from the user ID and public key fingerprint in the key. - -The instantiate() and update() operations are then modified to look like this: - - int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); - int (*update)(struct key *key, struct key_preparsed_payload *prep); - -and the new payload data is passed in *prep, whether or not it was preparsed. - -Signed-off-by: David Howells ---- - 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 - #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; - size_t key_len; - -- if (datalen <= 0 || datalen > 32767 || !data) -+ if (datalen <= 0 || datalen > 32767 || !prep->data) - return -EINVAL; - - datablob = kmalloc(datalen + 1, GFP_KERNEL); - if (!datablob) - return -ENOMEM; -- memcpy(datablob, data, datalen); -+ memcpy(datablob, prep->data, datalen); - datablob[datalen] = '\0'; - - options = trusted_options_alloc(); -@@ -1011,17 +1012,18 @@ static void trusted_rcu_free(struct rcu_head *rcu) - /* - * trusted_update - reseal an existing key with new PCR values - */ --static int trusted_update(struct key *key, const void *data, size_t datalen) -+static int trusted_update(struct key *key, struct key_preparsed_payload *prep) - { - struct trusted_key_payload *p = key->payload.data; - struct trusted_key_payload *new_p; - struct trusted_key_options *new_o; -+ size_t datalen = prep->datalen; - char *datablob; - int ret = 0; - - if (!p->migratable) - return -EPERM; -- if (datalen <= 0 || datalen > 32767 || !data) -+ if (datalen <= 0 || datalen > 32767 || !prep->data) - return -EINVAL; - - datablob = kmalloc(datalen + 1, GFP_KERNEL); -@@ -1038,7 +1040,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen) - goto out; - } - -- memcpy(datablob, data, datalen); -+ memcpy(datablob, prep->data, datalen); - datablob[datalen] = '\0'; - ret = datablob_parse(datablob, new_p, new_o); - if (ret != Opt_update) { -diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c -index c7660a2..55dc889 100644 ---- a/security/keys/user_defined.c -+++ b/security/keys/user_defined.c -@@ -58,13 +58,14 @@ EXPORT_SYMBOL_GPL(key_type_logon); - /* - * instantiate a user defined key - */ --int user_instantiate(struct key *key, const void *data, size_t datalen) -+int user_instantiate(struct key *key, struct key_preparsed_payload *prep) - { - struct user_key_payload *upayload; -+ size_t datalen = prep->datalen; - int ret; - - ret = -EINVAL; -- if (datalen <= 0 || datalen > 32767 || !data) -+ if (datalen <= 0 || datalen > 32767 || !prep->data) - goto error; - - ret = key_payload_reserve(key, datalen); -@@ -78,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen) - - /* attach the data */ - upayload->datalen = datalen; -- memcpy(upayload->data, data, datalen); -+ memcpy(upayload->data, prep->data, datalen); - rcu_assign_keypointer(key, upayload); - ret = 0; - -@@ -92,13 +93,14 @@ EXPORT_SYMBOL_GPL(user_instantiate); - * update a user defined key - * - the key's semaphore is write-locked - */ --int user_update(struct key *key, const void *data, size_t datalen) -+int user_update(struct key *key, struct key_preparsed_payload *prep) - { - struct user_key_payload *upayload, *zap; -+ size_t datalen = prep->datalen; - int ret; - - ret = -EINVAL; -- if (datalen <= 0 || datalen > 32767 || !data) -+ if (datalen <= 0 || datalen > 32767 || !prep->data) - goto error; - - /* construct a replacement payload */ -@@ -108,7 +110,7 @@ int user_update(struct key *key, const void *data, size_t datalen) - goto error; - - upayload->datalen = datalen; -- memcpy(upayload->data, data, datalen); -+ memcpy(upayload->data, prep->data, datalen); - - /* check the quota and attach the new data */ - zap = upayload; --- -1.7.11.4 - - -From a3f7dff6cbc2eb6be871a58fef34cacf7f78abf8 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Thu, 13 Sep 2012 13:09:33 +0100 -Subject: [PATCH 03/26] MPILIB: Provide count_leading/trailing_zeros() based - on arch functions - -Provide count_leading/trailing_zeros() macros based on extant arch bit scanning -functions rather than reimplementing from scratch in MPILIB. - -Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x). - -Also move the definition to asm-generic as other people may be interested in -using it. - -Signed-off-by: David Howells -Cc: David S. Miller -Cc: Dmitry Kasatkin -Cc: Arnd Bergmann ---- - 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 -+ -+/** -+ * 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 -+ - /* You have to define the following before including this file: - * - * UWtype -- An unsigned type, default type for operations (typically a "word") -@@ -146,12 +148,6 @@ do { \ - : "1" ((USItype)(n1)), \ - "r" ((USItype)(n0)), \ - "r" ((USItype)(d))) -- --#define count_leading_zeros(count, x) \ -- __asm__ ("clz %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x))) --#define COUNT_LEADING_ZEROS_0 32 - #endif /* __a29k__ */ - - #if defined(__alpha) && W_TYPE_SIZE == 64 -@@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd(); - : "1" ((USItype)(nh)), \ - "0" ((USItype)(nl)), \ - "g" ((USItype)(d))) --#define count_leading_zeros(count, x) \ -- __asm__ ("bsch/1 %1,%0" \ -- : "=g" (count) \ -- : "g" ((USItype)(x)), \ -- "0" ((USItype)0)) - #endif - - /*************************************** -@@ -354,27 +345,6 @@ do { USItype __r; \ - } while (0) - extern USItype __udiv_qrnnd(); - #endif /* LONGLONG_STANDALONE */ --#define count_leading_zeros(count, x) \ --do { \ -- USItype __tmp; \ -- __asm__ ( \ -- "ldi 1,%0\n" \ -- "extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ -- "extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n" \ -- "ldo 16(%0),%0 ; Yes. Perform add.\n" \ -- "extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ -- "extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n" \ -- "ldo 8(%0),%0 ; Yes. Perform add.\n" \ -- "extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ -- "extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n" \ -- "ldo 4(%0),%0 ; Yes. Perform add.\n" \ -- "extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ -- "extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n" \ -- "ldo 2(%0),%0 ; Yes. Perform add.\n" \ -- "extru %1,30,1,%1 ; Extract bit 1.\n" \ -- "sub %0,%1,%0 ; Subtract it. " \ -- : "=r" (count), "=r" (__tmp) : "1" (x)); \ --} while (0) - #endif /* hppa */ - - /*************************************** -@@ -457,15 +427,6 @@ do { \ - : "0" ((USItype)(n0)), \ - "1" ((USItype)(n1)), \ - "rm" ((USItype)(d))) --#define count_leading_zeros(count, x) \ --do { \ -- USItype __cbtmp; \ -- __asm__ ("bsrl %1,%0" \ -- : "=r" (__cbtmp) : "rm" ((USItype)(x))); \ -- (count) = __cbtmp ^ 31; \ --} while (0) --#define count_trailing_zeros(count, x) \ -- __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) - #ifndef UMUL_TIME - #define UMUL_TIME 40 - #endif -@@ -536,15 +497,6 @@ do { \ - "dI" ((USItype)(d))); \ - (r) = __rq.__i.__l; (q) = __rq.__i.__h; \ - } while (0) --#define count_leading_zeros(count, x) \ --do { \ -- USItype __cbtmp; \ -- __asm__ ("scanbit %1,%0" \ -- : "=r" (__cbtmp) \ -- : "r" ((USItype)(x))); \ -- (count) = __cbtmp ^ 31; \ --} while (0) --#define COUNT_LEADING_ZEROS_0 (-32) /* sic */ - #if defined(__i960mx) /* what is the proper symbol to test??? */ - #define rshift_rhlc(r, h, l, c) \ - do { \ -@@ -603,11 +555,6 @@ do { \ - : "0" ((USItype)(n0)), \ - "1" ((USItype)(n1)), \ - "dmi" ((USItype)(d))) --#define count_leading_zeros(count, x) \ -- __asm__ ("bfffo %1{%b2:%b2},%0" \ -- : "=d" ((USItype)(count)) \ -- : "od" ((USItype)(x)), "n" (0)) --#define COUNT_LEADING_ZEROS_0 32 - #else /* not mc68020 */ - #define umul_ppmm(xh, xl, a, b) \ - do { USItype __umul_tmp1, __umul_tmp2; \ -@@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \ - "rJ" ((USItype)(bh)), \ - "rJ" ((USItype)(al)), \ - "rJ" ((USItype)(bl))) --#define count_leading_zeros(count, x) \ --do { \ -- USItype __cbtmp; \ -- __asm__ ("ff1 %0,%1" \ -- : "=r" (__cbtmp) \ -- : "r" ((USItype)(x))); \ -- (count) = __cbtmp ^ 31; \ --} while (0) --#define COUNT_LEADING_ZEROS_0 63 /* sic */ - #if defined(__m88110__) - #define umul_ppmm(wh, wl, u, v) \ - do { \ -@@ -779,12 +717,6 @@ do { \ - : "0" (__xx.__ll), \ - "g" ((USItype)(d))); \ - (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) --#define count_trailing_zeros(count, x) \ --do { \ -- __asm__("ffsd %2,%0" \ -- : "=r"((USItype) (count)) \ -- : "0"((USItype) 0), "r"((USItype) (x))); \ -- } while (0) - #endif /* __ns32000__ */ - - /*************************************** -@@ -855,11 +787,6 @@ do { \ - "rI" ((USItype)(al)), \ - "r" ((USItype)(bl))); \ - } while (0) --#define count_leading_zeros(count, x) \ -- __asm__ ("{cntlz|cntlzw} %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x))) --#define COUNT_LEADING_ZEROS_0 32 - #if defined(_ARCH_PPC) - #define umul_ppmm(ph, pl, m0, m1) \ - do { \ -@@ -1001,19 +928,6 @@ do { \ - } while (0) - #define UMUL_TIME 20 - #define UDIV_TIME 200 --#define count_leading_zeros(count, x) \ --do { \ -- if ((x) >= 0x10000) \ -- __asm__ ("clz %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x) >> 16)); \ -- else { \ -- __asm__ ("clz %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x))); \ -- (count) += 16; \ -- } \ --} while (0) - #endif /* RT/ROMP */ - - /*************************************** -@@ -1142,13 +1056,6 @@ do { \ - "rI" ((USItype)(d)) \ - : "%g1" __AND_CLOBBER_CC) - #define UDIV_TIME 37 --#define count_leading_zeros(count, x) \ -- __asm__ ("scan %1,0,%0" \ -- : "=r" ((USItype)(x)) \ -- : "r" ((USItype)(count))) --/* Early sparclites return 63 for an argument of 0, but they warn that future -- implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 -- undefined. */ - #endif /* __sparclite__ */ - #endif /* __sparc_v8__ */ - /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */ -@@ -1454,47 +1361,6 @@ do { \ - #define udiv_qrnnd __udiv_qrnnd_c - #endif - --#undef count_leading_zeros --#if !defined(count_leading_zeros) -- extern --#ifdef __STDC__ -- const --#endif -- unsigned char __clz_tab[]; --#define count_leading_zeros(count, x) \ --do { \ -- UWtype __xr = (x); \ -- UWtype __a; \ -- \ -- if (W_TYPE_SIZE <= 32) { \ -- __a = __xr < ((UWtype) 1 << 2*__BITS4) \ -- ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \ -- : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ -- } \ -- else { \ -- for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ -- if (((__xr >> __a) & 0xff) != 0) \ -- break; \ -- } \ -- \ -- (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ --} while (0) -- /* This version gives a well-defined value for zero. */ --#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE --#endif -- --#if !defined(count_trailing_zeros) --/* Define count_trailing_zeros using count_leading_zeros. The latter might be -- defined in asm, but if it is not, the C version above is good enough. */ --#define count_trailing_zeros(count, x) \ --do { \ -- UWtype __ctz_x = (x); \ -- UWtype __ctz_c; \ -- count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \ -- (count) = W_TYPE_SIZE - 1 - __ctz_c; \ --} while (0) --#endif -- - #ifndef UDIV_NEEDS_NORMALIZATION - #define UDIV_NEEDS_NORMALIZATION 0 - #endif -diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c -index 5687248..503537e 100644 ---- a/lib/mpi/mpi-bit.c -+++ b/lib/mpi/mpi-bit.c -@@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a) - if (a->nlimbs) { - mpi_limb_t alimb = a->d[a->nlimbs - 1]; - if (alimb) -- count_leading_zeros(n, alimb); -+ n = count_leading_zeros(alimb); - else - n = BITS_PER_MPI_LIMB; - n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB; -diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c -index 67f3e79..5464c87 100644 ---- a/lib/mpi/mpi-pow.c -+++ b/lib/mpi/mpi-pow.c -@@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) - mp = mp_marker = mpi_alloc_limb_space(msize); - if (!mp) - goto enomem; -- count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); -+ mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]); - if (mod_shift_cnt) - mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); - else -@@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) - - i = esize - 1; - e = ep[i]; -- count_leading_zeros(c, e); -+ c = count_leading_zeros(e); - e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ - c = BITS_PER_MPI_LIMB - 1 - c; - --- -1.7.11.4 - - -From 79e4c942f35117b405402acf0f075ff79260e546 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Thu, 13 Sep 2012 15:17:21 +0100 -Subject: [PATCH 04/26] KEYS: Document asymmetric key type - -In-source documentation for the asymmetric key type. This will be located in: - - Documentation/crypto/asymmetric-keys.txt - -Signed-off-by: David Howells ---- - 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:" 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 ":" 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 -+ -+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 -+ -+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 -+ -+and looks like the following: -+ -+ struct asymmetric_key_parser { -+ struct module *owner; -+ const char *name; -+ -+ int (*parse)(struct key_preparsed_payload *prep); -+ }; -+ -+The owner and name fields should be set to the owning module and the name of -+the parser. -+ -+There is currently only a single operation defined by the parser, and it is -+mandatory: -+ -+ (1) parse(). -+ -+ This is called to preparse the key from the key creation and update paths. -+ In particular, it is called during the key creation _before_ a key is -+ allocated, and as such, is permitted to provide the key's description in -+ the case that the caller declines to do so. -+ -+ The caller passes a pointer to the following struct with all of the fields -+ cleared, except for data, datalen and quotalen [see -+ Documentation/security/keys.txt]. -+ -+ struct key_preparsed_payload { -+ char *description; -+ void *type_data[2]; -+ void *payload; -+ const void *data; -+ size_t datalen; -+ size_t quotalen; -+ }; -+ -+ The instantiation data is in a blob pointed to by data and is datalen in -+ size. The parse() function is not permitted to change these two values at -+ all, and shouldn't change any of the other values _unless_ they are -+ recognise the blob format and will not return -EBADMSG to indicate it is -+ not theirs. -+ -+ If the parser is happy with the blob, it should propose a description for -+ the key and attach it to ->description, ->type_data[0] should be set to -+ point to the subtype to be used, ->payload should be set to point to the -+ initialised data for that subtype, ->type_data[1] should point to a hex -+ fingerprint and quotalen should be updated to indicate how much quota this -+ key should account for. -+ -+ When clearing up, the data attached to ->type_data[1] and ->description -+ will be kfree()'d and the data attached to ->payload will be passed to the -+ subtype's ->destroy() method to be disposed of. A module reference for -+ the subtype pointed to by ->type_data[0] will be put. -+ -+ -+ If the data format is not recognised, -EBADMSG should be returned. If it -+ is recognised, but the key cannot for some reason be set up, some other -+ negative error code should be returned. On success, 0 should be returned. -+ -+ The key's fingerprint string may be partially matched upon. For a -+ public-key algorithm such as RSA and DSA this will likely be a printable -+ hex version of the key's fingerprint. -+ -+Functions are provided to register and unregister parsers: -+ -+ int register_asymmetric_key_parser(struct asymmetric_key_parser *parser); -+ void unregister_asymmetric_key_parser(struct asymmetric_key_parser *subtype); -+ -+Parsers may not have the same name. The names are otherwise only used for -+displaying in debugging messages. --- -1.7.11.4 - - -From 2fb78e0d337ac41f2cddad18fc5c34374e5298ab Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Thu, 13 Sep 2012 15:17:21 +0100 -Subject: [PATCH 05/26] KEYS: Implement asymmetric key type - -Create a key type that can be used to represent an asymmetric key type for use -in appropriate cryptographic operations, such as encryption, decryption, -signature generation and signature verification. - -The key type is "asymmetric" and can provide access to a variety of -cryptographic algorithms. - -Possibly, this would be better as "public_key" - but that has the disadvantage -that "public key" is an overloaded term. - -Signed-off-by: David Howells ---- - 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 -+#include -+#include -+#include -+#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: -+ * -+ * "" - request a key by description -+ * "id:" - request a key matching the 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 -+#include -+ -+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 -+ -+extern struct key_type key_type_asymmetric; -+ -+/* -+ * The payload is at the discretion of the subtype. -+ */ -+ -+#endif /* _KEYS_ASYMMETRIC_TYPE_H */ --- -1.7.11.4 - - -From d28ffd9e0c8987e5af59ae38bb48779b0d221f00 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Thu, 13 Sep 2012 15:17:32 +0100 -Subject: [PATCH 06/26] KEYS: Asymmetric key pluggable data parsers - -The instantiation data passed to the asymmetric key type are expected to be -formatted in some way, and there are several possible standard ways to format -the data. - -The two obvious standards are OpenPGP keys and X.509 certificates. The latter -is especially useful when dealing with UEFI, and the former might be useful -when dealing with, say, eCryptfs. - -Further, it might be desirable to provide formatted blobs that indicate -hardware is to be accessed to retrieve the keys or that the keys live -unretrievably in a hardware store, but that the keys can be used by means of -the hardware. - -From userspace, the keys can be loaded using the keyctl command, for example, -an X.509 binary certificate: - - keyctl padd asymmetric foo @s ---- - 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 -+#include - #include - #include - #include -@@ -18,6 +19,9 @@ - - MODULE_LICENSE("GPL"); - -+static LIST_HEAD(asymmetric_key_parsers); -+static DECLARE_RWSEM(asymmetric_key_parsers_sem); -+ - /* - * Match asymmetric keys on (part of) their name - * We have some shorthand methods for matching keys. We allow: -@@ -107,12 +111,79 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m) - } - - /* -+ * Preparse a asymmetric payload to get format the contents appropriately for the -+ * internal payload to cut down on the number of scans of the data performed. -+ * -+ * We also generate a proposed description from the contents of the key that -+ * can be used to name the key if the user doesn't want to provide one. -+ */ -+static int asymmetric_key_preparse(struct key_preparsed_payload *prep) -+{ -+ struct asymmetric_key_parser *parser; -+ int ret; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ if (prep->datalen == 0) -+ return -EINVAL; -+ -+ down_read(&asymmetric_key_parsers_sem); -+ -+ ret = -EBADMSG; -+ list_for_each_entry(parser, &asymmetric_key_parsers, link) { -+ pr_debug("Trying parser '%s'\n", parser->name); -+ -+ ret = parser->parse(prep); -+ if (ret != -EBADMSG) { -+ pr_debug("Parser recognised the format (ret %d)\n", -+ ret); -+ break; -+ } -+ } -+ -+ up_read(&asymmetric_key_parsers_sem); -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ret; -+} -+ -+/* -+ * Clean up the preparse data -+ */ -+static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) -+{ -+ struct asymmetric_key_subtype *subtype = prep->type_data[0]; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ if (subtype) { -+ subtype->destroy(prep->payload); -+ module_put(subtype->owner); -+ } -+ kfree(prep->type_data[1]); -+ kfree(prep->description); -+} -+ -+/* - * Instantiate a asymmetric_key defined key. The key was preparsed, so we just - * have to transfer the data here. - */ - static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep) - { -- return -EOPNOTSUPP; -+ int ret; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ ret = key_payload_reserve(key, prep->quotalen); -+ if (ret == 0) { -+ key->type_data.p[0] = prep->type_data[0]; -+ key->type_data.p[1] = prep->type_data[1]; -+ key->payload.data = prep->payload; -+ prep->type_data[0] = NULL; -+ prep->type_data[1] = NULL; -+ prep->payload = NULL; -+ } -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ret; - } - - /* -@@ -132,6 +203,8 @@ static void asymmetric_key_destroy(struct key *key) - - struct key_type key_type_asymmetric = { - .name = "asymmetric", -+ .preparse = asymmetric_key_preparse, -+ .free_preparse = asymmetric_key_free_preparse, - .instantiate = asymmetric_key_instantiate, - .match = asymmetric_key_match, - .destroy = asymmetric_key_destroy, -@@ -139,6 +212,51 @@ struct key_type key_type_asymmetric = { - }; - EXPORT_SYMBOL_GPL(key_type_asymmetric); - -+/** -+ * register_asymmetric_key_parser - Register a asymmetric key blob parser -+ * @parser: The parser to register -+ */ -+int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) -+{ -+ struct asymmetric_key_parser *cursor; -+ int ret; -+ -+ down_write(&asymmetric_key_parsers_sem); -+ -+ list_for_each_entry(cursor, &asymmetric_key_parsers, link) { -+ if (strcmp(cursor->name, parser->name) == 0) { -+ pr_err("Asymmetric key parser '%s' already registered\n", -+ parser->name); -+ ret = -EEXIST; -+ goto out; -+ } -+ } -+ -+ list_add_tail(&parser->link, &asymmetric_key_parsers); -+ -+ pr_notice("Asymmetric key parser '%s' registered\n", parser->name); -+ ret = 0; -+ -+out: -+ up_write(&asymmetric_key_parsers_sem); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); -+ -+/** -+ * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser -+ * @parser: The parser to unregister -+ */ -+void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) -+{ -+ down_write(&asymmetric_key_parsers_sem); -+ list_del(&parser->link); -+ up_write(&asymmetric_key_parsers_sem); -+ -+ pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); -+} -+EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); -+ - /* - * Module stuff - */ -diff --git a/include/keys/asymmetric-parser.h b/include/keys/asymmetric-parser.h -new file mode 100644 -index 0000000..09b3b48 ---- /dev/null -+++ b/include/keys/asymmetric-parser.h -@@ -0,0 +1,37 @@ -+/* Asymmetric public-key cryptography data parser -+ * -+ * See Documentation/crypto/asymmetric-keys.txt -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#ifndef _KEYS_ASYMMETRIC_PARSER_H -+#define _KEYS_ASYMMETRIC_PARSER_H -+ -+/* -+ * Key data parser. Called during key instantiation. -+ */ -+struct asymmetric_key_parser { -+ struct list_head link; -+ struct module *owner; -+ const char *name; -+ -+ /* Attempt to parse a key from the data blob passed to add_key() or -+ * keyctl_instantiate(). Should also generate a proposed description -+ * that the caller can optionally use for the key. -+ * -+ * Return EBADMSG if not recognised. -+ */ -+ int (*parse)(struct key_preparsed_payload *prep); -+}; -+ -+extern int register_asymmetric_key_parser(struct asymmetric_key_parser *); -+extern void unregister_asymmetric_key_parser(struct asymmetric_key_parser *); -+ -+#endif /* _KEYS_ASYMMETRIC_PARSER_H */ --- -1.7.11.4 - - -From 171881bb3693176db4d0f85f78066fcdb6266525 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:24:55 +0100 -Subject: [PATCH 07/26] KEYS: Asymmetric public-key algorithm crypto key - subtype - -Add a subtype for supporting asymmetric public-key encryption algorithms such -as DSA (FIPS-186) and RSA (PKCS#1 / RFC1337). - -Signed-off-by: David Howells ---- - 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 -+#include -+#include -+#include -+#include -+#include -+#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 -+ -+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 -+ -+enum pkey_algo { -+ PKEY_ALGO_DSA, -+ PKEY_ALGO_RSA, -+ PKEY_ALGO__LAST -+}; -+ -+extern const char *const pkey_algo[PKEY_ALGO__LAST]; -+ -+enum pkey_hash_algo { -+ PKEY_HASH_MD4, -+ PKEY_HASH_MD5, -+ PKEY_HASH_SHA1, -+ PKEY_HASH_RIPE_MD_160, -+ PKEY_HASH_SHA256, -+ PKEY_HASH_SHA384, -+ PKEY_HASH_SHA512, -+ PKEY_HASH_SHA224, -+ PKEY_HASH__LAST -+}; -+ -+extern const char *const pkey_hash_algo[PKEY_HASH__LAST]; -+ -+enum pkey_id_type { -+ PKEY_ID_PGP, /* OpenPGP generated key ID */ -+ PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ -+ PKEY_ID_TYPE__LAST -+}; -+ -+extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST]; -+ -+/* -+ * Cryptographic data for the public-key subtype of the asymmetric key type. -+ * -+ * Note that this may include private part of the key as well as the public -+ * part. -+ */ -+struct public_key { -+ const struct public_key_algorithm *algo; -+ u8 capabilities; -+#define PKEY_CAN_ENCRYPT 0x01 -+#define PKEY_CAN_DECRYPT 0x02 -+#define PKEY_CAN_SIGN 0x04 -+#define PKEY_CAN_VERIFY 0x08 -+ enum pkey_id_type id_type : 8; -+ union { -+ MPI mpi[5]; -+ struct { -+ MPI p; /* DSA prime */ -+ MPI q; /* DSA group order */ -+ MPI g; /* DSA group generator */ -+ MPI y; /* DSA public-key value = g^x mod p */ -+ MPI x; /* DSA secret exponent (if present) */ -+ } dsa; -+ struct { -+ MPI n; /* RSA public modulus */ -+ MPI e; /* RSA public encryption exponent */ -+ MPI d; /* RSA secret encryption exponent (if present) */ -+ MPI p; /* RSA secret prime (if present) */ -+ MPI q; /* RSA secret prime (if present) */ -+ } rsa; -+ }; -+}; -+ -+extern void public_key_destroy(void *payload); -+ -+/* -+ * Public key cryptography signature data -+ */ -+struct public_key_signature { -+ u8 *digest; -+ u8 digest_size; /* Number of bytes in digest */ -+ u8 nr_mpi; /* Occupancy of mpi[] */ -+ enum pkey_hash_algo pkey_hash_algo : 8; -+ union { -+ MPI mpi[2]; -+ struct { -+ MPI s; /* m^d mod n */ -+ } rsa; -+ struct { -+ MPI r; -+ MPI s; -+ } dsa; -+ }; -+}; -+ -+#endif /* _LINUX_PUBLIC_KEY_H */ --- -1.7.11.4 - - -From 8e45e274bb3f8bb90306e0102a2c48ea1ef179fb Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:25:04 +0100 -Subject: [PATCH 08/26] KEYS: Provide signature verification with an - asymmetric key - -Provide signature verification using an asymmetric-type key to indicate the -public key to be used. - -The API is a single function that can be found in crypto/public_key.h: - - int verify_signature(const struct key *key, - const struct public_key_signature *sig) - -The first argument is the appropriate key to be used and the second argument -is the parsed signature data: - - struct public_key_signature { - u8 *digest; - u16 digest_size; - enum pkey_hash_algo pkey_hash_algo : 8; - union { - MPI mpi[2]; - struct { - MPI s; /* m^d mod n */ - } rsa; - struct { - MPI r; - MPI s; - } dsa; - }; - }; - -This should be filled in prior to calling the function. The hash algorithm -should already have been called and the hash finalised and the output should -be in a buffer pointed to by the 'digest' member. - -Any extra data to be added to the hash by the hash format (eg. PGP) should -have been added by the caller prior to finalising the hash. - -It is assumed that the signature is made up of a number of MPI values. If an -algorithm becomes available for which this is not the case, the above structure -will have to change. - -It is also assumed that it will have been checked that the signature algorithm -matches the key algorithm. - -Signed-off-by: David Howells ---- - 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 -+#include -+#include -+#include -+#include "asymmetric_keys.h" -+ -+/** -+ * verify_signature - Initiate the use of an asymmetric key to verify a signature -+ * @key: The asymmetric key to verify against -+ * @sig: The signature to check -+ * -+ * Returns 0 if successful or else an error. -+ */ -+int verify_signature(const struct key *key, -+ const struct public_key_signature *sig) -+{ -+ const struct asymmetric_key_subtype *subtype; -+ int ret; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ if (key->type != &key_type_asymmetric) -+ return -EINVAL; -+ subtype = asymmetric_key_subtype(key); -+ if (!subtype || -+ !key->payload.data) -+ return -EINVAL; -+ if (!subtype->verify_signature) -+ return -ENOTSUPP; -+ -+ ret = subtype->verify_signature(key, sig); -+ -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(verify_signature); -diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h -index 4b8b6c1..f5b0224 100644 ---- a/include/crypto/public_key.h -+++ b/include/crypto/public_key.h -@@ -101,4 +101,8 @@ struct public_key_signature { - }; - }; - -+struct key; -+extern int verify_signature(const struct key *key, -+ const struct public_key_signature *sig); -+ - #endif /* _LINUX_PUBLIC_KEY_H */ --- -1.7.11.4 - - -From 941e72448fc68f41a56798112a6f20df6bcd0ad0 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:25:22 +0100 -Subject: [PATCH 09/26] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA - signature verification - -Reinstate and export mpi_cmp() and mpi_cmp_ui() from the MPI library for use by -RSA signature verification as per RFC3447 section 5.2.2 step 1. - -Signed-off-by: David Howells ---- - lib/mpi/Makefile | 1 + - lib/mpi/mpi-cmp.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 71 insertions(+) - create mode 100644 lib/mpi/mpi-cmp.c - -diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile -index 45ca90a..019a68c 100644 ---- a/lib/mpi/Makefile -+++ b/lib/mpi/Makefile -@@ -14,6 +14,7 @@ mpi-y = \ - generic_mpih-add1.o \ - mpicoder.o \ - mpi-bit.o \ -+ mpi-cmp.o \ - mpih-cmp.o \ - mpih-div.o \ - mpih-mul.o \ -diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c -new file mode 100644 -index 0000000..1871e7b ---- /dev/null -+++ b/lib/mpi/mpi-cmp.c -@@ -0,0 +1,70 @@ -+/* mpi-cmp.c - MPI functions -+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc. -+ * -+ * This file is part of GnuPG. -+ * -+ * GnuPG is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * GnuPG is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA -+ */ -+ -+#include "mpi-internal.h" -+ -+int mpi_cmp_ui(MPI u, unsigned long v) -+{ -+ mpi_limb_t limb = v; -+ -+ mpi_normalize(u); -+ if (!u->nlimbs && !limb) -+ return 0; -+ if (u->sign) -+ return -1; -+ if (u->nlimbs > 1) -+ return 1; -+ -+ if (u->d[0] == limb) -+ return 0; -+ else if (u->d[0] > limb) -+ return 1; -+ else -+ return -1; -+} -+EXPORT_SYMBOL_GPL(mpi_cmp_ui); -+ -+int mpi_cmp(MPI u, MPI v) -+{ -+ mpi_size_t usize, vsize; -+ int cmp; -+ -+ mpi_normalize(u); -+ mpi_normalize(v); -+ usize = u->nlimbs; -+ vsize = v->nlimbs; -+ if (!u->sign && v->sign) -+ return 1; -+ if (u->sign && !v->sign) -+ return -1; -+ if (usize != vsize && !u->sign && !v->sign) -+ return usize - vsize; -+ if (usize != vsize && u->sign && v->sign) -+ return vsize + usize; -+ if (!usize) -+ return 0; -+ cmp = mpihelp_cmp(u->d, v->d, usize); -+ if (!cmp) -+ return 0; -+ if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0)) -+ return 1; -+ return -1; -+} -+EXPORT_SYMBOL_GPL(mpi_cmp); --- -1.7.11.4 - - -From ca876ff8fde3c6febb8a8578ca0e1608576071bf Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:25:40 +0100 -Subject: [PATCH 10/26] RSA: Implement signature verification algorithm - [PKCS#1 / RFC3447] - -Implement RSA public key cryptography [PKCS#1 / RFC3447]. At this time, only -the signature verification algorithm is supported. This uses the asymmetric -public key subtype to hold its key data. - -Signed-off-by: David Howells ---- - 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 -+#include -+#include -+#include "public_key.h" -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("RSA Public Key Algorithm"); -+ -+#define kenter(FMT, ...) \ -+ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) -+#define kleave(FMT, ...) \ -+ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) -+ -+/* -+ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. -+ */ -+static const u8 RSA_digest_info_MD5[] = { -+ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, -+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ -+ 0x05, 0x00, 0x04, 0x10 -+}; -+ -+static const u8 RSA_digest_info_SHA1[] = { -+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, -+ 0x2B, 0x0E, 0x03, 0x02, 0x1A, -+ 0x05, 0x00, 0x04, 0x14 -+}; -+ -+static const u8 RSA_digest_info_RIPE_MD_160[] = { -+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, -+ 0x2B, 0x24, 0x03, 0x02, 0x01, -+ 0x05, 0x00, 0x04, 0x14 -+}; -+ -+static const u8 RSA_digest_info_SHA224[] = { -+ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, -+ 0x05, 0x00, 0x04, 0x1C -+}; -+ -+static const u8 RSA_digest_info_SHA256[] = { -+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, -+ 0x05, 0x00, 0x04, 0x20 -+}; -+ -+static const u8 RSA_digest_info_SHA384[] = { -+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, -+ 0x05, 0x00, 0x04, 0x30 -+}; -+ -+static const u8 RSA_digest_info_SHA512[] = { -+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, -+ 0x05, 0x00, 0x04, 0x40 -+}; -+ -+static const struct { -+ const u8 *data; -+ size_t size; -+} RSA_ASN1_templates[PKEY_HASH__LAST] = { -+#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } -+ [PKEY_HASH_MD5] = _(MD5), -+ [PKEY_HASH_SHA1] = _(SHA1), -+ [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), -+ [PKEY_HASH_SHA256] = _(SHA256), -+ [PKEY_HASH_SHA384] = _(SHA384), -+ [PKEY_HASH_SHA512] = _(SHA512), -+ [PKEY_HASH_SHA224] = _(SHA224), -+#undef _ -+}; -+ -+/* -+ * RSAVP1() function [RFC3447 sec 5.2.2] -+ */ -+static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) -+{ -+ MPI m; -+ int ret; -+ -+ /* (1) Validate 0 <= s < n */ -+ if (mpi_cmp_ui(s, 0) < 0) { -+ kleave(" = -EBADMSG [s < 0]"); -+ return -EBADMSG; -+ } -+ if (mpi_cmp(s, key->rsa.n) >= 0) { -+ kleave(" = -EBADMSG [s >= n]"); -+ return -EBADMSG; -+ } -+ -+ m = mpi_alloc(0); -+ if (!m) -+ return -ENOMEM; -+ -+ /* (2) m = s^e mod n */ -+ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); -+ if (ret < 0) { -+ mpi_free(m); -+ return ret; -+ } -+ -+ *_m = m; -+ return 0; -+} -+ -+/* -+ * Integer to Octet String conversion [RFC3447 sec 4.1] -+ */ -+static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) -+{ -+ unsigned X_size, x_size; -+ int X_sign; -+ u8 *X; -+ -+ /* Make sure the string is the right length. The number should begin -+ * with { 0x00, 0x01, ... } so we have to account for 15 leading zero -+ * bits not being reported by MPI. -+ */ -+ x_size = mpi_get_nbits(x); -+ pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); -+ if (x_size != xLen * 8 - 15) -+ return -ERANGE; -+ -+ X = mpi_get_buffer(x, &X_size, &X_sign); -+ if (!X) -+ return -ENOMEM; -+ if (X_sign < 0) { -+ kfree(X); -+ return -EBADMSG; -+ } -+ if (X_size != xLen - 1) { -+ kfree(X); -+ return -EBADMSG; -+ } -+ -+ *_X = X; -+ return 0; -+} -+ -+/* -+ * Perform the RSA signature verification. -+ * @H: Value of hash of data and metadata -+ * @EM: The computed signature value -+ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) -+ * @hash_size: The size of H -+ * @asn1_template: The DigestInfo ASN.1 template -+ * @asn1_size: Size of asm1_template[] -+ */ -+static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, -+ const u8 *asn1_template, size_t asn1_size) -+{ -+ unsigned PS_end, T_offset, i; -+ -+ kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); -+ -+ if (k < 2 + 1 + asn1_size + hash_size) -+ return -EBADMSG; -+ -+ /* Decode the EMSA-PKCS1-v1_5 */ -+ if (EM[1] != 0x01) { -+ kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); -+ return -EBADMSG; -+ } -+ -+ T_offset = k - (asn1_size + hash_size); -+ PS_end = T_offset - 1; -+ if (EM[PS_end] != 0x00) { -+ kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); -+ return -EBADMSG; -+ } -+ -+ for (i = 2; i < PS_end; i++) { -+ if (EM[i] != 0xff) { -+ kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); -+ return -EBADMSG; -+ } -+ } -+ -+ if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { -+ kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); -+ return -EBADMSG; -+ } -+ -+ if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { -+ kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); -+ return -EKEYREJECTED; -+ } -+ -+ kleave(" = 0"); -+ return 0; -+} -+ -+/* -+ * Perform the verification step [RFC3447 sec 8.2.2]. -+ */ -+static int RSA_verify_signature(const struct public_key *key, -+ const struct public_key_signature *sig) -+{ -+ size_t tsize; -+ int ret; -+ -+ /* Variables as per RFC3447 sec 8.2.2 */ -+ const u8 *H = sig->digest; -+ u8 *EM = NULL; -+ MPI m = NULL; -+ size_t k; -+ -+ kenter(""); -+ -+ if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) -+ return -ENOTSUPP; -+ -+ /* (1) Check the signature size against the public key modulus size */ -+ k = (mpi_get_nbits(key->rsa.n) + 7) / 8; -+ -+ tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; -+ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); -+ if (tsize != k) { -+ ret = -EBADMSG; -+ goto error; -+ } -+ -+ /* (2b) Apply the RSAVP1 verification primitive to the public key */ -+ ret = RSAVP1(key, sig->rsa.s, &m); -+ if (ret < 0) -+ goto error; -+ -+ /* (2c) Convert the message representative (m) to an encoded message -+ * (EM) of length k octets. -+ * -+ * NOTE! The leading zero byte is suppressed by MPI, so we pass a -+ * pointer to the _preceding_ byte to RSA_verify()! -+ */ -+ ret = RSA_I2OSP(m, k, &EM); -+ if (ret < 0) -+ goto error; -+ -+ ret = RSA_verify(H, EM - 1, k, sig->digest_size, -+ RSA_ASN1_templates[sig->pkey_hash_algo].data, -+ RSA_ASN1_templates[sig->pkey_hash_algo].size); -+ -+error: -+ kfree(EM); -+ mpi_free(m); -+ kleave(" = %d", ret); -+ return ret; -+} -+ -+const struct public_key_algorithm RSA_public_key_algorithm = { -+ .name = "RSA", -+ .n_pub_mpi = 2, -+ .n_sec_mpi = 3, -+ .n_sig_mpi = 1, -+ .verify_signature = RSA_verify_signature, -+}; -+EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); --- -1.7.11.4 - - -From e179a9b04469ea018a8fdb53f11c57222ba540a0 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:28:05 +0100 -Subject: [PATCH 11/26] RSA: Fix signature verification for shorter signatures - -gpg can produce a signature file where length of signature is less than the -modulus size because the amount of space an MPI takes up is kept as low as -possible by discarding leading zeros. This regularly happens for several -modules during the build. - -Fix it by relaxing check in RSA verification code. - -Thanks to Tomas Mraz and Miloslav Trmac for help. - -Signed-off-by: Milan Broz -Signed-off-by: David Howells ---- - crypto/asymmetric_keys/rsa.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c -index 9b31ee2..4a6a069 100644 ---- a/crypto/asymmetric_keys/rsa.c -+++ b/crypto/asymmetric_keys/rsa.c -@@ -224,15 +224,23 @@ static int RSA_verify_signature(const struct public_key *key, - return -ENOTSUPP; - - /* (1) Check the signature size against the public key modulus size */ -- k = (mpi_get_nbits(key->rsa.n) + 7) / 8; -+ k = mpi_get_nbits(key->rsa.n); -+ tsize = mpi_get_nbits(sig->rsa.s); - -- tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; -+ /* According to RFC 4880 sec 3.2, length of MPI is computed starting -+ * from most significant bit. So the RFC 3447 sec 8.2.2 size check -+ * must be relaxed to conform with shorter signatures - so we fail here -+ * only if signature length is longer than modulus size. -+ */ - pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); -- if (tsize != k) { -+ if (k < tsize) { - ret = -EBADMSG; - goto error; - } - -+ /* Round up and convert to octets */ -+ k = (k + 7) / 8; -+ - /* (2b) Apply the RSAVP1 verification primitive to the public key */ - ret = RSAVP1(key, sig->rsa.s, &m); - if (ret < 0) --- -1.7.11.4 - - -From d412c256ea6170b6aeceb9f1eb1737d991473634 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:30:46 +0100 -Subject: [PATCH 12/26] X.509: Implement simple static OID registry - -Implement a simple static OID registry that allows the mapping of an encoded -OID to an enum value for ease of use. - -The OID registry index enum appears in the: - - linux/oid_registry.h - -header file. A script generates the registry from lines in the header file -that look like: - - OID_foo,/*1.2.3.4*/ - -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 ---- - 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 -+ -+/* -+ * 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/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, " \n"; -+ exit(2); -+} -+ -+# -+# Open the file to read from -+# -+open IN_FILE, "<$ARGV[0]" || die; -+while () { -+ 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 -+#include -+#include "oid_registry_data.c" -+ -+/** -+ * look_up_OID - Find an OID registration for the specified data -+ * @data: Binary representation of the OID -+ * @datasize: Size of the binary representation -+ */ -+enum OID look_up_OID(const void *data, size_t datasize) -+{ -+ const unsigned char *octets = data; -+ enum OID oid; -+ unsigned char xhash; -+ unsigned i, j, k, hash; -+ size_t len; -+ -+ /* Hash the OID data */ -+ hash = datasize - 1; -+ -+ for (i = 0; i < datasize; i++) -+ hash += octets[i] * 33; -+ hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash; -+ hash &= 0xff; -+ -+ /* Binary search the OID registry. OIDs are stored in ascending order -+ * of hash value then ascending order of size and then in ascending -+ * order of reverse value. -+ */ -+ i = 0; -+ k = OID__NR; -+ while (i < k) { -+ j = (i + k) / 2; -+ -+ xhash = oid_search_table[j].hash; -+ if (xhash > hash) { -+ k = j; -+ continue; -+ } -+ if (xhash < hash) { -+ i = j + 1; -+ continue; -+ } -+ -+ oid = oid_search_table[j].oid; -+ len = oid_index[oid + 1] - oid_index[oid]; -+ if (len > datasize) { -+ k = j; -+ continue; -+ } -+ if (len < datasize) { -+ i = j + 1; -+ continue; -+ } -+ -+ /* Variation is most likely to be at the tail end of the -+ * OID, so do the comparison in reverse. -+ */ -+ while (len > 0) { -+ unsigned char a = oid_data[oid_index[oid] + --len]; -+ unsigned char b = octets[len]; -+ if (a > b) { -+ k = j; -+ goto next; -+ } -+ if (a < b) { -+ i = j + 1; -+ goto next; -+ } -+ } -+ return oid; -+ next: -+ ; -+ } -+ -+ return OID__NR; -+} -+EXPORT_SYMBOL_GPL(look_up_OID); --- -1.7.11.4 - - -From 098335ed1edc5ec7ae7a346416654e12bb9bcd65 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:30:51 +0100 -Subject: [PATCH 13/26] X.509: Add utility functions to render OIDs as strings - -Add a pair of utility functions to render OIDs as strings. The first takes an -encoded OID and turns it into a "a.b.c.d" form string: - - int sprint_oid(const void *data, size_t datasize, - char *buffer, size_t bufsize); - -The second takes an OID enum index and calls the first on the data held -therein: - - int sprint_OID(enum OID oid, char *buffer, size_t bufsize); - -Signed-off-by: David Howells ---- - 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 - #include -+#include -+#include -+#include - #include "oid_registry_data.c" - - /** -@@ -87,3 +90,81 @@ enum OID look_up_OID(const void *data, size_t datasize) - return OID__NR; - } - EXPORT_SYMBOL_GPL(look_up_OID); -+ -+/* -+ * sprint_OID - Print an Object Identifier into a buffer -+ * @data: The encoded OID to print -+ * @datasize: The size of the encoded OID -+ * @buffer: The buffer to render into -+ * @bufsize: The size of the buffer -+ * -+ * The OID is rendered into the buffer in "a.b.c.d" format and the number of -+ * bytes is returned. -EBADMSG is returned if the data could not be intepreted -+ * and -ENOBUFS if the buffer was too small. -+ */ -+int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize) -+{ -+ const unsigned char *v = data, *end = v + datasize; -+ unsigned long num; -+ unsigned char n; -+ size_t ret; -+ int count; -+ -+ if (v >= end) -+ return -EBADMSG; -+ -+ n = *v++; -+ ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40); -+ buffer += count; -+ bufsize -= count; -+ if (bufsize == 0) -+ return -ENOBUFS; -+ -+ while (v < end) { -+ num = 0; -+ n = *v++; -+ if (!(n & 0x80)) { -+ num = n; -+ } else { -+ num = n & 0x7f; -+ do { -+ if (v >= end) -+ return -EBADMSG; -+ n = *v++; -+ num <<= 7; -+ num |= n & 0x7f; -+ } while (n & 0x80); -+ } -+ ret += count = snprintf(buffer, bufsize, ".%lu", num); -+ buffer += count; -+ bufsize -= count; -+ if (bufsize == 0) -+ return -ENOBUFS; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(sprint_oid); -+ -+/** -+ * sprint_OID - Print an Object Identifier into a buffer -+ * @oid: The OID to print -+ * @buffer: The buffer to render into -+ * @bufsize: The size of the buffer -+ * -+ * The OID is rendered into the buffer in "a.b.c.d" format and the number of -+ * bytes is returned. -+ */ -+int sprint_OID(enum OID oid, char *buffer, size_t bufsize) -+{ -+ int ret; -+ -+ BUG_ON(oid >= OID__NR); -+ -+ ret = sprint_oid(oid_data + oid_index[oid], -+ oid_index[oid + 1] - oid_index[oid], -+ buffer, bufsize); -+ BUG_ON(ret == -EBADMSG); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(sprint_OID); --- -1.7.11.4 - - -From 3ddb8a2f1fe420777491641d39328741d9a28565 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Fri, 21 Sep 2012 23:31:13 +0100 -Subject: [PATCH 14/26] X.509: Add simple ASN.1 grammar compiler - -Add a simple ASN.1 grammar compiler. This produces a bytecode output that can -be fed to a decoder to inform the decoder how to interpret the ASN.1 stream it -is trying to parse. - -Action functions can be specified in the grammar by interpolating: - - ({ foo }) - -after a type, for example: - - SubjectPublicKeyInfo ::= SEQUENCE { - algorithm AlgorithmIdentifier, - subjectPublicKey BIT STRING ({ do_key_data }) - } - -The decoder is expected to call these after matching this type and parsing the -contents if it is a constructed type. - -The grammar compiler does not currently support the SET type (though it does -support SET OF) as I can't see a good way of tracking which members have been -encountered yet without using up extra stack space. - -Currently, the grammar compiler will fail if more than 256 bytes of bytecode -would be produced or more than 256 actions have been specified as it uses -8-bit jump values and action indices to keep space usage down. - -Signed-off-by: David Howells ---- - 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 -+#endif -+#include -+ -+typedef int (*asn1_action_t)(void *context, -+ size_t hdrlen, /* In case of ANY type */ -+ unsigned char tag, /* In case of ANY type */ -+ const void *value, size_t vlen); -+ -+struct asn1_decoder { -+ const unsigned char *machine; -+ size_t machlen; -+ const asn1_action_t *actions; -+}; -+ -+enum asn1_opcode { -+ /* The tag-matching ops come first and the odd-numbered slots -+ * are for OR_SKIP ops. -+ */ -+#define ASN1_OP_MATCH__SKIP 0x01 -+#define ASN1_OP_MATCH__ACT 0x02 -+#define ASN1_OP_MATCH__JUMP 0x04 -+#define ASN1_OP_MATCH__ANY 0x08 -+#define ASN1_OP_MATCH__COND 0x10 -+ -+ ASN1_OP_MATCH = 0x00, -+ ASN1_OP_MATCH_OR_SKIP = 0x01, -+ ASN1_OP_MATCH_ACT = 0x02, -+ ASN1_OP_MATCH_ACT_OR_SKIP = 0x03, -+ ASN1_OP_MATCH_JUMP = 0x04, -+ ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, -+ ASN1_OP_MATCH_ANY = 0x08, -+ ASN1_OP_MATCH_ANY_ACT = 0x0a, -+ /* Everything before here matches unconditionally */ -+ -+ ASN1_OP_COND_MATCH_OR_SKIP = 0x11, -+ ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, -+ ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, -+ ASN1_OP_COND_MATCH_ANY = 0x18, -+ ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, -+ -+ /* Everything before here will want a tag from the data */ -+#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT -+ -+ /* These are here to help fill up space */ -+ ASN1_OP_COND_FAIL = 0x1b, -+ ASN1_OP_COMPLETE = 0x1c, -+ ASN1_OP_ACT = 0x1d, -+ ASN1_OP_RETURN = 0x1e, -+ -+ /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ -+ ASN1_OP_END_SEQ = 0x20, -+ ASN1_OP_END_SET = 0x21, -+ ASN1_OP_END_SEQ_OF = 0x22, -+ ASN1_OP_END_SET_OF = 0x23, -+ ASN1_OP_END_SEQ_ACT = 0x24, -+ ASN1_OP_END_SET_ACT = 0x25, -+ ASN1_OP_END_SEQ_OF_ACT = 0x26, -+ ASN1_OP_END_SET_OF_ACT = 0x27, -+#define ASN1_OP_END__SET 0x01 -+#define ASN1_OP_END__OF 0x02 -+#define ASN1_OP_END__ACT 0x04 -+ -+ ASN1_OP__NR -+}; -+ -+#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG) -+#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG) -+#define _jump_target(N) (N) -+#define _action(N) (N) -+ -+#endif /* _LINUX_ASN1_BER_BYTECODE_H */ -diff --git a/init/Kconfig b/init/Kconfig -index af6c7f8..66cc885 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1612,4 +1612,12 @@ config PADATA - depends on SMP - bool - -+config ASN1 -+ tristate -+ help -+ Build a simple ASN.1 grammar compiler that produces a bytecode output -+ that can be interpreted by the ASN.1 stream decoder and used to -+ inform it as to what tags are to be expected in a stream and what -+ functions to call on what tags. -+ - source "kernel/Kconfig.locks" -diff --git a/scripts/.gitignore b/scripts/.gitignore -index 65f362d..fb070fa 100644 ---- a/scripts/.gitignore -+++ b/scripts/.gitignore -@@ -10,3 +10,4 @@ ihex2fw - recordmcount - docproc - sortextable -+asn1_compiler -diff --git a/scripts/Makefile b/scripts/Makefile -index a55b006..01e7adb 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash - hostprogs-$(CONFIG_IKCONFIG) += bin2c - hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount - hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable -+hostprogs-$(CONFIG_ASN1) += asn1_compiler - - HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include -+HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include - - always := $(hostprogs-y) $(hostprogs-m) - -diff --git a/scripts/Makefile.build b/scripts/Makefile.build -index ff1720d..0e801c3 100644 ---- a/scripts/Makefile.build -+++ b/scripts/Makefile.build -@@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@ - $(obj)/%.lds: $(src)/%.lds.S FORCE - $(call if_changed_dep,cpp_lds_S) - -+# ASN.1 grammar -+# --------------------------------------------------------------------------- -+quiet_cmd_asn1_compiler = ASN.1 $@ -+ cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ -+ $(subst .h,.c,$@) $(subst .c,.h,$@) -+ -+.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h -+ -+$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler -+ $(call cmd,asn1_compiler) -+ - # Build the compiled-in targets - # --------------------------------------------------------------------------- - -diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c -new file mode 100644 -index 0000000..db0e5cd ---- /dev/null -+++ b/scripts/asn1_compiler.c -@@ -0,0 +1,1545 @@ -+/* Simplified ASN.1 notation parser -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 \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 \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 \n"); -+ fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name); -+ fprintf(out, "\n"); -+ if (ferror(out)) { -+ perror(outputname); -+ exit(1); -+ } -+ -+ /* Tabulate the action functions we might have to call */ -+ fprintf(hdr, "\n"); -+ index = 0; -+ for (action = action_list; action; action = action->next) { -+ action->index = index++; -+ fprintf(hdr, -+ "extern int %s(void *, size_t, unsigned char," -+ " const void *, size_t);\n", -+ action->name); -+ } -+ fprintf(hdr, "\n"); -+ -+ fprintf(out, "enum %s_actions {\n", grammar_name); -+ for (action = action_list; action; action = action->next) -+ fprintf(out, "\tACT_%s = %u,\n", -+ action->name, action->index); -+ fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions); -+ fprintf(out, "};\n"); -+ -+ fprintf(out, "\n"); -+ fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n", -+ grammar_name, grammar_name); -+ for (action = action_list; action; action = action->next) -+ fprintf(out, "\t[%4u] = %s,\n", action->index, action->name); -+ fprintf(out, "};\n"); -+ -+ if (ferror(out)) { -+ perror(outputname); -+ exit(1); -+ } -+ -+ /* We do two passes - the first one calculates all the offsets */ -+ printf("Pass 1\n"); -+ nr_entries = 0; -+ root = &type_list[0]; -+ render_element(NULL, root->element, NULL); -+ render_opcode(NULL, "ASN1_OP_COMPLETE,\n"); -+ render_out_of_line_list(NULL); -+ -+ for (e = element_list; e; e = e->list_next) -+ e->flags &= ~ELEMENT_RENDERED; -+ -+ /* And then we actually render */ -+ printf("Pass 2\n"); -+ fprintf(out, "\n"); -+ fprintf(out, "static const unsigned char %s_machine[] = {\n", -+ grammar_name); -+ -+ nr_entries = 0; -+ root = &type_list[0]; -+ render_element(out, root->element, NULL); -+ render_opcode(out, "ASN1_OP_COMPLETE,\n"); -+ render_out_of_line_list(out); -+ -+ fprintf(out, "};\n"); -+ -+ fprintf(out, "\n"); -+ fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name); -+ fprintf(out, "\t.machine = %s_machine,\n", grammar_name); -+ fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name); -+ fprintf(out, "\t.actions = %s_action_table,\n", grammar_name); -+ fprintf(out, "};\n"); -+} -+ -+/* -+ * Render the out-of-line elements -+ */ -+static void render_out_of_line_list(FILE *out) -+{ -+ struct element *e, *ce; -+ const char *act; -+ int entry; -+ -+ while ((e = render_list)) { -+ render_list = e->render_next; -+ if (!render_list) -+ render_list_p = &render_list; -+ -+ render_more(out, "\n"); -+ e->entry_index = entry = nr_entries; -+ render_depth++; -+ for (ce = e->children; ce; ce = ce->next) -+ render_element(out, ce, NULL); -+ render_depth--; -+ -+ act = e->action ? "_ACT" : ""; -+ switch (e->compound) { -+ case SEQUENCE: -+ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); -+ break; -+ case SEQUENCE_OF: -+ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); -+ render_opcode(out, "_jump_target(%u),\n", entry); -+ break; -+ case SET: -+ render_opcode(out, "ASN1_OP_END_SET%s,\n", act); -+ break; -+ case SET_OF: -+ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); -+ render_opcode(out, "_jump_target(%u),\n", entry); -+ break; -+ } -+ if (e->action) -+ render_opcode(out, "_action(ACT_%s),\n", -+ e->action->name); -+ render_opcode(out, "ASN1_OP_RETURN,\n"); -+ } -+} -+ -+/* -+ * Render an element. -+ */ -+static void render_element(FILE *out, struct element *e, struct element *tag) -+{ -+ struct element *ec; -+ const char *cond, *act; -+ int entry, skippable = 0, outofline = 0; -+ -+ if (e->flags & ELEMENT_SKIPPABLE || -+ (tag && tag->flags & ELEMENT_SKIPPABLE)) -+ skippable = 1; -+ -+ if ((e->type_def && e->type_def->ref_count > 1) || -+ skippable) -+ outofline = 1; -+ -+ if (e->type_def && out) { -+ render_more(out, "\t// %*.*s\n", -+ (int)e->type_def->name->size, (int)e->type_def->name->size, -+ e->type_def->name->value); -+ } -+ -+ /* Render the operation */ -+ cond = (e->flags & ELEMENT_CONDITIONAL || -+ (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; -+ act = e->action ? "_ACT" : ""; -+ switch (e->compound) { -+ case ANY: -+ render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); -+ if (e->name) -+ render_more(out, "\t\t// %*.*s", -+ (int)e->name->size, (int)e->name->size, -+ e->name->value); -+ render_more(out, "\n"); -+ goto dont_render_tag; -+ -+ case TAG_OVERRIDE: -+ render_element(out, e->children, e); -+ return; -+ -+ case SEQUENCE: -+ case SEQUENCE_OF: -+ case SET: -+ case SET_OF: -+ render_opcode(out, "ASN1_OP_%sMATCH%s%s,", -+ cond, -+ outofline ? "_JUMP" : "", -+ skippable ? "_OR_SKIP" : ""); -+ break; -+ -+ case CHOICE: -+ goto dont_render_tag; -+ -+ case TYPE_REF: -+ if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) -+ goto dont_render_tag; -+ default: -+ render_opcode(out, "ASN1_OP_%sMATCH%s%s,", -+ cond, act, -+ skippable ? "_OR_SKIP" : ""); -+ break; -+ } -+ -+ if (e->name) -+ render_more(out, "\t\t// %*.*s", -+ (int)e->name->size, (int)e->name->size, -+ e->name->value); -+ render_more(out, "\n"); -+ -+ /* Render the tag */ -+ if (!tag) -+ tag = e; -+ if (tag->class == ASN1_UNIV && -+ tag->tag != 14 && -+ tag->tag != 15 && -+ tag->tag != 31) -+ render_opcode(out, "_tag(%s, %s, %s),\n", -+ asn1_classes[tag->class], -+ asn1_methods[tag->method | e->method], -+ asn1_universal_tags[tag->tag]); -+ else -+ render_opcode(out, "_tagn(%s, %s, %2u),\n", -+ asn1_classes[tag->class], -+ asn1_methods[tag->method | e->method], -+ tag->tag); -+ tag = NULL; -+dont_render_tag: -+ -+ /* Deal with compound types */ -+ switch (e->compound) { -+ case TYPE_REF: -+ render_element(out, e->type->type->element, tag); -+ if (e->action) -+ render_opcode(out, "ASN1_OP_ACT,\n"); -+ break; -+ -+ case SEQUENCE: -+ if (outofline) { -+ /* Render out-of-line for multiple use or -+ * skipability */ -+ render_opcode(out, "_jump_target(%u),", e->entry_index); -+ if (e->type_def && e->type_def->name) -+ render_more(out, "\t\t// --> %*.*s", -+ (int)e->type_def->name->size, -+ (int)e->type_def->name->size, -+ e->type_def->name->value); -+ render_more(out, "\n"); -+ if (!(e->flags & ELEMENT_RENDERED)) { -+ e->flags |= ELEMENT_RENDERED; -+ *render_list_p = e; -+ render_list_p = &e->render_next; -+ } -+ return; -+ } else { -+ /* Render inline for single use */ -+ render_depth++; -+ for (ec = e->children; ec; ec = ec->next) -+ render_element(out, ec, NULL); -+ render_depth--; -+ render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); -+ } -+ break; -+ -+ case SEQUENCE_OF: -+ case SET_OF: -+ if (outofline) { -+ /* Render out-of-line for multiple use or -+ * skipability */ -+ render_opcode(out, "_jump_target(%u),", e->entry_index); -+ if (e->type_def && e->type_def->name) -+ render_more(out, "\t\t// --> %*.*s", -+ (int)e->type_def->name->size, -+ (int)e->type_def->name->size, -+ e->type_def->name->value); -+ render_more(out, "\n"); -+ if (!(e->flags & ELEMENT_RENDERED)) { -+ e->flags |= ELEMENT_RENDERED; -+ *render_list_p = e; -+ render_list_p = &e->render_next; -+ } -+ return; -+ } else { -+ /* Render inline for single use */ -+ entry = nr_entries; -+ render_depth++; -+ render_element(out, e->children, NULL); -+ render_depth--; -+ if (e->compound == SEQUENCE_OF) -+ render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); -+ else -+ render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); -+ render_opcode(out, "_jump_target(%u),\n", entry); -+ } -+ break; -+ -+ case SET: -+ /* I can't think of a nice way to do SET support without having -+ * a stack of bitmasks to make sure no element is repeated. -+ * The bitmask has also to be checked that no non-optional -+ * elements are left out whilst not preventing optional -+ * elements from being left out. -+ */ -+ fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); -+ exit(1); -+ -+ case CHOICE: -+ for (ec = e->children; ec; ec = ec->next) -+ render_element(out, ec, NULL); -+ if (!skippable) -+ render_opcode(out, "ASN1_OP_COND_FAIL,\n"); -+ if (e->action) -+ render_opcode(out, "ASN1_OP_ACT,\n"); -+ break; -+ -+ default: -+ break; -+ } -+ -+ if (e->action) -+ render_opcode(out, "_action(ACT_%s),\n", e->action->name); -+} --- -1.7.11.4 - - -From 8ea3f94cc16a23e3edbebf12f4223e654eb8219d Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:11:16 +0100 -Subject: [PATCH 15/26] X.509: Add an ASN.1 decoder - -Add an ASN.1 BER/DER/CER decoder. This uses the bytecode from the ASN.1 -compiler in the previous patch to inform it as to what to expect to find in the -encoded byte stream. The output from the compiler also tells it what functions -to call on what tags, thus allowing the caller to retrieve information. - -The decoder is called as follows: - - int asn1_decoder(const struct asn1_decoder *decoder, - void *context, - const unsigned char *data, - size_t datalen); - -The decoder argument points to the bytecode from the ASN.1 compiler. context -is the caller's context and is passed to the action functions. data and -datalen define the byte stream to be decoded. - - -Note that the decoder is currently limited to datalen being less than 64K. -This reduces the amount of stack space used by the decoder because ASN.1 is a -nested construct. Similarly, the decoder is limited to a maximum of 10 levels -of constructed data outside of a leaf node also in an effort to keep stack -usage down. - -These restrictions can be raised if necessary. - -Signed-off-by: David Howells ---- - 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 -+ -+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 -+ - obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o - obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o - -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 -+#include -+#include -+#include -+#include -+ -+static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { -+ /* OPC TAG JMP ACT */ -+ [ASN1_OP_MATCH] = 1 + 1, -+ [ASN1_OP_MATCH_OR_SKIP] = 1 + 1, -+ [ASN1_OP_MATCH_ACT] = 1 + 1 + 1, -+ [ASN1_OP_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, -+ [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, -+ [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, -+ [ASN1_OP_MATCH_ANY] = 1, -+ [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, -+ [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, -+ [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, -+ [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, -+ [ASN1_OP_COND_MATCH_ANY] = 1, -+ [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, -+ [ASN1_OP_COND_FAIL] = 1, -+ [ASN1_OP_COMPLETE] = 1, -+ [ASN1_OP_ACT] = 1 + 1, -+ [ASN1_OP_RETURN] = 1, -+ [ASN1_OP_END_SEQ] = 1, -+ [ASN1_OP_END_SEQ_OF] = 1 + 1, -+ [ASN1_OP_END_SET] = 1, -+ [ASN1_OP_END_SET_OF] = 1 + 1, -+ [ASN1_OP_END_SEQ_ACT] = 1 + 1, -+ [ASN1_OP_END_SEQ_OF_ACT] = 1 + 1 + 1, -+ [ASN1_OP_END_SET_ACT] = 1 + 1, -+ [ASN1_OP_END_SET_OF_ACT] = 1 + 1 + 1, -+}; -+ -+/* -+ * Find the length of an indefinite length object -+ */ -+static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, -+ const char **_errmsg, size_t *_err_dp) -+{ -+ unsigned char tag, tmp; -+ size_t dp = 0, len, n; -+ int indef_level = 1; -+ -+next_tag: -+ if (unlikely(datalen - dp < 2)) { -+ if (datalen == dp) -+ goto missing_eoc; -+ goto data_overrun_error; -+ } -+ -+ /* Extract a tag from the data */ -+ tag = data[dp++]; -+ if (tag == 0) { -+ /* It appears to be an EOC. */ -+ if (data[dp++] != 0) -+ goto invalid_eoc; -+ if (--indef_level <= 0) -+ return dp; -+ goto next_tag; -+ } -+ -+ if (unlikely((tag & 0x1f) == 0x1f)) { -+ do { -+ if (unlikely(datalen - dp < 2)) -+ goto data_overrun_error; -+ tmp = data[dp++]; -+ } while (tmp & 0x80); -+ } -+ -+ /* Extract the length */ -+ len = data[dp++]; -+ if (len < 0x7f) { -+ dp += len; -+ goto next_tag; -+ } -+ -+ if (unlikely(len == 0x80)) { -+ /* Indefinite length */ -+ if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5)) -+ goto indefinite_len_primitive; -+ indef_level++; -+ goto next_tag; -+ } -+ -+ n = len - 0x80; -+ if (unlikely(n > sizeof(size_t) - 1)) -+ goto length_too_long; -+ if (unlikely(n > datalen - dp)) -+ goto data_overrun_error; -+ for (len = 0; n > 0; n--) { -+ len <<= 8; -+ len |= data[dp++]; -+ } -+ dp += len; -+ goto next_tag; -+ -+length_too_long: -+ *_errmsg = "Unsupported length"; -+ goto error; -+indefinite_len_primitive: -+ *_errmsg = "Indefinite len primitive not permitted"; -+ goto error; -+invalid_eoc: -+ *_errmsg = "Invalid length EOC"; -+ goto error; -+data_overrun_error: -+ *_errmsg = "Data overrun error"; -+ goto error; -+missing_eoc: -+ *_errmsg = "Missing EOC in indefinite len cons"; -+error: -+ *_err_dp = dp; -+ return -1; -+} -+ -+/** -+ * asn1_ber_decoder - Decoder BER/DER/CER ASN.1 according to pattern -+ * @decoder: The decoder definition (produced by asn1_compiler) -+ * @context: The caller's context (to be passed to the action functions) -+ * @data: The encoded data -+ * @datasize: The size of the encoded data -+ * -+ * Decode BER/DER/CER encoded ASN.1 data according to a bytecode pattern -+ * produced by asn1_compiler. Action functions are called on marked tags to -+ * allow the caller to retrieve significant data. -+ * -+ * LIMITATIONS: -+ * -+ * To keep down the amount of stack used by this function, the following limits -+ * have been imposed: -+ * -+ * (1) This won't handle datalen > 65535 without increasing the size of the -+ * cons stack elements and length_too_long checking. -+ * -+ * (2) The stack of constructed types is 10 deep. If the depth of non-leaf -+ * constructed types exceeds this, the decode will fail. -+ * -+ * (3) The SET type (not the SET OF type) isn't really supported as tracking -+ * what members of the set have been seen is a pain. -+ */ -+int asn1_ber_decoder(const struct asn1_decoder *decoder, -+ void *context, -+ const unsigned char *data, -+ size_t datalen) -+{ -+ const unsigned char *machine = decoder->machine; -+ const asn1_action_t *actions = decoder->actions; -+ size_t machlen = decoder->machlen; -+ enum asn1_opcode op; -+ unsigned char tag = 0, csp = 0, jsp = 0, optag = 0, hdr = 0; -+ const char *errmsg; -+ size_t pc = 0, dp = 0, tdp = 0, len = 0; -+ int ret; -+ -+ unsigned char flags = 0; -+#define FLAG_INDEFINITE_LENGTH 0x01 -+#define FLAG_MATCHED 0x02 -+#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag -+ * - ie. whether or not we are going to parse -+ * a compound type. -+ */ -+ -+#define NR_CONS_STACK 10 -+ unsigned short cons_dp_stack[NR_CONS_STACK]; -+ unsigned short cons_datalen_stack[NR_CONS_STACK]; -+ unsigned char cons_hdrlen_stack[NR_CONS_STACK]; -+#define NR_JUMP_STACK 10 -+ unsigned char jump_stack[NR_JUMP_STACK]; -+ -+ if (datalen > 65535) -+ return -EMSGSIZE; -+ -+next_op: -+ pr_debug("next_op: pc=\e[32m%zu\e[m/%zu dp=\e[33m%zu\e[m/%zu C=%d J=%d\n", -+ pc, machlen, dp, datalen, csp, jsp); -+ if (unlikely(pc >= machlen)) -+ goto machine_overrun_error; -+ op = machine[pc]; -+ if (unlikely(pc + asn1_op_lengths[op] > machlen)) -+ goto machine_overrun_error; -+ -+ /* If this command is meant to match a tag, then do that before -+ * evaluating the command. -+ */ -+ if (op <= ASN1_OP__MATCHES_TAG) { -+ unsigned char tmp; -+ -+ /* Skip conditional matches if possible */ -+ if ((op & ASN1_OP_MATCH__COND && -+ flags & FLAG_MATCHED) || -+ dp == datalen) { -+ pc += asn1_op_lengths[op]; -+ goto next_op; -+ } -+ -+ flags = 0; -+ hdr = 2; -+ -+ /* Extract a tag from the data */ -+ if (unlikely(dp >= datalen - 1)) -+ goto data_overrun_error; -+ tag = data[dp++]; -+ if (unlikely((tag & 0x1f) == 0x1f)) -+ goto long_tag_not_supported; -+ -+ if (op & ASN1_OP_MATCH__ANY) { -+ pr_debug("- any %02x\n", tag); -+ } else { -+ /* Extract the tag from the machine -+ * - Either CONS or PRIM are permitted in the data if -+ * CONS is not set in the op stream, otherwise CONS -+ * is mandatory. -+ */ -+ optag = machine[pc + 1]; -+ flags |= optag & FLAG_CONS; -+ -+ /* Determine whether the tag matched */ -+ tmp = optag ^ tag; -+ tmp &= ~(optag & ASN1_CONS_BIT); -+ pr_debug("- match? %02x %02x %02x\n", tag, optag, tmp); -+ if (tmp != 0) { -+ /* All odd-numbered tags are MATCH_OR_SKIP. */ -+ if (op & ASN1_OP_MATCH__SKIP) { -+ pc += asn1_op_lengths[op]; -+ dp--; -+ goto next_op; -+ } -+ goto tag_mismatch; -+ } -+ } -+ flags |= FLAG_MATCHED; -+ -+ len = data[dp++]; -+ if (len > 0x7f) { -+ if (unlikely(len == 0x80)) { -+ /* Indefinite length */ -+ if (unlikely(!(tag & ASN1_CONS_BIT))) -+ goto indefinite_len_primitive; -+ flags |= FLAG_INDEFINITE_LENGTH; -+ if (unlikely(2 > datalen - dp)) -+ goto data_overrun_error; -+ } else { -+ int n = len - 0x80; -+ if (unlikely(n > 2)) -+ goto length_too_long; -+ if (unlikely(dp >= datalen - n)) -+ goto data_overrun_error; -+ hdr += n; -+ for (len = 0; n > 0; n--) { -+ len <<= 8; -+ len |= data[dp++]; -+ } -+ if (unlikely(len > datalen - dp)) -+ goto data_overrun_error; -+ } -+ } -+ -+ if (flags & FLAG_CONS) { -+ /* For expected compound forms, we stack the positions -+ * of the start and end of the data. -+ */ -+ if (unlikely(csp >= NR_CONS_STACK)) -+ goto cons_stack_overflow; -+ cons_dp_stack[csp] = dp; -+ cons_hdrlen_stack[csp] = hdr; -+ if (!(flags & FLAG_INDEFINITE_LENGTH)) { -+ cons_datalen_stack[csp] = datalen; -+ datalen = dp + len; -+ } else { -+ cons_datalen_stack[csp] = 0; -+ } -+ csp++; -+ } -+ -+ pr_debug("- TAG: %02x %zu%s\n", -+ tag, len, flags & FLAG_CONS ? " CONS" : ""); -+ tdp = dp; -+ } -+ -+ /* Decide how to handle the operation */ -+ switch (op) { -+ case ASN1_OP_MATCH_ANY_ACT: -+ case ASN1_OP_COND_MATCH_ANY_ACT: -+ ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); -+ if (ret < 0) -+ return ret; -+ goto skip_data; -+ -+ case ASN1_OP_MATCH_ACT: -+ case ASN1_OP_MATCH_ACT_OR_SKIP: -+ case ASN1_OP_COND_MATCH_ACT_OR_SKIP: -+ ret = actions[machine[pc + 2]](context, hdr, tag, data + dp, len); -+ if (ret < 0) -+ return ret; -+ goto skip_data; -+ -+ case ASN1_OP_MATCH: -+ case ASN1_OP_MATCH_OR_SKIP: -+ case ASN1_OP_MATCH_ANY: -+ case ASN1_OP_COND_MATCH_OR_SKIP: -+ case ASN1_OP_COND_MATCH_ANY: -+ skip_data: -+ if (!(flags & FLAG_CONS)) { -+ if (flags & FLAG_INDEFINITE_LENGTH) { -+ len = asn1_find_indefinite_length( -+ data + dp, datalen - dp, &errmsg, &dp); -+ if (len < 0) -+ goto error; -+ } -+ pr_debug("- LEAF: %zu\n", len); -+ dp += len; -+ } -+ pc += asn1_op_lengths[op]; -+ goto next_op; -+ -+ case ASN1_OP_MATCH_JUMP: -+ case ASN1_OP_MATCH_JUMP_OR_SKIP: -+ case ASN1_OP_COND_MATCH_JUMP_OR_SKIP: -+ pr_debug("- MATCH_JUMP\n"); -+ if (unlikely(jsp == NR_JUMP_STACK)) -+ goto jump_stack_overflow; -+ jump_stack[jsp++] = pc + asn1_op_lengths[op]; -+ pc = machine[pc + 2]; -+ goto next_op; -+ -+ case ASN1_OP_COND_FAIL: -+ if (unlikely(!(flags & FLAG_MATCHED))) -+ goto tag_mismatch; -+ pc += asn1_op_lengths[op]; -+ goto next_op; -+ -+ case ASN1_OP_COMPLETE: -+ if (unlikely(jsp != 0 || csp != 0)) { -+ pr_err("ASN.1 decoder error: Stacks not empty at completion (%u, %u)\n", -+ jsp, csp); -+ return -EBADMSG; -+ } -+ return 0; -+ -+ case ASN1_OP_END_SET: -+ case ASN1_OP_END_SET_ACT: -+ if (unlikely(!(flags & FLAG_MATCHED))) -+ goto tag_mismatch; -+ case ASN1_OP_END_SEQ: -+ case ASN1_OP_END_SET_OF: -+ case ASN1_OP_END_SEQ_OF: -+ case ASN1_OP_END_SEQ_ACT: -+ case ASN1_OP_END_SET_OF_ACT: -+ case ASN1_OP_END_SEQ_OF_ACT: -+ if (unlikely(csp <= 0)) -+ goto cons_stack_underflow; -+ csp--; -+ tdp = cons_dp_stack[csp]; -+ hdr = cons_hdrlen_stack[csp]; -+ len = datalen; -+ datalen = cons_datalen_stack[csp]; -+ pr_debug("- end cons t=%zu dp=%zu l=%zu/%zu\n", -+ tdp, dp, len, datalen); -+ if (datalen == 0) { -+ /* Indefinite length - check for the EOC. */ -+ datalen = len; -+ if (unlikely(datalen - dp < 2)) -+ goto data_overrun_error; -+ if (data[dp++] != 0) { -+ if (op & ASN1_OP_END__OF) { -+ dp--; -+ csp++; -+ pc = machine[pc + 1]; -+ pr_debug("- continue\n"); -+ goto next_op; -+ } -+ goto missing_eoc; -+ } -+ if (data[dp++] != 0) -+ goto invalid_eoc; -+ len = dp - tdp - 2; -+ } else { -+ if (dp < len && (op & ASN1_OP_END__OF)) { -+ datalen = len; -+ csp++; -+ pc = machine[pc + 1]; -+ pr_debug("- continue\n"); -+ goto next_op; -+ } -+ if (dp != len) -+ goto cons_length_error; -+ len -= tdp; -+ pr_debug("- cons len l=%zu d=%zu\n", len, dp - tdp); -+ } -+ -+ if (op & ASN1_OP_END__ACT) { -+ unsigned char act; -+ if (op & ASN1_OP_END__OF) -+ act = machine[pc + 2]; -+ else -+ act = machine[pc + 1]; -+ ret = actions[act](context, hdr, 0, data + tdp, len); -+ } -+ pc += asn1_op_lengths[op]; -+ goto next_op; -+ -+ case ASN1_OP_ACT: -+ ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); -+ pc += asn1_op_lengths[op]; -+ goto next_op; -+ -+ case ASN1_OP_RETURN: -+ if (unlikely(jsp <= 0)) -+ goto jump_stack_underflow; -+ pc = jump_stack[--jsp]; -+ goto next_op; -+ -+ default: -+ break; -+ } -+ -+ /* Shouldn't reach here */ -+ pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op); -+ return -EBADMSG; -+ -+data_overrun_error: -+ errmsg = "Data overrun error"; -+ goto error; -+machine_overrun_error: -+ errmsg = "Machine overrun error"; -+ goto error; -+jump_stack_underflow: -+ errmsg = "Jump stack underflow"; -+ goto error; -+jump_stack_overflow: -+ errmsg = "Jump stack overflow"; -+ goto error; -+cons_stack_underflow: -+ errmsg = "Cons stack underflow"; -+ goto error; -+cons_stack_overflow: -+ errmsg = "Cons stack overflow"; -+ goto error; -+cons_length_error: -+ errmsg = "Cons length error"; -+ goto error; -+missing_eoc: -+ errmsg = "Missing EOC in indefinite len cons"; -+ goto error; -+invalid_eoc: -+ errmsg = "Invalid length EOC"; -+ goto error; -+length_too_long: -+ errmsg = "Unsupported length"; -+ goto error; -+indefinite_len_primitive: -+ errmsg = "Indefinite len primitive not permitted"; -+ goto error; -+tag_mismatch: -+ errmsg = "Unexpected tag"; -+ goto error; -+long_tag_not_supported: -+ errmsg = "Long tag not supported"; -+error: -+ pr_debug("\nASN1: %s [m=%zu d=%zu ot=%02x t=%02x l=%zu]\n", -+ errmsg, pc, dp, optag, tag, len); -+ return -EBADMSG; -+} -+EXPORT_SYMBOL_GPL(asn1_ber_decoder); --- -1.7.11.4 - - -From f055a9091c35be0171d39ca8e76bb4677d89eef1 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:11:27 +0100 -Subject: [PATCH 16/26] MPILIB: Provide a function to read raw data into an - MPI - -Provide a function to read raw data of a predetermined size into an MPI rather -than expecting the size to be encoded within the data. The data is assumed to -represent an unsigned integer, and the resulting MPI will be positive. - -The function looks like this: - - MPI mpi_read_raw_data(const void *, size_t); - -This is useful for reading ASN.1 integer primitives where the length is encoded -in the ASN.1 metadata. - -Signed-off-by: David Howells ---- - 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 -+#include - #include "mpi-internal.h" - - #define MAX_EXTERN_MPI_BITS 16384 - -+/** -+ * mpi_read_raw_data - Read a raw byte stream as a positive integer -+ * @xbuffer: The data to read -+ * @nbytes: The amount of data to read -+ */ -+MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes) -+{ -+ const uint8_t *buffer = xbuffer; -+ int i, j; -+ unsigned nbits, nlimbs; -+ mpi_limb_t a; -+ MPI val = NULL; -+ -+ while (nbytes >= 0 && buffer[0] == 0) { -+ buffer++; -+ nbytes--; -+ } -+ -+ nbits = nbytes * 8; -+ if (nbits > MAX_EXTERN_MPI_BITS) { -+ pr_info("MPI: mpi too large (%u bits)\n", nbits); -+ return NULL; -+ } -+ if (nbytes > 0) -+ nbits -= count_leading_zeros(buffer[0]); -+ else -+ nbits = 0; -+ -+ nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; -+ val = mpi_alloc(nlimbs); -+ if (!val) -+ return NULL; -+ val->nbits = nbits; -+ val->sign = 0; -+ val->nlimbs = nlimbs; -+ -+ if (nbytes > 0) { -+ i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; -+ i %= BYTES_PER_MPI_LIMB; -+ for (j = nlimbs; j > 0; j--) { -+ a = 0; -+ for (; i < BYTES_PER_MPI_LIMB; i++) { -+ a <<= 8; -+ a |= *buffer++; -+ } -+ i = 0; -+ val->d[j - 1] = a; -+ } -+ } -+ return val; -+} -+EXPORT_SYMBOL_GPL(mpi_read_raw_data); -+ - MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) - { - const uint8_t *buffer = xbuffer; --- -1.7.11.4 - - -From 3d816cdad8cdd5412ecc8f539bb09daef52ba361 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:11:48 +0100 -Subject: [PATCH 17/26] X.509: Add a crypto key parser for binary (DER) X.509 - certificates - -Add a crypto key parser for binary (DER) encoded X.509 certificates. The -certificate is parsed and, if possible, the signature is verified. - -An X.509 key can be added like this: - - # keyctl padd crypto bar @s ---- - 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 -+#include -+#include -+#include -+#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 -+ -+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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "asymmetric_keys.h" -+#include "public_key.h" -+#include "x509_parser.h" -+ -+static const -+struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = { -+ [PKEY_ALGO_DSA] = NULL, -+#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ -+ defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) -+ [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, -+#endif -+}; -+ -+/* -+ * Check the signature on a certificate using the provided public key -+ */ -+static int x509_check_signature(const struct public_key *pub, -+ const struct x509_certificate *cert) -+{ -+ struct public_key_signature *sig; -+ struct crypto_shash *tfm; -+ struct shash_desc *desc; -+ size_t digest_size, desc_size; -+ int ret; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ /* Allocate the hashing algorithm we're going to need and find out how -+ * big the hash operational data will be. -+ */ -+ tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0); -+ if (IS_ERR(tfm)) -+ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); -+ -+ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); -+ digest_size = crypto_shash_digestsize(tfm); -+ -+ /* We allocate the hash operational data storage on the end of our -+ * context data. -+ */ -+ ret = -ENOMEM; -+ sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); -+ if (!sig) -+ goto error_no_sig; -+ -+ sig->pkey_hash_algo = cert->sig_hash_algo; -+ sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; -+ sig->digest_size = digest_size; -+ -+ desc = (void *)sig + sizeof(*sig); -+ desc->tfm = tfm; -+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ ret = crypto_shash_init(desc); -+ if (ret < 0) -+ goto error; -+ -+ ret = -ENOMEM; -+ sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); -+ if (!sig->rsa.s) -+ goto error; -+ -+ ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); -+ if (ret < 0) -+ goto error_mpi; -+ -+ ret = pub->algo->verify_signature(pub, sig); -+ -+ pr_debug("Cert Verification: %d\n", ret); -+ -+error_mpi: -+ mpi_free(sig->rsa.s); -+error: -+ kfree(sig); -+error_no_sig: -+ crypto_free_shash(tfm); -+ -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ret; -+} -+ -+/* -+ * Attempt to parse a data blob for a key as an X509 certificate. -+ */ -+static int x509_key_preparse(struct key_preparsed_payload *prep) -+{ -+ struct x509_certificate *cert; -+ time_t now; -+ size_t srlen, sulen; -+ char *desc = NULL; -+ int ret; -+ -+ cert = x509_cert_parse(prep->data, prep->datalen); -+ if (IS_ERR(cert)) -+ return PTR_ERR(cert); -+ -+ pr_devel("Cert Issuer: %s\n", cert->issuer); -+ pr_devel("Cert Subject: %s\n", cert->subject); -+ pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); -+ pr_devel("Cert Valid: %lu - %lu\n", cert->valid_from, cert->valid_to); -+ pr_devel("Cert Signature: %s + %s\n", -+ pkey_algo[cert->sig_pkey_algo], -+ pkey_hash_algo[cert->sig_hash_algo]); -+ -+ if (!cert->fingerprint || !cert->authority) { -+ pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", -+ cert->subject); -+ ret = -EKEYREJECTED; -+ goto error_free_cert; -+ } -+ -+ now = CURRENT_TIME.tv_sec; -+ if (now < cert->valid_from) { -+ pr_warn("Cert %s is not yet valid\n", cert->fingerprint); -+ ret = -EKEYREJECTED; -+ goto error_free_cert; -+ } -+ if (now >= cert->valid_to) { -+ pr_warn("Cert %s has expired\n", cert->fingerprint); -+ ret = -EKEYEXPIRED; -+ goto error_free_cert; -+ } -+ -+ cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo]; -+ cert->pub->id_type = PKEY_ID_X509; -+ -+ /* Check the signature on the key */ -+ if (strcmp(cert->fingerprint, cert->authority) == 0) { -+ ret = x509_check_signature(cert->pub, cert); -+ if (ret < 0) -+ goto error_free_cert; -+ } -+ -+ /* Propose a description */ -+ sulen = strlen(cert->subject); -+ srlen = strlen(cert->fingerprint); -+ ret = -ENOMEM; -+ desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); -+ if (!desc) -+ goto error_free_cert; -+ memcpy(desc, cert->subject, sulen); -+ desc[sulen] = ':'; -+ desc[sulen + 1] = ' '; -+ memcpy(desc + sulen + 2, cert->fingerprint, srlen); -+ desc[sulen + 2 + srlen] = 0; -+ -+ /* We're pinning the module by being linked against it */ -+ __module_get(public_key_subtype.owner); -+ prep->type_data[0] = &public_key_subtype; -+ prep->type_data[1] = cert->fingerprint; -+ prep->payload = cert->pub; -+ prep->description = desc; -+ prep->quotalen = 100; -+ -+ /* We've finished with the certificate */ -+ cert->pub = NULL; -+ cert->fingerprint = NULL; -+ desc = NULL; -+ ret = 0; -+ -+error_free_cert: -+ x509_free_certificate(cert); -+ return ret; -+} -+ -+static struct asymmetric_key_parser x509_key_parser = { -+ .owner = THIS_MODULE, -+ .name = "x509", -+ .parse = x509_key_preparse, -+}; -+ -+/* -+ * Module stuff -+ */ -+static int __init x509_key_init(void) -+{ -+ return register_asymmetric_key_parser(&x509_key_parser); -+} -+ -+static void __exit x509_key_exit(void) -+{ -+ unregister_asymmetric_key_parser(&x509_key_parser); -+} -+ -+module_init(x509_key_init); -+module_exit(x509_key_exit); -diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1 -new file mode 100644 -index 0000000..4ec7cc6 ---- /dev/null -+++ b/crypto/asymmetric_keys/x509_rsakey.asn1 -@@ -0,0 +1,4 @@ -+RSAPublicKey ::= SEQUENCE { -+ modulus INTEGER ({ rsa_extract_mpi }), -- n -+ publicExponent INTEGER ({ rsa_extract_mpi }) -- e -+ } --- -1.7.11.4 - - -From 955fc6ec995f6bec6c487eb46027e108e240ebe3 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:25 +0100 -Subject: [PATCH 18/26] MOD: Fix Rusty's module_sig_check() - -Make the following fixes to Rusty's module_sig_check() function: - - (1) mod_verify_sig() is not defined, resulting in a compilation error and - thereby breaking git bisect, so provide a dummy that returns an error. - - (2) Using strlen() on a static string is a waste of resources. Further, you - may end up with two copies of the string emitted. - - (3) Doing a memchr() of the bytes beyond the last position that the marker - can be in is a waste of resources. - -While we're at it, push responsibility for the return value entirely off to -mod_verify_sig() if we find a signature. - -Signed-off-by: David Howells ---- - kernel/Makefile | 1 + - kernel/module-internal.h | 14 ++++++++++++++ - kernel/module.c | 41 +++++++++++++++++++++++------------------ - kernel/module_signing.c | 23 +++++++++++++++++++++++ - 4 files changed, 61 insertions(+), 18 deletions(-) - create mode 100644 kernel/module-internal.h - create mode 100644 kernel/module_signing.c - -diff --git a/kernel/Makefile b/kernel/Makefile -index c0cc67a..08ba8a6 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -55,6 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o - obj-$(CONFIG_PROVE_LOCKING) += spinlock.o - obj-$(CONFIG_UID16) += uid16.o - obj-$(CONFIG_MODULES) += module.o -+obj-$(CONFIG_MODULE_SIG) += module_signing.o - obj-$(CONFIG_KALLSYMS) += kallsyms.o - obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o - obj-$(CONFIG_KEXEC) += kexec.o -diff --git a/kernel/module-internal.h b/kernel/module-internal.h -new file mode 100644 -index 0000000..14da0ea ---- /dev/null -+++ b/kernel/module-internal.h -@@ -0,0 +1,14 @@ -+/* Module internals -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+extern int mod_verify_sig(const void *mod, unsigned long modlen, -+ const void *sig, unsigned long siglen, -+ bool *_sig_ok); -diff --git a/kernel/module.c b/kernel/module.c -index 5c6f65c..ab69599 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -58,6 +58,7 @@ - #include - #include - #include -+#include "module-internal.h" - - #define CREATE_TRACE_POINTS - #include -@@ -2438,34 +2439,38 @@ static inline void kmemleak_load_module(const struct module *mod, - #endif - - #ifdef CONFIG_MODULE_SIG -+ - static int module_sig_check(struct load_info *info, - const void *mod, unsigned long *len) - { -+ static const char module_sig_string[] = MODULE_SIG_STRING; - int err = 0; -- const unsigned long markerlen = strlen(MODULE_SIG_STRING); -- const void *p = mod, *end = mod + *len; -- -- /* Poor man's memmem. */ -- while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) { -- if (p + markerlen > end) -- break; -- -- if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) { -- const void *sig = p + markerlen; -- /* Truncate module up to signature. */ -- *len = p - mod; -- err = mod_verify_sig(mod, *len, -- sig, end - sig, -- &info->sig_ok); -- break; -- } -- p++; -+ const unsigned long markerlen = sizeof(module_sig_string) - 1; -+ const void *p = mod, *end = mod + *len, *sig; -+ const void *limit = end - markerlen - 1; -+ -+ if (markerlen < *len) { -+ /* Poor man's memmem. */ -+ do { -+ p = memchr(p, MODULE_SIG_STRING[0], limit - p); -+ if (!p) -+ break; -+ if (memcmp(p, module_sig_string, markerlen) != 0) -+ continue; -+ goto found_marker; -+ } while (++p < limit); - } - - /* Not having a signature is only an error if we're strict. */ - if (!err && !info->sig_ok && sig_enforce) - err = -EKEYREJECTED; - return err; -+ -+found_marker: -+ sig = p + markerlen; -+ /* Truncate module up to signature. */ -+ *len = p - mod; -+ return mod_verify_sig(mod, *len, sig, end - sig, &info->sig_ok); - } - #else /* !CONFIG_MODULE_SIG */ - static int module_sig_check(struct load_info *info, -diff --git a/kernel/module_signing.c b/kernel/module_signing.c -new file mode 100644 -index 0000000..0af10a5 ---- /dev/null -+++ b/kernel/module_signing.c -@@ -0,0 +1,23 @@ -+/* Module signature checker -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#include -+#include "module-internal.h" -+ -+/* -+ * Verify the signature on a module. -+ */ -+int mod_verify_sig(const void *mod, unsigned long modlen, -+ const void *sig, unsigned long siglen, -+ bool *_sig_ok) -+{ -+ return -EKEYREJECTED; -+} --- -1.7.11.4 - - -From 4c31831859550149cdba65a37d72416c87dbbef6 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:25 +0100 -Subject: [PATCH 19/26] MODSIGN: Provide gitignore and make clean rules for - extra files - -Provide gitignore and make clean rules for extra files to hide and clean up the -extra files produced by module signing stuff once it is added. Also add a -clean up rule for the module content extractor program used to extract the data -to be signed. - -Signed-off-by: David Howells ---- - .gitignore | 13 +++++++++++++ - Makefile | 1 + - 2 files changed, 14 insertions(+) - -diff --git a/.gitignore b/.gitignore -index 57af07c..9736304 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -14,6 +14,10 @@ - *.o.* - *.a - *.s -+*.ko.unsigned -+*.ko.stripped -+*.ko.stripped.dig -+*.ko.stripped.sig - *.ko - *.so - *.so.dbg -@@ -84,3 +88,12 @@ GTAGS - *.orig - *~ - \#*# -+ -+# -+# Leavings from module signing -+# -+extra_certificates -+signing_key.priv -+signing_key.x509 -+signing_key.x509.keyid -+signing_key.x509.signer -diff --git a/Makefile b/Makefile -index 371ce88..644048d 100644 ---- a/Makefile -+++ b/Makefile -@@ -1239,6 +1239,7 @@ clean: $(clean-dirs) - $(call cmd,rmfiles) - @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ - \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ -+ -o -name '*.ko.*' \ - -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ - -o -name '*.symtypes' -o -name 'modules.order' \ - -o -name modules.builtin -o -name '.tmp_*.o.*' \ --- -1.7.11.4 - - -From 6977e69eef4379f34a2ad264856d74ac292284df Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:25 +0100 -Subject: [PATCH 20/26] MODSIGN: Provide Kconfig options - -Provide kernel configuration options for module signing. - -The following configuration options are added: - - CONFIG_MODULE_SIG_SHA1 - CONFIG_MODULE_SIG_SHA224 - CONFIG_MODULE_SIG_SHA256 - CONFIG_MODULE_SIG_SHA384 - CONFIG_MODULE_SIG_SHA512 - -These select the cryptographic hash used to digest the data prior to signing. -Additionally, the crypto module selected will be built into the kernel as it -won't be possible to load it as a module without incurring a circular -dependency when the kernel tries to check its signature. - -Signed-off-by: David Howells ---- - init/Kconfig | 38 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 38 insertions(+) - -diff --git a/init/Kconfig b/init/Kconfig -index fa8ccad..00d4579 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1593,12 +1593,50 @@ config MODULE_SIG - is simply appended to the module. For more information see - Documentation/module-signing.txt. - -+ !!!WARNING!!! If you enable this option, you MUST make sure that the -+ module DOES NOT get stripped after being signed. This includes the -+ debuginfo strip done by some packagers (such as rpmbuild) and -+ inclusion into an initramfs that wants the module size reduced. -+ - config MODULE_SIG_FORCE - bool "Require modules to be validly signed" - depends on MODULE_SIG - help - Reject unsigned modules or signed modules for which we don't have a - key. Without this, such modules will simply taint the kernel. -+ -+choice -+ prompt "Which hash algorithm should modules be signed with?" -+ depends on MODULE_SIG -+ help -+ This determines which sort of hashing algorithm will be used during -+ signature generation. This algorithm _must_ be built into the kernel -+ directly so that signature verification can take place. It is not -+ possible to load a signed module containing the algorithm to check -+ the signature on that module. -+ -+config MODULE_SIG_SHA1 -+ bool "Sign modules with SHA-1" -+ select CRYPTO_SHA1 -+ -+config MODULE_SIG_SHA224 -+ bool "Sign modules with SHA-224" -+ select CRYPTO_SHA256 -+ -+config MODULE_SIG_SHA256 -+ bool "Sign modules with SHA-256" -+ select CRYPTO_SHA256 -+ -+config MODULE_SIG_SHA384 -+ bool "Sign modules with SHA-384" -+ select CRYPTO_SHA512 -+ -+config MODULE_SIG_SHA512 -+ bool "Sign modules with SHA-512" -+ select CRYPTO_SHA512 -+ -+endchoice -+ - endif # MODULES - - config INIT_ALL_POSSIBLE --- -1.7.11.4 - - -From 60378703cf88ed221ee602727c37ae241565d44a Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:25 +0100 -Subject: [PATCH 21/26] MODSIGN: Automatically generate module signing keys if - missing - -Automatically generate keys for module signing if they're absent so that -allyesconfig doesn't break. The builder should consider generating their own -key and certificate, however, so that the keys are appropriately named. - -The private key for the module signer should be placed in signing_key.priv -(unencrypted!) and the public key in an X.509 certificate as signing_key.x509. - -If a transient key is desired for signing the modules, a config file for -'openssl req' can be placed in x509.genkey, looking something like the -following: - - [ req ] - default_bits = 4096 - distinguished_name = req_distinguished_name - prompt = no - x509_extensions = myexts - - [ req_distinguished_name ] - O = Magarathea - CN = Glacier signing key - emailAddress = slartibartfast@magrathea.h2g2 - - [ myexts ] - basicConstraints=critical,CA:FALSE - keyUsage=digitalSignature - subjectKeyIdentifier=hash - authorityKeyIdentifier=hash - -The build process will use this to configure: - - openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \ - -x509 -config x509.genkey \ - -outform DER -out signing_key.x509 \ - -keyout signing_key.priv - -to generate the key. - -Note that it is required that the X.509 certificate have a subjectKeyIdentifier -and an authorityKeyIdentifier. Without those, the certificate will be -rejected. These can be used to check the validity of a certificate. - -Note that 'make distclean' will remove signing_key.{priv,x509} and x509.genkey, -whether or not they were generated automatically. - -Signed-off-by: David Howells ---- - kernel/Makefile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 49 insertions(+) - -diff --git a/kernel/Makefile b/kernel/Makefile -index 08ba8a6..83f1565 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -132,3 +132,52 @@ quiet_cmd_timeconst = TIMEC $@ - targets += timeconst.h - $(obj)/timeconst.h: $(src)/timeconst.pl FORCE - $(call if_changed,timeconst) -+ -+ifeq ($(CONFIG_MODULE_SIG),y) -+ -+############################################################################### -+# -+# If module signing is requested, say by allyesconfig, but a key has not been -+# supplied, then one will need to be generated to make sure the build does not -+# fail and that the kernel may be used afterwards. -+# -+############################################################################### -+signing_key.priv signing_key.x509: x509.genkey -+ @echo "###" -+ @echo "### Now generating an X.509 key pair to be used for signing modules." -+ @echo "###" -+ @echo "### If this takes a long time, you might wish to run rngd in the" -+ @echo "### background to keep the supply of entropy topped up. It" -+ @echo "### needs to be run as root, and should use a hardware random" -+ @echo "### number generator if one is available, eg:" -+ @echo "###" -+ @echo "### rngd -r /dev/hwrandom" -+ @echo "###" -+ openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \ -+ -x509 -config x509.genkey \ -+ -outform DER -out signing_key.x509 \ -+ -keyout signing_key.priv -+ @echo "###" -+ @echo "### Key pair generated." -+ @echo "###" -+ -+x509.genkey: -+ @echo Generating X.509 key generation config -+ @echo >x509.genkey "[ req ]" -+ @echo >>x509.genkey "default_bits = 4096" -+ @echo >>x509.genkey "distinguished_name = req_distinguished_name" -+ @echo >>x509.genkey "prompt = no" -+ @echo >>x509.genkey "x509_extensions = myexts" -+ @echo >>x509.genkey -+ @echo >>x509.genkey "[ req_distinguished_name ]" -+ @echo >>x509.genkey "O = Magarathea" -+ @echo >>x509.genkey "CN = Glacier signing key" -+ @echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2" -+ @echo >>x509.genkey -+ @echo >>x509.genkey "[ myexts ]" -+ @echo >>x509.genkey "basicConstraints=critical,CA:FALSE" -+ @echo >>x509.genkey "keyUsage=digitalSignature" -+ @echo >>x509.genkey "subjectKeyIdentifier=hash" -+ @echo >>x509.genkey "authorityKeyIdentifier=keyid" -+endif -+CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey --- -1.7.11.4 - - -From 798049d9df83c8fd87fd5ddb97a77054558f4361 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:25 +0100 -Subject: [PATCH 22/26] MODSIGN: Provide module signing public keys to the - kernel - -Include a PGP keyring containing the public keys required to perform module -verification in the kernel image during build and create a special keyring -during boot which is then populated with keys of crypto type holding the public -keys found in the PGP keyring. - -These can be seen by root: - -[root@andromeda ~]# cat /proc/keys -07ad4ee0 I----- 1 perm 3f010000 0 0 crypto modsign.0: RSA 87b9b3bd [] -15c7f8c3 I----- 1 perm 1f030000 0 0 keyring .module_sign: 1/4 -... - -It is probably worth permitting root to invalidate these keys, resulting in -their removal and preventing further modules from being loaded with that key. - -Signed-off-by: David Howells ---- - kernel/Makefile | 11 ++++- - kernel/modsign_pubkey.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++ - kernel/module-internal.h | 2 + - 3 files changed, 123 insertions(+), 2 deletions(-) - create mode 100644 kernel/modsign_pubkey.c - -diff --git a/kernel/Makefile b/kernel/Makefile -index 83f1565..63f8386 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -55,7 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o - obj-$(CONFIG_PROVE_LOCKING) += spinlock.o - obj-$(CONFIG_UID16) += uid16.o - obj-$(CONFIG_MODULES) += module.o --obj-$(CONFIG_MODULE_SIG) += module_signing.o -+obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o - obj-$(CONFIG_KALLSYMS) += kallsyms.o - obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o - obj-$(CONFIG_KEXEC) += kexec.o -@@ -134,6 +134,13 @@ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE - $(call if_changed,timeconst) - - ifeq ($(CONFIG_MODULE_SIG),y) -+# -+# Pull the signing certificate and any extra certificates into the kernel -+# -+extra_certificates: -+ touch $@ -+ -+kernel/modsign_pubkey.o: signing_key.x509 extra_certificates - - ############################################################################### - # -@@ -180,4 +187,4 @@ x509.genkey: - @echo >>x509.genkey "subjectKeyIdentifier=hash" - @echo >>x509.genkey "authorityKeyIdentifier=keyid" - endif --CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey -+CLEAN_FILES += signing_key.priv signing_key.x509 x509.genkey extra_certificates -diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c -new file mode 100644 -index 0000000..f504d9f ---- /dev/null -+++ b/kernel/modsign_pubkey.c -@@ -0,0 +1,112 @@ -+/* Public keys for module signature verification -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "module-internal.h" -+ -+struct key *modsign_keyring; -+ -+extern __initdata const u8 modsign_certificate_list[]; -+extern __initdata const u8 modsign_certificate_list_end[]; -+asm(".section .init.data,\"aw\"\n" -+ "modsign_certificate_list:\n" -+ ".incbin \"signing_key.x509\"\n" -+ ".incbin \"extra_certificates\"\n" -+ "modsign_certificate_list_end:" -+ ); -+ -+/* -+ * We need to make sure ccache doesn't cache the .o file as it doesn't notice -+ * if modsign.pub changes. -+ */ -+static __initdata const char annoy_ccache[] = __TIME__ "foo"; -+ -+/* -+ * Load the compiled-in keys -+ */ -+static __init int module_verify_init(void) -+{ -+ pr_notice("Initialise module verification\n"); -+ -+ modsign_keyring = key_alloc(&key_type_keyring, ".module_sign", -+ 0, 0, current_cred(), -+ (KEY_POS_ALL & ~KEY_POS_SETATTR) | -+ KEY_USR_VIEW | KEY_USR_READ, -+ KEY_ALLOC_NOT_IN_QUOTA); -+ if (IS_ERR(modsign_keyring)) -+ panic("Can't allocate module signing keyring\n"); -+ -+ if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0) -+ panic("Can't instantiate module signing keyring\n"); -+ -+ return 0; -+} -+ -+/* -+ * Must be initialised before we try and load the keys into the keyring. -+ */ -+device_initcall(module_verify_init); -+ -+/* -+ * Load the compiled-in keys -+ */ -+static __init int load_module_signing_keys(void) -+{ -+ key_ref_t key; -+ const u8 *p, *end; -+ size_t plen; -+ -+ pr_notice("Loading module verification certificates\n"); -+ -+ end = modsign_certificate_list_end; -+ p = modsign_certificate_list; -+ while (p < end) { -+ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more -+ * than 256 bytes in size. -+ */ -+ if (end - p < 4) -+ goto dodgy_cert; -+ if (p[0] != 0x30 && -+ p[1] != 0x82) -+ goto dodgy_cert; -+ plen = (p[2] << 8) | p[3]; -+ plen += 4; -+ if (plen > end - p) -+ goto dodgy_cert; -+ -+ key = key_create_or_update(make_key_ref(modsign_keyring, 1), -+ "asymmetric", -+ NULL, -+ p, -+ plen, -+ (KEY_POS_ALL & ~KEY_POS_SETATTR) | -+ KEY_USR_VIEW, -+ KEY_ALLOC_NOT_IN_QUOTA); -+ if (IS_ERR(key)) -+ pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n", -+ PTR_ERR(key)); -+ else -+ pr_notice("MODSIGN: Loaded cert '%s'\n", -+ key_ref_to_ptr(key)->description); -+ p += plen; -+ } -+ -+ return 0; -+ -+dodgy_cert: -+ pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n"); -+ return 0; -+} -+late_initcall(load_module_signing_keys); -diff --git a/kernel/module-internal.h b/kernel/module-internal.h -index 14da0ea..648f481 100644 ---- a/kernel/module-internal.h -+++ b/kernel/module-internal.h -@@ -9,6 +9,8 @@ - * 2 of the Licence, or (at your option) any later version. - */ - -+extern struct key *modsign_keyring; -+ - extern int mod_verify_sig(const void *mod, unsigned long modlen, - const void *sig, unsigned long siglen, - bool *_sig_ok); --- -1.7.11.4 - - -From dcac300c703bc9a237deab7c7f0301f3803a3a9a Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:26 +0100 -Subject: [PATCH 23/26] MODSIGN: Implement module signature checking - -Check the signature on the module against the keys compiled into the kernel or -available in a hardware key store. - -Currently, only RSA keys are supported - though that's easy enough to change, -and the signature is expected to contain raw components (so not a PGP or -PKCS#7 formatted blob). - -The signature blob is expected to consist of the following pieces in order: - - (1) The binary identifier for the key. This is expected to match the - SubjectKeyIdentifier from an X.509 certificate. Only X.509 type - identifiers are currently supported. - - (2) The signature data, consisting of a series of MPIs in which each is in - the format of a 2-byte BE word sizes followed by the content data. - - (3) A 12 byte information block of the form: - - struct module_signature { - enum pkey_algo algo : 8; - enum pkey_hash_algo hash : 8; - enum pkey_id_type id_type : 8; - u8 __pad; - __be32 id_length; - __be32 sig_length; - }; - - The three enums are defined in crypto/public_key.h. - - 'algo' contains the public-key algorithm identifier (0->DSA, 1->RSA). - - 'hash' contains the digest algorithm identifier (0->MD4, 1->MD5, 2->SHA1, - etc.). - - 'id_type' contains the public-key identifier type (0->PGP, 1->X.509). - - '__pad' should be 0. - - 'id_length' should contain in the binary identifier length in BE form. - - 'sig_length' should contain in the signature data length in BE form. - - The lengths are in BE order rather than CPU order to make dealing with - cross-compilation easier. +From a6a74ede612b526dd0f958c2eee5adfa9b038b95 Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Mon, 15 Oct 2012 10:14:09 -0400 +Subject: [PATCH 1/2] Revert "MODSIGN: Sign modules during the build process" -Signed-off-by: David Howells +This reverts commit 80d65e58e93ffdabf58202653a0435bd3cf2d82e. --- - init/Kconfig | 8 ++ - kernel/module_signing.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 230 insertions(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 00d4579..63fcbeb 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1588,6 +1588,14 @@ config MODULE_SRCVERSION_ALL - config MODULE_SIG - bool "Module signature verification" - depends on MODULES -+ select CONFIG_KEYS -+ select CONFIG_CRYPTO -+ select ASYMMETRIC_KEY_TYPE -+ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE -+ select PUBLIC_KEY_ALGO_RSA -+ select ASN1 -+ select OID_REGISTRY -+ select X509_CERTIFICATE_PARSER - help - Check modules for valid signatures upon load: the signature - is simply appended to the module. For more information see -diff --git a/kernel/module_signing.c b/kernel/module_signing.c -index 0af10a5..83eb505 100644 ---- a/kernel/module_signing.c -+++ b/kernel/module_signing.c -@@ -10,14 +10,235 @@ - */ - - #include -+#include -+#include -+#include -+#include - #include "module-internal.h" + scripts/Makefile.modpost | 77 +------------------------------ + scripts/sign-file | 115 ----------------------------------------------- + 2 files changed, 1 insertion(+), 191 deletions(-) + delete mode 100644 scripts/sign-file + +diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost +index 0020891..a1cb022 100644 +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -14,8 +14,7 @@ + # 3) create one .mod.c file pr. module + # 4) create one Module.symvers file with CRC for all exported symbols + # 5) compile all .mod.c files +-# 6) final link of the module to a (or ) file +-# 7) signs the modules to a file ++# 6) final link of the module to a 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 - /* -+ * Module signature information block. -+ * -+ * The constituents of the signature section are, in order: -+ * -+ * - Signer's name -+ * - Key identifier -+ * - Signature data -+ * - Information block -+ */ -+struct module_signature { -+ enum pkey_algo algo : 8; /* Public-key crypto algorithm */ -+ enum pkey_hash_algo hash : 8; /* Digest algorithm */ -+ enum pkey_id_type id_type : 8; /* Key identifier type */ -+ u8 signer_len; /* Length of signer's name */ -+ u8 key_id_len; /* Length of key identifier */ -+ u8 __pad[3]; -+ __be32 sig_len; /* Length of signature data */ -+}; -+ -+/* -+ * Digest the module contents. -+ */ -+static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash, -+ const void *mod, -+ unsigned long modlen) -+{ -+ struct public_key_signature *pks; -+ struct crypto_shash *tfm; -+ struct shash_desc *desc; -+ size_t digest_size, desc_size; -+ int ret; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ /* Allocate the hashing algorithm we're going to need and find out how -+ * big the hash operational data will be. -+ */ -+ tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0); -+ if (IS_ERR(tfm)) -+ return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); -+ -+ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); -+ digest_size = crypto_shash_digestsize(tfm); -+ -+ /* We allocate the hash operational data storage on the end of our -+ * context data and the digest output buffer on the end of that. -+ */ -+ ret = -ENOMEM; -+ pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); -+ if (!pks) -+ goto error_no_pks; -+ -+ pks->pkey_hash_algo = hash; -+ pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; -+ pks->digest_size = digest_size; -+ -+ desc = (void *)pks + sizeof(*pks); -+ desc->tfm = tfm; -+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ ret = crypto_shash_init(desc); -+ if (ret < 0) -+ goto error; -+ -+ ret = crypto_shash_finup(desc, mod, modlen, pks->digest); -+ if (ret < 0) -+ goto error; -+ -+ crypto_free_shash(tfm); -+ pr_devel("<==%s() = ok\n", __func__); -+ return pks; -+ -+error: -+ kfree(pks); -+error_no_pks: -+ crypto_free_shash(tfm); -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ERR_PTR(ret); -+} -+ -+/* -+ * Extract an MPI array from the signature data. This represents the actual -+ * signature. Each raw MPI is prefaced by a BE 2-byte value indicating the -+ * size of the MPI in bytes. -+ * -+ * RSA signatures only have one MPI, so currently we only read one. -+ */ -+static int mod_extract_mpi_array(struct public_key_signature *pks, -+ const void *data, size_t len) -+{ -+ size_t nbytes; -+ MPI mpi; -+ -+ if (len < 3) -+ return -EBADMSG; -+ nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1]; -+ data += 2; -+ len -= 2; -+ if (len != nbytes) -+ return -EBADMSG; -+ -+ mpi = mpi_read_raw_data(data, nbytes); -+ if (!mpi) -+ return -ENOMEM; -+ pks->mpi[0] = mpi; -+ pks->nr_mpi = 1; -+ return 0; -+} -+ -+/* -+ * Request an asymmetric key. -+ */ -+static struct key *request_asymmetric_key(const char *signer, size_t signer_len, -+ const u8 *key_id, size_t key_id_len) -+{ -+ key_ref_t key; -+ size_t i; -+ char *id, *q; -+ -+ pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len); -+ -+ /* Construct an identifier. */ -+ id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL); -+ if (!id) -+ return ERR_PTR(-ENOKEY); -+ -+ memcpy(id, signer, signer_len); -+ -+ q = id + signer_len; -+ *q++ = ':'; -+ *q++ = ' '; -+ for (i = 0; i < key_id_len; i++) { -+ *q++ = hex_asc[*key_id >> 4]; -+ *q++ = hex_asc[*key_id++ & 0x0f]; -+ } -+ -+ *q = 0; -+ -+ pr_debug("Look up: \"%s\"\n", id); -+ -+ key = keyring_search(make_key_ref(modsign_keyring, 1), -+ &key_type_asymmetric, id); -+ kfree(id); -+ -+ if (IS_ERR(key)) { -+ switch (PTR_ERR(key)) { -+ /* Hide some search errors */ -+ case -EACCES: -+ case -ENOTDIR: -+ case -EAGAIN: -+ return ERR_PTR(-ENOKEY); -+ default: -+ return ERR_CAST(key); -+ } -+ } -+ -+ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); -+ return key_ref_to_ptr(key); -+} -+ -+/* - * Verify the signature on a module. - */ - int mod_verify_sig(const void *mod, unsigned long modlen, - const void *sig, unsigned long siglen, - bool *_sig_ok) - { -- return -EKEYREJECTED; -+ struct public_key_signature *pks; -+ struct module_signature ms; -+ struct key *key; -+ size_t sig_len; -+ int ret; -+ -+ pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen); -+ -+ if (siglen <= sizeof(ms)) -+ return -EBADMSG; -+ -+ memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms)); -+ siglen -= sizeof(ms); -+ -+ sig_len = be32_to_cpu(ms.sig_len); -+ if (sig_len >= siglen || -+ siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len) -+ return -EBADMSG; -+ -+ /* For the moment, only support RSA and X.509 identifiers */ -+ if (ms.algo != PKEY_ALGO_RSA || -+ ms.id_type != PKEY_ID_X509) -+ return -ENOPKG; -+ -+ if (ms.hash >= PKEY_HASH__LAST || -+ !pkey_hash_algo[ms.hash]) -+ return -ENOPKG; -+ -+ key = request_asymmetric_key(sig, ms.signer_len, -+ sig + ms.signer_len, ms.key_id_len); -+ if (IS_ERR(key)) -+ return PTR_ERR(key); -+ -+ pks = mod_make_digest(ms.hash, mod, modlen); -+ if (IS_ERR(pks)) { -+ ret = PTR_ERR(pks); -+ goto error_put_key; -+ } -+ -+ ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len, -+ sig_len); -+ if (ret < 0) -+ goto error_free_pks; -+ -+ ret = verify_signature(key, pks); -+ pr_devel("verify_signature() = %d\n", ret); -+ -+ if (ret == 0) -+ *_sig_ok = true; -+ -+error_free_pks: -+ mpi_free(pks->rsa.s); -+ kfree(pks); -+error_put_key: -+ key_put(key); -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ret; - } --- -1.7.11.4 - - -From 89fbf1de73ed1ef29a3943d9f3bcf69a433191da Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 17:13:26 +0100 -Subject: [PATCH 24/26] MODSIGN: Provide a script for generating a key ID from - an X.509 cert - -Provide a script to parse an X.509 certificate and certain pieces of -information from it in order to generate a key identifier to be included within -a module signature. - -The script takes the Subject Name and extracts (if present) the -organizationName (O), the commonName (CN) and the emailAddress and fabricates -the signer's name from them: - - (1) If both O and CN exist, then the name will be "O: CN", unless: - - (a) CN is prefixed by O, in which case only CN is used. - - (b) CN and O share at least the first 7 characters, in which case only CN - is used. - - (2) Otherwise, CN is used if present. - - (3) Otherwise, O is used if present. - - (4) Otherwise the emailAddress is used, if present. - - (5) Otherwise a blank name is used. - -The script emits a binary encoded identifier in the following form: - - - 2 BE bytes indicating the length of the signer's name. - - - 2 BE bytes indicating the length of the subject key identifier. - - - The characters of the signer's name. - - - The bytes of the subject key identifier. - -Signed-off-by: David Howells ---- - 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 -+# -+# 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]; + # 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 +deleted file mode 100644 +index e58e34e..0000000 +--- a/scripts/sign-file ++++ /dev/null +@@ -1,115 +0,0 @@ +-#!/bin/sh +-# +-# Sign a module file using the given key. +-# +-# Format: sign-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.11.4 +1.7.12.1 -From 007c8fc3412f0a55cd3a32c5e42236703a17d1c1 Mon Sep 17 00:00:00 2001 +From b29453cb9b235041f789c81b1982179acb6d3d06 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 24 Sep 2012 10:46:36 -0400 -Subject: [PATCH 25/26] MODSIGN: Add modules_sign make target +Subject: [PATCH 2/2] MODSIGN: Add modules_sign make target If CONFIG_MODULE_SIG is set, and 'make modules_sign' is called then this patch will cause the modules to get a signature installed. The make target @@ -8838,10 +301,10 @@ Signed-off-by: Josh Boyer create mode 100644 scripts/sign-file diff --git a/Makefile b/Makefile -index 644048d..4479147 100644 +index 5be2ee8..618cfbbf 100644 --- a/Makefile +++ b/Makefile -@@ -965,6 +965,12 @@ _modinst_post: _modinst_ +@@ -968,6 +968,12 @@ _modinst_post: _modinst_ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst $(call cmd,depmod) @@ -8934,7 +397,7 @@ index 0000000..17326bc +.PHONY: $(PHONY) diff --git a/scripts/sign-file b/scripts/sign-file new file mode 100644 -index 0000000..1a472bb +index 0000000..e58e34e --- /dev/null +++ b/scripts/sign-file @@ -0,0 +1,115 @@ @@ -8950,7 +413,7 @@ index 0000000..1a472bb +CONFIG_MODULE_SIG_SHA512=y +if [ -r .config ] +then -+ source ./.config ++ . ./.config +fi + +key="$1" @@ -9054,265 +517,5 @@ index 0000000..1a472bb +# Permit in-place signing +mv $dst~ $dst || exit $? -- -1.7.11.4 - - -From 33c6737b352ec10a7e0d7b053fbb084c0b7a9d36 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Mon, 24 Sep 2012 20:51:59 +0100 -Subject: [PATCH 26/26] MODSIGN: Extend the policy on signature check failure - -Extend the policy on handling various sorts of signature check failure such as -not having the requisite key available or being in FIPS mode. - -If the key specified is not known (ENOKEY) permit the module to be loaded in -non-enforcing mode, otherwise reject it. - -If in FIPS mode, any loading failure shall cause a panic. - -Also print a warning if we try and fail to find a module signing key: - - Request for unknown module key 'Magrathea: Glacier signing key: 5dd0839552bd6af498253f8af1e65da3472941c6' err -11 - -This contains the identity field and the key ID from the signature as well as -the error code. The error codes are the raw return from keyring_search() and -may be translated to -ENOKEY. - -Signed-off-by: David Howells ---- - kernel/Makefile | 2 +- - kernel/module.c | 9 ++++++++- - kernel/module_signing.c | 3 +++ - 3 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/kernel/Makefile b/kernel/Makefile -index 63f8386..111a845 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -177,7 +177,7 @@ x509.genkey: - @echo >>x509.genkey "x509_extensions = myexts" - @echo >>x509.genkey - @echo >>x509.genkey "[ req_distinguished_name ]" -- @echo >>x509.genkey "O = Magarathea" -+ @echo >>x509.genkey "O = Magrathea" - @echo >>x509.genkey "CN = Glacier signing key" - @echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2" - @echo >>x509.genkey -diff --git a/kernel/module.c b/kernel/module.c -index ab69599..de16959 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -58,6 +58,7 @@ - #include - #include - #include -+#include - #include "module-internal.h" - - #define CREATE_TRACE_POINTS -@@ -2470,7 +2471,13 @@ found_marker: - sig = p + markerlen; - /* Truncate module up to signature. */ - *len = p - mod; -- return mod_verify_sig(mod, *len, sig, end - sig, &info->sig_ok); -+ err = mod_verify_sig(mod, *len, sig, end - sig, &info->sig_ok); -+ if (err < 0 && fips_enabled) -+ panic("Module verification failed with error %d in FIPS mode\n", -+ err); -+ if (err == -ENOKEY && !sig_enforce) -+ err = 0; -+ return err; - } - #else /* !CONFIG_MODULE_SIG */ - static int module_sig_check(struct load_info *info, -diff --git a/kernel/module_signing.c b/kernel/module_signing.c -index 83eb505..2beea56 100644 ---- a/kernel/module_signing.c -+++ b/kernel/module_signing.c -@@ -159,6 +159,9 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len, - - key = keyring_search(make_key_ref(modsign_keyring, 1), - &key_type_asymmetric, id); -+ if (IS_ERR(key)) -+ pr_warn("Request for unknown module key '%s' err %ld\n", -+ id, PTR_ERR(key)); - kfree(id); - - if (IS_ERR(key)) { --- -1.7.11.4 - -The current choice of lifetime for the autogenerated X.509 of 100 years, -putting the validTo date in 2112, causes problems on 32-bit systems where a -32-bit time_t wraps in 2106. 64-bit x86_64 systems seem to be unaffected. - -This can result in something like: - - Loading module verification certificates - X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired - MODSIGN: Problem loading in-kernel X.509 certificate (-127) - -Or: - - X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 is not yet valid - MODSIGN: Problem loading in-kernel X.509 certificate (-129) - -Instead of turning the dates into time_t values and comparing, turn the system -clock and the ASN.1 dates into tm structs and compare those piecemeal instead. - -Reported-by: Rusty Russell -Signed-off-by: David Howells ---- - - 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 diff --git a/secure-boot-20120924.patch b/secure-boot-20120924.patch index 54825ef..06681ca 100644 --- a/secure-boot-20120924.patch +++ b/secure-boot-20120924.patch @@ -11,13 +11,13 @@ capability set if required. Signed-off-by: Matthew Garrett --- - include/linux/capability.h | 6 +++++- + include/uapi/linux/capability.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index d10b7ed..4345bc8 100644 ---- a/include/linux/capability.h -+++ b/include/linux/capability.h +--- a/include/uapi/linux/capability.h ++++ b/include/uapi/linux/capability.h @@ -364,7 +364,11 @@ struct cpu_vfs_cap_data { #define CAP_BLOCK_SUSPEND 36