aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2015-07-20 16:16:30 -0400
committerDavid Howells <dhowells@redhat.com>2015-08-07 11:26:14 -0400
commit1329e8cc69b93a0b1bc6d197b30dcff628c18dbf (patch)
treec468b5fe99777d0e5072b1bc41f43ef47253cf8e
parent19e91b69d77bab16405cc284b451378e89a4110c (diff)
modsign: Extract signing cert from CONFIG_MODULE_SIG_KEY if needed
Where an external PEM file or PKCS#11 URI is given, we can get the cert from it for ourselves instead of making the user drop signing_key.x509 in place for us. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--Documentation/module-signing.txt11
-rw-r--r--init/Kconfig8
-rw-r--r--kernel/Makefile38
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/extract-cert.c132
5 files changed, 181 insertions, 11 deletions
diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt
index 84597c7ea175..693001920890 100644
--- a/Documentation/module-signing.txt
+++ b/Documentation/module-signing.txt
@@ -93,17 +93,16 @@ This has a number of options available:
93 Setting this option to something other than its default of 93 Setting this option to something other than its default of
94 "signing_key.priv" will disable the autogeneration of signing keys and 94 "signing_key.priv" will disable the autogeneration of signing keys and
95 allow the kernel modules to be signed with a key of your choosing. 95 allow the kernel modules to be signed with a key of your choosing.
96 The string provided should identify a file containing a private key 96 The string provided should identify a file containing both a private
97 in PEM form, or — on systems where the OpenSSL ENGINE_pkcs11 is 97 key and its corresponding X.509 certificate in PEM form, or — on
98 appropriately installed — a PKCS#11 URI as defined by RFC7512. 98 systems where the OpenSSL ENGINE_pkcs11 is functional — a PKCS#11 URI
99 as defined by RFC7512. In the latter case, the PKCS#11 URI should
100 reference both a certificate and a private key.
99 101
100 If the PEM file containing the private key is encrypted, or if the 102 If the PEM file containing the private key is encrypted, or if the
101 PKCS#11 token requries a PIN, this can be provided at build time by 103 PKCS#11 token requries a PIN, this can be provided at build time by
102 means of the KBUILD_SIGN_PIN variable. 104 means of the KBUILD_SIGN_PIN variable.
103 105
104 The corresponding X.509 certificate in DER form should still be placed
105 in a file named signing_key.x509 in the top-level build directory.
106
107 106
108======================= 107=======================
109GENERATING SIGNING KEYS 108GENERATING SIGNING KEYS
diff --git a/init/Kconfig b/init/Kconfig
index 1b1148e9181b..e2e0a1d27886 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1953,10 +1953,10 @@ config MODULE_SIG_KEY
1953 default "signing_key.priv" 1953 default "signing_key.priv"
1954 depends on MODULE_SIG 1954 depends on MODULE_SIG
1955 help 1955 help
1956 Provide the file name of a private key in PKCS#8 PEM format, or 1956 Provide the file name of a private key/certificate in PEM format,
1957 a PKCS#11 URI according to RFC7512. The corresponding X.509 1957 or a PKCS#11 URI according to RFC7512. The file should contain, or
1958 certificate in DER form should be present in signing_key.x509 1958 the URI should identify, both the certificate and its corresponding
1959 in the top-level build directory. 1959 private key.
1960 1960
1961 If this option is unchanged from its default "signing_key.priv", 1961 If this option is unchanged from its default "signing_key.priv",
1962 then the kernel will automatically generate the private key and 1962 then the kernel will automatically generate the private key and
diff --git a/kernel/Makefile b/kernel/Makefile
index 2c937ace292e..fa2f8b84b18a 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -210,5 +210,43 @@ x509.genkey:
210 @echo >>x509.genkey "keyUsage=digitalSignature" 210 @echo >>x509.genkey "keyUsage=digitalSignature"
211 @echo >>x509.genkey "subjectKeyIdentifier=hash" 211 @echo >>x509.genkey "subjectKeyIdentifier=hash"
212 @echo >>x509.genkey "authorityKeyIdentifier=keyid" 212 @echo >>x509.genkey "authorityKeyIdentifier=keyid"
213else
214# For external (PKCS#11 or PEM) key, we need to obtain the certificate from
215# CONFIG_MODULE_SIG_KEY automatically.
216quiet_cmd_extract_der = CERT_DER $(2)
217 cmd_extract_der = scripts/extract-cert "$(2)" signing_key.x509
218
219# CONFIG_MODULE_SIG_KEY is either a PKCS#11 URI or a filename. It is
220# surrounded by quotes, and may contain spaces. To strip the quotes
221# with $(patsubst) we need to turn the spaces into something else.
222# And if it's a filename, those spaces need to be escaped as '\ ' in
223# order to use it in dependencies or $(wildcard).
224space :=
225space +=
226space_escape := %%%SPACE%%%
227X509_SOURCE_temp := $(subst $(space),$(space_escape),$(CONFIG_MODULE_SIG_KEY))
228# We need this to check for absolute paths or PKCS#11 URIs.
229X509_SOURCE_ONEWORD := $(patsubst "%",%,$(X509_SOURCE_temp))
230# This is the actual source filename/URI without the quotes
231X509_SOURCE := $(subst $(space_escape),$(space),$(X509_SOURCE_ONEWORD))
232# This\ version\ with\ spaces\ escaped\ for\ $(wildcard)\ and\ dependencies
233X509_SOURCE_ESCAPED := $(subst $(space_escape),\$(space),$(X509_SOURCE_ONEWORD))
234
235ifeq ($(patsubst pkcs11:%,%,$(X509_SOURCE_ONEWORD)),$(X509_SOURCE_ONEWORD))
236# If it's a filename, depend on it.
237X509_DEP := $(X509_SOURCE_ESCAPED)
238ifeq ($(patsubst /%,%,$(X509_SOURCE_ONEWORD)),$(X509_SOURCE_ONEWORD))
239ifeq ($(wildcard $(X509_SOURCE_ESCAPED)),)
240ifneq ($(wildcard $(srctree)/$(X509_SOURCE_ESCAPED)),)
241# Non-absolute filename, found in source tree and not build tree
242X509_SOURCE := $(srctree)/$(X509_SOURCE)
243X509_DEP := $(srctree)/$(X509_SOURCE_ESCAPED)
244endif
245endif
246endif
247endif
248
249signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP)
250 $(call cmd,extract_der,$(X509_SOURCE))
213endif 251endif
214endif 252endif
diff --git a/scripts/Makefile b/scripts/Makefile
index b12fe020664d..236f683510bd 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -16,11 +16,12 @@ hostprogs-$(CONFIG_VT) += conmakehash
16hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount 16hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
17hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable 17hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
18hostprogs-$(CONFIG_ASN1) += asn1_compiler 18hostprogs-$(CONFIG_ASN1) += asn1_compiler
19hostprogs-$(CONFIG_MODULE_SIG) += sign-file 19hostprogs-$(CONFIG_MODULE_SIG) += sign-file extract-cert
20 20
21HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include 21HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
22HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include 22HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
23HOSTLOADLIBES_sign-file = -lcrypto 23HOSTLOADLIBES_sign-file = -lcrypto
24HOSTLOADLIBES_extract-cert = -lcrypto
24 25
25always := $(hostprogs-y) $(hostprogs-m) 26always := $(hostprogs-y) $(hostprogs-m)
26 27
diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c
new file mode 100644
index 000000000000..4fd5b2f07b45
--- /dev/null
+++ b/scripts/extract-cert.c
@@ -0,0 +1,132 @@
1/* Extract X.509 certificate in DER form from PKCS#11 or PEM.
2 *
3 * Copyright © 2014 Red Hat, Inc. All Rights Reserved.
4 * Copyright © 2015 Intel Corporation.
5 *
6 * Authors: David Howells <dhowells@redhat.com>
7 * David Woodhouse <dwmw2@infradead.org>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public Licence
11 * as published by the Free Software Foundation; either version
12 * 2 of the Licence, or (at your option) any later version.
13 */
14#define _GNU_SOURCE
15#include <stdio.h>
16#include <stdlib.h>
17#include <stdint.h>
18#include <stdbool.h>
19#include <string.h>
20#include <getopt.h>
21#include <err.h>
22#include <arpa/inet.h>
23#include <openssl/bio.h>
24#include <openssl/evp.h>
25#include <openssl/pem.h>
26#include <openssl/pkcs7.h>
27#include <openssl/err.h>
28#include <openssl/engine.h>
29
30#define PKEY_ID_PKCS7 2
31
32static __attribute__((noreturn))
33void format(void)
34{
35 fprintf(stderr,
36 "Usage: scripts/extract-cert <source> <dest>\n");
37 exit(2);
38}
39
40static void display_openssl_errors(int l)
41{
42 const char *file;
43 char buf[120];
44 int e, line;
45
46 if (ERR_peek_error() == 0)
47 return;
48 fprintf(stderr, "At main.c:%d:\n", l);
49
50 while ((e = ERR_get_error_line(&file, &line))) {
51 ERR_error_string(e, buf);
52 fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
53 }
54}
55
56static void drain_openssl_errors(void)
57{
58 const char *file;
59 int line;
60
61 if (ERR_peek_error() == 0)
62 return;
63 while (ERR_get_error_line(&file, &line)) {}
64}
65
66#define ERR(cond, fmt, ...) \
67 do { \
68 bool __cond = (cond); \
69 display_openssl_errors(__LINE__); \
70 if (__cond) { \
71 err(1, fmt, ## __VA_ARGS__); \
72 } \
73 } while(0)
74
75static const char *key_pass;
76
77int main(int argc, char **argv)
78{
79 char *cert_src, *cert_dst;
80 X509 *x509;
81 BIO *b;
82
83 OpenSSL_add_all_algorithms();
84 ERR_load_crypto_strings();
85 ERR_clear_error();
86
87 key_pass = getenv("KBUILD_SIGN_PIN");
88
89 if (argc != 3)
90 format();
91
92 cert_src = argv[1];
93 cert_dst = argv[2];
94
95 if (!strncmp(cert_src, "pkcs11:", 7)) {
96 ENGINE *e;
97 struct {
98 const char *cert_id;
99 X509 *cert;
100 } parms;
101
102 parms.cert_id = cert_src;
103 parms.cert = NULL;
104
105 ENGINE_load_builtin_engines();
106 drain_openssl_errors();
107 e = ENGINE_by_id("pkcs11");
108 ERR(!e, "Load PKCS#11 ENGINE");
109 if (ENGINE_init(e))
110 drain_openssl_errors();
111 else
112 ERR(1, "ENGINE_init");
113 if (key_pass)
114 ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
115 ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
116 ERR(!parms.cert, "Get X.509 from PKCS#11");
117 x509 = parms.cert;
118 } else {
119 b = BIO_new_file(cert_src, "rb");
120 ERR(!b, "%s", cert_src);
121 x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
122 ERR(!x509, "%s", cert_src);
123 BIO_free(b);
124 }
125
126 b = BIO_new_file(cert_dst, "wb");
127 ERR(!b, "%s", cert_dst);
128 ERR(!i2d_X509_bio(b, x509), cert_dst);
129 BIO_free(b);
130
131 return 0;
132}