summaryrefslogtreecommitdiffstats
path: root/certs
diff options
context:
space:
mode:
Diffstat (limited to 'certs')
-rw-r--r--certs/.gitignore1
-rw-r--r--certs/Kconfig4
-rw-r--r--certs/Makefile125
-rw-r--r--certs/default_x509.genkey17
-rw-r--r--certs/extract-cert.c162
5 files changed, 214 insertions, 95 deletions
diff --git a/certs/.gitignore b/certs/.gitignore
index 8c3763f80be3..9e42fe3e02f5 100644
--- a/certs/.gitignore
+++ b/certs/.gitignore
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
+/extract-cert
/x509_certificate_list
/x509_revocation_list
diff --git a/certs/Kconfig b/certs/Kconfig
index ae7f2e876a31..73d1350c223a 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -17,21 +17,19 @@ config MODULE_SIG_KEY
choice
prompt "Type of module signing key to be generated"
- default MODULE_SIG_KEY_TYPE_RSA
+ depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
help
The type of module signing key type to generate. This option
does not apply if a #PKCS11 URI is used.
config MODULE_SIG_KEY_TYPE_RSA
bool "RSA"
- depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
help
Use an RSA key for module signing.
config MODULE_SIG_KEY_TYPE_ECDSA
bool "ECDSA"
select CRYPTO_ECDSA
- depends on MODULE_SIG || (IMA_APPRAISE_MODSIG && MODULES)
help
Use an elliptic curve key (NIST P384) for module signing. Consider
using a strong hash like sha256 or sha384 for hashing modules.
diff --git a/certs/Makefile b/certs/Makefile
index 279433783b10..f7041c29a2e0 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -6,31 +6,21 @@
obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o common.o
obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o common.o
obj-$(CONFIG_SYSTEM_REVOCATION_LIST) += revocation_certificates.o
-ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"")
+ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),)
obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_hashes.o
else
obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist_nohashes.o
endif
-ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
+quiet_cmd_extract_certs = CERT $@
+ cmd_extract_certs = $(obj)/extract-cert $(2) $@
-$(eval $(call config_filename,SYSTEM_TRUSTED_KEYS))
-
-# GCC doesn't include .incbin files in -MD generated dependencies (PR#66871)
$(obj)/system_certificates.o: $(obj)/x509_certificate_list
-# Cope with signing_key.x509 existing in $(srctree) not $(objtree)
-AFLAGS_system_certificates.o := -I$(srctree)
-
-quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2))
- cmd_extract_certs = scripts/extract-cert $(2) $@
+$(obj)/x509_certificate_list: $(CONFIG_SYSTEM_TRUSTED_KEYS) $(obj)/extract-cert FORCE
+ $(call if_changed,extract_certs,$(if $(CONFIG_SYSTEM_TRUSTED_KEYS),$<,""))
targets += x509_certificate_list
-$(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE
- $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS))
-endif # CONFIG_SYSTEM_TRUSTED_KEYRING
-
-clean-files := x509_certificate_list .x509.list x509_revocation_list
ifeq ($(CONFIG_MODULE_SIG),y)
SIGN_KEY = y
@@ -50,103 +40,54 @@ ifdef SIGN_KEY
# fail and that the kernel may be used afterwards.
#
###############################################################################
-ifndef CONFIG_MODULE_SIG_HASH
-$(error Could not determine digest type to use from kernel config)
-endif
-
-redirect_openssl = 2>&1
-quiet_redirect_openssl = 2>&1
-silent_redirect_openssl = 2>/dev/null
-openssl_available = $(shell openssl help 2>/dev/null && echo yes)
# We do it this way rather than having a boolean option for enabling an
# external private key, because 'make randconfig' might enable such a
# boolean option and we unfortunately can't make it depend on !RANDCONFIG.
-ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
+ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem)
-ifeq ($(openssl_available),yes)
-X509TEXT=$(shell openssl x509 -in "certs/signing_key.pem" -text 2>/dev/null)
-endif
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_ECDSA) := -newkey ec -pkeyopt ec_paramgen_curve:secp384r1
-# Support user changing key type
-ifdef CONFIG_MODULE_SIG_KEY_TYPE_ECDSA
-keytype_openssl = -newkey ec -pkeyopt ec_paramgen_curve:secp384r1
-ifeq ($(openssl_available),yes)
-$(if $(findstring id-ecPublicKey,$(X509TEXT)),,$(shell rm -f "certs/signing_key.pem"))
-endif
-endif # CONFIG_MODULE_SIG_KEY_TYPE_ECDSA
+quiet_cmd_gen_key = GENKEY $@
+ cmd_gen_key = openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
+ -batch -x509 -config $< \
+ -outform PEM -out $@ -keyout $@ $(keytype-y) 2>&1
-ifdef CONFIG_MODULE_SIG_KEY_TYPE_RSA
-ifeq ($(openssl_available),yes)
-$(if $(findstring rsaEncryption,$(X509TEXT)),,$(shell rm -f "certs/signing_key.pem"))
-endif
-endif # CONFIG_MODULE_SIG_KEY_TYPE_RSA
-
-$(obj)/signing_key.pem: $(obj)/x509.genkey
- @$(kecho) "###"
- @$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
- @$(kecho) "###"
- @$(kecho) "### If this takes a long time, you might wish to run rngd in the"
- @$(kecho) "### background to keep the supply of entropy topped up. It"
- @$(kecho) "### needs to be run as root, and uses a hardware random"
- @$(kecho) "### number generator if one is available."
- @$(kecho) "###"
- $(Q)openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
- -batch -x509 -config $(obj)/x509.genkey \
- -outform PEM -out $(obj)/signing_key.pem \
- -keyout $(obj)/signing_key.pem \
- $(keytype_openssl) \
- $($(quiet)redirect_openssl)
- @$(kecho) "###"
- @$(kecho) "### Key pair generated."
- @$(kecho) "###"
+$(obj)/signing_key.pem: $(obj)/x509.genkey FORCE
+ $(call if_changed,gen_key)
+
+targets += signing_key.pem
+quiet_cmd_copy_x509_config = COPY $@
+ cmd_copy_x509_config = cat $(srctree)/$(src)/default_x509.genkey > $@
+
+# You can provide your own config file. If not present, copy the default one.
$(obj)/x509.genkey:
- @$(kecho) Generating X.509 key generation config
- @echo >$@ "[ req ]"
- @echo >>$@ "default_bits = 4096"
- @echo >>$@ "distinguished_name = req_distinguished_name"
- @echo >>$@ "prompt = no"
- @echo >>$@ "string_mask = utf8only"
- @echo >>$@ "x509_extensions = myexts"
- @echo >>$@
- @echo >>$@ "[ req_distinguished_name ]"
- @echo >>$@ "#O = Unspecified company"
- @echo >>$@ "CN = Build time autogenerated kernel key"
- @echo >>$@ "#emailAddress = unspecified.user@unspecified.company"
- @echo >>$@
- @echo >>$@ "[ myexts ]"
- @echo >>$@ "basicConstraints=critical,CA:FALSE"
- @echo >>$@ "keyUsage=digitalSignature"
- @echo >>$@ "subjectKeyIdentifier=hash"
- @echo >>$@ "authorityKeyIdentifier=keyid"
-endif # CONFIG_MODULE_SIG_KEY
+ $(call cmd,copy_x509_config)
-$(eval $(call config_filename,MODULE_SIG_KEY))
+endif # CONFIG_MODULE_SIG_KEY
# If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it
-ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME)))
-X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME)
+ifneq ($(filter-out pkcs11:%, %(CONFIG_MODULE_SIG_KEY)),)
+X509_DEP := $(CONFIG_MODULE_SIG_KEY)
endif
-# GCC PR#66871 again.
$(obj)/system_certificates.o: $(obj)/signing_key.x509
-targets += signing_key.x509
-$(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE
- $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
+$(obj)/signing_key.x509: $(X509_DEP) $(obj)/extract-cert FORCE
+ $(call if_changed,extract_certs,$(if $(X509_DEP),$<,$(CONFIG_MODULE_SIG_KEY)))
endif # CONFIG_MODULE_SIG
-ifeq ($(CONFIG_SYSTEM_REVOCATION_LIST),y)
-
-$(eval $(call config_filename,SYSTEM_REVOCATION_KEYS))
+targets += signing_key.x509
$(obj)/revocation_certificates.o: $(obj)/x509_revocation_list
-quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2))
- cmd_extract_certs = scripts/extract-cert $(2) $@
+$(obj)/x509_revocation_list: $(CONFIG_SYSTEM_REVOCATION_KEYS) $(obj)/extract-cert FORCE
+ $(call if_changed,extract_certs,$(if $(CONFIG_SYSTEM_REVOCATION_KEYS),$<,""))
targets += x509_revocation_list
-$(obj)/x509_revocation_list: scripts/extract-cert $(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(SYSTEM_REVOCATION_KEYS_FILENAME) FORCE
- $(call if_changed,extract_certs,$(SYSTEM_REVOCATION_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_REVOCATION_KEYS))
-endif
+
+hostprogs := extract-cert
+
+HOSTCFLAGS_extract-cert.o = $(shell pkg-config --cflags libcrypto 2> /dev/null)
+HOSTLDLIBS_extract-cert = $(shell pkg-config --libs libcrypto 2> /dev/null || echo -lcrypto)
diff --git a/certs/default_x509.genkey b/certs/default_x509.genkey
new file mode 100644
index 000000000000..d4c6628cb8e5
--- /dev/null
+++ b/certs/default_x509.genkey
@@ -0,0 +1,17 @@
+[ req ]
+default_bits = 4096
+distinguished_name = req_distinguished_name
+prompt = no
+string_mask = utf8only
+x509_extensions = myexts
+
+[ req_distinguished_name ]
+#O = Unspecified company
+CN = Build time autogenerated kernel key
+#emailAddress = unspecified.user@unspecified.company
+
+[ myexts ]
+basicConstraints=critical,CA:FALSE
+keyUsage=digitalSignature
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid
diff --git a/certs/extract-cert.c b/certs/extract-cert.c
new file mode 100644
index 000000000000..f7ef7862f207
--- /dev/null
+++ b/certs/extract-cert.c
@@ -0,0 +1,162 @@
+/* Extract X.509 certificate in DER form from PKCS#11 or PEM.
+ *
+ * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
+ * Copyright © 2015 Intel Corporation.
+ *
+ * Authors: David Howells <dhowells@redhat.com>
+ * David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <err.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/engine.h>
+
+#define PKEY_ID_PKCS7 2
+
+static __attribute__((noreturn))
+void format(void)
+{
+ fprintf(stderr,
+ "Usage: extract-cert <source> <dest>\n");
+ exit(2);
+}
+
+static void display_openssl_errors(int l)
+{
+ const char *file;
+ char buf[120];
+ int e, line;
+
+ if (ERR_peek_error() == 0)
+ return;
+ fprintf(stderr, "At main.c:%d:\n", l);
+
+ while ((e = ERR_get_error_line(&file, &line))) {
+ ERR_error_string(e, buf);
+ fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
+ }
+}
+
+static void drain_openssl_errors(void)
+{
+ const char *file;
+ int line;
+
+ if (ERR_peek_error() == 0)
+ return;
+ while (ERR_get_error_line(&file, &line)) {}
+}
+
+#define ERR(cond, fmt, ...) \
+ do { \
+ bool __cond = (cond); \
+ display_openssl_errors(__LINE__); \
+ if (__cond) { \
+ err(1, fmt, ## __VA_ARGS__); \
+ } \
+ } while(0)
+
+static const char *key_pass;
+static BIO *wb;
+static char *cert_dst;
+static int kbuild_verbose;
+
+static void write_cert(X509 *x509)
+{
+ char buf[200];
+
+ if (!wb) {
+ wb = BIO_new_file(cert_dst, "wb");
+ ERR(!wb, "%s", cert_dst);
+ }
+ X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf));
+ ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst);
+ if (kbuild_verbose)
+ fprintf(stderr, "Extracted cert: %s\n", buf);
+}
+
+int main(int argc, char **argv)
+{
+ char *cert_src;
+
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+ ERR_clear_error();
+
+ kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0");
+
+ key_pass = getenv("KBUILD_SIGN_PIN");
+
+ if (argc != 3)
+ format();
+
+ cert_src = argv[1];
+ cert_dst = argv[2];
+
+ if (!cert_src[0]) {
+ /* Invoked with no input; create empty file */
+ FILE *f = fopen(cert_dst, "wb");
+ ERR(!f, "%s", cert_dst);
+ fclose(f);
+ exit(0);
+ } else if (!strncmp(cert_src, "pkcs11:", 7)) {
+ ENGINE *e;
+ struct {
+ const char *cert_id;
+ X509 *cert;
+ } parms;
+
+ parms.cert_id = cert_src;
+ parms.cert = NULL;
+
+ ENGINE_load_builtin_engines();
+ drain_openssl_errors();
+ e = ENGINE_by_id("pkcs11");
+ ERR(!e, "Load PKCS#11 ENGINE");
+ if (ENGINE_init(e))
+ drain_openssl_errors();
+ else
+ ERR(1, "ENGINE_init");
+ if (key_pass)
+ ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
+ ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
+ ERR(!parms.cert, "Get X.509 from PKCS#11");
+ write_cert(parms.cert);
+ } else {
+ BIO *b;
+ X509 *x509;
+
+ b = BIO_new_file(cert_src, "rb");
+ ERR(!b, "%s", cert_src);
+
+ while (1) {
+ x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
+ if (wb && !x509) {
+ unsigned long err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
+ ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
+ ERR_clear_error();
+ break;
+ }
+ }
+ ERR(!x509, "%s", cert_src);
+ write_cert(x509);
+ }
+ }
+
+ BIO_free(wb);
+
+ return 0;
+}