diff --git a/.gitignore b/.gitignore
index 4ad4a98b884b9c..17fa24dd7e4606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,6 +97,7 @@ GTAGS
# Leavings from module signing
#
extra_certificates
+signing_key.pem
signing_key.priv
signing_key.x509
x509.genkey
diff --git a/Documentation/Changes b/Documentation/Changes
index 646cdaa6e9d133..6d886300485827 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -43,6 +43,7 @@ o udev 081 # udevd --version
o grub 0.93 # grub --version || grub-install --version
o mcelog 0.6 # mcelog --version
o iptables 1.4.2 # iptables -V
+o openssl & libcrypto 1.0.1k # openssl version
Kernel compilation
@@ -79,6 +80,17 @@ BC
You will need bc to build kernels 3.10 and higher
+OpenSSL
+-------
+
+Module signing and external certificate handling use the OpenSSL program and
+crypto library to do key creation and signature generation.
+
+You will need openssl to build kernels 3.7 and higher if module signing is
+enabled. You will also need openssl development packages to build kernels 4.3
+and higher.
+
+
System utilities
================
@@ -295,6 +307,10 @@ Binutils
--------
o
+OpenSSL
+-------
+o
+
System utilities
****************
@@ -392,4 +408,3 @@ o
NFS-Utils
---------
o
-
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index 6466704d47b5a5..0ff6a466a05b24 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -174,6 +174,11 @@ The output directory is often set using "O=..." on the commandline.
The value can be overridden in which case the default value is ignored.
+KBUILD_SIGN_PIN
+--------------------------------------------------
+This variable allows a passphrase or PIN to be passed to the sign-file
+utility when signing kernel modules, if the private key requires such.
+
KBUILD_MODPOST_WARN
--------------------------------------------------
KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined
diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt
index c72702ec1ded8b..a78bf1ffa68cb4 100644
--- a/Documentation/module-signing.txt
+++ b/Documentation/module-signing.txt
@@ -89,6 +89,32 @@ This has a number of options available:
their signatures checked without causing a dependency loop.
+ (4) "File name or PKCS#11 URI of module signing key" (CONFIG_MODULE_SIG_KEY)
+
+ Setting this option to something other than its default of
+ "certs/signing_key.pem" will disable the autogeneration of signing keys
+ and allow the kernel modules to be signed with a key of your choosing.
+ The string provided should identify a file containing both a private key
+ and its corresponding X.509 certificate in PEM form, or — on systems where
+ the OpenSSL ENGINE_pkcs11 is functional — a PKCS#11 URI as defined by
+ RFC7512. In the latter case, the PKCS#11 URI should reference both a
+ certificate and a private key.
+
+ If the PEM file containing the private key is encrypted, or if the
+ PKCS#11 token requries a PIN, this can be provided at build time by
+ means of the KBUILD_SIGN_PIN variable.
+
+
+ (5) "Additional X.509 keys for default system keyring" (CONFIG_SYSTEM_TRUSTED_KEYS)
+
+ This option can be set to the filename of a PEM-encoded file containing
+ additional certificates which will be included in the system keyring by
+ default.
+
+Note that enabling module signing adds a dependency on the OpenSSL devel
+packages to the kernel build processes for the tool that does the signing.
+
+
=======================
GENERATING SIGNING KEYS
=======================
@@ -100,16 +126,16 @@ it can be deleted or stored securely. The public key gets built into the
kernel so that it can be used to check the signatures as the modules are
loaded.
-Under normal conditions, the kernel build will automatically generate a new
-keypair using openssl if one does not exist in the files:
+Under normal conditions, when CONFIG_MODULE_SIG_KEY is unchanged from its
+default, the kernel build will automatically generate a new keypair using
+openssl if one does not exist in the file:
- signing_key.priv
- signing_key.x509
+ certs/signing_key.pem
during the building of vmlinux (the public part of the key needs to be built
into vmlinux) using parameters in the:
- x509.genkey
+ certs/x509.genkey
file (which is also generated if it does not already exist).
@@ -135,8 +161,12 @@ kernel sources tree and the openssl command. The following is an example to
generate the public/private key files:
openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \
- -config x509.genkey -outform DER -out signing_key.x509 \
- -keyout signing_key.priv
+ -config x509.genkey -outform PEM -out kernel_key.pem \
+ -keyout kernel_key.pem
+
+The full pathname for the resulting kernel_key.pem file can then be specified
+in the CONFIG_MODULE_SIG_KEY option, and the certificate and key therein will
+be used instead of an autogenerated keypair.
=========================
@@ -152,10 +182,9 @@ in a keyring called ".system_keyring" that can be seen by:
302d2d52 I------ 1 perm 1f010000 0 0 asymmetri Fedora kernel signing key: d69a84e6bce3d216b979e9505b3e3ef9a7118079: X509.RSA a7118079 []
...
-Beyond the public key generated specifically for module signing, any file
-placed in the kernel source root directory or the kernel build root directory
-whose name is suffixed with ".x509" will be assumed to be an X.509 public key
-and will be added to the keyring.
+Beyond the public key generated specifically for module signing, additional
+trusted certificates can be provided in a PEM-encoded file referenced by the
+CONFIG_SYSTEM_TRUSTED_KEYS configuration option.
Further, the architecture code may take public keys from a hardware store and
add those in also (e.g. from the UEFI key database).
@@ -181,7 +210,7 @@ To manually sign a module, use the scripts/sign-file tool available in
the Linux kernel source tree. The script requires 4 arguments:
1. The hash algorithm (e.g., sha256)
- 2. The private key filename
+ 2. The private key filename or PKCS#11 URI
3. The public key filename
4. The kernel module to be signed
@@ -194,6 +223,9 @@ The hash algorithm used does not have to match the one configured, but if it
doesn't, you should make sure that hash algorithm is either built into the
kernel or can be loaded without requiring itself.
+If the private key requires a passphrase or PIN, it can be provided in the
+$KBUILD_SIGN_PIN environment variable.
+
============================
SIGNED MODULES AND STRIPPING
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt
index de5e1aeca7fb95..5e6d07fbed07c5 100644
--- a/Documentation/security/Smack.txt
+++ b/Documentation/security/Smack.txt
@@ -28,6 +28,10 @@ Smack kernels use the CIPSO IP option. Some network
configurations are intolerant of IP options and can impede
access to systems that use them as Smack does.
+Smack is used in the Tizen operating system. Please
+go to http://wiki.tizen.org for information about how
+Smack is used in Tizen.
+
The current git repository for Smack user space is:
git://github.com/smack-team/smack.git
@@ -108,6 +112,8 @@ in the smackfs filesystem. This pseudo-filesystem is mounted
on /sys/fs/smackfs.
access
+ Provided for backward compatibility. The access2 interface
+ is preferred and should be used instead.
This interface reports whether a subject with the specified
Smack label has a particular access to an object with a
specified Smack label. Write a fixed format access rule to
@@ -136,6 +142,8 @@ change-rule
those in the fourth string. If there is no such rule it will be
created using the access specified in the third and the fourth strings.
cipso
+ Provided for backward compatibility. The cipso2 interface
+ is preferred and should be used instead.
This interface allows a specific CIPSO header to be assigned
to a Smack label. The format accepted on write is:
"%24s%4d%4d"["%4d"]...
@@ -157,7 +165,19 @@ direct
doi
This contains the CIPSO domain of interpretation used in
network packets.
+ipv6host
+ This interface allows specific IPv6 internet addresses to be
+ treated as single label hosts. Packets are sent to single
+ label hosts only from processes that have Smack write access
+ to the host label. All packets received from single label hosts
+ are given the specified label. The format accepted on write is:
+ "%h:%h:%h:%h:%h:%h:%h:%h label" or
+ "%h:%h:%h:%h:%h:%h:%h:%h/%d label".
+ The "::" address shortcut is not supported.
+ If label is "-DELETE" a matched entry will be deleted.
load
+ Provided for backward compatibility. The load2 interface
+ is preferred and should be used instead.
This interface allows access control rules in addition to
the system defined rules to be specified. The format accepted
on write is:
@@ -181,6 +201,8 @@ load2
permissions that are not allowed. The string "r-x--" would
specify read and execute access.
load-self
+ Provided for backward compatibility. The load-self2 interface
+ is preferred and should be used instead.
This interface allows process specific access rules to be
defined. These rules are only consulted if access would
otherwise be permitted, and are intended to provide additional
@@ -205,6 +227,8 @@ netlabel
received from single label hosts are given the specified
label. The format accepted on write is:
"%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label".
+ If the label specified is "-CIPSO" the address is treated
+ as a host that supports CIPSO headers.
onlycap
This contains labels processes must have for CAP_MAC_ADMIN
and CAP_MAC_OVERRIDE to be effective. If this file is empty
@@ -232,7 +256,8 @@ unconfined
is dangerous and can ruin the proper labeling of your system.
It should never be used in production.
-You can add access rules in /etc/smack/accesses. They take the form:
+If you are using the smackload utility
+you can add access rules in /etc/smack/accesses. They take the form:
subjectlabel objectlabel access
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt
index 227a63f018a27d..d9ee7d7a6c7fda 100644
--- a/Documentation/security/Yama.txt
+++ b/Documentation/security/Yama.txt
@@ -1,9 +1,7 @@
-Yama is a Linux Security Module that collects a number of system-wide DAC
-security protections that are not handled by the core kernel itself. To
-select it at boot time, specify "security=yama" (though this will disable
-any other LSM).
-
-Yama is controlled through sysctl in /proc/sys/kernel/yama:
+Yama is a Linux Security Module that collects system-wide DAC security
+protections that are not handled by the core kernel itself. This is
+selectable at build-time with CONFIG_SECURITY_YAMA, and can be controlled
+at run-time through sysctls in /proc/sys/kernel/yama:
- ptrace_scope
diff --git a/MAINTAINERS b/MAINTAINERS
index 4d8c8e10fb392f..6dfc2242715d60 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2621,6 +2621,15 @@ S: Supported
F: Documentation/filesystems/ceph.txt
F: fs/ceph/
+CERTIFICATE HANDLING:
+M: David Howells
+M: David Woodhouse
+L: keyrings@linux-nfs.org
+S: Maintained
+F: Documentation/module-signing.txt
+F: certs/
+F: scripts/extract-cert.c
+
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
L: linux-usb@vger.kernel.org
S: Orphan
@@ -5994,7 +6003,7 @@ F: kernel/kexec.c
KEYS/KEYRINGS:
M: David Howells
-L: keyrings@linux-nfs.org
+L: keyrings@vger.kernel.org
S: Maintained
F: Documentation/security/keys.txt
F: include/linux/key.h
@@ -6006,7 +6015,7 @@ KEYS-TRUSTED
M: David Safford
M: Mimi Zohar
L: linux-security-module@vger.kernel.org
-L: keyrings@linux-nfs.org
+L: keyrings@vger.kernel.org
S: Supported
F: Documentation/security/keys-trusted-encrypted.txt
F: include/keys/trusted-type.h
@@ -6017,7 +6026,7 @@ KEYS-ENCRYPTED
M: Mimi Zohar
M: David Safford
L: linux-security-module@vger.kernel.org
-L: keyrings@linux-nfs.org
+L: keyrings@vger.kernel.org
S: Supported
F: Documentation/security/keys-trusted-encrypted.txt
F: include/keys/encrypted-type.h
@@ -9264,6 +9273,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
S: Supported
F: security/apparmor/
+YAMA SECURITY MODULE
+M: Kees Cook
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
+S: Supported
+F: security/yama/
+
SENSABLE PHANTOM
M: Jiri Slaby
S: Maintained
diff --git a/Makefile b/Makefile
index c3615937df3891..d67856ea1917e8 100644
--- a/Makefile
+++ b/Makefile
@@ -875,10 +875,9 @@ INITRD_COMPRESS-$(CONFIG_RD_LZ4) := lz4
# export INITRD_COMPRESS := $(INITRD_COMPRESS-y)
ifdef CONFIG_MODULE_SIG_ALL
-MODSECKEY = ./signing_key.priv
-MODPUBKEY = ./signing_key.x509
-export MODPUBKEY
-mod_sign_cmd = perl $(srctree)/scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODSECKEY) $(MODPUBKEY)
+$(eval $(call config_filename,MODULE_SIG_KEY))
+
+mod_sign_cmd = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY) certs/signing_key.x509
else
mod_sign_cmd = true
endif
@@ -886,7 +885,7 @@ export mod_sign_cmd
ifeq ($(KBUILD_EXTMOD),)
-core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
@@ -1178,8 +1177,8 @@ MRPROPER_DIRS += include/config usr/include include/generated \
arch/*/include/generated .tmp_objdiff
MRPROPER_FILES += .config .config.old .version .old_version \
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
- signing_key.priv signing_key.x509 x509.genkey \
- extra_certificates signing_key.x509.keyid \
+ signing_key.pem signing_key.priv signing_key.x509 \
+ x509.genkey extra_certificates signing_key.x509.keyid \
signing_key.x509.signer vmlinux-gdb.py
# clean - Delete most, but leave enough to build external modules
diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig
index 1646cce032c34a..642b50946943cc 100644
--- a/arch/mips/configs/pistachio_defconfig
+++ b/arch/mips/configs/pistachio_defconfig
@@ -320,7 +320,6 @@ CONFIG_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_YAMA=y
-CONFIG_SECURITY_YAMA_STACKED=y
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_HMAC=y
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 961e51e9c6f64b..0f8a6bbaaa443c 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -533,7 +533,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
int ret;
ret = verify_pefile_signature(kernel, kernel_len,
- system_trusted_keyring, &trusted);
+ system_trusted_keyring,
+ VERIFYING_KEXEC_PE_SIGNATURE,
+ &trusted);
if (ret < 0)
return ret;
if (!trusted)
diff --git a/certs/Kconfig b/certs/Kconfig
new file mode 100644
index 00000000000000..b030b9c7ed34ad
--- /dev/null
+++ b/certs/Kconfig
@@ -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
diff --git a/certs/Makefile b/certs/Makefile
new file mode 100644
index 00000000000000..28ac694dd11aac
--- /dev/null
+++ b/certs/Makefile
@@ -0,0 +1,94 @@
+#
+# Makefile for the linux kernel signature checking certificates.
+#
+
+obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
+
+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
+
+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))
+endif
diff --git a/kernel/system_certificates.S b/certs/system_certificates.S
similarity index 80%
rename from kernel/system_certificates.S
rename to certs/system_certificates.S
index 3e9868d47535b4..9216e8c817649e 100644
--- a/kernel/system_certificates.S
+++ b/certs/system_certificates.S
@@ -7,7 +7,10 @@
.globl VMLINUX_SYMBOL(system_certificate_list)
VMLINUX_SYMBOL(system_certificate_list):
__cert_list_start:
- .incbin "kernel/x509_certificate_list"
+#ifdef CONFIG_MODULE_SIG
+ .incbin "certs/signing_key.x509"
+#endif
+ .incbin "certs/x509_certificate_list"
__cert_list_end:
.align 8
diff --git a/kernel/system_keyring.c b/certs/system_keyring.c
similarity index 68%
rename from kernel/system_keyring.c
rename to certs/system_keyring.c
index 875f64e8935bbf..2570598b784de0 100644
--- a/kernel/system_keyring.c
+++ b/certs/system_keyring.c
@@ -16,7 +16,7 @@
#include
#include
#include
-#include "module-internal.h"
+#include
struct key *system_trusted_keyring;
EXPORT_SYMBOL_GPL(system_trusted_keyring);
@@ -104,3 +104,54 @@ static __init int load_system_certificate_list(void)
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 */
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b582ea7f78d3f4..48ee3e175dac25 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1635,5 +1635,6 @@ config CRYPTO_HASH_INFO
source "drivers/crypto/Kconfig"
source crypto/asymmetric_keys/Kconfig
+source certs/Kconfig
endif # if CRYPTO
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index e47fcd9ac5e86f..cd1406f9b14ab2 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -15,15 +15,21 @@ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
x509_key_parser-y := \
x509-asn1.o \
+ x509_akid-asn1.o \
x509_rsakey-asn1.o \
x509_cert_parser.o \
x509_public_key.o
-$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h
+$(obj)/x509_cert_parser.o: \
+ $(obj)/x509-asn1.h \
+ $(obj)/x509_akid-asn1.h \
+ $(obj)/x509_rsakey-asn1.h
$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
+$(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h
$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
clean-files += x509-asn1.c x509-asn1.h
+clean-files += x509_akid-asn1.c x509_akid-asn1.h
clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
#
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index b0e4ed23d6683c..1916680ad81b08 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -12,6 +12,7 @@
*/
#include
#include
+#include
#include
#include
#include
@@ -20,6 +21,16 @@
MODULE_LICENSE("GPL");
+const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
+ [VERIFYING_MODULE_SIGNATURE] = "mod sig",
+ [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig",
+ [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig",
+ [VERIFYING_KEY_SIGNATURE] = "key sig",
+ [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig",
+ [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig",
+};
+EXPORT_SYMBOL_GPL(key_being_used_for);
+
static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem);
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
index 214a992123cdd5..adcef59eec0b6a 100644
--- a/crypto/asymmetric_keys/mscode_parser.c
+++ b/crypto/asymmetric_keys/mscode_parser.c
@@ -97,6 +97,15 @@ int mscode_note_digest_algo(void *context, size_t hdrlen,
case OID_sha256:
ctx->digest_algo = HASH_ALGO_SHA256;
break;
+ case OID_sha384:
+ ctx->digest_algo = HASH_ALGO_SHA384;
+ break;
+ case OID_sha512:
+ ctx->digest_algo = HASH_ALGO_SHA512;
+ break;
+ case OID_sha224:
+ ctx->digest_algo = HASH_ALGO_SHA224;
+ break;
case OID__NR:
sprint_oid(value, vlen, buffer, sizeof(buffer));
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1
index a5a14ef28c869a..1eca740b816ace 100644
--- a/crypto/asymmetric_keys/pkcs7.asn1
+++ b/crypto/asymmetric_keys/pkcs7.asn1
@@ -1,14 +1,14 @@
PKCS7ContentInfo ::= SEQUENCE {
- contentType ContentType,
+ contentType ContentType ({ pkcs7_check_content_type }),
content [0] EXPLICIT SignedData OPTIONAL
}
ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
SignedData ::= SEQUENCE {
- version INTEGER,
+ version INTEGER ({ pkcs7_note_signeddata_version }),
digestAlgorithms DigestAlgorithmIdentifiers,
- contentInfo ContentInfo,
+ contentInfo ContentInfo ({ pkcs7_note_content }),
certificates CHOICE {
certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
certSequence [2] IMPLICIT Certificates
@@ -21,7 +21,7 @@ SignedData ::= SEQUENCE {
}
ContentInfo ::= SEQUENCE {
- contentType ContentType,
+ contentType ContentType ({ pkcs7_note_OID }),
content [0] EXPLICIT Data OPTIONAL
}
@@ -68,8 +68,8 @@ SignerInfos ::= CHOICE {
}
SignerInfo ::= SEQUENCE {
- version INTEGER,
- issuerAndSerialNumber IssuerAndSerialNumber,
+ version INTEGER ({ pkcs7_note_signerinfo_version }),
+ sid SignerIdentifier, -- CMS variant, not PKCS#7
digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
authenticatedAttributes CHOICE {
aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
@@ -88,6 +88,12 @@ SignerInfo ::= SEQUENCE {
} OPTIONAL
} ({ pkcs7_note_signed_info })
+SignerIdentifier ::= CHOICE {
+ -- RFC5652 sec 5.3
+ issuerAndSerialNumber IssuerAndSerialNumber,
+ subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier
+}
+
IssuerAndSerialNumber ::= SEQUENCE {
issuer Name ({ pkcs7_sig_note_issuer }),
serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial })
@@ -95,6 +101,8 @@ IssuerAndSerialNumber ::= SEQUENCE {
CertificateSerialNumber ::= INTEGER
+SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid })
+
SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
AuthenticatedAttribute ::= SEQUENCE {
@@ -103,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE {
}
UnauthenticatedAttribute ::= SEQUENCE {
- type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+ type OBJECT IDENTIFIER,
values SET OF ANY
}
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
index 3d13b042da7358..e2d0edbbc71acd 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -14,16 +14,26 @@
#include
#include
#include
+#include
#include
#include
#include
#include "pkcs7_parser.h"
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PKCS#7 testing key type");
+
+static unsigned pkcs7_usage;
+module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(pkcs7_usage,
+ "Usage to specify when verifying the PKCS#7 message");
+
/*
* Preparse a PKCS#7 wrapped and validated data blob.
*/
static int pkcs7_preparse(struct key_preparsed_payload *prep)
{
+ enum key_being_used_for usage = pkcs7_usage;
struct pkcs7_message *pkcs7;
const void *data, *saved_prep_data;
size_t datalen, saved_prep_datalen;
@@ -32,6 +42,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
kenter("");
+ if (usage >= NR__KEY_BEING_USED_FOR) {
+ pr_err("Invalid usage type %d\n", usage);
+ return -EINVAL;
+ }
+
saved_prep_data = prep->data;
saved_prep_datalen = prep->datalen;
pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
@@ -40,7 +55,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
goto error;
}
- ret = pkcs7_verify(pkcs7);
+ ret = pkcs7_verify(pkcs7, usage);
if (ret < 0)
goto error_free;
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 3bd5a1e4c493e2..758acabf2d8197 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -33,6 +33,9 @@ struct pkcs7_parse_context {
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer;
+ const void *raw_skid;
+ unsigned raw_skid_size;
+ bool expect_skid;
};
/*
@@ -78,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7)
}
EXPORT_SYMBOL_GPL(pkcs7_free_message);
+/*
+ * Check authenticatedAttributes are provided or not provided consistently.
+ */
+static int pkcs7_check_authattrs(struct pkcs7_message *msg)
+{
+ struct pkcs7_signed_info *sinfo;
+ bool want;
+
+ sinfo = msg->signed_infos;
+ if (sinfo->authattrs) {
+ want = true;
+ msg->have_authattrs = true;
+ }
+
+ for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
+ if (!!sinfo->authattrs != want)
+ goto inconsistent;
+ return 0;
+
+inconsistent:
+ pr_warn("Inconsistently supplied authAttrs\n");
+ return -EINVAL;
+}
+
/**
* pkcs7_parse_message - Parse a PKCS#7 message
* @data: The raw binary ASN.1 encoded message to be parsed
@@ -110,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
goto out;
}
+ ret = pkcs7_check_authattrs(ctx->msg);
+ if (ret < 0)
+ goto out;
+
msg = ctx->msg;
ctx->msg = NULL;
@@ -198,6 +229,14 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
case OID_sha256:
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
break;
+ case OID_sha384:
+ ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384;
+ break;
+ case OID_sha512:
+ ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512;
+ break;
+ case OID_sha224:
+ ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224;
default:
printk("Unsupported digest algo: %u\n", ctx->last_oid);
return -ENOPKG;
@@ -225,6 +264,100 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
return 0;
}
+/*
+ * We only support signed data [RFC2315 sec 9].
+ */
+int pkcs7_check_content_type(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ if (ctx->last_oid != OID_signed_data) {
+ pr_warn("Only support pkcs7_signedData type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Note the SignedData version
+ */
+int pkcs7_note_signeddata_version(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ unsigned version;
+
+ if (vlen != 1)
+ goto unsupported;
+
+ ctx->msg->version = version = *(const u8 *)value;
+ switch (version) {
+ case 1:
+ /* PKCS#7 SignedData [RFC2315 sec 9.1]
+ * CMS ver 1 SignedData [RFC5652 sec 5.1]
+ */
+ break;
+ case 3:
+ /* CMS ver 3 SignedData [RFC2315 sec 5.1] */
+ break;
+ default:
+ goto unsupported;
+ }
+
+ return 0;
+
+unsupported:
+ pr_warn("Unsupported SignedData version\n");
+ return -EINVAL;
+}
+
+/*
+ * Note the SignerInfo version
+ */
+int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+ unsigned version;
+
+ if (vlen != 1)
+ goto unsupported;
+
+ version = *(const u8 *)value;
+ switch (version) {
+ case 1:
+ /* PKCS#7 SignerInfo [RFC2315 sec 9.2]
+ * CMS ver 1 SignerInfo [RFC5652 sec 5.3]
+ */
+ if (ctx->msg->version != 1)
+ goto version_mismatch;
+ ctx->expect_skid = false;
+ break;
+ case 3:
+ /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
+ if (ctx->msg->version == 1)
+ goto version_mismatch;
+ ctx->expect_skid = true;
+ break;
+ default:
+ goto unsupported;
+ }
+
+ return 0;
+
+unsupported:
+ pr_warn("Unsupported SignerInfo version\n");
+ return -EINVAL;
+version_mismatch:
+ pr_warn("SignedData-SignerInfo version mismatch\n");
+ return -EBADMSG;
+}
+
/*
* Extract a certificate and store it in the context.
*/
@@ -283,6 +416,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen,
return 0;
}
+/*
+ * Note the content type.
+ */
+int pkcs7_note_content(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ if (ctx->last_oid != OID_data &&
+ ctx->last_oid != OID_msIndirectData) {
+ pr_warn("Unsupported data type %d\n", ctx->last_oid);
+ return -EINVAL;
+ }
+
+ ctx->msg->data_type = ctx->last_oid;
+ return 0;
+}
+
/*
* Extract the data from the message and store that and its content type OID in
* the context.
@@ -298,45 +450,119 @@ int pkcs7_note_data(void *context, size_t hdrlen,
ctx->msg->data = value;
ctx->msg->data_len = vlen;
ctx->msg->data_hdrlen = hdrlen;
- ctx->msg->data_type = ctx->last_oid;
return 0;
}
/*
- * Parse authenticated attributes
+ * Parse authenticated attributes.
*/
int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;
+ struct pkcs7_signed_info *sinfo = ctx->sinfo;
+ enum OID content_type;
pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
switch (ctx->last_oid) {
+ case OID_contentType:
+ if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
+ goto repeated;
+ content_type = look_up_OID(value, vlen);
+ if (content_type != ctx->msg->data_type) {
+ pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
+ ctx->msg->data_type, sinfo->index,
+ content_type);
+ return -EBADMSG;
+ }
+ return 0;
+
+ case OID_signingTime:
+ if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
+ goto repeated;
+ /* Should we check that the signing time is consistent
+ * with the signer's X.509 cert?
+ */
+ return x509_decode_time(&sinfo->signing_time,
+ hdrlen, tag, value, vlen);
+
case OID_messageDigest:
+ if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
+ goto repeated;
if (tag != ASN1_OTS)
return -EBADMSG;
- ctx->sinfo->msgdigest = value;
- ctx->sinfo->msgdigest_len = vlen;
+ sinfo->msgdigest = value;
+ sinfo->msgdigest_len = vlen;
+ return 0;
+
+ case OID_smimeCapabilites:
+ if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
+ goto repeated;
+ if (ctx->msg->data_type != OID_msIndirectData) {
+ pr_warn("S/MIME Caps only allowed with Authenticode\n");
+ return -EKEYREJECTED;
+ }
+ return 0;
+
+ /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
+ * char URLs and cont[1] 8-bit char URLs.
+ *
+ * Microsoft StatementType seems to contain a list of OIDs that
+ * are also used as extendedKeyUsage types in X.509 certs.
+ */
+ case OID_msSpOpusInfo:
+ if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
+ goto repeated;
+ goto authenticode_check;
+ case OID_msStatementType:
+ if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
+ goto repeated;
+ authenticode_check:
+ if (ctx->msg->data_type != OID_msIndirectData) {
+ pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
+ return -EKEYREJECTED;
+ }
+ /* I'm not sure how to validate these */
return 0;
default:
return 0;
}
+
+repeated:
+ /* We permit max one item per AuthenticatedAttribute and no repeats */
+ pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
+ return -EKEYREJECTED;
}
/*
- * Note the set of auth attributes for digestion purposes [RFC2315 9.3]
+ * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
*/
int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;
+ struct pkcs7_signed_info *sinfo = ctx->sinfo;
+
+ if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
+ !test_bit(sinfo_has_message_digest, &sinfo->aa_set) ||
+ (ctx->msg->data_type == OID_msIndirectData &&
+ !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) {
+ pr_warn("Missing required AuthAttr\n");
+ return -EBADMSG;
+ }
+
+ if (ctx->msg->data_type != OID_msIndirectData &&
+ test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
+ pr_warn("Unexpected Authenticode AuthAttr\n");
+ return -EBADMSG;
+ }
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
- ctx->sinfo->authattrs = value - (hdrlen - 1);
- ctx->sinfo->authattrs_len = vlen + (hdrlen - 1);
+ sinfo->authattrs = value - (hdrlen - 1);
+ sinfo->authattrs_len = vlen + (hdrlen - 1);
return 0;
}
@@ -366,6 +592,22 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
return 0;
}
+/*
+ * Note the issuing cert's subjectKeyIdentifier
+ */
+int pkcs7_sig_note_skid(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs7_parse_context *ctx = context;
+
+ pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
+
+ ctx->raw_skid = value;
+ ctx->raw_skid_size = vlen;
+ return 0;
+}
+
/*
* Note the signature data
*/
@@ -398,14 +640,27 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
struct pkcs7_signed_info *sinfo = ctx->sinfo;
struct asymmetric_key_id *kid;
+ if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
+ pr_warn("Authenticode requires AuthAttrs\n");
+ return -EBADMSG;
+ }
+
/* Generate cert issuer + serial number key ID */
- kid = asymmetric_key_generate_id(ctx->raw_serial,
- ctx->raw_serial_size,
- ctx->raw_issuer,
- ctx->raw_issuer_size);
+ if (!ctx->expect_skid) {
+ kid = asymmetric_key_generate_id(ctx->raw_serial,
+ ctx->raw_serial_size,
+ ctx->raw_issuer,
+ ctx->raw_issuer_size);
+ } else {
+ kid = asymmetric_key_generate_id(ctx->raw_skid,
+ ctx->raw_skid_size,
+ "", 0);
+ }
if (IS_ERR(kid))
return PTR_ERR(kid);
+ pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
+
sinfo->signing_cert_id = kid;
sinfo->index = ++ctx->sinfo_index;
*ctx->ppsinfo = sinfo;
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index efc7dc9b8f9cfb..a66b19ebcf47e4 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -21,9 +21,9 @@
struct pkcs7_signed_info {
struct pkcs7_signed_info *next;
struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
- unsigned index;
- bool trusted;
- bool unsupported_crypto; /* T if not usable due to missing crypto */
+ unsigned index;
+ bool trusted;
+ bool unsupported_crypto; /* T if not usable due to missing crypto */
/* Message digest - the digest of the Content Data (or NULL) */
const void *msgdigest;
@@ -32,8 +32,18 @@ struct pkcs7_signed_info {
/* Authenticated Attribute data (or NULL) */
unsigned authattrs_len;
const void *authattrs;
+ unsigned long aa_set;
+#define sinfo_has_content_type 0
+#define sinfo_has_signing_time 1
+#define sinfo_has_message_digest 2
+#define sinfo_has_smime_caps 3
+#define sinfo_has_ms_opus_info 4
+#define sinfo_has_ms_statement_type 5
+ time64_t signing_time;
- /* Issuing cert serial number and issuer's name */
+ /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
+ * or issuing cert's SKID [CMS ver 3].
+ */
struct asymmetric_key_id *signing_cert_id;
/* Message signature.
@@ -50,6 +60,8 @@ struct pkcs7_message {
struct x509_certificate *certs; /* Certificate list */
struct x509_certificate *crl; /* Revocation list */
struct pkcs7_signed_info *signed_infos;
+ u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
+ bool have_authattrs; /* T if have authattrs */
/* Content Data (or NULL) */
enum OID data_type; /* Type of Data */
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 1d29376072da4a..90d6d47965b082 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
/* Look to see if this certificate is present in the trusted
* keys.
*/
- key = x509_request_asymmetric_key(trust_keyring, x509->id,
+ key = x509_request_asymmetric_key(trust_keyring,
+ x509->id, x509->skid,
false);
if (!IS_ERR(key)) {
/* One of the X.509 certificates in the PKCS#7 message
@@ -85,8 +86,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
/* No match - see if the root certificate has a signer amongst the
* trusted keys.
*/
- if (last && last->authority) {
- key = x509_request_asymmetric_key(trust_keyring, last->authority,
+ if (last && (last->akid_id || last->akid_skid)) {
+ key = x509_request_asymmetric_key(trust_keyring,
+ last->akid_id,
+ last->akid_skid,
false);
if (!IS_ERR(key)) {
x509 = last;
@@ -103,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
*/
key = x509_request_asymmetric_key(trust_keyring,
sinfo->signing_cert_id,
+ NULL,
false);
if (!IS_ERR(key)) {
pr_devel("sinfo %u: Direct signer is key %x\n",
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index cd455450b069e3..d20c0b4b880ed1 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* message digest attribute amongst them which corresponds to the
* digest we just calculated.
*/
- if (sinfo->msgdigest) {
+ if (sinfo->authattrs) {
u8 tag;
+ if (!sinfo->msgdigest) {
+ pr_warn("Sig %u: No messageDigest\n", sinfo->index);
+ ret = -EKEYREJECTED;
+ goto error;
+ }
+
if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
pr_debug("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
@@ -170,6 +176,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct x509_certificate *x509 = sinfo->signer, *p;
+ struct asymmetric_key_id *auth;
int ret;
kenter("");
@@ -187,11 +194,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
goto maybe_missing_crypto_in_x509;
pr_debug("- issuer %s\n", x509->issuer);
- if (x509->authority)
- pr_debug("- authkeyid %*phN\n",
- x509->authority->len, x509->authority->data);
-
- if (!x509->authority ||
+ if (x509->akid_id)
+ pr_debug("- authkeyid.id %*phN\n",
+ x509->akid_id->len, x509->akid_id->data);
+ if (x509->akid_skid)
+ pr_debug("- authkeyid.skid %*phN\n",
+ x509->akid_skid->len, x509->akid_skid->data);
+
+ if ((!x509->akid_id && !x509->akid_skid) ||
strcmp(x509->subject, x509->issuer) == 0) {
/* If there's no authority certificate specified, then
* the certificate must be self-signed and is the root
@@ -215,21 +225,42 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
/* Look through the X.509 certificates in the PKCS#7 message's
* list to see if the next one is there.
*/
- pr_debug("- want %*phN\n",
- x509->authority->len, x509->authority->data);
- for (p = pkcs7->certs; p; p = p->next) {
- if (!p->skid)
- continue;
- pr_debug("- cmp [%u] %*phN\n",
- p->index, p->skid->len, p->skid->data);
- if (asymmetric_key_id_same(p->skid, x509->authority))
- goto found_issuer;
+ auth = x509->akid_id;
+ if (auth) {
+ pr_debug("- want %*phN\n", auth->len, auth->data);
+ for (p = pkcs7->certs; p; p = p->next) {
+ pr_debug("- cmp [%u] %*phN\n",
+ p->index, p->id->len, p->id->data);
+ if (asymmetric_key_id_same(p->id, auth))
+ goto found_issuer_check_skid;
+ }
+ } else {
+ auth = x509->akid_skid;
+ pr_debug("- want %*phN\n", auth->len, auth->data);
+ for (p = pkcs7->certs; p; p = p->next) {
+ if (!p->skid)
+ continue;
+ pr_debug("- cmp [%u] %*phN\n",
+ p->index, p->skid->len, p->skid->data);
+ if (asymmetric_key_id_same(p->skid, auth))
+ goto found_issuer;
+ }
}
/* We didn't find the root of this chain */
pr_debug("- top\n");
return 0;
+ found_issuer_check_skid:
+ /* We matched issuer + serialNumber, but if there's an
+ * authKeyId.keyId, that must match the CA subjKeyId also.
+ */
+ if (x509->akid_skid &&
+ !asymmetric_key_id_same(p->skid, x509->akid_skid)) {
+ pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
+ sinfo->index, x509->index, p->index);
+ return -EKEYREJECTED;
+ }
found_issuer:
pr_debug("- subject %s\n", p->subject);
if (p->seen) {
@@ -289,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
pr_devel("Using X.509[%u] for sig %u\n",
sinfo->signer->index, sinfo->index);
+ /* Check that the PKCS#7 signing time is valid according to the X.509
+ * certificate. We can't, however, check against the system clock
+ * since that may not have been set yet and may be wrong.
+ */
+ if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) {
+ if (sinfo->signing_time < sinfo->signer->valid_from ||
+ sinfo->signing_time > sinfo->signer->valid_to) {
+ pr_warn("Message signed outside of X.509 validity window\n");
+ return -EKEYREJECTED;
+ }
+ }
+
/* Verify the PKCS#7 binary against the key */
ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
if (ret < 0)
@@ -303,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
/**
* pkcs7_verify - Verify a PKCS#7 message
* @pkcs7: The PKCS#7 message to be verified
+ * @usage: The use to which the key is being put
*
* Verify a PKCS#7 message is internally consistent - that is, the data digest
* matches the digest in the AuthAttrs and any signature in the message or one
@@ -314,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
*
* Returns, in order of descending priority:
*
+ * (*) -EKEYREJECTED if a key was selected that had a usage restriction at
+ * odds with the specified usage, or:
+ *
* (*) -EKEYREJECTED if a signature failed to match for which we found an
* appropriate X.509 certificate, or:
*
@@ -325,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
* (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
* (note that a signature chain may be of zero length), or:
*/
-int pkcs7_verify(struct pkcs7_message *pkcs7)
+int pkcs7_verify(struct pkcs7_message *pkcs7,
+ enum key_being_used_for usage)
{
struct pkcs7_signed_info *sinfo;
struct x509_certificate *x509;
@@ -334,12 +382,48 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
kenter("");
+ switch (usage) {
+ case VERIFYING_MODULE_SIGNATURE:
+ if (pkcs7->data_type != OID_data) {
+ pr_warn("Invalid module sig (not pkcs7-data)\n");
+ return -EKEYREJECTED;
+ }
+ if (pkcs7->have_authattrs) {
+ pr_warn("Invalid module sig (has authattrs)\n");
+ return -EKEYREJECTED;
+ }
+ break;
+ case VERIFYING_FIRMWARE_SIGNATURE:
+ if (pkcs7->data_type != OID_data) {
+ pr_warn("Invalid firmware sig (not pkcs7-data)\n");
+ return -EKEYREJECTED;
+ }
+ if (!pkcs7->have_authattrs) {
+ pr_warn("Invalid firmware sig (missing authattrs)\n");
+ return -EKEYREJECTED;
+ }
+ break;
+ case VERIFYING_KEXEC_PE_SIGNATURE:
+ if (pkcs7->data_type != OID_msIndirectData) {
+ pr_warn("Invalid kexec sig (not Authenticode)\n");
+ return -EKEYREJECTED;
+ }
+ /* Authattr presence checked in parser */
+ break;
+ case VERIFYING_UNSPECIFIED_SIGNATURE:
+ if (pkcs7->data_type != OID_data) {
+ pr_warn("Invalid unspecified sig (not pkcs7-data)\n");
+ return -EKEYREJECTED;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
ret = x509_get_sig_params(x509);
if (ret < 0)
return ret;
- pr_debug("X.509[%u] %*phN\n",
- n, x509->authority->len, x509->authority->data);
}
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
@@ -359,3 +443,28 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
return enopkg;
}
EXPORT_SYMBOL_GPL(pkcs7_verify);
+
+/**
+ * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message
+ * @pkcs7: The PKCS#7 message
+ * @data: The data to be verified
+ * @datalen: The amount of data
+ *
+ * Supply the detached data needed to verify a PKCS#7 message. Note that no
+ * attempt to retain/pin the data is made. That is left to the caller. The
+ * data will not be modified by pkcs7_verify() and will not be freed when the
+ * PKCS#7 message is freed.
+ *
+ * Returns -EINVAL if data is already supplied in the message, 0 otherwise.
+ */
+int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
+ const void *data, size_t datalen)
+{
+ if (pkcs7->data) {
+ pr_debug("Data already supplied\n");
+ return -EINVAL;
+ }
+ pkcs7->data = data;
+ pkcs7->data_len = datalen;
+ return 0;
+}
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 2f6e4fb1a1ea14..81efccbe22d5b2 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo);
const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
[PKEY_ID_PGP] = "PGP",
[PKEY_ID_X509] = "X509",
+ [PKEY_ID_PKCS7] = "PKCS#7",
};
EXPORT_SYMBOL_GPL(pkey_id_type_name);
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 2421f46184ce87..897b734dabf9ba 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -393,6 +393,7 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
* @pebuf: Buffer containing the PE binary image
* @pelen: Length of the binary image
* @trust_keyring: Signing certificates to use as starting points
+ * @usage: The use to which the key is being put.
* @_trusted: Set to true if trustworth, false otherwise
*
* Validate that the certificate chain inside the PKCS#7 message inside the PE
@@ -417,7 +418,9 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
* May also return -ENOMEM.
*/
int verify_pefile_signature(const void *pebuf, unsigned pelen,
- struct key *trusted_keyring, bool *_trusted)
+ struct key *trusted_keyring,
+ enum key_being_used_for usage,
+ bool *_trusted)
{
struct pkcs7_message *pkcs7;
struct pefile_context ctx;
@@ -462,7 +465,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
if (ret < 0)
goto error;
- ret = pkcs7_verify(pkcs7);
+ ret = pkcs7_verify(pkcs7, usage);
if (ret < 0)
goto error;
diff --git a/crypto/asymmetric_keys/x509_akid.asn1 b/crypto/asymmetric_keys/x509_akid.asn1
new file mode 100644
index 00000000000000..1a33231a75a89d
--- /dev/null
+++ b/crypto/asymmetric_keys/x509_akid.asn1
@@ -0,0 +1,35 @@
+-- X.509 AuthorityKeyIdentifier
+-- rfc5280 section 4.2.1.1
+
+AuthorityKeyIdentifier ::= SEQUENCE {
+ keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL
+ }
+
+KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid })
+
+CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial })
+
+GeneralNames ::= SEQUENCE OF GeneralName
+
+GeneralName ::= CHOICE {
+ otherName [0] ANY,
+ rfc822Name [1] IA5String,
+ dNSName [2] IA5String,
+ x400Address [3] ANY,
+ directoryName [4] Name ({ x509_akid_note_name }),
+ ediPartyName [5] ANY,
+ uniformResourceIdentifier [6] IA5String,
+ iPAddress [7] OCTET STRING,
+ registeredID [8] OBJECT IDENTIFIER
+ }
+
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+ attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
+ attributeValue ANY ({ x509_extract_name_segment })
+ }
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index a668d90302d38c..af71878dc15bff 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -18,6 +18,7 @@
#include "public_key.h"
#include "x509_parser.h"
#include "x509-asn1.h"
+#include "x509_akid-asn1.h"
#include "x509_rsakey-asn1.h"
struct x509_parse_context {
@@ -35,6 +36,10 @@ struct x509_parse_context {
u16 o_offset; /* Offset of organizationName (O) */
u16 cn_offset; /* Offset of commonName (CN) */
u16 email_offset; /* Offset of emailAddress */
+ unsigned raw_akid_size;
+ const void *raw_akid; /* Raw authorityKeyId in ASN.1 */
+ const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */
+ unsigned akid_raw_issuer_size;
};
/*
@@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert)
kfree(cert->subject);
kfree(cert->id);
kfree(cert->skid);
- kfree(cert->authority);
+ kfree(cert->akid_id);
+ kfree(cert->akid_skid);
kfree(cert->sig.digest);
mpi_free(cert->sig.rsa.s);
kfree(cert);
@@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
if (ret < 0)
goto error_decode;
+ /* Decode the AuthorityKeyIdentifier */
+ if (ctx->raw_akid) {
+ pr_devel("AKID: %u %*phN\n",
+ ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
+ ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
+ ctx->raw_akid, ctx->raw_akid_size);
+ if (ret < 0) {
+ pr_warn("Couldn't decode AuthKeyIdentifier\n");
+ goto error_decode;
+ }
+ }
+
/* Decode the public key */
ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx,
ctx->key, ctx->key_size);
@@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen,
struct x509_parse_context *ctx = context;
struct asymmetric_key_id *kid;
const unsigned char *v = value;
- int i;
pr_debug("Extension: %u\n", ctx->last_oid);
@@ -437,9 +454,7 @@ int x509_process_extension(void *context, size_t hdrlen,
ctx->cert->raw_skid_size = vlen;
ctx->cert->raw_skid = v;
- kid = asymmetric_key_generate_id(ctx->cert->raw_subject,
- ctx->cert->raw_subject_size,
- v, vlen);
+ kid = asymmetric_key_generate_id(v, vlen, "", 0);
if (IS_ERR(kid))
return PTR_ERR(kid);
ctx->cert->skid = kid;
@@ -449,117 +464,113 @@ int x509_process_extension(void *context, size_t hdrlen,
if (ctx->last_oid == OID_authorityKeyIdentifier) {
/* Get hold of the CA key fingerprint */
- if (ctx->cert->authority || vlen < 5)
- return -EBADMSG;
-
- /* Authority Key Identifier must be a Constructed SEQUENCE */
- if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)))
- return -EBADMSG;
-
- /* Authority Key Identifier is not indefinite length */
- if (unlikely(vlen == ASN1_INDEFINITE_LENGTH))
- return -EBADMSG;
-
- if (vlen < ASN1_INDEFINITE_LENGTH) {
- /* Short Form length */
- if (v[1] != vlen - 2 ||
- v[2] != SEQ_TAG_KEYID ||
- v[3] > vlen - 4)
- return -EBADMSG;
-
- vlen = v[3];
- v += 4;
- } else {
- /* Long Form length */
- size_t seq_len = 0;
- size_t sub = v[1] - ASN1_INDEFINITE_LENGTH;
-
- if (sub > 2)
- return -EBADMSG;
-
- /* calculate the length from subsequent octets */
- v += 2;
- for (i = 0; i < sub; i++) {
- seq_len <<= 8;
- seq_len |= v[i];
- }
-
- if (seq_len != vlen - 2 - sub ||
- v[sub] != SEQ_TAG_KEYID ||
- v[sub + 1] > vlen - 4 - sub)
- return -EBADMSG;
-
- vlen = v[sub + 1];
- v += (sub + 2);
- }
-
- kid = asymmetric_key_generate_id(ctx->cert->raw_issuer,
- ctx->cert->raw_issuer_size,
- v, vlen);
- if (IS_ERR(kid))
- return PTR_ERR(kid);
- pr_debug("authkeyid %*phN\n", kid->len, kid->data);
- ctx->cert->authority = kid;
+ ctx->raw_akid = v;
+ ctx->raw_akid_size = vlen;
return 0;
}
return 0;
}
-/*
- * Record a certificate time.
+/**
+ * x509_decode_time - Decode an X.509 time ASN.1 object
+ * @_t: The time to fill in
+ * @hdrlen: The length of the object header
+ * @tag: The object tag
+ * @value: The object value
+ * @vlen: The size of the object value
+ *
+ * Decode an ASN.1 universal time or generalised time field into a struct the
+ * kernel can handle and check it for validity. The time is decoded thus:
+ *
+ * [RFC5280 §4.1.2.5]
+ * CAs conforming to this profile MUST always encode certificate validity
+ * dates through the year 2049 as UTCTime; certificate validity dates in
+ * 2050 or later MUST be encoded as GeneralizedTime. Conforming
+ * applications MUST be able to process validity dates that are encoded in
+ * either UTCTime or GeneralizedTime.
*/
-static int x509_note_time(struct tm *tm, size_t hdrlen,
- unsigned char tag,
- const unsigned char *value, size_t vlen)
+int x509_decode_time(time64_t *_t, size_t hdrlen,
+ unsigned char tag,
+ const unsigned char *value, size_t vlen)
{
+ static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
const unsigned char *p = value;
+ unsigned year, mon, day, hour, min, sec, mon_len;
-#define dec2bin(X) ((X) - '0')
+#define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
if (tag == ASN1_UNITIM) {
/* UTCTime: YYMMDDHHMMSSZ */
if (vlen != 13)
goto unsupported_time;
- tm->tm_year = DD2bin(p);
- if (tm->tm_year >= 50)
- tm->tm_year += 1900;
+ year = DD2bin(p);
+ if (year >= 50)
+ year += 1900;
else
- tm->tm_year += 2000;
+ year += 2000;
} else if (tag == ASN1_GENTIM) {
/* GenTime: YYYYMMDDHHMMSSZ */
if (vlen != 15)
goto unsupported_time;
- tm->tm_year = DD2bin(p) * 100 + DD2bin(p);
+ year = DD2bin(p) * 100 + DD2bin(p);
+ if (year >= 1950 && year <= 2049)
+ goto invalid_time;
} else {
goto unsupported_time;
}
- tm->tm_year -= 1900;
- tm->tm_mon = DD2bin(p) - 1;
- tm->tm_mday = DD2bin(p);
- tm->tm_hour = DD2bin(p);
- tm->tm_min = DD2bin(p);
- tm->tm_sec = DD2bin(p);
+ mon = DD2bin(p);
+ day = DD2bin(p);
+ hour = DD2bin(p);
+ min = DD2bin(p);
+ sec = DD2bin(p);
if (*p != 'Z')
goto unsupported_time;
+ mon_len = month_lengths[mon];
+ if (mon == 2) {
+ if (year % 4 == 0) {
+ mon_len = 29;
+ if (year % 100 == 0) {
+ year /= 100;
+ if (year % 4 != 0)
+ mon_len = 28;
+ }
+ }
+ }
+
+ if (year < 1970 ||
+ mon < 1 || mon > 12 ||
+ day < 1 || day > mon_len ||
+ hour < 0 || hour > 23 ||
+ min < 0 || min > 59 ||
+ sec < 0 || sec > 59)
+ goto invalid_time;
+
+ *_t = mktime64(year, mon, day, hour, min, sec);
return 0;
unsupported_time:
- pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n",
- tag, (int)vlen, (int)vlen, value);
+ pr_debug("Got unsupported time [tag %02x]: '%*phN'\n",
+ tag, (int)vlen, value);
+ return -EBADMSG;
+invalid_time:
+ pr_debug("Got invalid time [tag %02x]: '%*phN'\n",
+ tag, (int)vlen, value);
return -EBADMSG;
}
+EXPORT_SYMBOL_GPL(x509_decode_time);
int x509_note_not_before(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
- return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
+ return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
}
int x509_note_not_after(void *context, size_t hdrlen,
@@ -567,5 +578,71 @@ int x509_note_not_after(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
- return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
+ return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
+}
+
+/*
+ * Note a key identifier-based AuthorityKeyIdentifier
+ */
+int x509_akid_note_kid(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ struct asymmetric_key_id *kid;
+
+ pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
+
+ if (ctx->cert->akid_skid)
+ return 0;
+
+ kid = asymmetric_key_generate_id(value, vlen, "", 0);
+ if (IS_ERR(kid))
+ return PTR_ERR(kid);
+ pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+ ctx->cert->akid_skid = kid;
+ return 0;
+}
+
+/*
+ * Note a directoryName in an AuthorityKeyIdentifier
+ */
+int x509_akid_note_name(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ pr_debug("AKID: name: %*phN\n", (int)vlen, value);
+
+ ctx->akid_raw_issuer = value;
+ ctx->akid_raw_issuer_size = vlen;
+ return 0;
+}
+
+/*
+ * Note a serial number in an AuthorityKeyIdentifier
+ */
+int x509_akid_note_serial(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+ struct asymmetric_key_id *kid;
+
+ pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
+
+ if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
+ return 0;
+
+ kid = asymmetric_key_generate_id(value,
+ vlen,
+ ctx->akid_raw_issuer,
+ ctx->akid_raw_issuer_size);
+ if (IS_ERR(kid))
+ return PTR_ERR(kid);
+
+ pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+ ctx->cert->akid_id = kid;
+ return 0;
}
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 3dfe6b5d6f0b90..1de01eaec88490 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -19,11 +19,12 @@ struct x509_certificate {
struct public_key_signature sig; /* Signature parameters */
char *issuer; /* Name of certificate issuer */
char *subject; /* Name of certificate subject */
- struct asymmetric_key_id *id; /* Serial number + issuer */
+ struct asymmetric_key_id *id; /* Issuer + Serial number */
struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */
- struct asymmetric_key_id *authority; /* Authority key identifier (optional) */
- struct tm valid_from;
- struct tm valid_to;
+ struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */
+ struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */
+ time64_t valid_from;
+ time64_t valid_to;
const void *tbs; /* Signed data */
unsigned tbs_size; /* Size of signed data */
unsigned raw_sig_size; /* Size of sigature */
@@ -48,6 +49,9 @@ struct x509_certificate {
*/
extern void x509_free_certificate(struct x509_certificate *cert);
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
+extern int x509_decode_time(time64_t *_t, size_t hdrlen,
+ unsigned char tag,
+ const unsigned char *value, size_t vlen);
/*
* x509_public_key.c
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 24f17e6c590488..6d88dd15c98da8 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup);
/**
* x509_request_asymmetric_key - Request a key by X.509 certificate params.
* @keyring: The keys to search.
- * @kid: The key ID.
+ * @id: The issuer & serialNumber to look for or NULL.
+ * @skid: The subjectKeyIdentifier to look for or NULL.
* @partial: Use partial match if true, exact if false.
*
- * Find a key in the given keyring by subject name and key ID. These might,
- * for instance, be the issuer name and the authority key ID of an X.509
- * certificate that needs to be verified.
+ * Find a key in the given keyring by identifier. The preferred identifier is
+ * the issuer + serialNumber and the fallback identifier is the
+ * subjectKeyIdentifier. If both are given, the lookup is by the former, but
+ * the latter must also match.
*/
struct key *x509_request_asymmetric_key(struct key *keyring,
- const struct asymmetric_key_id *kid,
+ const struct asymmetric_key_id *id,
+ const struct asymmetric_key_id *skid,
bool partial)
{
- key_ref_t key;
- char *id, *p;
-
+ struct key *key;
+ key_ref_t ref;
+ const char *lookup;
+ char *req, *p;
+ int len;
+
+ if (id) {
+ lookup = id->data;
+ len = id->len;
+ } else {
+ lookup = skid->data;
+ len = skid->len;
+ }
+
/* Construct an identifier "id:". */
- p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
- if (!id)
+ p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
+ if (!req)
return ERR_PTR(-ENOMEM);
if (partial) {
@@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
*p++ = 'x';
}
*p++ = ':';
- p = bin2hex(p, kid->data, kid->len);
+ p = bin2hex(p, lookup, len);
*p = 0;
- pr_debug("Look up: \"%s\"\n", id);
+ pr_debug("Look up: \"%s\"\n", req);
- key = keyring_search(make_key_ref(keyring, 1),
- &key_type_asymmetric, id);
- if (IS_ERR(key))
- pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
- kfree(id);
+ ref = keyring_search(make_key_ref(keyring, 1),
+ &key_type_asymmetric, req);
+ if (IS_ERR(ref))
+ pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
+ kfree(req);
- if (IS_ERR(key)) {
- switch (PTR_ERR(key)) {
+ if (IS_ERR(ref)) {
+ switch (PTR_ERR(ref)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
- return ERR_CAST(key);
+ return ERR_CAST(ref);
+ }
+ }
+
+ key = key_ref_to_ptr(ref);
+ if (id && skid) {
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+ if (!kids->id[1]) {
+ pr_debug("issuer+serial match, but expected SKID missing\n");
+ goto reject;
+ }
+ if (!asymmetric_key_id_same(skid, kids->id[1])) {
+ pr_debug("issuer+serial match, but SKID does not\n");
+ goto reject;
}
}
+
+ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
+ return key;
- pr_devel("<==%s() = 0 [%x]\n", __func__,
- key_serial(key_ref_to_ptr(key)));
- return key_ref_to_ptr(key);
+reject:
+ key_put(key);
+ return ERR_PTR(-EKEYREJECTED);
}
EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
@@ -227,10 +257,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
if (!trust_keyring)
return -EOPNOTSUPP;
- if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
+ if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
return -EPERM;
- key = x509_request_asymmetric_key(trust_keyring, cert->authority,
+ key = x509_request_asymmetric_key(trust_keyring,
+ cert->akid_id, cert->akid_skid,
false);
if (!IS_ERR(key)) {
if (!use_builtin_keys
@@ -271,14 +302,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
}
pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
- pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
- cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
- cert->valid_from.tm_mday, cert->valid_from.tm_hour,
- cert->valid_from.tm_min, cert->valid_from.tm_sec);
- pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
- cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
- cert->valid_to.tm_mday, cert->valid_to.tm_hour,
- cert->valid_to.tm_min, cert->valid_to.tm_sec);
+ pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
pr_devel("Cert Signature: %s + %s\n",
pkey_algo_name[cert->sig.pkey_algo],
hash_algo_name[cert->sig.pkey_hash_algo]);
@@ -287,8 +311,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
cert->pub->id_type = PKEY_ID_X509;
/* Check the signature on the key if it appears to be self-signed */
- if (!cert->authority ||
- asymmetric_key_id_same(cert->skid, cert->authority)) {
+ if ((!cert->akid_skid && !cert->akid_id) ||
+ asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
+ asymmetric_key_id_same(cert->id, cert->akid_id)) {
ret = x509_check_signature(cert->pub, cert); /* self-signed */
if (ret < 0)
goto error_free_cert;
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
index 691c79172a2691..441aff9b5aa759 100644
--- a/include/crypto/pkcs7.h
+++ b/include/crypto/pkcs7.h
@@ -9,6 +9,11 @@
* 2 of the Licence, or (at your option) any later version.
*/
+#ifndef _CRYPTO_PKCS7_H
+#define _CRYPTO_PKCS7_H
+
+#include
+
struct key;
struct pkcs7_message;
@@ -33,4 +38,10 @@ extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
/*
* pkcs7_verify.c
*/
-extern int pkcs7_verify(struct pkcs7_message *pkcs7);
+extern int pkcs7_verify(struct pkcs7_message *pkcs7,
+ enum key_being_used_for usage);
+
+extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
+ const void *data, size_t datalen);
+
+#endif /* _CRYPTO_PKCS7_H */
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 54add206990166..067c242b1e152d 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -33,11 +33,26 @@ extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST];
enum pkey_id_type {
PKEY_ID_PGP, /* OpenPGP generated key ID */
PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
+ PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
PKEY_ID_TYPE__LAST
};
extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
+/*
+ * The use to which an asymmetric key is being put.
+ */
+enum key_being_used_for {
+ VERIFYING_MODULE_SIGNATURE,
+ VERIFYING_FIRMWARE_SIGNATURE,
+ VERIFYING_KEXEC_PE_SIGNATURE,
+ VERIFYING_KEY_SIGNATURE,
+ VERIFYING_KEY_SELF_SIGNATURE,
+ VERIFYING_UNSPECIFIED_SIGNATURE,
+ NR__KEY_BEING_USED_FOR
+};
+extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
+
/*
* Cryptographic data for the public-key subtype of the asymmetric key type.
*
@@ -101,7 +116,8 @@ extern int verify_signature(const struct key *key,
struct asymmetric_key_id;
extern struct key *x509_request_asymmetric_key(struct key *keyring,
- const struct asymmetric_key_id *kid,
+ const struct asymmetric_key_id *id,
+ const struct asymmetric_key_id *skid,
bool partial);
#endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 72665eb8069269..b20cd885c1fd84 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -15,6 +15,7 @@
#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
#include
+#include
extern struct key *system_trusted_keyring;
static inline struct key *get_system_trusted_keyring(void)
@@ -28,4 +29,10 @@ static inline struct key *get_system_trusted_keyring(void)
}
#endif
+#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
+extern int system_verify_data(const void *data, unsigned long len,
+ const void *raw_pkcs7, size_t pkcs7_len,
+ enum key_being_used_for usage);
+#endif
+
#endif /* _KEYS_SYSTEM_KEYRING_H */
diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h
index 945d44ae529c31..ab3a6c002f7b9d 100644
--- a/include/linux/asn1_ber_bytecode.h
+++ b/include/linux/asn1_ber_bytecode.h
@@ -45,23 +45,27 @@ enum asn1_opcode {
ASN1_OP_MATCH_JUMP = 0x04,
ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
ASN1_OP_MATCH_ANY = 0x08,
+ ASN1_OP_MATCH_ANY_OR_SKIP = 0x09,
ASN1_OP_MATCH_ANY_ACT = 0x0a,
+ ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 0x0b,
/* Everything before here matches unconditionally */
ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
ASN1_OP_COND_MATCH_ANY = 0x18,
+ ASN1_OP_COND_MATCH_ANY_OR_SKIP = 0x19,
ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
+ ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 0x1b,
/* Everything before here will want a tag from the data */
-#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT
+#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP
/* These are here to help fill up space */
- ASN1_OP_COND_FAIL = 0x1b,
- ASN1_OP_COMPLETE = 0x1c,
- ASN1_OP_ACT = 0x1d,
- ASN1_OP_RETURN = 0x1e,
+ ASN1_OP_COND_FAIL = 0x1c,
+ ASN1_OP_COMPLETE = 0x1d,
+ ASN1_OP_ACT = 0x1e,
+ ASN1_OP_MAYBE_ACT = 0x1f,
/* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
ASN1_OP_END_SEQ = 0x20,
@@ -76,6 +80,8 @@ enum asn1_opcode {
#define ASN1_OP_END__OF 0x02
#define ASN1_OP_END__ACT 0x04
+ ASN1_OP_RETURN = 0x28,
+
ASN1_OP__NR
};
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
index 1cc89e9df480cc..ffb9c9da4f39f8 100644
--- a/include/linux/lsm_audit.h
+++ b/include/linux/lsm_audit.h
@@ -40,6 +40,11 @@ struct lsm_network_audit {
} fam;
};
+struct lsm_ioctlop_audit {
+ struct path path;
+ u16 cmd;
+};
+
/* Auxiliary data to use in generating the audit record. */
struct common_audit_data {
char type;
@@ -53,6 +58,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_KMOD 8
#define LSM_AUDIT_DATA_INODE 9
#define LSM_AUDIT_DATA_DENTRY 10
+#define LSM_AUDIT_DATA_IOCTL_OP 11
union {
struct path path;
struct dentry *dentry;
@@ -68,6 +74,7 @@ struct common_audit_data {
} key_struct;
#endif
char *kmod_name;
+ struct lsm_ioctlop_audit *op;
} u;
/* this union contains LSM specific data */
union {
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 9429f054c32396..ec3a6bab29de3a 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1881,8 +1881,10 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
extern int __init security_module_enable(const char *module);
extern void __init capability_add_hooks(void);
-#ifdef CONFIG_SECURITY_YAMA_STACKED
-void __init yama_add_hooks(void);
+#ifdef CONFIG_SECURITY_YAMA
+extern void __init yama_add_hooks(void);
+#else
+static inline void __init yama_add_hooks(void) { }
#endif
#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index c2bbf672b84eb5..d2fa9ca42e9a74 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -41,7 +41,7 @@ enum OID {
OID_signed_data, /* 1.2.840.113549.1.7.2 */
/* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
OID_email_address, /* 1.2.840.113549.1.9.1 */
- OID_content_type, /* 1.2.840.113549.1.9.3 */
+ OID_contentType, /* 1.2.840.113549.1.9.3 */
OID_messageDigest, /* 1.2.840.113549.1.9.4 */
OID_signingTime, /* 1.2.840.113549.1.9.5 */
OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
@@ -54,6 +54,8 @@ enum OID {
/* Microsoft Authenticode & Software Publishing */
OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
+ OID_msStatementType, /* 1.3.6.1.4.1.311.2.1.11 */
+ OID_msSpOpusInfo, /* 1.3.6.1.4.1.311.2.1.12 */
OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */
OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
@@ -61,6 +63,9 @@ enum OID {
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
OID_sha1, /* 1.3.14.3.2.26 */
OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
+ OID_sha384, /* 2.16.840.1.101.3.4.2.2 */
+ OID_sha512, /* 2.16.840.1.101.3.4.2.3 */
+ OID_sha224, /* 2.16.840.1.101.3.4.2.4 */
/* Distinguished Name attribute IDs [RFC 2256] */
OID_commonName, /* 2.5.4.3 */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 987a73a40ef846..061265f9287676 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -34,6 +34,7 @@
#define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP)
#define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT)
+#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT)
/* single stepping state bits (used on ARM and PA-RISC) */
#define PT_SINGLESTEP_BIT 31
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index a19ddacdac30ae..f4265039a94c8f 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -78,7 +78,7 @@ static inline long prctl_set_seccomp(unsigned long arg2, char __user *arg3)
static inline int seccomp_mode(struct seccomp *s)
{
- return 0;
+ return SECCOMP_MODE_DISABLED;
}
#endif /* CONFIG_SECCOMP */
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h
index ac34819214f913..da2049b5161ce7 100644
--- a/include/linux/verify_pefile.h
+++ b/include/linux/verify_pefile.h
@@ -12,7 +12,11 @@
#ifndef _LINUX_VERIFY_PEFILE_H
#define _LINUX_VERIFY_PEFILE_H
+#include
+
extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
- struct key *trusted_keyring, bool *_trusted);
+ struct key *trusted_keyring,
+ enum key_being_used_for usage,
+ bool *_trusted);
#endif /* _LINUX_VERIFY_PEFILE_H */
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index cf1019e15f5bc5..a7a69798661440 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -89,9 +89,11 @@ struct ptrace_peeksiginfo_args {
#define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP)
/* eventless options */
-#define PTRACE_O_EXITKILL (1 << 20)
+#define PTRACE_O_EXITKILL (1 << 20)
+#define PTRACE_O_SUSPEND_SECCOMP (1 << 21)
-#define PTRACE_O_MASK (0x000000ff | PTRACE_O_EXITKILL)
+#define PTRACE_O_MASK (\
+ 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP)
#include
diff --git a/init/Kconfig b/init/Kconfig
index 9cabd866b34b74..02da9f1fd9df16 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1765,17 +1765,23 @@ config MMAP_ALLOW_UNINITIALIZED
See Documentation/nommu-mmap.txt for more information.
-config SYSTEM_TRUSTED_KEYRING
- bool "Provide system-wide ring of trusted keys"
- depends on KEYS
+config SYSTEM_DATA_VERIFICATION
+ def_bool n
+ select SYSTEM_TRUSTED_KEYRING
+ select KEYS
+ select CRYPTO
+ select ASYMMETRIC_KEY_TYPE
+ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select PUBLIC_KEY_ALGO_RSA
+ select ASN1
+ select OID_REGISTRY
+ select X509_CERTIFICATE_PARSER
+ select PKCS7_MESSAGE_PARSER
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.
+ Provide PKCS#7 message verification using the contents of the system
+ trusted keyring to provide public keys. This then can be used for
+ module verification, kexec image verification and firmware blob
+ verification.
config PROFILING
bool "Profiling support"
@@ -1885,20 +1891,16 @@ config MODULE_SRCVERSION_ALL
config MODULE_SIG
bool "Module signature verification"
depends on MODULES
- select SYSTEM_TRUSTED_KEYRING
- select KEYS
- select CRYPTO
- select ASYMMETRIC_KEY_TYPE
- select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
- select PUBLIC_KEY_ALGO_RSA
- select ASN1
- select OID_REGISTRY
- select X509_CERTIFICATE_PARSER
+ select SYSTEM_DATA_VERIFICATION
help
Check modules for valid signatures upon load: the signature
is simply appended to the module. For more information see
Documentation/module-signing.txt.
+ Note that this option adds the OpenSSL development packages as a
+ kernel build dependency so that the signing tool can use its crypto
+ library.
+
!!!WARNING!!! If you enable this option, you MUST make sure that the
module DOES NOT get stripped after being signed. This includes the
debuginfo strip done by some packagers (such as rpmbuild) and
diff --git a/kernel/Makefile b/kernel/Makefile
index 718fb8afab7afb..330387cfb730cd 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
@@ -112,99 +111,3 @@ $(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE
targets += config_data.h
$(obj)/config_data.h: $(obj)/config_data.gz FORCE
$(call filechk,ikconfiggz)
-
-###############################################################################
-#
-# 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.
-#
-# 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.
-#
-###############################################################################
-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 ***)
-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
-
-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)")
-
-targets += $(obj)/x509_certificate_list
-$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
- $(call if_changed,x509certs)
-
-targets += $(obj)/.x509.list
-$(obj)/.x509.list:
- @echo $(X509_CERTIFICATES) >$@
-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
-
-signing_key.priv signing_key.x509: 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 DER -out signing_key.x509 \
- -keyout signing_key.priv 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
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index be5b8fac4bd0de..bd62f5cda74673 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -10,11 +10,8 @@
*/
#include
-#include
-#include
-#include
-#include
#include
+#include
#include "module-internal.h"
/*
@@ -28,170 +25,22 @@
* - 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.
- */
-static struct public_key_signature *mod_make_digest(enum hash_algo hash,
- const void *mod,
- unsigned long modlen)
-{
- struct public_key_signature *pks;
- struct crypto_shash *tfm;
- struct shash_desc *desc;
- size_t digest_size, desc_size;
- 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);
- if (ret < 0)
- goto error;
-
- ret = crypto_shash_finup(desc, mod, modlen, pks->digest);
- if (ret < 0)
- goto error;
-
- crypto_free_shash(tfm);
- pr_devel("<==%s() = ok\n", __func__);
- return pks;
-
-error:
- kfree(pks);
-error_no_pks:
- crypto_free_shash(tfm);
- 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);
-}
-
/*
* Verify the signature on a module.
*/
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 +54,24 @@ 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 system_verify_data(mod, modlen, mod + modlen, sig_len,
+ VERIFYING_MODULE_SIGNATURE);
}
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index c8e0e050a36afb..787320de68e024 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 245df6b32b81f8..5bd4779282df00 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;
@@ -549,7 +548,11 @@ void secure_computing_strict(int this_syscall)
{
int mode = current->seccomp.mode;
- if (mode == 0)
+ if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+ unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+ return;
+
+ if (mode == SECCOMP_MODE_DISABLED)
return;
else if (mode == SECCOMP_MODE_STRICT)
__secure_computing_strict(this_syscall);
@@ -650,6 +653,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 */
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c
index 1a000bb050f9f9..2b3f46c049d458 100644
--- a/lib/asn1_decoder.c
+++ b/lib/asn1_decoder.c
@@ -24,15 +24,20 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
[ASN1_OP_MATCH_JUMP] = 1 + 1 + 1,
[ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
[ASN1_OP_MATCH_ANY] = 1,
+ [ASN1_OP_MATCH_ANY_OR_SKIP] = 1,
[ASN1_OP_MATCH_ANY_ACT] = 1 + 1,
+ [ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
[ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1,
[ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
[ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
[ASN1_OP_COND_MATCH_ANY] = 1,
+ [ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1,
[ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1,
+ [ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
[ASN1_OP_COND_FAIL] = 1,
[ASN1_OP_COMPLETE] = 1,
[ASN1_OP_ACT] = 1 + 1,
+ [ASN1_OP_MAYBE_ACT] = 1 + 1,
[ASN1_OP_RETURN] = 1,
[ASN1_OP_END_SEQ] = 1,
[ASN1_OP_END_SEQ_OF] = 1 + 1,
@@ -177,6 +182,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
unsigned char flags = 0;
#define FLAG_INDEFINITE_LENGTH 0x01
#define FLAG_MATCHED 0x02
+#define FLAG_LAST_MATCHED 0x04 /* Last tag matched */
#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag
* - ie. whether or not we are going to parse
* a compound type.
@@ -208,9 +214,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
unsigned char tmp;
/* Skip conditional matches if possible */
- if ((op & ASN1_OP_MATCH__COND &&
- flags & FLAG_MATCHED) ||
- dp == datalen) {
+ if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) ||
+ (op & ASN1_OP_MATCH__SKIP && dp == datalen)) {
+ flags &= ~FLAG_LAST_MATCHED;
pc += asn1_op_lengths[op];
goto next_op;
}
@@ -302,7 +308,9 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
/* Decide how to handle the operation */
switch (op) {
case ASN1_OP_MATCH_ANY_ACT:
+ case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:
case ASN1_OP_COND_MATCH_ANY_ACT:
+ case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP:
ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len);
if (ret < 0)
return ret;
@@ -319,8 +327,10 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
case ASN1_OP_MATCH:
case ASN1_OP_MATCH_OR_SKIP:
case ASN1_OP_MATCH_ANY:
+ case ASN1_OP_MATCH_ANY_OR_SKIP:
case ASN1_OP_COND_MATCH_OR_SKIP:
case ASN1_OP_COND_MATCH_ANY:
+ case ASN1_OP_COND_MATCH_ANY_OR_SKIP:
skip_data:
if (!(flags & FLAG_CONS)) {
if (flags & FLAG_INDEFINITE_LENGTH) {
@@ -422,8 +432,15 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
pc += asn1_op_lengths[op];
goto next_op;
+ case ASN1_OP_MAYBE_ACT:
+ if (!(flags & FLAG_LAST_MATCHED)) {
+ pc += asn1_op_lengths[op];
+ goto next_op;
+ }
case ASN1_OP_ACT:
ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
+ if (ret < 0)
+ return ret;
pc += asn1_op_lengths[op];
goto next_op;
@@ -431,6 +448,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
if (unlikely(jsp <= 0))
goto jump_stack_underflow;
pc = jump_stack[--jsp];
+ flags |= FLAG_MATCHED | FLAG_LAST_MATCHED;
goto next_op;
default:
@@ -438,7 +456,8 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
}
/* Shouldn't reach here */
- pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op);
+ pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n",
+ op, pc);
return -EBADMSG;
data_overrun_error:
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 5ecfe93f202871..12efbbefd4d754 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -10,3 +10,5 @@ recordmcount
docproc
sortextable
asn1_compiler
+extract-cert
+sign-file
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index d3437b82ac256c..608ac65c61e34c 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -303,3 +303,54 @@ why = \
echo-why = $(call escsq, $(strip $(why)))
endif
+
+###############################################################################
+#
+# 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.
+#
+###############################################################################
+#
+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
+#
+###############################################################################
diff --git a/scripts/Makefile b/scripts/Makefile
index 2016a64497ab1c..1b2661712d449a 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -16,9 +16,13 @@ hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
hostprogs-$(CONFIG_ASN1) += asn1_compiler
+hostprogs-$(CONFIG_MODULE_SIG) += sign-file
+hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
+HOSTLOADLIBES_sign-file = -lcrypto
+HOSTLOADLIBES_extract-cert = -lcrypto
always := $(hostprogs-y) $(hostprogs-m)
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index e48a4e9d88682b..07650eeaaf06dd 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -22,7 +22,7 @@ quiet_cmd_modules_install = INSTALL $@
mkdir -p $(2) ; \
cp $@ $(2) ; \
$(mod_strip_cmd) $(2)/$(notdir $@) ; \
- $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \
+ $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) && \
$(mod_compress_cmd) $(2)/$(notdir $@)
# Modules built outside the kernel source tree go into extra by default
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c
index 7750e9c31483b9..e000f44e37b877 100644
--- a/scripts/asn1_compiler.c
+++ b/scripts/asn1_compiler.c
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -293,8 +294,8 @@ static const char *const directives[NR__DIRECTIVES] = {
struct action {
struct action *next;
+ char *name;
unsigned char index;
- char name[];
};
static struct action *action_list;
@@ -305,15 +306,17 @@ struct token {
enum token_type token_type : 8;
unsigned char size;
struct action *action;
- const char *value;
+ char *content;
struct type *type;
};
static struct token *token_list;
static unsigned nr_tokens;
-static _Bool verbose;
+static bool verbose_opt;
+static bool debug_opt;
-#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
+#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
+#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
static int directive_compare(const void *_key, const void *_pdir)
{
@@ -325,11 +328,9 @@ static int directive_compare(const void *_key, const void *_pdir)
dlen = strlen(dir);
clen = (dlen < token->size) ? dlen : token->size;
- //debug("cmp(%*.*s,%s) = ",
- // (int)token->size, (int)token->size, token->value,
- // dir);
+ //debug("cmp(%s,%s) = ", token->content, dir);
- val = memcmp(token->value, dir, clen);
+ val = memcmp(token->content, dir, clen);
if (val != 0) {
//debug("%d [cmp]\n", val);
return val;
@@ -349,7 +350,7 @@ static int directive_compare(const void *_key, const void *_pdir)
static void tokenise(char *buffer, char *end)
{
struct token *tokens;
- char *line, *nl, *p, *q;
+ char *line, *nl, *start, *p, *q;
unsigned tix, lineno;
/* Assume we're going to have half as many tokens as we have
@@ -408,11 +409,11 @@ static void tokenise(char *buffer, char *end)
break;
tokens[tix].line = lineno;
- tokens[tix].value = p;
+ start = p;
/* Handle string tokens */
if (isalpha(*p)) {
- const char **dir;
+ const char **dir, *start = p;
/* Can be a directive, type name or element
* name. Find the end of the name.
@@ -423,10 +424,18 @@ static void tokenise(char *buffer, char *end)
tokens[tix].size = q - p;
p = q;
+ tokens[tix].content = malloc(tokens[tix].size + 1);
+ if (!tokens[tix].content) {
+ perror(NULL);
+ exit(1);
+ }
+ memcpy(tokens[tix].content, start, tokens[tix].size);
+ tokens[tix].content[tokens[tix].size] = 0;
+
/* If it begins with a lowercase letter then
* it's an element name
*/
- if (islower(tokens[tix].value[0])) {
+ if (islower(tokens[tix].content[0])) {
tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
continue;
}
@@ -455,6 +464,13 @@ static void tokenise(char *buffer, char *end)
q++;
tokens[tix].size = q - p;
p = q;
+ tokens[tix].content = malloc(tokens[tix].size + 1);
+ if (!tokens[tix].content) {
+ perror(NULL);
+ exit(1);
+ }
+ memcpy(tokens[tix].content, start, tokens[tix].size);
+ tokens[tix].content[tokens[tix].size] = 0;
tokens[tix++].token_type = TOKEN_NUMBER;
continue;
}
@@ -463,6 +479,7 @@ static void tokenise(char *buffer, char *end)
if (memcmp(p, "::=", 3) == 0) {
p += 3;
tokens[tix].size = 3;
+ tokens[tix].content = "::=";
tokens[tix++].token_type = TOKEN_ASSIGNMENT;
continue;
}
@@ -472,12 +489,14 @@ static void tokenise(char *buffer, char *end)
if (memcmp(p, "({", 2) == 0) {
p += 2;
tokens[tix].size = 2;
+ tokens[tix].content = "({";
tokens[tix++].token_type = TOKEN_OPEN_ACTION;
continue;
}
if (memcmp(p, "})", 2) == 0) {
p += 2;
tokens[tix].size = 2;
+ tokens[tix].content = "})";
tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
continue;
}
@@ -488,22 +507,27 @@ static void tokenise(char *buffer, char *end)
switch (*p) {
case '{':
p += 1;
+ tokens[tix].content = "{";
tokens[tix++].token_type = TOKEN_OPEN_CURLY;
continue;
case '}':
p += 1;
+ tokens[tix].content = "}";
tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
continue;
case '[':
p += 1;
+ tokens[tix].content = "[";
tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
continue;
case ']':
p += 1;
+ tokens[tix].content = "]";
tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
continue;
case ',':
p += 1;
+ tokens[tix].content = ",";
tokens[tix++].token_type = TOKEN_COMMA;
continue;
default:
@@ -518,22 +542,20 @@ static void tokenise(char *buffer, char *end)
}
nr_tokens = tix;
- debug("Extracted %u tokens\n", nr_tokens);
+ verbose("Extracted %u tokens\n", nr_tokens);
#if 0
{
int n;
for (n = 0; n < nr_tokens; n++)
- debug("Token %3u: '%*.*s'\n",
- n,
- (int)token_list[n].size, (int)token_list[n].size,
- token_list[n].value);
+ debug("Token %3u: '%s'\n", n, token_list[n].content);
}
#endif
}
static void build_type_list(void);
static void parse(void);
+static void dump_elements(void);
static void render(FILE *out, FILE *hdr);
/*
@@ -548,16 +570,27 @@ int main(int argc, char **argv)
char *kbuild_verbose;
int fd;
+ kbuild_verbose = getenv("KBUILD_VERBOSE");
+ if (kbuild_verbose)
+ verbose_opt = atoi(kbuild_verbose);
+
+ while (argc > 4) {
+ if (strcmp(argv[1], "-v") == 0)
+ verbose_opt = true;
+ else if (strcmp(argv[1], "-d") == 0)
+ debug_opt = true;
+ else
+ break;
+ memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
+ argc--;
+ }
+
if (argc != 4) {
- fprintf(stderr, "Format: %s \n",
+ fprintf(stderr, "Format: %s [-v] [-d] \n",
argv[0]);
exit(2);
}
- kbuild_verbose = getenv("KBUILD_VERBOSE");
- if (kbuild_verbose)
- verbose = atoi(kbuild_verbose);
-
filename = argv[1];
outputname = argv[2];
headername = argv[3];
@@ -608,6 +641,7 @@ int main(int argc, char **argv)
tokenise(buffer, buffer + readlen);
build_type_list();
parse();
+ dump_elements();
out = fopen(outputname, "w");
if (!out) {
@@ -666,7 +700,7 @@ struct element {
unsigned flags;
#define ELEMENT_IMPLICIT 0x0001
#define ELEMENT_EXPLICIT 0x0002
-#define ELEMENT_MARKED 0x0004
+#define ELEMENT_TAG_SPECIFIED 0x0004
#define ELEMENT_RENDERED 0x0008
#define ELEMENT_SKIPPABLE 0x0010
#define ELEMENT_CONDITIONAL 0x0020
@@ -693,7 +727,7 @@ static int type_index_compare(const void *_a, const void *_b)
if ((*a)->name->size != (*b)->name->size)
return (*a)->name->size - (*b)->name->size;
else
- return memcmp((*a)->name->value, (*b)->name->value,
+ return memcmp((*a)->name->content, (*b)->name->content,
(*a)->name->size);
}
@@ -706,7 +740,7 @@ static int type_finder(const void *_key, const void *_ti)
if (token->size != type->name->size)
return token->size - type->name->size;
else
- return memcmp(token->value, type->name->value,
+ return memcmp(token->content, type->name->content,
token->size);
}
@@ -756,14 +790,11 @@ static void build_type_list(void)
qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
- debug("Extracted %u types\n", nr_types);
+ verbose("Extracted %u types\n", nr_types);
#if 0
for (n = 0; n < nr_types; n++) {
struct type *type = type_index[n];
- debug("- %*.*s\n",
- (int)type->name->size,
- (int)type->name->size,
- type->name->value);
+ debug("- %*.*s\n", type->name->content);
}
#endif
}
@@ -793,15 +824,14 @@ static void parse(void)
type->element->type_def = type;
if (cursor != type[1].name) {
- fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
} while (type++, !(type->flags & TYPE_STOP_MARKER));
- debug("Extracted %u actions\n", nr_actions);
+ verbose("Extracted %u actions\n", nr_actions);
}
static struct element *element_list;
@@ -862,33 +892,31 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
cursor++;
break;
default:
- fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
if (cursor >= end)
goto overrun_error;
if (cursor->token_type != TOKEN_NUMBER) {
- fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
element->tag &= ~0x1f;
- element->tag |= strtoul(cursor->value, &p, 10);
- if (p - cursor->value != cursor->size)
+ element->tag |= strtoul(cursor->content, &p, 10);
+ element->flags |= ELEMENT_TAG_SPECIFIED;
+ if (p - cursor->content != cursor->size)
abort();
cursor++;
if (cursor >= end)
goto overrun_error;
if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
- fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
cursor++;
@@ -988,9 +1016,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
type_finder);
if (!ref) {
- fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Type '%s' undefined\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
cursor->type = *ref;
@@ -1039,9 +1066,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
break;
default:
- fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
@@ -1058,20 +1084,18 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
if (cursor >= end)
goto overrun_error;
if (cursor->token_type != TOKEN_ELEMENT_NAME) {
- fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
- action = malloc(sizeof(struct action) + cursor->size + 1);
+ action = malloc(sizeof(struct action));
if (!action) {
perror(NULL);
exit(1);
}
action->index = 0;
- memcpy(action->name, cursor->value, cursor->size);
- action->name[cursor->size] = 0;
+ action->name = cursor->content;
for (ppaction = &action_list;
*ppaction;
@@ -1101,9 +1125,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
if (cursor >= end)
goto overrun_error;
if (cursor->token_type != TOKEN_CLOSE_ACTION) {
- fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
cursor++;
@@ -1113,9 +1136,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end,
return top;
parse_error:
- fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
overrun_error:
@@ -1133,9 +1155,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end,
struct token *cursor = *_cursor, *name;
if (cursor->token_type != TOKEN_OPEN_CURLY) {
- fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
cursor++;
@@ -1176,9 +1197,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end,
children->flags &= ~ELEMENT_CONDITIONAL;
if (cursor->token_type != TOKEN_CLOSE_CURLY) {
- fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
- filename, cursor->line,
- (int)cursor->size, (int)cursor->size, cursor->value);
+ fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
+ filename, cursor->line, cursor->content);
exit(1);
}
cursor++;
@@ -1191,6 +1211,52 @@ static struct element *parse_compound(struct token **_cursor, struct token *end,
exit(1);
}
+static void dump_element(const struct element *e, int level)
+{
+ const struct element *c;
+ const struct type *t = e->type_def;
+ const char *name = e->name ? e->name->content : ".";
+ const char *tname = t && t->name ? t->name->content : ".";
+ char tag[32];
+
+ if (e->class == 0 && e->method == 0 && e->tag == 0)
+ strcpy(tag, "<...>");
+ else if (e->class == ASN1_UNIV)
+ sprintf(tag, "%s %s %s",
+ asn1_classes[e->class],
+ asn1_methods[e->method],
+ asn1_universal_tags[e->tag]);
+ else
+ sprintf(tag, "%s %s %u",
+ asn1_classes[e->class],
+ asn1_methods[e->method],
+ e->tag);
+
+ printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
+ e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
+ e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
+ e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
+ e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
+ e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
+ "-tTqQcaro"[e->compound],
+ level, "",
+ tag,
+ tname,
+ name,
+ e->action ? e->action->name : "");
+ if (e->compound == TYPE_REF)
+ dump_element(e->type->type->element, level + 3);
+ else
+ for (c = e->children; c; c = c->next)
+ dump_element(c, level + 3);
+}
+
+static void dump_elements(void)
+{
+ if (debug_opt)
+ dump_element(type_list[0].element, 0);
+}
+
static void render_element(FILE *out, struct element *e, struct element *tag);
static void render_out_of_line_list(FILE *out);
@@ -1292,7 +1358,7 @@ static void render(FILE *out, FILE *hdr)
}
/* We do two passes - the first one calculates all the offsets */
- debug("Pass 1\n");
+ verbose("Pass 1\n");
nr_entries = 0;
root = &type_list[0];
render_element(NULL, root->element, NULL);
@@ -1303,7 +1369,7 @@ static void render(FILE *out, FILE *hdr)
e->flags &= ~ELEMENT_RENDERED;
/* And then we actually render */
- debug("Pass 2\n");
+ verbose("Pass 2\n");
fprintf(out, "\n");
fprintf(out, "static const unsigned char %s_machine[] = {\n",
grammar_name);
@@ -1376,7 +1442,7 @@ static void render_out_of_line_list(FILE *out)
*/
static void render_element(FILE *out, struct element *e, struct element *tag)
{
- struct element *ec;
+ struct element *ec, *x;
const char *cond, *act;
int entry, skippable = 0, outofline = 0;
@@ -1389,9 +1455,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
outofline = 1;
if (e->type_def && out) {
- render_more(out, "\t// %*.*s\n",
- (int)e->type_def->name->size, (int)e->type_def->name->size,
- e->type_def->name->value);
+ render_more(out, "\t// %s\n", e->type_def->name->content);
}
/* Render the operation */
@@ -1400,11 +1464,10 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
act = e->action ? "_ACT" : "";
switch (e->compound) {
case ANY:
- render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
+ render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
+ cond, act, skippable ? "_OR_SKIP" : "");
if (e->name)
- render_more(out, "\t\t// %*.*s",
- (int)e->name->size, (int)e->name->size,
- e->name->value);
+ render_more(out, "\t\t// %s", e->name->content);
render_more(out, "\n");
goto dont_render_tag;
@@ -1435,15 +1498,15 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
break;
}
- if (e->name)
- render_more(out, "\t\t// %*.*s",
- (int)e->name->size, (int)e->name->size,
- e->name->value);
+ x = tag ?: e;
+ if (x->name)
+ render_more(out, "\t\t// %s", x->name->content);
render_more(out, "\n");
/* Render the tag */
- if (!tag)
+ if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
tag = e;
+
if (tag->class == ASN1_UNIV &&
tag->tag != 14 &&
tag->tag != 15 &&
@@ -1465,7 +1528,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
case TYPE_REF:
render_element(out, e->type->type->element, tag);
if (e->action)
- render_opcode(out, "ASN1_OP_ACT,\n");
+ render_opcode(out, "ASN1_OP_%sACT,\n",
+ skippable ? "MAYBE_" : "");
break;
case SEQUENCE:
@@ -1474,10 +1538,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
* skipability */
render_opcode(out, "_jump_target(%u),", e->entry_index);
if (e->type_def && e->type_def->name)
- render_more(out, "\t\t// --> %*.*s",
- (int)e->type_def->name->size,
- (int)e->type_def->name->size,
- e->type_def->name->value);
+ render_more(out, "\t\t// --> %s",
+ e->type_def->name->content);
render_more(out, "\n");
if (!(e->flags & ELEMENT_RENDERED)) {
e->flags |= ELEMENT_RENDERED;
@@ -1502,10 +1564,8 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
* skipability */
render_opcode(out, "_jump_target(%u),", e->entry_index);
if (e->type_def && e->type_def->name)
- render_more(out, "\t\t// --> %*.*s",
- (int)e->type_def->name->size,
- (int)e->type_def->name->size,
- e->type_def->name->value);
+ render_more(out, "\t\t// --> %s",
+ e->type_def->name->content);
render_more(out, "\n");
if (!(e->flags & ELEMENT_RENDERED)) {
e->flags |= ELEMENT_RENDERED;
@@ -1539,7 +1599,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag)
case CHOICE:
for (ec = e->children; ec; ec = ec->next)
- render_element(out, ec, NULL);
+ render_element(out, ec, ec);
if (!skippable)
render_opcode(out, "ASN1_OP_COND_FAIL,\n");
if (e->action)
diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c
new file mode 100644
index 00000000000000..fd0db015c65c27
--- /dev/null
+++ b/scripts/extract-cert.c
@@ -0,0 +1,166 @@
+/* Extract X.509 certificate in DER form from PKCS#11 or PEM.
+ *
+ * Copyright © 2014 Red Hat, Inc. All Rights Reserved.
+ * Copyright © 2015 Intel Corporation.
+ *
+ * Authors: David Howells
+ * David Woodhouse
+ *
+ * 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.
+ */
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define PKEY_ID_PKCS7 2
+
+static __attribute__((noreturn))
+void format(void)
+{
+ fprintf(stderr,
+ "Usage: scripts/extract-cert