diff options
author | Josh Boyer <jwboyer@redhat.com> | 2013-09-03 17:26:36 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@redhat.com> | 2013-09-03 17:28:29 -0400 |
commit | d7ee6f3b0e2cb9569f384eeac7d1c8f5c6a93e91 (patch) | |
tree | a623b63f6c9af5dc3fea61ca1212407a1a85af5b /keys-x509-improv.patch | |
parent | 663b7fc9c809c19db57c8bc4244db85d86b7d05b (diff) | |
download | kernel-d7ee6f3b0e2cb9569f384eeac7d1c8f5c6a93e91.tar.gz kernel-d7ee6f3b0e2cb9569f384eeac7d1c8f5c6a93e91.tar.xz kernel-d7ee6f3b0e2cb9569f384eeac7d1c8f5c6a93e91.zip |
Add system_keyring patches back in
Diffstat (limited to 'keys-x509-improv.patch')
-rw-r--r-- | keys-x509-improv.patch | 1580 |
1 files changed, 1580 insertions, 0 deletions
diff --git a/keys-x509-improv.patch b/keys-x509-improv.patch new file mode 100644 index 000000000..b3341cf50 --- /dev/null +++ b/keys-x509-improv.patch @@ -0,0 +1,1580 @@ +From abaac4978b6719e7ae12babb6be5e35184b61cde Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:07:13 +0100 +Subject: [PATCH 01/14] KEYS: Load *.x509 files into kernel keyring + +Load all the files matching the pattern "*.x509" that are to be found in kernel +base source dir and base build dir into the module signing keyring. + +The "extra_certificates" file is then redundant. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/Makefile | 35 +++++++++++++++++++++++++++++------ + kernel/modsign_certificate.S | 3 +-- + 2 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/kernel/Makefile b/kernel/Makefile +index 470839d..4a2ee4e 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -141,17 +141,40 @@ $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE + $(call if_changed,bc) + + ifeq ($(CONFIG_MODULE_SIG),y) ++############################################################################### + # +-# Pull the signing certificate and any extra certificates into the kernel ++# Roll all the X.509 certificates that we can find together and pull ++# them into the kernel. + # ++############################################################################### ++X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509) ++X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509 ++X509_CERTIFICATES := $(sort $(X509_CERTIFICATES-y)) ++ ++ifeq ($(X509_CERTIFICATES),) ++$(warning *** No X.509 certificates found ***) ++endif ++ ++ifneq ($(wildcard $(obj)/.x509.list),) ++ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES)) ++$(info X.509 certificate list changed) ++$(shell rm $(obj)/.x509.list) ++endif ++endif ++ ++kernel/modsign_certificate.o: $(obj)/x509_certificate_list + +-quiet_cmd_touch = TOUCH $@ +- cmd_touch = touch $@ ++quiet_cmd_x509certs = CERTS $@ ++ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ ++targets += $(obj)/x509_certificate_list ++$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list ++ $(call if_changed,x509certs) + +-extra_certificates: +- $(call cmd,touch) ++targets += $(obj)/.x509.list ++$(obj)/.x509.list: ++ @echo $(X509_CERTIFICATES) >$@ + +-kernel/modsign_certificate.o: signing_key.x509 extra_certificates ++clean-files := x509_certificate_list .x509.list + + ############################################################################### + # +diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S +index 4a9a86d..6fe03c7 100644 +--- a/kernel/modsign_certificate.S ++++ b/kernel/modsign_certificate.S +@@ -7,6 +7,5 @@ + .section ".init.data","aw" + + GLOBAL(modsign_certificate_list) +- .incbin "signing_key.x509" +- .incbin "extra_certificates" ++ .incbin "kernel/x509_certificate_list" + GLOBAL(modsign_certificate_list_end) +-- +1.8.3.1 + + + +From 2d6ac2896c3b4b48be96b7dbdfda1668609e35aa Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:07:30 +0100 +Subject: [PATCH 03/14] KEYS: Separate the kernel signature checking keyring + from module signing + +Separate the kernel signature checking keyring from module signing so that it +can be used by code other than the module-signing code. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + include/keys/system_keyring.h | 23 ++++++++++ + init/Kconfig | 13 ++++++ + kernel/Makefile | 17 ++++--- + kernel/modsign_certificate.S | 11 ----- + kernel/modsign_pubkey.c | 104 ------------------------------------------ + kernel/module-internal.h | 2 - + kernel/module_signing.c | 3 +- + kernel/system_certificates.S | 11 +++++ + kernel/system_keyring.c | 103 +++++++++++++++++++++++++++++++++++++++++ + 9 files changed, 163 insertions(+), 124 deletions(-) + create mode 100644 include/keys/system_keyring.h + delete mode 100644 kernel/modsign_certificate.S + delete mode 100644 kernel/modsign_pubkey.c + create mode 100644 kernel/system_certificates.S + create mode 100644 kernel/system_keyring.c + +diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h +new file mode 100644 +index 0000000..8dabc39 +--- /dev/null ++++ b/include/keys/system_keyring.h +@@ -0,0 +1,23 @@ ++/* System keyring containing trusted public keys. ++ * ++ * Copyright (C) 2013 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_SYSTEM_KEYRING_H ++#define _KEYS_SYSTEM_KEYRING_H ++ ++#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING ++ ++#include <linux/key.h> ++ ++extern struct key *system_trusted_keyring; ++ ++#endif ++ ++#endif /* _KEYS_SYSTEM_KEYRING_H */ +diff --git a/init/Kconfig b/init/Kconfig +index 247084b..6abf0e0 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1664,6 +1664,18 @@ config BASE_SMALL + default 0 if BASE_FULL + default 1 if !BASE_FULL + ++config SYSTEM_TRUSTED_KEYRING ++ bool "Provide system-wide ring of trusted keys" ++ depends on KEYS ++ help ++ Provide a system keyring to which trusted keys can be added. Keys in ++ the keyring are considered to be trusted. Keys may be added at will ++ by the kernel from compiled-in data and from hardware key stores, but ++ userspace may only add extra keys if those keys can be verified by ++ keys already in the keyring. ++ ++ Keys in this keyring are used by module signature checking. ++ + menuconfig MODULES + bool "Enable loadable module support" + help +@@ -1736,6 +1748,7 @@ config MODULE_SRCVERSION_ALL + config MODULE_SIG + bool "Module signature verification" + depends on MODULES ++ select SYSTEM_TRUSTED_KEYRING + select KEYS + select CRYPTO + select ASYMMETRIC_KEY_TYPE +diff --git a/kernel/Makefile b/kernel/Makefile +index 7bd1565..68f7182 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -52,8 +52,9 @@ obj-$(CONFIG_SMP) += spinlock.o + obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o + obj-$(CONFIG_PROVE_LOCKING) += spinlock.o + obj-$(CONFIG_UID16) += uid16.o ++obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o + obj-$(CONFIG_MODULES) += module.o +-obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.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 +@@ -140,13 +141,14 @@ targets += timeconst.h + $(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE + $(call if_changed,bc) + +-ifeq ($(CONFIG_MODULE_SIG),y) + ############################################################################### + # +-# Roll all the X.509 certificates that we can find together and pull +-# them into the kernel. ++# Roll all the X.509 certificates that we can find together and pull them into ++# the kernel so that they get loaded into the system trusted keyring during ++# boot. + # + ############################################################################### ++ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) + X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509) + X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509 + X509_CERTIFICATES := $(sort $(realpath $(X509_CERTIFICATES-y))) +@@ -162,10 +164,11 @@ $(shell rm $(obj)/.x509.list) + endif + endif + +-kernel/modsign_certificate.o: $(obj)/x509_certificate_list ++kernel/system_certificates.o: $(obj)/x509_certificate_list + + quiet_cmd_x509certs = CERTS $@ +- cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ ++ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)") ++ + targets += $(obj)/x509_certificate_list + $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list + $(call if_changed,x509certs) +@@ -175,7 +178,9 @@ $(obj)/.x509.list: + @echo $(X509_CERTIFICATES) >$@ + + clean-files := x509_certificate_list .x509.list ++endif + ++ifeq ($(CONFIG_MODULE_SIG),y) + ############################################################################### + # + # If module signing is requested, say by allyesconfig, but a key has not been +diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S +deleted file mode 100644 +index 6fe03c7..0000000 +--- a/kernel/modsign_certificate.S ++++ /dev/null +@@ -1,11 +0,0 @@ +-#include <linux/export.h> +- +-#define GLOBAL(name) \ +- .globl VMLINUX_SYMBOL(name); \ +- VMLINUX_SYMBOL(name): +- +- .section ".init.data","aw" +- +-GLOBAL(modsign_certificate_list) +- .incbin "kernel/x509_certificate_list" +-GLOBAL(modsign_certificate_list_end) +diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c +deleted file mode 100644 +index 2b6e699..0000000 +--- a/kernel/modsign_pubkey.c ++++ /dev/null +@@ -1,104 +0,0 @@ +-/* Public keys for module signature verification +- * +- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. +- * Written by David Howells (dhowells@redhat.com) +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public Licence +- * as published by the Free Software Foundation; either version +- * 2 of the Licence, or (at your option) any later version. +- */ +- +-#include <linux/kernel.h> +-#include <linux/sched.h> +-#include <linux/cred.h> +-#include <linux/err.h> +-#include <keys/asymmetric-type.h> +-#include "module-internal.h" +- +-struct key *modsign_keyring; +- +-extern __initdata const u8 modsign_certificate_list[]; +-extern __initdata const u8 modsign_certificate_list_end[]; +- +-/* +- * 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 = keyring_alloc(".module_sign", +- KUIDT_INIT(0), KGIDT_INIT(0), +- current_cred(), +- ((KEY_POS_ALL & ~KEY_POS_SETATTR) | +- KEY_USR_VIEW | KEY_USR_READ), +- KEY_ALLOC_NOT_IN_QUOTA, NULL); +- if (IS_ERR(modsign_keyring)) +- panic("Can't allocate 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 24f9247..915e123 100644 +--- a/kernel/module-internal.h ++++ b/kernel/module-internal.h +@@ -9,6 +9,4 @@ + * 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); +diff --git a/kernel/module_signing.c b/kernel/module_signing.c +index f2970bd..0034e36 100644 +--- a/kernel/module_signing.c ++++ b/kernel/module_signing.c +@@ -14,6 +14,7 @@ + #include <crypto/public_key.h> + #include <crypto/hash.h> + #include <keys/asymmetric-type.h> ++#include <keys/system_keyring.h> + #include "module-internal.h" + + /* +@@ -157,7 +158,7 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len, + + pr_debug("Look up: \"%s\"\n", id); + +- key = keyring_search(make_key_ref(modsign_keyring, 1), ++ key = keyring_search(make_key_ref(system_trusted_keyring, 1), + &key_type_asymmetric, id); + if (IS_ERR(key)) + pr_warn("Request for unknown module key '%s' err %ld\n", +diff --git a/kernel/system_certificates.S b/kernel/system_certificates.S +new file mode 100644 +index 0000000..5cffe86 +--- /dev/null ++++ b/kernel/system_certificates.S +@@ -0,0 +1,11 @@ ++#include <linux/export.h> ++ ++#define GLOBAL(name) \ ++ .globl VMLINUX_SYMBOL(name); \ ++ VMLINUX_SYMBOL(name): ++ ++ .section ".init.data","aw" ++ ++GLOBAL(system_certificate_list) ++ .incbin "kernel/x509_certificate_list" ++GLOBAL(system_certificate_list_end) +diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c +new file mode 100644 +index 0000000..cd5cd3f +--- /dev/null ++++ b/kernel/system_keyring.c +@@ -0,0 +1,103 @@ ++/* System trusted keyring for trusted public keys ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/export.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/cred.h> ++#include <linux/err.h> ++#include <keys/asymmetric-type.h> ++#include <keys/system_keyring.h> ++#include "module-internal.h" ++ ++struct key *system_trusted_keyring; ++EXPORT_SYMBOL_GPL(system_trusted_keyring); ++ ++extern __initdata const u8 system_certificate_list[]; ++extern __initdata const u8 system_certificate_list_end[]; ++ ++/* ++ * Load the compiled-in keys ++ */ ++static __init int system_trusted_keyring_init(void) ++{ ++ pr_notice("Initialise system trusted keyring\n"); ++ ++ system_trusted_keyring = ++ keyring_alloc(".system_keyring", ++ KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), ++ ((KEY_POS_ALL & ~KEY_POS_SETATTR) | ++ KEY_USR_VIEW | KEY_USR_READ), ++ KEY_ALLOC_NOT_IN_QUOTA, NULL); ++ if (IS_ERR(system_trusted_keyring)) ++ panic("Can't allocate system trusted keyring\n"); ++ ++ return 0; ++} ++ ++/* ++ * Must be initialised before we try and load the keys into the keyring. ++ */ ++device_initcall(system_trusted_keyring_init); ++ ++/* ++ * Load the compiled-in list of X.509 certificates. ++ */ ++static __init int load_system_certificate_list(void) ++{ ++ key_ref_t key; ++ const u8 *p, *end; ++ size_t plen; ++ ++ pr_notice("Loading compiled-in X.509 certificates\n"); ++ ++ end = system_certificate_list_end; ++ p = system_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(system_trusted_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("Problem loading in-kernel X.509 certificate (%ld)\n", ++ PTR_ERR(key)); ++ } else { ++ pr_notice("Loaded X.509 cert '%s'\n", ++ key_ref_to_ptr(key)->description); ++ key_ref_put(key); ++ } ++ p += plen; ++ } ++ ++ return 0; ++ ++dodgy_cert: ++ pr_err("Problem parsing in-kernel X.509 certificate list\n"); ++ return 0; ++} ++late_initcall(load_system_certificate_list); +-- +1.8.3.1 + + +From 6f90d07a776d7babf30a3322dafd66c8c25db681 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:07:37 +0100 +Subject: [PATCH 04/14] KEYS: Add a 'trusted' flag and a 'trusted only' flag + +Add KEY_FLAG_TRUSTED to indicate that a key either comes from a trusted source +or had a cryptographic signature chain that led back to a trusted key the +kernel already possessed. + +Add KEY_FLAGS_TRUSTED_ONLY to indicate that a keyring will only accept links to +keys marked with KEY_FLAGS_TRUSTED. + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +--- + include/linux/key-type.h | 1 + + include/linux/key.h | 3 +++ + kernel/system_keyring.c | 4 +++- + security/keys/key.c | 8 ++++++++ + security/keys/keyring.c | 4 ++++ + 5 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/include/linux/key-type.h b/include/linux/key-type.h +index f58737b..a74c3a8 100644 +--- a/include/linux/key-type.h ++++ b/include/linux/key-type.h +@@ -45,6 +45,7 @@ struct key_preparsed_payload { + const void *data; /* Raw data */ + size_t datalen; /* Raw datalen */ + size_t quotalen; /* Quota length for proposed payload */ ++ bool trusted; /* True if key is trusted */ + }; + + typedef int (*request_key_actor_t)(struct key_construction *key, +diff --git a/include/linux/key.h b/include/linux/key.h +index 010dbb6..80d6774 100644 +--- a/include/linux/key.h ++++ b/include/linux/key.h +@@ -168,6 +168,8 @@ struct key { + #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ + #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ + #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ ++#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ ++#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ + + /* the key type and key description string + * - the desc is used to match a key against search criteria +@@ -218,6 +220,7 @@ extern struct key *key_alloc(struct key_type *type, + #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ + #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ + #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ ++#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */ + + extern void key_revoke(struct key *key); + extern void key_invalidate(struct key *key); +diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c +index cd5cd3f..4ca7072 100644 +--- a/kernel/system_keyring.c ++++ b/kernel/system_keyring.c +@@ -40,6 +40,7 @@ static __init int system_trusted_keyring_init(void) + if (IS_ERR(system_trusted_keyring)) + panic("Can't allocate system trusted keyring\n"); + ++ set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags); + return 0; + } + +@@ -82,7 +83,8 @@ static __init int load_system_certificate_list(void) + plen, + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW, +- KEY_ALLOC_NOT_IN_QUOTA); ++ KEY_ALLOC_NOT_IN_QUOTA | ++ KEY_ALLOC_TRUSTED); + if (IS_ERR(key)) { + pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", + PTR_ERR(key)); +diff --git a/security/keys/key.c b/security/keys/key.c +index a819b5c..d331ea9 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -300,6 +300,8 @@ struct key *key_alloc(struct key_type *type, const char *desc, + + if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) + key->flags |= 1 << KEY_FLAG_IN_QUOTA; ++ if (flags & KEY_ALLOC_TRUSTED) ++ key->flags |= 1 << KEY_FLAG_TRUSTED; + + memset(&key->type_data, 0, sizeof(key->type_data)); + +@@ -813,6 +815,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + prep.data = payload; + prep.datalen = plen; + prep.quotalen = index_key.type->def_datalen; ++ prep.trusted = flags & KEY_ALLOC_TRUSTED; + if (index_key.type->preparse) { + ret = index_key.type->preparse(&prep); + if (ret < 0) { +@@ -827,6 +830,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, + } + index_key.desc_len = strlen(index_key.description); + ++ key_ref = ERR_PTR(-EPERM); ++ if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags)) ++ goto error_free_prep; ++ flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0; ++ + ret = __key_link_begin(keyring, &index_key, &edit); + if (ret < 0) { + key_ref = ERR_PTR(ret); +diff --git a/security/keys/keyring.c b/security/keys/keyring.c +index f7cdea2..9b6f6e0 100644 +--- a/security/keys/keyring.c ++++ b/security/keys/keyring.c +@@ -1183,6 +1183,10 @@ int key_link(struct key *keyring, struct key *key) + key_check(keyring); + key_check(key); + ++ if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) && ++ !test_bit(KEY_FLAG_TRUSTED, &key->flags)) ++ return -EPERM; ++ + ret = __key_link_begin(keyring, &key->index_key, &edit); + if (ret == 0) { + kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); +-- +1.8.3.1 + + +From 559cc3ad765e1b443bc89965be9ef9ff3caabdcc Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:15:10 +0100 +Subject: [PATCH 05/14] KEYS: Rename public key parameter name arrays + +Rename the arrays of public key parameters (public key algorithm names, hash +algorithm names and ID type names) so that the array name ends in "_name". + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/public_key.c | 14 +++++++------- + crypto/asymmetric_keys/x509_public_key.c | 8 ++++---- + include/crypto/public_key.h | 6 +++--- + kernel/module_signing.c | 4 ++-- + 4 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c +index cb2e291..b313df1 100644 +--- a/crypto/asymmetric_keys/public_key.c ++++ b/crypto/asymmetric_keys/public_key.c +@@ -22,13 +22,13 @@ + + MODULE_LICENSE("GPL"); + +-const char *const pkey_algo[PKEY_ALGO__LAST] = { ++const char *const pkey_algo_name[PKEY_ALGO__LAST] = { + [PKEY_ALGO_DSA] = "DSA", + [PKEY_ALGO_RSA] = "RSA", + }; +-EXPORT_SYMBOL_GPL(pkey_algo); ++EXPORT_SYMBOL_GPL(pkey_algo_name); + +-const char *const pkey_hash_algo[PKEY_HASH__LAST] = { ++const char *const pkey_hash_algo_name[PKEY_HASH__LAST] = { + [PKEY_HASH_MD4] = "md4", + [PKEY_HASH_MD5] = "md5", + [PKEY_HASH_SHA1] = "sha1", +@@ -38,13 +38,13 @@ const char *const pkey_hash_algo[PKEY_HASH__LAST] = { + [PKEY_HASH_SHA512] = "sha512", + [PKEY_HASH_SHA224] = "sha224", + }; +-EXPORT_SYMBOL_GPL(pkey_hash_algo); ++EXPORT_SYMBOL_GPL(pkey_hash_algo_name); + +-const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { ++const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { + [PKEY_ID_PGP] = "PGP", + [PKEY_ID_X509] = "X509", + }; +-EXPORT_SYMBOL_GPL(pkey_id_type); ++EXPORT_SYMBOL_GPL(pkey_id_type_name); + + /* + * Provide a part of a description of the key for /proc/keys. +@@ -56,7 +56,7 @@ static void public_key_describe(const struct key *asymmetric_key, + + if (key) + seq_printf(m, "%s.%s", +- pkey_id_type[key->id_type], key->algo->name); ++ pkey_id_type_name[key->id_type], key->algo->name); + } + + /* +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 06007f0..afbbc36 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -49,7 +49,7 @@ static int x509_check_signature(const struct public_key *pub, + /* 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); ++ tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig_hash_algo], 0, 0); + if (IS_ERR(tfm)) + return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); + +@@ -117,7 +117,7 @@ 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 Key Algo: %s\n", pkey_algo_name[cert->pkey_algo]); + pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", + cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, + cert->valid_from.tm_mday, cert->valid_from.tm_hour, +@@ -127,8 +127,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + 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]); ++ pkey_algo_name[cert->sig_pkey_algo], ++ pkey_hash_algo_name[cert->sig_hash_algo]); + + if (!cert->fingerprint || !cert->authority) { + pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", +diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h +index f5b0224..619d570 100644 +--- a/include/crypto/public_key.h ++++ b/include/crypto/public_key.h +@@ -22,7 +22,7 @@ enum pkey_algo { + PKEY_ALGO__LAST + }; + +-extern const char *const pkey_algo[PKEY_ALGO__LAST]; ++extern const char *const pkey_algo_name[PKEY_ALGO__LAST]; + + enum pkey_hash_algo { + PKEY_HASH_MD4, +@@ -36,7 +36,7 @@ enum pkey_hash_algo { + PKEY_HASH__LAST + }; + +-extern const char *const pkey_hash_algo[PKEY_HASH__LAST]; ++extern const char *const pkey_hash_algo_name[PKEY_HASH__LAST]; + + enum pkey_id_type { + PKEY_ID_PGP, /* OpenPGP generated key ID */ +@@ -44,7 +44,7 @@ enum pkey_id_type { + PKEY_ID_TYPE__LAST + }; + +-extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST]; ++extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; + + /* + * Cryptographic data for the public-key subtype of the asymmetric key type. +diff --git a/kernel/module_signing.c b/kernel/module_signing.c +index 0034e36..0b6b870 100644 +--- a/kernel/module_signing.c ++++ b/kernel/module_signing.c +@@ -55,7 +55,7 @@ static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash, + /* 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); ++ tfm = crypto_alloc_shash(pkey_hash_algo_name[hash], 0, 0); + if (IS_ERR(tfm)) + return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); + +@@ -218,7 +218,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) + return -ENOPKG; + + if (ms.hash >= PKEY_HASH__LAST || +- !pkey_hash_algo[ms.hash]) ++ !pkey_hash_algo_name[ms.hash]) + return -ENOPKG; + + key = request_asymmetric_key(sig, ms.signer_len, +-- +1.8.3.1 + + +From a0aab2065bbdd0bc56ae6d7767e1df7c58b8997f Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:15:18 +0100 +Subject: [PATCH 06/14] KEYS: Move the algorithm pointer array from x509 to + public_key.c + +Move the public-key algorithm pointer array from x509_public_key.c to +public_key.c as it isn't X.509 specific. + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/public_key.c | 8 ++++++++ + crypto/asymmetric_keys/x509_public_key.c | 11 +---------- + include/crypto/public_key.h | 1 + + 3 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c +index b313df1..796ce08 100644 +--- a/crypto/asymmetric_keys/public_key.c ++++ b/crypto/asymmetric_keys/public_key.c +@@ -28,6 +28,14 @@ const char *const pkey_algo_name[PKEY_ALGO__LAST] = { + }; + EXPORT_SYMBOL_GPL(pkey_algo_name); + ++const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = { ++#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ ++ defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) ++ [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, ++#endif ++}; ++EXPORT_SYMBOL_GPL(pkey_algo); ++ + const char *const pkey_hash_algo_name[PKEY_HASH__LAST] = { + [PKEY_HASH_MD4] = "md4", + [PKEY_HASH_MD5] = "md5", +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index afbbc36..fe38628 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -23,15 +23,6 @@ + #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 + */ +@@ -174,7 +165,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + goto error_free_cert; + } + +- cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo]; ++ cert->pub->algo = pkey_algo[cert->pkey_algo]; + cert->pub->id_type = PKEY_ID_X509; + + /* Check the signature on the key */ +diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h +index 619d570..46bde25 100644 +--- a/include/crypto/public_key.h ++++ b/include/crypto/public_key.h +@@ -23,6 +23,7 @@ enum pkey_algo { + }; + + extern const char *const pkey_algo_name[PKEY_ALGO__LAST]; ++extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST]; + + enum pkey_hash_algo { + PKEY_HASH_MD4, +-- +1.8.3.1 + + +From 7009b65ddc1d8bf62dc017795265b9cf331a4d70 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:15:24 +0100 +Subject: [PATCH 07/14] KEYS: Store public key algo ID in public_key struct + +Store public key algo ID in public_key struct for reference purposes. This +allows it to be removed from the x509_certificate struct and used to find a +default in public_key_verify_signature(). + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/x509_cert_parser.c | 5 +++-- + crypto/asymmetric_keys/x509_parser.h | 1 - + crypto/asymmetric_keys/x509_public_key.c | 4 ++-- + include/crypto/public_key.h | 1 + + 4 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c +index facbf26..8cc253d 100644 +--- a/crypto/asymmetric_keys/x509_cert_parser.c ++++ b/crypto/asymmetric_keys/x509_cert_parser.c +@@ -343,8 +343,9 @@ int x509_extract_key_data(void *context, size_t hdrlen, + 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->cert->pub->pkey_algo = PKEY_ALGO_RSA; ++ ++ /* Discard the BIT STRING metadata */ + ctx->key = value + 1; + ctx->key_size = vlen - 1; + return 0; +diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h +index f86dc5f..e583ad0 100644 +--- a/crypto/asymmetric_keys/x509_parser.h ++++ b/crypto/asymmetric_keys/x509_parser.h +@@ -20,7 +20,6 @@ struct x509_certificate { + char *authority; /* Authority key fingerprint as hex */ + 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 */ + const void *tbs; /* Signed data */ +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index fe38628..fac574c 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -108,7 +108,7 @@ 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_name[cert->pkey_algo]); ++ pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); + pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", + cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, + cert->valid_from.tm_mday, cert->valid_from.tm_hour, +@@ -165,7 +165,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + goto error_free_cert; + } + +- cert->pub->algo = pkey_algo[cert->pkey_algo]; ++ cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; + cert->pub->id_type = PKEY_ID_X509; + + /* Check the signature on the key */ +diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h +index 46bde25..05778df 100644 +--- a/include/crypto/public_key.h ++++ b/include/crypto/public_key.h +@@ -60,6 +60,7 @@ struct public_key { + #define PKEY_CAN_DECRYPT 0x02 + #define PKEY_CAN_SIGN 0x04 + #define PKEY_CAN_VERIFY 0x08 ++ enum pkey_algo pkey_algo : 8; + enum pkey_id_type id_type : 8; + union { + MPI mpi[5]; +-- +1.8.3.1 + + +From cad6ff6b429f31611ccb231cfe6adcb69d891352 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:15:30 +0100 +Subject: [PATCH 08/14] KEYS: Split public_key_verify_signature() and make + available + +Modify public_key_verify_signature() so that it now takes a public_key struct +rather than a key struct and supply a wrapper that takes a key struct. The +wrapper is then used by the asymmetric key subtype and the modified function is +used by X.509 self-signature checking and can be used by other things also. + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/public_key.c | 40 +++++++++++++++++++++++++------- + crypto/asymmetric_keys/public_key.h | 6 +++++ + crypto/asymmetric_keys/x509_public_key.c | 2 +- + 3 files changed, 39 insertions(+), 9 deletions(-) + +diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c +index 796ce08..49ac8d8 100644 +--- a/crypto/asymmetric_keys/public_key.c ++++ b/crypto/asymmetric_keys/public_key.c +@@ -86,21 +86,45 @@ 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) ++int public_key_verify_signature(const struct public_key *pk, ++ const struct public_key_signature *sig) + { +- const struct public_key *pk = key->payload.data; ++ const struct public_key_algorithm *algo; ++ ++ BUG_ON(!pk); ++ BUG_ON(!pk->mpi[0]); ++ BUG_ON(!pk->mpi[1]); ++ BUG_ON(!sig); ++ BUG_ON(!sig->digest); ++ BUG_ON(!sig->mpi[0]); ++ ++ algo = pk->algo; ++ if (!algo) { ++ if (pk->pkey_algo >= PKEY_ALGO__LAST) ++ return -ENOPKG; ++ algo = pkey_algo[pk->pkey_algo]; ++ if (!algo) ++ return -ENOPKG; ++ } + +- if (!pk->algo->verify_signature) ++ if (!algo->verify_signature) + return -ENOTSUPP; + +- if (sig->nr_mpi != pk->algo->n_sig_mpi) { ++ if (sig->nr_mpi != algo->n_sig_mpi) { + pr_debug("Signature has %u MPI not %u\n", +- sig->nr_mpi, pk->algo->n_sig_mpi); ++ sig->nr_mpi, algo->n_sig_mpi); + return -EINVAL; + } + +- return pk->algo->verify_signature(pk, sig); ++ return algo->verify_signature(pk, sig); ++} ++EXPORT_SYMBOL_GPL(public_key_verify_signature); ++ ++static int public_key_verify_signature_2(const struct key *key, ++ const struct public_key_signature *sig) ++{ ++ const struct public_key *pk = key->payload.data; ++ return public_key_verify_signature(pk, sig); + } + + /* +@@ -111,6 +135,6 @@ struct asymmetric_key_subtype public_key_subtype = { + .name = "public_key", + .describe = public_key_describe, + .destroy = public_key_destroy, +- .verify_signature = public_key_verify_signature, ++ .verify_signature = public_key_verify_signature_2, + }; + EXPORT_SYMBOL_GPL(public_key_subtype); +diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h +index 5e5e356..5c37a22 100644 +--- a/crypto/asymmetric_keys/public_key.h ++++ b/crypto/asymmetric_keys/public_key.h +@@ -28,3 +28,9 @@ struct public_key_algorithm { + }; + + extern const struct public_key_algorithm RSA_public_key_algorithm; ++ ++/* ++ * public_key.c ++ */ ++extern int public_key_verify_signature(const struct public_key *pk, ++ const struct public_key_signature *sig); +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index fac574c..8cb2f70 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -76,7 +76,7 @@ static int x509_check_signature(const struct public_key *pub, + if (ret < 0) + goto error_mpi; + +- ret = pub->algo->verify_signature(pub, sig); ++ ret = public_key_verify_signature(pub, sig); + + pr_debug("Cert Verification: %d\n", ret); + +-- +1.8.3.1 + + +From 87854340605a64fcc54109ea415d9e54c45e8533 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:15:37 +0100 +Subject: [PATCH 09/14] KEYS: Store public key algo ID in public_key_signature + struct + +Store public key algorithm ID in public_key_signature struct for reference +purposes. This allows a public_key_signature struct to be embedded in +struct x509_certificate and other places more easily. + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + include/crypto/public_key.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h +index 05778df..b34fda4 100644 +--- a/include/crypto/public_key.h ++++ b/include/crypto/public_key.h +@@ -90,6 +90,7 @@ struct public_key_signature { + u8 *digest; + u8 digest_size; /* Number of bytes in digest */ + u8 nr_mpi; /* Occupancy of mpi[] */ ++ enum pkey_algo pkey_algo : 8; + enum pkey_hash_algo pkey_hash_algo : 8; + union { + MPI mpi[2]; +-- +1.8.3.1 + + +From ae4684a05d87123de310b69c616922dc993694ca Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:16:34 +0100 +Subject: [PATCH 10/14] X.509: struct x509_certificate needs struct tm + declaring + +struct x509_certificate needs struct tm declaring by #inclusion of linux/time.h +prior to its definition. + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/x509_parser.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h +index e583ad0..2d01182 100644 +--- a/crypto/asymmetric_keys/x509_parser.h ++++ b/crypto/asymmetric_keys/x509_parser.h +@@ -9,6 +9,7 @@ + * 2 of the Licence, or (at your option) any later version. + */ + ++#include <linux/time.h> + #include <crypto/public_key.h> + + struct x509_certificate { +-- +1.8.3.1 + + +From dacde6f44ebe5a5c89bd1a25b35b1b63c139b375 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:18:02 +0100 +Subject: [PATCH 11/14] X.509: Embed public_key_signature struct and create + filler function + +Embed a public_key_signature struct in struct x509_certificate, eliminating +now unnecessary fields, and split x509_check_signature() to create a filler +function for it that attaches a digest of the signed data and an MPI that +represents the signature data. x509_free_certificate() is then modified to +deal with these. + +Whilst we're at it, export both x509_check_signature() and the new +x509_get_sig_params(). + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/x509_cert_parser.c | 30 +++++------ + crypto/asymmetric_keys/x509_parser.h | 16 ++++-- + crypto/asymmetric_keys/x509_public_key.c | 83 +++++++++++++++++-------------- + 3 files changed, 74 insertions(+), 55 deletions(-) + +diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c +index 8cc253d..144201c 100644 +--- a/crypto/asymmetric_keys/x509_cert_parser.c ++++ b/crypto/asymmetric_keys/x509_cert_parser.c +@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert) + kfree(cert->subject); + kfree(cert->fingerprint); + kfree(cert->authority); ++ kfree(cert->sig.digest); ++ mpi_free(cert->sig.rsa.s); + kfree(cert); + } + } +@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, + return -ENOPKG; /* Unsupported combination */ + + case OID_md4WithRSAEncryption: +- ctx->cert->sig_hash_algo = PKEY_HASH_MD5; +- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; ++ ctx->cert->sig.pkey_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; ++ ctx->cert->sig.pkey_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; ++ ctx->cert->sig.pkey_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; ++ ctx->cert->sig.pkey_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; ++ ctx->cert->sig.pkey_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; ++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA224; ++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + break; + } + +@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen, + return -EINVAL; + } + +- ctx->cert->sig = value; +- ctx->cert->sig_size = vlen; ++ ctx->cert->raw_sig = value; ++ ctx->cert->raw_sig_size = vlen; + return 0; + } + +diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h +index 2d01182..87d9cc2 100644 +--- a/crypto/asymmetric_keys/x509_parser.h ++++ b/crypto/asymmetric_keys/x509_parser.h +@@ -21,12 +21,11 @@ struct x509_certificate { + char *authority; /* Authority key fingerprint as hex */ + struct tm valid_from; + struct tm valid_to; +- 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 */ ++ unsigned tbs_size; /* Size of signed data */ ++ unsigned raw_sig_size; /* Size of sigature */ ++ const void *raw_sig; /* Signature data */ ++ struct public_key_signature sig; /* Signature parameters */ + }; + + /* +@@ -34,3 +33,10 @@ struct x509_certificate { + */ + extern void x509_free_certificate(struct x509_certificate *cert); + extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); ++ ++/* ++ * x509_public_key.c ++ */ ++extern int x509_get_sig_params(struct x509_certificate *cert); ++extern int x509_check_signature(const struct public_key *pub, ++ struct x509_certificate *cert); +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 8cb2f70..b7c81d8 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -24,72 +24,83 @@ + #include "x509_parser.h" + + /* +- * Check the signature on a certificate using the provided public key ++ * Set up the signature parameters in an X.509 certificate. This involves ++ * digesting the signed data and extracting the signature. + */ +-static int x509_check_signature(const struct public_key *pub, +- const struct x509_certificate *cert) ++int x509_get_sig_params(struct x509_certificate *cert) + { +- struct public_key_signature *sig; + struct crypto_shash *tfm; + struct shash_desc *desc; + size_t digest_size, desc_size; ++ void *digest; + int ret; + + pr_devel("==>%s()\n", __func__); +- ++ ++ if (cert->sig.rsa.s) ++ return 0; ++ ++ cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size); ++ if (!cert->sig.rsa.s) ++ return -ENOMEM; ++ cert->sig.nr_mpi = 1; ++ + /* 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_name[cert->sig_hash_algo], 0, 0); ++ tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig.pkey_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. ++ /* We allocate the hash operational data storage on the end of the ++ * digest storage space. + */ + ret = -ENOMEM; +- sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); +- if (!sig) +- goto error_no_sig; ++ digest = kzalloc(digest_size + desc_size, GFP_KERNEL); ++ if (!digest) ++ goto error; + +- sig->pkey_hash_algo = cert->sig_hash_algo; +- sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; +- sig->digest_size = digest_size; ++ cert->sig.digest = digest; ++ cert->sig.digest_size = digest_size; + +- desc = (void *)sig + sizeof(*sig); +- desc->tfm = tfm; +- desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ desc = digest + digest_size; ++ desc->tfm = tfm; ++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_init(desc); + if (ret < 0) + goto error; ++ might_sleep(); ++ ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest); ++error: ++ crypto_free_shash(tfm); ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(x509_get_sig_params); + +- ret = -ENOMEM; +- sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); +- if (!sig->rsa.s) +- goto error; ++/* ++ * Check the signature on a certificate using the provided public key ++ */ ++int x509_check_signature(const struct public_key *pub, ++ struct x509_certificate *cert) ++{ ++ int ret; + +- ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); +- if (ret < 0) +- goto error_mpi; ++ pr_devel("==>%s()\n", __func__); + +- ret = public_key_verify_signature(pub, sig); ++ ret = x509_get_sig_params(cert); ++ if (ret < 0) ++ return ret; + ++ ret = public_key_verify_signature(pub, &cert->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; + } ++EXPORT_SYMBOL_GPL(x509_check_signature); + + /* + * Attempt to parse a data blob for a key as an X509 certificate. +@@ -118,8 +129,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + 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_name[cert->sig_pkey_algo], +- pkey_hash_algo_name[cert->sig_hash_algo]); ++ pkey_algo_name[cert->sig.pkey_algo], ++ pkey_hash_algo_name[cert->sig.pkey_hash_algo]); + + if (!cert->fingerprint || !cert->authority) { + pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", +-- +1.8.3.1 + + +From 650fdcb141f65f3a03dc7eba1179c823fd1a3a54 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:18:15 +0100 +Subject: [PATCH 12/14] X.509: Check the algorithm IDs obtained from parsing an + X.509 certificate + +Check that the algorithm IDs obtained from the ASN.1 parse by OID lookup +corresponds to algorithms that are available to us. + +Reported-by: Kees Cook <keescook@chromium.org> +Signed-off-by: David Howells <dhowells@redhat.com> +--- + crypto/asymmetric_keys/x509_public_key.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index b7c81d8..eb368d4 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -119,6 +119,17 @@ 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); ++ ++ if (cert->pub->pkey_algo >= PKEY_ALGO__LAST || ++ cert->sig.pkey_algo >= PKEY_ALGO__LAST || ++ cert->sig.pkey_hash_algo >= PKEY_HASH__LAST || ++ !pkey_algo[cert->pub->pkey_algo] || ++ !pkey_algo[cert->sig.pkey_algo] || ++ !pkey_hash_algo_name[cert->sig.pkey_hash_algo]) { ++ ret = -ENOPKG; ++ goto error_free_cert; ++ } ++ + pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); + pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", + cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, +-- +1.8.3.1 + + +From 8671bdd55802c4b93b9205b6ecd02c7e351ac5c5 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 30 Aug 2013 16:18:31 +0100 +Subject: [PATCH 13/14] X.509: Handle certificates that lack an + authorityKeyIdentifier field + +Handle certificates that lack an authorityKeyIdentifier field by assuming +they're self-signed and checking their signatures against themselves. + +Signed-off-by: David Howells <dhowells@redhat.com> +Reviewed-by: Kees Cook <keescook@chromium.org> +Reviewed-by: Josh Boyer <jwboyer@redhat.com> +--- + crypto/asymmetric_keys/x509_public_key.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index eb368d4..0f55e3b 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -143,8 +143,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + pkey_algo_name[cert->sig.pkey_algo], + pkey_hash_algo_name[cert->sig.pkey_hash_algo]); + +- if (!cert->fingerprint || !cert->authority) { +- pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", ++ if (!cert->fingerprint) { ++ pr_warn("Cert for '%s' must have a SubjKeyId extension\n", + cert->subject); + ret = -EKEYREJECTED; + goto error_free_cert; +@@ -190,8 +190,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; + cert->pub->id_type = PKEY_ID_X509; + +- /* Check the signature on the key */ +- if (strcmp(cert->fingerprint, cert->authority) == 0) { ++ /* Check the signature on the key if it appears to be self-signed */ ++ if (!cert->authority || ++ strcmp(cert->fingerprint, cert->authority) == 0) { + ret = x509_check_signature(cert->pub, cert); + if (ret < 0) + goto error_free_cert; +-- +1.8.3.1 + + +From e2d665556f4b60ce76e880a62f98c81622271e71 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Tue, 18 Jun 2013 17:40:44 +0100 +Subject: [PATCH 14/14] X.509: Remove certificate date checks + +Remove the certificate date checks that are performed when a certificate is +parsed. There are two checks: a valid from and a valid to. The first check is +causing a lot of problems with system clocks that don't keep good time and the +second places an implicit expiry date upon the kernel when used for module +signing, so do we really need them? + +Signed-off-by: David Howells <dhowells@redhat.com> +cc: David Woodhouse <dwmw2@infradead.org> +cc: Rusty Russell <rusty@rustcorp.com.au> +cc: Josh Boyer <jwboyer@redhat.com> +cc: Alexander Holler <holler@ahsoftware.de> +cc: stable@vger.kernel.org +--- + crypto/asymmetric_keys/x509_public_key.c | 38 -------------------------------- + 1 file changed, 38 deletions(-) + +diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c +index 0f55e3b..c1540e8 100644 +--- a/crypto/asymmetric_keys/x509_public_key.c ++++ b/crypto/asymmetric_keys/x509_public_key.c +@@ -108,7 +108,6 @@ EXPORT_SYMBOL_GPL(x509_check_signature); + static int x509_key_preparse(struct key_preparsed_payload *prep) + { + struct x509_certificate *cert; +- struct tm now; + size_t srlen, sulen; + char *desc = NULL; + int ret; +@@ -150,43 +149,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) + goto error_free_cert; + } + +- time_to_tm(CURRENT_TIME.tv_sec, 0, &now); +- pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", +- now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, +- now.tm_hour, now.tm_min, now.tm_sec); +- if (now.tm_year < cert->valid_from.tm_year || +- (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.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; +- } +- + cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; + cert->pub->id_type = PKEY_ID_X509; + +-- +1.8.3.1 + |