aboutsummaryrefslogtreecommitdiffstats
path: root/certs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2015-08-14 10:20:41 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2015-08-14 11:06:13 -0400
commitcfc411e7fff3e15cd6354ff69773907e2c9d1c0c (patch)
treec67e679c1c2bbe4a657ce58d60e995c63535952b /certs
parent0e38c35815f50e5a347977d76fb5eb4c3bf020b5 (diff)
Move certificate handling to its own directory
Move certificate handling out of the kernel/ directory and into a certs/ directory to get all the weird stuff in one place and move the generated signing keys into this directory. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'certs')
-rw-r--r--certs/Kconfig42
-rw-r--r--certs/Makefile147
-rw-r--r--certs/system_certificates.S23
-rw-r--r--certs/system_keyring.c157
4 files changed, 369 insertions, 0 deletions
diff --git a/certs/Kconfig b/certs/Kconfig
new file mode 100644
index 000000000000..b030b9c7ed34
--- /dev/null
+++ b/certs/Kconfig
@@ -0,0 +1,42 @@
1menu "Certificates for signature checking"
2
3config MODULE_SIG_KEY
4 string "File name or PKCS#11 URI of module signing key"
5 default "certs/signing_key.pem"
6 depends on MODULE_SIG
7 help
8 Provide the file name of a private key/certificate in PEM format,
9 or a PKCS#11 URI according to RFC7512. The file should contain, or
10 the URI should identify, both the certificate and its corresponding
11 private key.
12
13 If this option is unchanged from its default "certs/signing_key.pem",
14 then the kernel will automatically generate the private key and
15 certificate as described in Documentation/module-signing.txt
16
17config SYSTEM_TRUSTED_KEYRING
18 bool "Provide system-wide ring of trusted keys"
19 depends on KEYS
20 help
21 Provide a system keyring to which trusted keys can be added. Keys in
22 the keyring are considered to be trusted. Keys may be added at will
23 by the kernel from compiled-in data and from hardware key stores, but
24 userspace may only add extra keys if those keys can be verified by
25 keys already in the keyring.
26
27 Keys in this keyring are used by module signature checking.
28
29config SYSTEM_TRUSTED_KEYS
30 string "Additional X.509 keys for default system keyring"
31 depends on SYSTEM_TRUSTED_KEYRING
32 help
33 If set, this option should be the filename of a PEM-formatted file
34 containing trusted X.509 certificates to be included in the default
35 system keyring. Any certificate used for module signing is implicitly
36 also trusted.
37
38 NOTE: If you previously provided keys for the system keyring in the
39 form of DER-encoded *.x509 files in the top-level build directory,
40 those are no longer used. You will need to set this option instead.
41
42endmenu
diff --git a/certs/Makefile b/certs/Makefile
new file mode 100644
index 000000000000..5d33486d3b20
--- /dev/null
+++ b/certs/Makefile
@@ -0,0 +1,147 @@
1#
2# Makefile for the linux kernel signature checking certificates.
3#
4
5obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
6
7###############################################################################
8#
9# When a Kconfig string contains a filename, it is suitable for
10# passing to shell commands. It is surrounded by double-quotes, and
11# any double-quotes or backslashes within it are escaped by
12# backslashes.
13#
14# This is no use for dependencies or $(wildcard). We need to strip the
15# surrounding quotes and the escaping from quotes and backslashes, and
16# we *do* need to escape any spaces in the string. So, for example:
17#
18# Usage: $(eval $(call config_filename,FOO))
19#
20# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option,
21# transformed as described above to be suitable for use within the
22# makefile.
23#
24# Also, if the filename is a relative filename and exists in the source
25# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to
26# be prefixed to *both* command invocation and dependencies.
27#
28# Note: We also print the filenames in the quiet_cmd_foo text, and
29# perhaps ought to have a version specially escaped for that purpose.
30# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good
31# enough. It'll strip the quotes in the common case where there's no
32# space and it's a simple filename, and it'll retain the quotes when
33# there's a space. There are some esoteric cases in which it'll print
34# the wrong thing, but we don't really care. The actual dependencies
35# and commands *do* get it right, with various combinations of single
36# and double quotes, backslashes and spaces in the filenames.
37#
38###############################################################################
39#
40quote := $(firstword " ")
41space :=
42space +=
43space_escape := %%%SPACE%%%
44#
45define config_filename
46ifneq ($$(CONFIG_$(1)),"")
47$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1)))))))
48ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME)))
49else
50ifeq ($$(wildcard $$($(1)_FILENAME)),)
51ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),)
52$(1)_SRCPREFIX := $(srctree)/
53endif
54endif
55endif
56endif
57endef
58#
59###############################################################################
60
61ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
62
63$(eval $(call config_filename,SYSTEM_TRUSTED_KEYS))
64
65# GCC doesn't include .incbin files in -MD generated dependencies (PR#66871)
66$(obj)/system_certificates.o: $(obj)/x509_certificate_list
67
68# Cope with signing_key.x509 existing in $(srctree) not $(objtree)
69AFLAGS_system_certificates.o := -I$(srctree)
70
71quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2))
72 cmd_extract_certs = scripts/extract-cert $(2) $@ || ( rm $@; exit 1)
73
74targets += x509_certificate_list
75$(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE
76 $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS))
77endif
78
79clean-files := x509_certificate_list .x509.list
80
81ifeq ($(CONFIG_MODULE_SIG),y)
82###############################################################################
83#
84# If module signing is requested, say by allyesconfig, but a key has not been
85# supplied, then one will need to be generated to make sure the build does not
86# fail and that the kernel may be used afterwards.
87#
88###############################################################################
89ifndef CONFIG_MODULE_SIG_HASH
90$(error Could not determine digest type to use from kernel config)
91endif
92
93# We do it this way rather than having a boolean option for enabling an
94# external private key, because 'make randconfig' might enable such a
95# boolean option and we unfortunately can't make it depend on !RANDCONFIG.
96ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
97$(obj)/signing_key.pem: $(obj)/x509.genkey
98 @echo "###"
99 @echo "### Now generating an X.509 key pair to be used for signing modules."
100 @echo "###"
101 @echo "### If this takes a long time, you might wish to run rngd in the"
102 @echo "### background to keep the supply of entropy topped up. It"
103 @echo "### needs to be run as root, and uses a hardware random"
104 @echo "### number generator if one is available."
105 @echo "###"
106 openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
107 -batch -x509 -config $(obj)/x509.genkey \
108 -outform PEM -out $(obj)/signing_key.pem \
109 -keyout $(obj)/signing_key.pem 2>&1
110 @echo "###"
111 @echo "### Key pair generated."
112 @echo "###"
113
114$(obj)/x509.genkey:
115 @echo Generating X.509 key generation config
116 @echo >$@ "[ req ]"
117 @echo >>$@ "default_bits = 4096"
118 @echo >>$@ "distinguished_name = req_distinguished_name"
119 @echo >>$@ "prompt = no"
120 @echo >>$@ "string_mask = utf8only"
121 @echo >>$@ "x509_extensions = myexts"
122 @echo >>$@
123 @echo >>$@ "[ req_distinguished_name ]"
124 @echo >>$@ "#O = Unspecified company"
125 @echo >>$@ "CN = Build time autogenerated kernel key"
126 @echo >>$@ "#emailAddress = unspecified.user@unspecified.company"
127 @echo >>$@
128 @echo >>$@ "[ myexts ]"
129 @echo >>$@ "basicConstraints=critical,CA:FALSE"
130 @echo >>$@ "keyUsage=digitalSignature"
131 @echo >>$@ "subjectKeyIdentifier=hash"
132 @echo >>$@ "authorityKeyIdentifier=keyid"
133endif
134
135$(eval $(call config_filename,MODULE_SIG_KEY))
136
137# If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it
138ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME)))
139X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME)
140endif
141
142# GCC PR#66871 again.
143$(obj)/system_certificates.o: $(obj)/signing_key.x509
144
145$(obj)/signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP)
146 $(call cmd,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
147endif
diff --git a/certs/system_certificates.S b/certs/system_certificates.S
new file mode 100644
index 000000000000..9216e8c81764
--- /dev/null
+++ b/certs/system_certificates.S
@@ -0,0 +1,23 @@
1#include <linux/export.h>
2#include <linux/init.h>
3
4 __INITRODATA
5
6 .align 8
7 .globl VMLINUX_SYMBOL(system_certificate_list)
8VMLINUX_SYMBOL(system_certificate_list):
9__cert_list_start:
10#ifdef CONFIG_MODULE_SIG
11 .incbin "certs/signing_key.x509"
12#endif
13 .incbin "certs/x509_certificate_list"
14__cert_list_end:
15
16 .align 8
17 .globl VMLINUX_SYMBOL(system_certificate_list_size)
18VMLINUX_SYMBOL(system_certificate_list_size):
19#ifdef CONFIG_64BIT
20 .quad __cert_list_end - __cert_list_start
21#else
22 .long __cert_list_end - __cert_list_start
23#endif
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
new file mode 100644
index 000000000000..2570598b784d
--- /dev/null
+++ b/certs/system_keyring.c
@@ -0,0 +1,157 @@
1/* System trusted keyring for trusted public keys
2 *
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/export.h>
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/cred.h>
16#include <linux/err.h>
17#include <keys/asymmetric-type.h>
18#include <keys/system_keyring.h>
19#include <crypto/pkcs7.h>
20
21struct key *system_trusted_keyring;
22EXPORT_SYMBOL_GPL(system_trusted_keyring);
23
24extern __initconst const u8 system_certificate_list[];
25extern __initconst const unsigned long system_certificate_list_size;
26
27/*
28 * Load the compiled-in keys
29 */
30static __init int system_trusted_keyring_init(void)
31{
32 pr_notice("Initialise system trusted keyring\n");
33
34 system_trusted_keyring =
35 keyring_alloc(".system_keyring",
36 KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
37 ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
38 KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
39 KEY_ALLOC_NOT_IN_QUOTA, NULL);
40 if (IS_ERR(system_trusted_keyring))
41 panic("Can't allocate system trusted keyring\n");
42
43 set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
44 return 0;
45}
46
47/*
48 * Must be initialised before we try and load the keys into the keyring.
49 */
50device_initcall(system_trusted_keyring_init);
51
52/*
53 * Load the compiled-in list of X.509 certificates.
54 */
55static __init int load_system_certificate_list(void)
56{
57 key_ref_t key;
58 const u8 *p, *end;
59 size_t plen;
60
61 pr_notice("Loading compiled-in X.509 certificates\n");
62
63 p = system_certificate_list;
64 end = p + system_certificate_list_size;
65 while (p < end) {
66 /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
67 * than 256 bytes in size.
68 */
69 if (end - p < 4)
70 goto dodgy_cert;
71 if (p[0] != 0x30 &&
72 p[1] != 0x82)
73 goto dodgy_cert;
74 plen = (p[2] << 8) | p[3];
75 plen += 4;
76 if (plen > end - p)
77 goto dodgy_cert;
78
79 key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
80 "asymmetric",
81 NULL,
82 p,
83 plen,
84 ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
85 KEY_USR_VIEW | KEY_USR_READ),
86 KEY_ALLOC_NOT_IN_QUOTA |
87 KEY_ALLOC_TRUSTED);
88 if (IS_ERR(key)) {
89 pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
90 PTR_ERR(key));
91 } else {
92 set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
93 pr_notice("Loaded X.509 cert '%s'\n",
94 key_ref_to_ptr(key)->description);
95 key_ref_put(key);
96 }
97 p += plen;
98 }
99
100 return 0;
101
102dodgy_cert:
103 pr_err("Problem parsing in-kernel X.509 certificate list\n");
104 return 0;
105}
106late_initcall(load_system_certificate_list);
107
108#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
109
110/**
111 * Verify a PKCS#7-based signature on system data.
112 * @data: The data to be verified.
113 * @len: Size of @data.
114 * @raw_pkcs7: The PKCS#7 message that is the signature.
115 * @pkcs7_len: The size of @raw_pkcs7.
116 * @usage: The use to which the key is being put.
117 */
118int system_verify_data(const void *data, unsigned long len,
119 const void *raw_pkcs7, size_t pkcs7_len,
120 enum key_being_used_for usage)
121{
122 struct pkcs7_message *pkcs7;
123 bool trusted;
124 int ret;
125
126 pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
127 if (IS_ERR(pkcs7))
128 return PTR_ERR(pkcs7);
129
130 /* The data should be detached - so we need to supply it. */
131 if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
132 pr_err("PKCS#7 signature with non-detached data\n");
133 ret = -EBADMSG;
134 goto error;
135 }
136
137 ret = pkcs7_verify(pkcs7, usage);
138 if (ret < 0)
139 goto error;
140
141 ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
142 if (ret < 0)
143 goto error;
144
145 if (!trusted) {
146 pr_err("PKCS#7 signature not signed with a trusted key\n");
147 ret = -ENOKEY;
148 }
149
150error:
151 pkcs7_free_message(pkcs7);
152 pr_devel("<==%s() = %d\n", __func__, ret);
153 return ret;
154}
155EXPORT_SYMBOL_GPL(system_verify_data);
156
157#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */