diff options
Diffstat (limited to 'certs')
-rw-r--r-- | certs/.gitignore | 1 | ||||
-rw-r--r-- | certs/Kconfig | 4 | ||||
-rw-r--r-- | certs/Makefile | 125 | ||||
-rw-r--r-- | certs/default_x509.genkey | 17 | ||||
-rw-r--r-- | certs/extract-cert.c | 162 |
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; +} |