From 8225d3853f34f6cf9caff15d8c385a528e0d7cb1 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 21 Nov 2014 10:06:01 -0500 Subject: seccomp: Replace smp_read_barrier_depends() with lockless_dereference() Recently lockless_dereference() was added which can be used in place of hard-coding smp_read_barrier_depends(). The following PATCH makes the change. Signed-off-by: Pranith Kumar Signed-off-by: Kees Cook --- kernel/seccomp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 4f44028943e6..980fd26da22e 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -175,17 +175,16 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) */ static u32 seccomp_run_filters(struct seccomp_data *sd) { - struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter); struct seccomp_data sd_local; u32 ret = SECCOMP_RET_ALLOW; + /* Make sure cross-thread synced filter points somewhere sane. */ + struct seccomp_filter *f = + lockless_dereference(current->seccomp.filter); /* Ensure unexpected behavior doesn't result in failing open. */ if (unlikely(WARN_ON(f == NULL))) return SECCOMP_RET_KILL; - /* Make sure cross-thread synced filter points somewhere sane. */ - smp_read_barrier_depends(); - if (!sd) { populate_seccomp_data(&sd_local); sd = &sd_local; -- cgit v1.2.3 From 13c4a90119d28cfcb6b5bdd820c233b86c2b0237 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Sat, 13 Jun 2015 09:02:48 -0600 Subject: seccomp: add ptrace options for suspend/resume This patch is the first step in enabling checkpoint/restore of processes with seccomp enabled. One of the things CRIU does while dumping tasks is inject code into them via ptrace to collect information that is only available to the process itself. However, if we are in a seccomp mode where these processes are prohibited from making these syscalls, then what CRIU does kills the task. This patch adds a new ptrace option, PTRACE_O_SUSPEND_SECCOMP, that enables a task from the init user namespace which has CAP_SYS_ADMIN and no seccomp filters to disable (and re-enable) seccomp filters for another task so that they can be successfully dumped (and restored). We restrict the set of processes that can disable seccomp through ptrace because although today ptrace can be used to bypass seccomp, there is some discussion of closing this loophole in the future and we would like this patch to not depend on that behavior and be future proofed for when it is removed. Note that seccomp can be suspended before any filters are actually installed; this behavior is useful on criu restore, so that we can suspend seccomp, restore the filters, unmap our restore code from the restored process' address space, and then resume the task by detaching and have the filters resumed as well. v2 changes: * require that the tracer have no seccomp filters installed * drop TIF_NOTSC manipulation from the patch * change from ptrace command to a ptrace option and use this ptrace option as the flag to check. This means that as soon as the tracer detaches/dies, seccomp is re-enabled and as a corrollary that one can not disable seccomp across PTRACE_ATTACHs. v3 changes: * get rid of various #ifdefs everywhere * report more sensible errors when PTRACE_O_SUSPEND_SECCOMP is incorrectly used v4 changes: * get rid of may_suspend_seccomp() in favor of a capable() check in ptrace directly v5 changes: * check that seccomp is not enabled (or suspended) on the tracer Signed-off-by: Tycho Andersen CC: Will Drewry CC: Roland McGrath CC: Pavel Emelyanov CC: Serge E. Hallyn Acked-by: Oleg Nesterov Acked-by: Andy Lutomirski [kees: access seccomp.mode through seccomp_mode() instead] Signed-off-by: Kees Cook --- kernel/ptrace.c | 13 +++++++++++++ kernel/seccomp.c | 8 ++++++++ 2 files changed, 21 insertions(+) (limited to 'kernel') diff --git a/kernel/ptrace.c b/kernel/ptrace.c index c8e0e050a36a..787320de68e0 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -556,6 +556,19 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data) if (data & ~(unsigned long)PTRACE_O_MASK) return -EINVAL; + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { + if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) || + !config_enabled(CONFIG_SECCOMP)) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || + current->ptrace & PT_SUSPEND_SECCOMP) + return -EPERM; + } + /* Avoid intermediate state when all opts are cleared */ flags = child->ptrace; flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 980fd26da22e..645e42d6fa4d 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -590,6 +590,10 @@ void secure_computing_strict(int this_syscall) { int mode = current->seccomp.mode; + if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && + unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) + return; + if (mode == 0) return; else if (mode == SECCOMP_MODE_STRICT) @@ -691,6 +695,10 @@ u32 seccomp_phase1(struct seccomp_data *sd) int this_syscall = sd ? sd->nr : syscall_get_nr(current, task_pt_regs(current)); + if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && + unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) + return SECCOMP_PHASE1_OK; + switch (mode) { case SECCOMP_MODE_STRICT: __secure_computing_strict(this_syscall); /* may call do_exit */ -- cgit v1.2.3 From 221272f97ca528048a577a3ff23d7774286ca5fd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 15 Jun 2015 15:29:16 -0700 Subject: seccomp: swap hard-coded zeros to defined name For clarity, if CONFIG_SECCOMP isn't defined, seccomp_mode() is returning "disabled". This makes that more clear, along with another 0-use, and results in no operational change. Signed-off-by: Kees Cook --- kernel/seccomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 645e42d6fa4d..383bd6caca81 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -594,7 +594,7 @@ void secure_computing_strict(int this_syscall) unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) return; - if (mode == 0) + if (mode == SECCOMP_MODE_DISABLED) return; else if (mode == SECCOMP_MODE_STRICT) __secure_computing_strict(this_syscall); -- cgit v1.2.3 From 3f1e1bea34740069f70c6bc92d0f712345d5c28e Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 20 Jul 2015 21:16:27 +0100 Subject: MODSIGN: Use PKCS#7 messages as module signatures Move to using PKCS#7 messages as module signatures because: (1) We have to be able to support the use of X.509 certificates that don't have a subjKeyId set. We're currently relying on this to look up the X.509 certificate in the trusted keyring list. (2) PKCS#7 message signed information blocks have a field that supplies the data required to match with the X.509 certificate that signed it. (3) The PKCS#7 certificate carries fields that specify the digest algorithm used to generate the signature in a standardised way and the X.509 certificates specify the public key algorithm in a standardised way - so we don't need our own methods of specifying these. (4) We now have PKCS#7 message support in the kernel for signed kexec purposes and we can make use of this. To make this work, the old sign-file script has been replaced with a program that needs compiling in a previous patch. The rules to build it are added here. Signed-off-by: David Howells Tested-by: Vivek Goyal --- kernel/module_signing.c | 220 ++++++++++-------------------------------------- 1 file changed, 44 insertions(+), 176 deletions(-) (limited to 'kernel') diff --git a/kernel/module_signing.c b/kernel/module_signing.c index be5b8fac4bd0..8eb20cc66b39 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -11,10 +11,9 @@ #include #include -#include -#include -#include #include +#include +#include #include "module-internal.h" /* @@ -28,157 +27,53 @@ * - Information block */ struct module_signature { - u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */ - u8 hash; /* Digest algorithm [enum hash_algo] */ - u8 id_type; /* Key identifier type [enum pkey_id_type] */ - u8 signer_len; /* Length of signer's name */ - u8 key_id_len; /* Length of key identifier */ + u8 algo; /* Public-key crypto algorithm [0] */ + u8 hash; /* Digest algorithm [0] */ + u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ + u8 signer_len; /* Length of signer's name [0] */ + u8 key_id_len; /* Length of key identifier [0] */ u8 __pad[3]; __be32 sig_len; /* Length of signature data */ }; /* - * Digest the module contents. + * Verify a PKCS#7-based signature on a module. */ -static struct public_key_signature *mod_make_digest(enum hash_algo hash, - const void *mod, - unsigned long modlen) +static int mod_verify_pkcs7(const void *mod, unsigned long modlen, + const void *raw_pkcs7, size_t pkcs7_len) { - struct public_key_signature *pks; - struct crypto_shash *tfm; - struct shash_desc *desc; - size_t digest_size, desc_size; + struct pkcs7_message *pkcs7; + bool trusted; int ret; - pr_devel("==>%s()\n", __func__); - - /* Allocate the hashing algorithm we're going to need and find out how - * big the hash operational data will be. - */ - tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); - if (IS_ERR(tfm)) - return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); - - desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); - digest_size = crypto_shash_digestsize(tfm); - - /* We allocate the hash operational data storage on the end of our - * context data and the digest output buffer on the end of that. - */ - ret = -ENOMEM; - pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); - if (!pks) - goto error_no_pks; - - pks->pkey_hash_algo = hash; - pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; - pks->digest_size = digest_size; - - desc = (void *)pks + sizeof(*pks); - desc->tfm = tfm; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - - ret = crypto_shash_init(desc); + 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, mod, modlen) < 0) { + pr_err("PKCS#7 signature with non-detached data\n"); + ret = -EBADMSG; + goto error; + } + + ret = pkcs7_verify(pkcs7); if (ret < 0) goto error; - ret = crypto_shash_finup(desc, mod, modlen, pks->digest); + ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); if (ret < 0) goto error; - crypto_free_shash(tfm); - pr_devel("<==%s() = ok\n", __func__); - return pks; + if (!trusted) { + pr_err("PKCS#7 signature not signed with a trusted key\n"); + ret = -ENOKEY; + } error: - kfree(pks); -error_no_pks: - crypto_free_shash(tfm); + pkcs7_free_message(pkcs7); pr_devel("<==%s() = %d\n", __func__, ret); - return ERR_PTR(ret); -} - -/* - * Extract an MPI array from the signature data. This represents the actual - * signature. Each raw MPI is prefaced by a BE 2-byte value indicating the - * size of the MPI in bytes. - * - * RSA signatures only have one MPI, so currently we only read one. - */ -static int mod_extract_mpi_array(struct public_key_signature *pks, - const void *data, size_t len) -{ - size_t nbytes; - MPI mpi; - - if (len < 3) - return -EBADMSG; - nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1]; - data += 2; - len -= 2; - if (len != nbytes) - return -EBADMSG; - - mpi = mpi_read_raw_data(data, nbytes); - if (!mpi) - return -ENOMEM; - pks->mpi[0] = mpi; - pks->nr_mpi = 1; - return 0; -} - -/* - * Request an asymmetric key. - */ -static struct key *request_asymmetric_key(const char *signer, size_t signer_len, - const u8 *key_id, size_t key_id_len) -{ - key_ref_t key; - size_t i; - char *id, *q; - - pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len); - - /* Construct an identifier. */ - id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL); - if (!id) - return ERR_PTR(-ENOKEY); - - memcpy(id, signer, signer_len); - - q = id + signer_len; - *q++ = ':'; - *q++ = ' '; - for (i = 0; i < key_id_len; i++) { - *q++ = hex_asc[*key_id >> 4]; - *q++ = hex_asc[*key_id++ & 0x0f]; - } - - *q = 0; - - pr_debug("Look up: \"%s\"\n", id); - - key = keyring_search(make_key_ref(system_trusted_keyring, 1), - &key_type_asymmetric, id); - if (IS_ERR(key)) - pr_warn("Request for unknown module key '%s' err %ld\n", - id, PTR_ERR(key)); - kfree(id); - - if (IS_ERR(key)) { - switch (PTR_ERR(key)) { - /* Hide some search errors */ - case -EACCES: - case -ENOTDIR: - case -EAGAIN: - return ERR_PTR(-ENOKEY); - default: - return ERR_CAST(key); - } - } - - pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); - return key_ref_to_ptr(key); + return ret; } /* @@ -186,12 +81,8 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len, */ int mod_verify_sig(const void *mod, unsigned long *_modlen) { - struct public_key_signature *pks; struct module_signature ms; - struct key *key; - const void *sig; size_t modlen = *_modlen, sig_len; - int ret; pr_devel("==>%s(,%zu)\n", __func__, modlen); @@ -205,46 +96,23 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) if (sig_len >= modlen) return -EBADMSG; modlen -= sig_len; - if ((size_t)ms.signer_len + ms.key_id_len >= modlen) - return -EBADMSG; - modlen -= (size_t)ms.signer_len + ms.key_id_len; - *_modlen = modlen; - sig = mod + modlen; - - /* For the moment, only support RSA and X.509 identifiers */ - if (ms.algo != PKEY_ALGO_RSA || - ms.id_type != PKEY_ID_X509) - return -ENOPKG; - if (ms.hash >= PKEY_HASH__LAST || - !hash_algo_name[ms.hash]) + if (ms.id_type != PKEY_ID_PKCS7) { + pr_err("Module is not signed with expected PKCS#7 message\n"); return -ENOPKG; - - key = request_asymmetric_key(sig, ms.signer_len, - sig + ms.signer_len, ms.key_id_len); - if (IS_ERR(key)) - return PTR_ERR(key); - - pks = mod_make_digest(ms.hash, mod, modlen); - if (IS_ERR(pks)) { - ret = PTR_ERR(pks); - goto error_put_key; } - ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len, - sig_len); - if (ret < 0) - goto error_free_pks; - - ret = verify_signature(key, pks); - pr_devel("verify_signature() = %d\n", ret); + if (ms.algo != 0 || + ms.hash != 0 || + ms.signer_len != 0 || + ms.key_id_len != 0 || + ms.__pad[0] != 0 || + ms.__pad[1] != 0 || + ms.__pad[2] != 0) { + pr_err("PKCS#7 signature info has unexpected non-zero params\n"); + return -EBADMSG; + } -error_free_pks: - mpi_free(pks->rsa.s); - kfree(pks); -error_put_key: - key_put(key); - pr_devel("<==%s() = %d\n", __func__, ret); - return ret; + return mod_verify_pkcs7(mod, modlen, mod + modlen, sig_len); } -- cgit v1.2.3 From 1c39449921fc6db1f942051f79868a19c92f4d47 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 20 Jul 2015 21:16:27 +0100 Subject: system_keyring.c doesn't need to #include module-internal.h system_keyring.c doesn't need to #include module-internal.h as it doesn't use the one thing that exports. Remove the inclusion. Signed-off-by: David Howells --- kernel/system_keyring.c | 1 - 1 file changed, 1 deletion(-) (limited to 'kernel') diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 875f64e8935b..4cda71ee51c7 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c @@ -16,7 +16,6 @@ #include #include #include -#include "module-internal.h" struct key *system_trusted_keyring; EXPORT_SYMBOL_GPL(system_trusted_keyring); -- cgit v1.2.3 From 091f6e26eb326adbd718f406e440c838bed8ebb6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 20 Jul 2015 21:16:28 +0100 Subject: MODSIGN: Extract the blob PKCS#7 signature verifier from module signing Extract the function that drives the PKCS#7 signature verification given a data blob and a PKCS#7 blob out from the module signing code and lump it with the system keyring code as it's generic. This makes it independent of module config options and opens it to use by the firmware loader. Signed-off-by: David Howells Cc: Luis R. Rodriguez Cc: Rusty Russell Cc: Ming Lei Cc: Seth Forshee Cc: Kyle McMartin --- kernel/module_signing.c | 44 +------------------------------------------ kernel/system_keyring.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 43 deletions(-) (limited to 'kernel') diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 8eb20cc66b39..70ad463f6df0 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -10,10 +10,8 @@ */ #include -#include #include #include -#include #include "module-internal.h" /* @@ -36,46 +34,6 @@ struct module_signature { __be32 sig_len; /* Length of signature data */ }; -/* - * Verify a PKCS#7-based signature on a module. - */ -static int mod_verify_pkcs7(const void *mod, unsigned long modlen, - const void *raw_pkcs7, size_t pkcs7_len) -{ - 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, mod, modlen) < 0) { - pr_err("PKCS#7 signature with non-detached data\n"); - ret = -EBADMSG; - goto error; - } - - ret = pkcs7_verify(pkcs7); - 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; -} - /* * Verify the signature on a module. */ @@ -114,5 +72,5 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) return -EBADMSG; } - return mod_verify_pkcs7(mod, modlen, mod + modlen, sig_len); + return system_verify_data(mod, modlen, mod + modlen, sig_len); } diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 4cda71ee51c7..95f2dcbc7616 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c @@ -16,6 +16,7 @@ #include #include #include +#include struct key *system_trusted_keyring; EXPORT_SYMBOL_GPL(system_trusted_keyring); @@ -103,3 +104,52 @@ dodgy_cert: 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. + */ +int system_verify_data(const void *data, unsigned long len, + const void *raw_pkcs7, size_t pkcs7_len) +{ + 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); + 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 */ -- cgit v1.2.3 From 19e91b69d77bab16405cc284b451378e89a4110c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 20 Jul 2015 21:16:29 +0100 Subject: modsign: Allow external signing key to be specified Signed-off-by: David Woodhouse Signed-off-by: David Howells --- kernel/Makefile | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 43c4c920f30a..2c937ace292e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -170,6 +170,10 @@ 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),"signing_key.priv") signing_key.priv signing_key.x509: x509.genkey @echo "###" @echo "### Now generating an X.509 key pair to be used for signing modules." @@ -207,3 +211,4 @@ x509.genkey: @echo >>x509.genkey "subjectKeyIdentifier=hash" @echo >>x509.genkey "authorityKeyIdentifier=keyid" endif +endif -- cgit v1.2.3 From 1329e8cc69b93a0b1bc6d197b30dcff628c18dbf Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 20 Jul 2015 21:16:30 +0100 Subject: 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 Signed-off-by: David Howells --- kernel/Makefile | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 2c937ace292e..fa2f8b84b18a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -210,5 +210,43 @@ x509.genkey: @echo >>x509.genkey "keyUsage=digitalSignature" @echo >>x509.genkey "subjectKeyIdentifier=hash" @echo >>x509.genkey "authorityKeyIdentifier=keyid" +else +# For external (PKCS#11 or PEM) key, we need to obtain the certificate from +# CONFIG_MODULE_SIG_KEY automatically. +quiet_cmd_extract_der = CERT_DER $(2) + cmd_extract_der = scripts/extract-cert "$(2)" signing_key.x509 + +# CONFIG_MODULE_SIG_KEY is either a PKCS#11 URI or a filename. It is +# surrounded by quotes, and may contain spaces. To strip the quotes +# with $(patsubst) we need to turn the spaces into something else. +# And if it's a filename, those spaces need to be escaped as '\ ' in +# order to use it in dependencies or $(wildcard). +space := +space += +space_escape := %%%SPACE%%% +X509_SOURCE_temp := $(subst $(space),$(space_escape),$(CONFIG_MODULE_SIG_KEY)) +# We need this to check for absolute paths or PKCS#11 URIs. +X509_SOURCE_ONEWORD := $(patsubst "%",%,$(X509_SOURCE_temp)) +# This is the actual source filename/URI without the quotes +X509_SOURCE := $(subst $(space_escape),$(space),$(X509_SOURCE_ONEWORD)) +# This\ version\ with\ spaces\ escaped\ for\ $(wildcard)\ and\ dependencies +X509_SOURCE_ESCAPED := $(subst $(space_escape),\$(space),$(X509_SOURCE_ONEWORD)) + +ifeq ($(patsubst pkcs11:%,%,$(X509_SOURCE_ONEWORD)),$(X509_SOURCE_ONEWORD)) +# If it's a filename, depend on it. +X509_DEP := $(X509_SOURCE_ESCAPED) +ifeq ($(patsubst /%,%,$(X509_SOURCE_ONEWORD)),$(X509_SOURCE_ONEWORD)) +ifeq ($(wildcard $(X509_SOURCE_ESCAPED)),) +ifneq ($(wildcard $(srctree)/$(X509_SOURCE_ESCAPED)),) +# Non-absolute filename, found in source tree and not build tree +X509_SOURCE := $(srctree)/$(X509_SOURCE) +X509_DEP := $(srctree)/$(X509_SOURCE_ESCAPED) +endif +endif +endif +endif + +signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP) + $(call cmd,extract_der,$(X509_SOURCE)) endif endif -- cgit v1.2.3 From fb1179499134bc718dc7557c7a6a95dc72f224cb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 20 Jul 2015 21:16:30 +0100 Subject: modsign: Use single PEM file for autogenerated key The current rule for generating signing_key.priv and signing_key.x509 is a classic example of a bad rule which has a tendency to break parallel make. When invoked to create *either* target, it generates the other target as a side-effect that make didn't predict. So let's switch to using a single file signing_key.pem which contains both key and certificate. That matches what we do in the case of an external key specified by CONFIG_MODULE_SIG_KEY anyway, so it's also slightly cleaner. Signed-off-by: David Woodhouse Signed-off-by: David Howells --- kernel/Makefile | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index fa2f8b84b18a..7453283981ca 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -173,8 +173,8 @@ 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),"signing_key.priv") -signing_key.priv signing_key.x509: x509.genkey +ifeq ($(CONFIG_MODULE_SIG_KEY),"signing_key.pem") +signing_key.pem: x509.genkey @echo "###" @echo "### Now generating an X.509 key pair to be used for signing modules." @echo "###" @@ -185,8 +185,8 @@ signing_key.priv signing_key.x509: x509.genkey @echo "###" openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ -batch -x509 -config x509.genkey \ - -outform DER -out signing_key.x509 \ - -keyout signing_key.priv 2>&1 + -outform PEM -out signing_key.pem \ + -keyout signing_key.pem 2>&1 @echo "###" @echo "### Key pair generated." @echo "###" @@ -210,9 +210,9 @@ x509.genkey: @echo >>x509.genkey "keyUsage=digitalSignature" @echo >>x509.genkey "subjectKeyIdentifier=hash" @echo >>x509.genkey "authorityKeyIdentifier=keyid" -else -# For external (PKCS#11 or PEM) key, we need to obtain the certificate from -# CONFIG_MODULE_SIG_KEY automatically. +endif + +# We need to obtain the certificate from CONFIG_MODULE_SIG_KEY. quiet_cmd_extract_der = CERT_DER $(2) cmd_extract_der = scripts/extract-cert "$(2)" signing_key.x509 @@ -249,4 +249,3 @@ endif signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP) $(call cmd,extract_der,$(X509_SOURCE)) endif -endif -- cgit v1.2.3 From 99d27b1b52bd5cdf9bd9f7661ca8641e9a1b55e6 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 20 Jul 2015 21:16:31 +0100 Subject: modsign: Add explicit CONFIG_SYSTEM_TRUSTED_KEYS option Let the user explicitly provide a file containing trusted keys, instead of just automatically finding files matching *.x509 in the build tree and trusting whatever we find. This really ought to be an *explicit* configuration, and the build rules for dealing with the files were fairly painful too. Fix applied from James Morris that removes an '=' from a macro definition in kernel/Makefile as this is a feature that only exists from GNU make 3.82 onwards. Signed-off-by: David Woodhouse Signed-off-by: David Howells --- kernel/Makefile | 125 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 60 deletions(-) (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 7453283981ca..575329777d9e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -114,46 +114,75 @@ $(obj)/config_data.h: $(obj)/config_data.gz FORCE ############################################################################### # -# Roll all the X.509 certificates that we can find together and pull them into -# the kernel so that they get loaded into the system trusted keyring during -# boot. +# 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. # -# We look in the source root and the build root for all files whose name ends -# in ".x509". Unfortunately, this will generate duplicate filenames, so we -# have make canonicalise the pathnames and then sort them to discard the -# duplicates. +# 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. # ############################################################################### -ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) -X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509) -X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += $(objtree)/signing_key.x509 -X509_CERTIFICATES-raw := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \ - $(or $(realpath $(CERT)),$(CERT)))) -X509_CERTIFICATES := $(subst $(realpath $(objtree))/,,$(X509_CERTIFICATES-raw)) - -ifeq ($(X509_CERTIFICATES),) -$(warning *** No X.509 certificates found ***) +# +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 - -ifneq ($(wildcard $(obj)/.x509.list),) -ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES)) -$(warning X.509 certificate list changed to "$(X509_CERTIFICATES)" from "$(shell cat $(obj)/.x509.list)") -$(shell rm $(obj)/.x509.list) endif endif +endef +# +############################################################################### + + +ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) + +$(eval $(call config_filename,SYSTEM_TRUSTED_KEYS)) + +SIGNING_X509-$(CONFIG_MODULE_SIG) += signing_key.x509 kernel/system_certificates.o: $(obj)/x509_certificate_list -quiet_cmd_x509certs = CERTS $@ - cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; $(kecho) " - Including cert $(X509)") +quiet_cmd_x509certs = CERTS $(SIGNING_X509-y) $(patsubst "%",%,$(2)) + cmd_x509certs = ( cat $(SIGNING_X509-y) /dev/null; \ + awk '/-----BEGIN CERTIFICATE-----/{flag=1;next}/-----END CERTIFICATE-----/{flag=0}flag' $(2) /dev/null | base64 -d ) > $@ || ( rm $@; exit 1) targets += $(obj)/x509_certificate_list -$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list - $(call if_changed,x509certs) +$(obj)/x509_certificate_list: $(SIGNING_X509-y) include/config/system/trusted/keys.h $(wildcard include/config/module/sig.h) $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) + $(call if_changed,x509certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS)) -targets += $(obj)/.x509.list -$(obj)/.x509.list: - @echo $(X509_CERTIFICATES) >$@ endif clean-files := x509_certificate_list .x509.list @@ -212,40 +241,16 @@ x509.genkey: @echo >>x509.genkey "authorityKeyIdentifier=keyid" endif -# We need to obtain the certificate from CONFIG_MODULE_SIG_KEY. -quiet_cmd_extract_der = CERT_DER $(2) - cmd_extract_der = scripts/extract-cert "$(2)" signing_key.x509 +$(eval $(call config_filename,MODULE_SIG_KEY)) -# CONFIG_MODULE_SIG_KEY is either a PKCS#11 URI or a filename. It is -# surrounded by quotes, and may contain spaces. To strip the quotes -# with $(patsubst) we need to turn the spaces into something else. -# And if it's a filename, those spaces need to be escaped as '\ ' in -# order to use it in dependencies or $(wildcard). -space := -space += -space_escape := %%%SPACE%%% -X509_SOURCE_temp := $(subst $(space),$(space_escape),$(CONFIG_MODULE_SIG_KEY)) -# We need this to check for absolute paths or PKCS#11 URIs. -X509_SOURCE_ONEWORD := $(patsubst "%",%,$(X509_SOURCE_temp)) -# This is the actual source filename/URI without the quotes -X509_SOURCE := $(subst $(space_escape),$(space),$(X509_SOURCE_ONEWORD)) -# This\ version\ with\ spaces\ escaped\ for\ $(wildcard)\ and\ dependencies -X509_SOURCE_ESCAPED := $(subst $(space_escape),\$(space),$(X509_SOURCE_ONEWORD)) - -ifeq ($(patsubst pkcs11:%,%,$(X509_SOURCE_ONEWORD)),$(X509_SOURCE_ONEWORD)) -# If it's a filename, depend on it. -X509_DEP := $(X509_SOURCE_ESCAPED) -ifeq ($(patsubst /%,%,$(X509_SOURCE_ONEWORD)),$(X509_SOURCE_ONEWORD)) -ifeq ($(wildcard $(X509_SOURCE_ESCAPED)),) -ifneq ($(wildcard $(srctree)/$(X509_SOURCE_ESCAPED)),) -# Non-absolute filename, found in source tree and not build tree -X509_SOURCE := $(srctree)/$(X509_SOURCE) -X509_DEP := $(srctree)/$(X509_SOURCE_ESCAPED) -endif -endif -endif +# 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 +quiet_cmd_extract_der = SIGNING_CERT $(patsubst "%",%,$(2)) + cmd_extract_der = scripts/extract-cert $(2) signing_key.x509 + signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP) - $(call cmd,extract_der,$(X509_SOURCE)) + $(call cmd,extract_der,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) endif -- cgit v1.2.3 From 770f2b98760ef0500183d7206724aac762433e2d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 20 Jul 2015 21:16:34 +0100 Subject: modsign: Use extract-cert to process CONFIG_SYSTEM_TRUSTED_KEYS Fix up the dependencies somewhat too, while we're at it. Signed-off-by: David Woodhouse Signed-off-by: David Howells --- kernel/Makefile | 25 ++++++++++++------------- kernel/system_certificates.S | 3 +++ 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 575329777d9e..65ef3846fbe8 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -166,23 +166,22 @@ endef # ############################################################################### - ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) $(eval $(call config_filename,SYSTEM_TRUSTED_KEYS)) -SIGNING_X509-$(CONFIG_MODULE_SIG) += signing_key.x509 - -kernel/system_certificates.o: $(obj)/x509_certificate_list +# GCC doesn't include .incbin files in -MD generated dependencies (PR#66871) +$(obj)/system_certificates.o: $(obj)/x509_certificate_list -quiet_cmd_x509certs = CERTS $(SIGNING_X509-y) $(patsubst "%",%,$(2)) - cmd_x509certs = ( cat $(SIGNING_X509-y) /dev/null; \ - awk '/-----BEGIN CERTIFICATE-----/{flag=1;next}/-----END CERTIFICATE-----/{flag=0}flag' $(2) /dev/null | base64 -d ) > $@ || ( rm $@; exit 1) +# Cope with signing_key.x509 existing in $(srctree) not $(objtree) +AFLAGS_system_certificates.o := -I$(srctree) -targets += $(obj)/x509_certificate_list -$(obj)/x509_certificate_list: $(SIGNING_X509-y) include/config/system/trusted/keys.h $(wildcard include/config/module/sig.h) $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) - $(call if_changed,x509certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS)) +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 @@ -248,9 +247,9 @@ ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME) endif -quiet_cmd_extract_der = SIGNING_CERT $(patsubst "%",%,$(2)) - cmd_extract_der = scripts/extract-cert $(2) signing_key.x509 +# GCC PR#66871 again. +$(obj)/system_certificates.o: signing_key.x509 signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP) - $(call cmd,extract_der,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) + $(call cmd,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) endif diff --git a/kernel/system_certificates.S b/kernel/system_certificates.S index 3e9868d47535..6ba2f75e7ba5 100644 --- a/kernel/system_certificates.S +++ b/kernel/system_certificates.S @@ -7,6 +7,9 @@ .globl VMLINUX_SYMBOL(system_certificate_list) VMLINUX_SYMBOL(system_certificate_list): __cert_list_start: +#ifdef CONFIG_MODULE_SIG + .incbin "signing_key.x509" +#endif .incbin "kernel/x509_certificate_list" __cert_list_end: -- cgit v1.2.3 From 99db44350672c8a5ee9a7b0a6f4cd6ff10136065 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 5 Aug 2015 15:22:27 +0100 Subject: PKCS#7: Appropriately restrict authenticated attributes and content type A PKCS#7 or CMS message can have per-signature authenticated attributes that are digested as a lump and signed by the authorising key for that signature. If such attributes exist, the content digest isn't itself signed, but rather it is included in a special authattr which then contributes to the signature. Further, we already require the master message content type to be pkcs7_signedData - but there's also a separate content type for the data itself within the SignedData object and this must be repeated inside the authattrs for each signer [RFC2315 9.2, RFC5652 11.1]. We should really validate the authattrs if they exist or forbid them entirely as appropriate. To this end: (1) Alter the PKCS#7 parser to reject any message that has more than one signature where at least one signature has authattrs and at least one that does not. (2) Validate authattrs if they are present and strongly restrict them. Only the following authattrs are permitted and all others are rejected: (a) contentType. This is checked to be an OID that matches the content type in the SignedData object. (b) messageDigest. This must match the crypto digest of the data. (c) signingTime. If present, we check that this is a valid, parseable UTCTime or GeneralTime and that the date it encodes fits within the validity window of the matching X.509 cert. (d) S/MIME capabilities. We don't check the contents. (e) Authenticode SP Opus Info. We don't check the contents. (f) Authenticode Statement Type. We don't check the contents. The message is rejected if (a) or (b) are missing. If the message is an Authenticode type, the message is rejected if (e) is missing; if not Authenticode, the message is rejected if (d) - (f) are present. The S/MIME capabilities authattr (d) unfortunately has to be allowed to support kernels already signed by the pesign program. This only affects kexec. sign-file suppresses them (CMS_NOSMIMECAP). The message is also rejected if an authattr is given more than once or if it contains more than one element in its set of values. (3) Add a parameter to pkcs7_verify() to select one of the following restrictions and pass in the appropriate option from the callers: (*) VERIFYING_MODULE_SIGNATURE This requires that the SignedData content type be pkcs7-data and forbids authattrs. sign-file sets CMS_NOATTR. We could be more flexible and permit authattrs optionally, but only permit minimal content. (*) VERIFYING_FIRMWARE_SIGNATURE This requires that the SignedData content type be pkcs7-data and requires authattrs. In future, this will require an attribute holding the target firmware name in addition to the minimal set. (*) VERIFYING_UNSPECIFIED_SIGNATURE This requires that the SignedData content type be pkcs7-data but allows either no authattrs or only permits the minimal set. (*) VERIFYING_KEXEC_PE_SIGNATURE This only supports the Authenticode SPC_INDIRECT_DATA content type and requires at least an SpcSpOpusInfo authattr in addition to the minimal set. It also permits an SPC_STATEMENT_TYPE authattr (and an S/MIME capabilities authattr because the pesign program doesn't remove these). (*) VERIFYING_KEY_SIGNATURE (*) VERIFYING_KEY_SELF_SIGNATURE These are invalid in this context but are included for later use when limiting the use of X.509 certs. (4) The pkcs7_test key type is given a module parameter to select between the above options for testing purposes. For example: echo 1 >/sys/module/pkcs7_test_key/parameters/usage keyctl padd pkcs7_test foo @s Signed-off-by: David Howells Reviewed-by: Marcel Holtmann Reviewed-by: David Woodhouse --- kernel/module_signing.c | 3 ++- kernel/system_keyring.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 70ad463f6df0..bd62f5cda746 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -72,5 +72,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) return -EBADMSG; } - return system_verify_data(mod, modlen, mod + modlen, sig_len); + return system_verify_data(mod, modlen, mod + modlen, sig_len, + VERIFYING_MODULE_SIGNATURE); } diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 95f2dcbc7616..2570598b784d 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c @@ -113,9 +113,11 @@ late_initcall(load_system_certificate_list); * @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) + const void *raw_pkcs7, size_t pkcs7_len, + enum key_being_used_for usage) { struct pkcs7_message *pkcs7; bool trusted; @@ -132,7 +134,7 @@ int system_verify_data(const void *data, unsigned long len, goto error; } - ret = pkcs7_verify(pkcs7); + ret = pkcs7_verify(pkcs7, usage); if (ret < 0) goto error; -- cgit v1.2.3 From cfc411e7fff3e15cd6354ff69773907e2c9d1c0c Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 14 Aug 2015 15:20:41 +0100 Subject: 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 Reviewed-by: David Woodhouse --- kernel/Makefile | 143 --------------------------------------- kernel/system_certificates.S | 23 ------- kernel/system_keyring.c | 157 ------------------------------------------- 3 files changed, 323 deletions(-) delete mode 100644 kernel/system_certificates.S delete mode 100644 kernel/system_keyring.c (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 65ef3846fbe8..1aa153a1be21 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -45,7 +45,6 @@ ifneq ($(CONFIG_SMP),y) obj-y += up.o endif obj-$(CONFIG_UID16) += uid16.o -obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SIG) += module_signing.o obj-$(CONFIG_KALLSYMS) += kallsyms.o @@ -111,145 +110,3 @@ $(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE targets += config_data.h $(obj)/config_data.h: $(obj)/config_data.gz FORCE $(call filechk,ikconfiggz) - -############################################################################### -# -# 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),"signing_key.pem") -signing_key.pem: 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 x509.genkey \ - -outform PEM -out signing_key.pem \ - -keyout signing_key.pem 2>&1 - @echo "###" - @echo "### Key pair generated." - @echo "###" - -x509.genkey: - @echo Generating X.509 key generation config - @echo >x509.genkey "[ req ]" - @echo >>x509.genkey "default_bits = 4096" - @echo >>x509.genkey "distinguished_name = req_distinguished_name" - @echo >>x509.genkey "prompt = no" - @echo >>x509.genkey "string_mask = utf8only" - @echo >>x509.genkey "x509_extensions = myexts" - @echo >>x509.genkey - @echo >>x509.genkey "[ req_distinguished_name ]" - @echo >>x509.genkey "#O = Unspecified company" - @echo >>x509.genkey "CN = Build time autogenerated kernel key" - @echo >>x509.genkey "#emailAddress = unspecified.user@unspecified.company" - @echo >>x509.genkey - @echo >>x509.genkey "[ myexts ]" - @echo >>x509.genkey "basicConstraints=critical,CA:FALSE" - @echo >>x509.genkey "keyUsage=digitalSignature" - @echo >>x509.genkey "subjectKeyIdentifier=hash" - @echo >>x509.genkey "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: signing_key.x509 - -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 diff --git a/kernel/system_certificates.S b/kernel/system_certificates.S deleted file mode 100644 index 6ba2f75e7ba5..000000000000 --- a/kernel/system_certificates.S +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - - __INITRODATA - - .align 8 - .globl VMLINUX_SYMBOL(system_certificate_list) -VMLINUX_SYMBOL(system_certificate_list): -__cert_list_start: -#ifdef CONFIG_MODULE_SIG - .incbin "signing_key.x509" -#endif - .incbin "kernel/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 diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c deleted file mode 100644 index 2570598b784d..000000000000 --- a/kernel/system_keyring.c +++ /dev/null @@ -1,157 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#include - -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 */ -- cgit v1.2.3