mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 04:33:26 +02:00
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>
This commit is contained in:
committed by
David Woodhouse
parent
0e38c35815
commit
cfc411e7ff
42
certs/Kconfig
Normal file
42
certs/Kconfig
Normal file
@@ -0,0 +1,42 @@
|
||||
menu "Certificates for signature checking"
|
||||
|
||||
config MODULE_SIG_KEY
|
||||
string "File name or PKCS#11 URI of module signing key"
|
||||
default "certs/signing_key.pem"
|
||||
depends on MODULE_SIG
|
||||
help
|
||||
Provide the file name of a private key/certificate in PEM format,
|
||||
or a PKCS#11 URI according to RFC7512. The file should contain, or
|
||||
the URI should identify, both the certificate and its corresponding
|
||||
private key.
|
||||
|
||||
If this option is unchanged from its default "certs/signing_key.pem",
|
||||
then the kernel will automatically generate the private key and
|
||||
certificate as described in Documentation/module-signing.txt
|
||||
|
||||
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.
|
||||
|
||||
config SYSTEM_TRUSTED_KEYS
|
||||
string "Additional X.509 keys for default system keyring"
|
||||
depends on SYSTEM_TRUSTED_KEYRING
|
||||
help
|
||||
If set, this option should be the filename of a PEM-formatted file
|
||||
containing trusted X.509 certificates to be included in the default
|
||||
system keyring. Any certificate used for module signing is implicitly
|
||||
also trusted.
|
||||
|
||||
NOTE: If you previously provided keys for the system keyring in the
|
||||
form of DER-encoded *.x509 files in the top-level build directory,
|
||||
those are no longer used. You will need to set this option instead.
|
||||
|
||||
endmenu
|
147
certs/Makefile
Normal file
147
certs/Makefile
Normal file
@@ -0,0 +1,147 @@
|
||||
#
|
||||
# Makefile for the linux kernel signature checking certificates.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# When a Kconfig string contains a filename, it is suitable for
|
||||
# passing to shell commands. It is surrounded by double-quotes, and
|
||||
# any double-quotes or backslashes within it are escaped by
|
||||
# backslashes.
|
||||
#
|
||||
# This is no use for dependencies or $(wildcard). We need to strip the
|
||||
# surrounding quotes and the escaping from quotes and backslashes, and
|
||||
# we *do* need to escape any spaces in the string. So, for example:
|
||||
#
|
||||
# Usage: $(eval $(call config_filename,FOO))
|
||||
#
|
||||
# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option,
|
||||
# transformed as described above to be suitable for use within the
|
||||
# makefile.
|
||||
#
|
||||
# Also, if the filename is a relative filename and exists in the source
|
||||
# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to
|
||||
# be prefixed to *both* command invocation and dependencies.
|
||||
#
|
||||
# Note: We also print the filenames in the quiet_cmd_foo text, and
|
||||
# perhaps ought to have a version specially escaped for that purpose.
|
||||
# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good
|
||||
# enough. It'll strip the quotes in the common case where there's no
|
||||
# space and it's a simple filename, and it'll retain the quotes when
|
||||
# there's a space. There are some esoteric cases in which it'll print
|
||||
# the wrong thing, but we don't really care. The actual dependencies
|
||||
# and commands *do* get it right, with various combinations of single
|
||||
# and double quotes, backslashes and spaces in the filenames.
|
||||
#
|
||||
###############################################################################
|
||||
#
|
||||
quote := $(firstword " ")
|
||||
space :=
|
||||
space +=
|
||||
space_escape := %%%SPACE%%%
|
||||
#
|
||||
define config_filename
|
||||
ifneq ($$(CONFIG_$(1)),"")
|
||||
$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1)))))))
|
||||
ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME)))
|
||||
else
|
||||
ifeq ($$(wildcard $$($(1)_FILENAME)),)
|
||||
ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),)
|
||||
$(1)_SRCPREFIX := $(srctree)/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
|
||||
|
||||
$(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) $@ || ( rm $@; exit 1)
|
||||
|
||||
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
|
||||
|
||||
clean-files := x509_certificate_list .x509.list
|
||||
|
||||
ifeq ($(CONFIG_MODULE_SIG),y)
|
||||
###############################################################################
|
||||
#
|
||||
# If module signing is requested, say by allyesconfig, but a key has not been
|
||||
# supplied, then one will need to be generated to make sure the build does not
|
||||
# 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
|
||||
|
||||
# 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")
|
||||
$(obj)/signing_key.pem: $(obj)/x509.genkey
|
||||
@echo "###"
|
||||
@echo "### Now generating an X.509 key pair to be used for signing modules."
|
||||
@echo "###"
|
||||
@echo "### If this takes a long time, you might wish to run rngd in the"
|
||||
@echo "### background to keep the supply of entropy topped up. It"
|
||||
@echo "### needs to be run as root, and uses a hardware random"
|
||||
@echo "### number generator if one is available."
|
||||
@echo "###"
|
||||
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 2>&1
|
||||
@echo "###"
|
||||
@echo "### Key pair generated."
|
||||
@echo "###"
|
||||
|
||||
$(obj)/x509.genkey:
|
||||
@echo 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
|
||||
|
||||
$(eval $(call config_filename,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)
|
||||
endif
|
||||
|
||||
# GCC PR#66871 again.
|
||||
$(obj)/system_certificates.o: $(obj)/signing_key.x509
|
||||
|
||||
$(obj)/signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP)
|
||||
$(call cmd,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
|
||||
endif
|
23
certs/system_certificates.S
Normal file
23
certs/system_certificates.S
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
__INITRODATA
|
||||
|
||||
.align 8
|
||||
.globl VMLINUX_SYMBOL(system_certificate_list)
|
||||
VMLINUX_SYMBOL(system_certificate_list):
|
||||
__cert_list_start:
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
.incbin "certs/signing_key.x509"
|
||||
#endif
|
||||
.incbin "certs/x509_certificate_list"
|
||||
__cert_list_end:
|
||||
|
||||
.align 8
|
||||
.globl VMLINUX_SYMBOL(system_certificate_list_size)
|
||||
VMLINUX_SYMBOL(system_certificate_list_size):
|
||||
#ifdef CONFIG_64BIT
|
||||
.quad __cert_list_end - __cert_list_start
|
||||
#else
|
||||
.long __cert_list_end - __cert_list_start
|
||||
#endif
|
157
certs/system_keyring.c
Normal file
157
certs/system_keyring.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/* 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 <crypto/pkcs7.h>
|
||||
|
||||
struct key *system_trusted_keyring;
|
||||
EXPORT_SYMBOL_GPL(system_trusted_keyring);
|
||||
|
||||
extern __initconst const u8 system_certificate_list[];
|
||||
extern __initconst const unsigned long system_certificate_list_size;
|
||||
|
||||
/*
|
||||
* 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_USR_SEARCH),
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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");
|
||||
|
||||
p = system_certificate_list;
|
||||
end = p + system_certificate_list_size;
|
||||
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_USR_READ),
|
||||
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));
|
||||
} else {
|
||||
set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
|
||||
|
||||
/**
|
||||
* Verify a PKCS#7-based signature on system data.
|
||||
* @data: The data to be verified.
|
||||
* @len: Size of @data.
|
||||
* @raw_pkcs7: The PKCS#7 message that is the signature.
|
||||
* @pkcs7_len: The size of @raw_pkcs7.
|
||||
* @usage: The use to which the key is being put.
|
||||
*/
|
||||
int system_verify_data(const void *data, unsigned long len,
|
||||
const void *raw_pkcs7, size_t pkcs7_len,
|
||||
enum key_being_used_for usage)
|
||||
{
|
||||
struct pkcs7_message *pkcs7;
|
||||
bool trusted;
|
||||
int ret;
|
||||
|
||||
pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
|
||||
if (IS_ERR(pkcs7))
|
||||
return PTR_ERR(pkcs7);
|
||||
|
||||
/* The data should be detached - so we need to supply it. */
|
||||
if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
|
||||
pr_err("PKCS#7 signature with non-detached data\n");
|
||||
ret = -EBADMSG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = pkcs7_verify(pkcs7, usage);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
if (!trusted) {
|
||||
pr_err("PKCS#7 signature not signed with a trusted key\n");
|
||||
ret = -ENOKEY;
|
||||
}
|
||||
|
||||
error:
|
||||
pkcs7_free_message(pkcs7);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(system_verify_data);
|
||||
|
||||
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
|
Reference in New Issue
Block a user