diff options
-rw-r--r-- | config-generic | 7 | ||||
-rw-r--r-- | config-x86-generic | 5 | ||||
-rw-r--r-- | genkey | 8 | ||||
-rw-r--r-- | kernel.spec | 56 | ||||
-rw-r--r-- | modsign-20111207.patch | 7361 |
5 files changed, 7435 insertions, 2 deletions
diff --git a/config-generic b/config-generic index a68f37f68..d63c834f7 100644 --- a/config-generic +++ b/config-generic @@ -3842,7 +3842,7 @@ CONFIG_CRYPTO_SEED=m CONFIG_CRYPTO_SEQIV=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TGR192=m @@ -4392,3 +4392,8 @@ CONFIG_INTEL_MID_PTI=m CONFIG_IOMMU_SUPPORT=y # CONFIG_PM_DEVFREQ is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_VERIFY_ELF is not set +# CONFIG_CRYPTO_KEY_TYPE is not set +# CONFIG_PGP_LIBRARY is not set +# CONFIG_PGP_PRELOAD is not set diff --git a/config-x86-generic b/config-x86-generic index 02e1fe7d1..d8f4d0332 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -403,3 +403,8 @@ CONFIG_DRM_GMA500=m # Maybe enable in debug kernels? # CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_MPILIB=y +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_SHA1 is not set +CONFIG_MODULE_SIG_SHA256=y +# CONFIG_MODULE_SIG_FORCE is not set @@ -0,0 +1,8 @@ +%pubring kernel.pub +%secring kernel.sec +Key-Type: RSA +Key-Length: 2048 +Name-Real: Fedora Project +Name-Comment: Kernel Module GPG key +%commit + diff --git a/kernel.spec b/kernel.spec index e4ee511a6..e3ec5d083 100644 --- a/kernel.spec +++ b/kernel.spec @@ -8,6 +8,14 @@ Summary: The Linux kernel # be 0. %global released_kernel 0 +# Sign modules on x86. Make sure the config files match this setting if more +# architectures are added. +%ifarch %{ix86} x86_64 +%global signmodules 1 +%else +%global signmodules 0 +%endif + # Save original buildid for later if it's defined %if 0%{?buildid:1} %global orig_buildid %{buildid} @@ -54,7 +62,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 2 +%global baserelease 3 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -573,9 +581,17 @@ BuildRequires: rpm-build >= 4.9.0-1, elfutils >= elfutils-0.153-1 %define debuginfo_args --strict-build-id -r %endif +%if %{signmodules} +BuildRequires: gnupg +%endif + Source0: ftp://ftp.kernel.org/pub/linux/kernel/v3.0/linux-%{kversion}.tar.xz Source1: compat-wireless-%{cwversion}.tar.bz2 +%if %{signmodules} +Source11: genkey +%endif + Source15: merge.pl Source16: mod-extra.list @@ -696,6 +712,7 @@ Patch700: linux-2.6-e1000-ich9-montevina.patch Patch800: linux-2.6-crash-driver.patch # crypto/ +Patch900: modsign-20111207.patch # virt + ksm patches Patch1555: fix_xen_guest_on_old_EC2.patch @@ -1430,6 +1447,7 @@ ApplyPatch linux-2.6-crash-driver.patch ApplyPatch linux-2.6-e1000-ich9-montevina.patch # crypto/ +ApplyPatch modsign-20111207.patch # Assorted Virt Fixes ApplyPatch fix_xen_guest_on_old_EC2.patch @@ -1556,6 +1574,30 @@ done # remove unnecessary SCM files find . -name .gitignore -exec rm -f {} \; >/dev/null +%if %{signmodules} +cat <<EOF +### +### Now generating a PGP key pair to be used for signing modules. +### +### If this takes a long time, you might wish to run rngd in the background to +### keep the supply of entropy topped up. It needs to be run as root, and +### should use a hardware random number generator if one is available, eg: +### +### rngd -r /dev/hwrandom +### +### If one isn't available, the pseudo-random number generator can be used: +### +### rngd -r /dev/urandom +### +EOF +gpg --homedir . --batch --gen-key %{SOURCE11} +cat <<EOF +### +### Key pair generated. +### +EOF +%endif + cd .. %if %{with_backports} @@ -1581,6 +1623,7 @@ cd .. # get rid of unwanted files resulting from patch fuzz find . \( -name "*.orig" -o -name "*~" \) -exec rm -f {} \; >/dev/null + ### ### build ### @@ -1679,6 +1722,14 @@ BuildKernel() { # Override $(mod-fw) because we don't want it to install any firmware # we'll get it from the linux-firmware package and we don't want conflicts make -s ARCH=$Arch INSTALL_MOD_PATH=$RPM_BUILD_ROOT modules_install KERNELRELEASE=$KernelVer mod-fw= + +%if %{signmodules} + if [ -z "$(readelf -n $(find fs/ -name \*.ko | head -n 1) | grep module.sig)" ]; then + echo "ERROR: modules are NOT signed" >&2; + exit 1; + fi +%endif + %ifarch %{vdso_arches} make -s ARCH=$Arch INSTALL_MOD_PATH=$RPM_BUILD_ROOT vdso_install KERNELRELEASE=$KernelVer if [ ! -s ldconfig-kernel.conf ]; then @@ -2377,6 +2428,9 @@ fi # ||----w | # || || %changelog +* Wed Mar 07 2012 Josh Boyer <jwboyer@redhat.com> +- Add modsign for x86 builds + * Wed Mar 07 2012 Dave Jones <davej@redhat.com> - 3.3.0-0.rc6.git2.2 - Disable debugging options. diff --git a/modsign-20111207.patch b/modsign-20111207.patch new file mode 100644 index 000000000..8e43422a3 --- /dev/null +++ b/modsign-20111207.patch @@ -0,0 +1,7361 @@ +From 5ba13e189c831b8ad2bfb14f4599b9b9d00cc5ae Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:04 +0000 +Subject: MPILIB: Export some more symbols + +Export some more symbols for use by the DSA key subtype. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + lib/mpi/mpi-cmp.c | 2 ++ + lib/mpi/mpi-div.c | 1 + + lib/mpi/mpi-inv.c | 1 + + lib/mpi/mpi-mpow.c | 1 + + lib/mpi/mpi-mul.c | 1 + + 5 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c +index 914bc42..1871e7b 100644 +--- a/lib/mpi/mpi-cmp.c ++++ b/lib/mpi/mpi-cmp.c +@@ -39,6 +39,7 @@ int mpi_cmp_ui(MPI u, unsigned long v) + else + return -1; + } ++EXPORT_SYMBOL_GPL(mpi_cmp_ui); + + int mpi_cmp(MPI u, MPI v) + { +@@ -66,3 +67,4 @@ int mpi_cmp(MPI u, MPI v) + return 1; + return -1; + } ++EXPORT_SYMBOL_GPL(mpi_cmp); +diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c +index c3087d1..3da9402 100644 +--- a/lib/mpi/mpi-div.c ++++ b/lib/mpi/mpi-div.c +@@ -59,6 +59,7 @@ nomem: + mpi_free(temp_divisor); + return rc; + } ++EXPORT_SYMBOL_GPL(mpi_fdiv_r); + + /**************** + * Division rounding the quotient towards -infinity. +diff --git a/lib/mpi/mpi-inv.c b/lib/mpi/mpi-inv.c +index 0951f98..bfc5ca1 100644 +--- a/lib/mpi/mpi-inv.c ++++ b/lib/mpi/mpi-inv.c +@@ -185,3 +185,4 @@ cleanup: + mpi_free(v); + return rc; + } ++EXPORT_SYMBOL_GPL(mpi_invm); +diff --git a/lib/mpi/mpi-mpow.c b/lib/mpi/mpi-mpow.c +index 4cc7593..5752194 100644 +--- a/lib/mpi/mpi-mpow.c ++++ b/lib/mpi/mpi-mpow.c +@@ -131,3 +131,4 @@ nomem: + kfree(G); + return rc; + } ++EXPORT_SYMBOL_GPL(mpi_mulpowm); +diff --git a/lib/mpi/mpi-mul.c b/lib/mpi/mpi-mul.c +index 1f3219e..3d514b9 100644 +--- a/lib/mpi/mpi-mul.c ++++ b/lib/mpi/mpi-mul.c +@@ -192,3 +192,4 @@ int mpi_mulm(MPI w, MPI u, MPI v, MPI m) + return -ENOMEM; + return mpi_fdiv_r(w, w, m); + } ++EXPORT_SYMBOL_GPL(mpi_mulm); +-- +1.7.9.1 + + +From 7a5782bc39eba97f3499e3d2686fe48d26f261b0 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:06 +0000 +Subject: KEYS: Move the key config into security/keys/Kconfig + +Move the key config into security/keys/Kconfig as there are going to be a lot +of key-related options. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/Kconfig | 68 +---------------------------------------------- + security/keys/Kconfig | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 72 insertions(+), 67 deletions(-) + create mode 100644 security/keys/Kconfig + +diff --git a/security/Kconfig b/security/Kconfig +index 51bd5a0..1c5a7a4 100644 +--- a/security/Kconfig ++++ b/security/Kconfig +@@ -4,73 +4,7 @@ + + menu "Security options" + +-config KEYS +- bool "Enable access key retention support" +- help +- This option provides support for retaining authentication tokens and +- access keys in the kernel. +- +- It also includes provision of methods by which such keys might be +- associated with a process so that network filesystems, encryption +- support and the like can find them. +- +- Furthermore, a special type of key is available that acts as keyring: +- a searchable sequence of keys. Each process is equipped with access +- to five standard keyrings: UID-specific, GID-specific, session, +- process and thread. +- +- If you are unsure as to whether this is required, answer N. +- +-config TRUSTED_KEYS +- tristate "TRUSTED KEYS" +- depends on KEYS && TCG_TPM +- select CRYPTO +- select CRYPTO_HMAC +- select CRYPTO_SHA1 +- help +- This option provides support for creating, sealing, and unsealing +- keys in the kernel. Trusted keys are random number symmetric keys, +- generated and RSA-sealed by the TPM. The TPM only unseals the keys, +- if the boot PCRs and other criteria match. Userspace will only ever +- see encrypted blobs. +- +- If you are unsure as to whether this is required, answer N. +- +-config ENCRYPTED_KEYS +- tristate "ENCRYPTED KEYS" +- depends on KEYS +- select CRYPTO +- select CRYPTO_HMAC +- select CRYPTO_AES +- select CRYPTO_CBC +- select CRYPTO_SHA256 +- select CRYPTO_RNG +- help +- This option provides support for create/encrypting/decrypting keys +- in the kernel. Encrypted keys are kernel generated random numbers, +- which are encrypted/decrypted with a 'master' symmetric key. The +- 'master' key can be either a trusted-key or user-key type. +- Userspace only ever sees/stores encrypted blobs. +- +- If you are unsure as to whether this is required, answer N. +- +-config KEYS_DEBUG_PROC_KEYS +- bool "Enable the /proc/keys file by which keys may be viewed" +- depends on KEYS +- help +- This option turns on support for the /proc/keys file - through which +- can be listed all the keys on the system that are viewable by the +- reading process. +- +- The only keys included in the list are those that grant View +- permission to the reading process whether or not it possesses them. +- Note that LSM security checks are still performed, and may further +- filter out keys that the current process is not authorised to view. +- +- Only key attributes are listed here; key payloads are not included in +- the resulting table. +- +- If you are unsure as to whether this is required, answer N. ++source security/keys/Kconfig + + config SECURITY_DMESG_RESTRICT + bool "Restrict unprivileged access to the kernel syslog" +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +new file mode 100644 +index 0000000..a90d6d3 +--- /dev/null ++++ b/security/keys/Kconfig +@@ -0,0 +1,71 @@ ++# ++# Key management configuration ++# ++ ++config KEYS ++ bool "Enable access key retention support" ++ help ++ This option provides support for retaining authentication tokens and ++ access keys in the kernel. ++ ++ It also includes provision of methods by which such keys might be ++ associated with a process so that network filesystems, encryption ++ support and the like can find them. ++ ++ Furthermore, a special type of key is available that acts as keyring: ++ a searchable sequence of keys. Each process is equipped with access ++ to five standard keyrings: UID-specific, GID-specific, session, ++ process and thread. ++ ++ If you are unsure as to whether this is required, answer N. ++ ++config TRUSTED_KEYS ++ tristate "TRUSTED KEYS" ++ depends on KEYS && TCG_TPM ++ select CRYPTO ++ select CRYPTO_HMAC ++ select CRYPTO_SHA1 ++ help ++ This option provides support for creating, sealing, and unsealing ++ keys in the kernel. Trusted keys are random number symmetric keys, ++ generated and RSA-sealed by the TPM. The TPM only unseals the keys, ++ if the boot PCRs and other criteria match. Userspace will only ever ++ see encrypted blobs. ++ ++ If you are unsure as to whether this is required, answer N. ++ ++config ENCRYPTED_KEYS ++ tristate "ENCRYPTED KEYS" ++ depends on KEYS ++ select CRYPTO ++ select CRYPTO_HMAC ++ select CRYPTO_AES ++ select CRYPTO_CBC ++ select CRYPTO_SHA256 ++ select CRYPTO_RNG ++ help ++ This option provides support for create/encrypting/decrypting keys ++ in the kernel. Encrypted keys are kernel generated random numbers, ++ which are encrypted/decrypted with a 'master' symmetric key. The ++ 'master' key can be either a trusted-key or user-key type. ++ Userspace only ever sees/stores encrypted blobs. ++ ++ If you are unsure as to whether this is required, answer N. ++ ++config KEYS_DEBUG_PROC_KEYS ++ bool "Enable the /proc/keys file by which keys may be viewed" ++ depends on KEYS ++ help ++ This option turns on support for the /proc/keys file - through which ++ can be listed all the keys on the system that are viewable by the ++ reading process. ++ ++ The only keys included in the list are those that grant View ++ permission to the reading process whether or not it possesses them. ++ Note that LSM security checks are still performed, and may further ++ filter out keys that the current process is not authorised to view. ++ ++ Only key attributes are listed here; key payloads are not included in ++ the resulting table. ++ ++ If you are unsure as to whether this is required, answer N. +-- +1.7.9.1 + + +From f8b45d1f0f1bdd4c29733f462f6f43518ea625d3 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:07 +0000 +Subject: KEYS: Announce key type (un)registration + +Announce the (un)registration of a key type in the core key code rather than +in the callers. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + net/dns_resolver/dns_key.c | 5 ----- + security/keys/key.c | 3 +++ + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c +index fa000d2..689d7c8 100644 +--- a/net/dns_resolver/dns_key.c ++++ b/net/dns_resolver/dns_key.c +@@ -249,9 +249,6 @@ static int __init init_dns_resolver(void) + struct key *keyring; + int ret; + +- printk(KERN_NOTICE "Registering the %s key type\n", +- key_type_dns_resolver.name); +- + /* create an override credential set with a special thread keyring in + * which DNS requests are cached + * +@@ -300,8 +297,6 @@ static void __exit exit_dns_resolver(void) + key_revoke(dns_resolver_cache->thread_keyring); + unregister_key_type(&key_type_dns_resolver); + put_cred(dns_resolver_cache); +- printk(KERN_NOTICE "Unregistered %s key type\n", +- key_type_dns_resolver.name); + } + + module_init(init_dns_resolver) +diff --git a/security/keys/key.c b/security/keys/key.c +index 4414abd..a8086a1 100644 +--- a/security/keys/key.c ++++ b/security/keys/key.c +@@ -957,6 +957,8 @@ int register_key_type(struct key_type *ktype) + + /* store the type */ + list_add(&ktype->link, &key_types_list); ++ ++ pr_notice("Key type %s registered\n", ktype->name); + ret = 0; + + out: +@@ -979,6 +981,7 @@ void unregister_key_type(struct key_type *ktype) + list_del_init(&ktype->link); + downgrade_write(&key_types_sem); + key_gc_keytype(ktype); ++ pr_notice("Key type %s unregistered\n", ktype->name); + up_read(&key_types_sem); + } + EXPORT_SYMBOL(unregister_key_type); +-- +1.7.9.1 + + +From bc9e72fd7ba0f06b89c2887a2e2eefef0441d92d Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:08 +0000 +Subject: KEYS: Reorganise keys Makefile + +Reorganise the keys directory Makefile to put all the core bits together and +the type-specific bits after. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/Makefile | 12 +++++++++--- + 1 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/security/keys/Makefile b/security/keys/Makefile +index a56f1ff..504aaa0 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -2,6 +2,9 @@ + # Makefile for key management + # + ++# ++# Core ++# + obj-y := \ + gc.o \ + key.o \ +@@ -12,9 +15,12 @@ obj-y := \ + request_key.o \ + request_key_auth.o \ + user_defined.o +- +-obj-$(CONFIG_TRUSTED_KEYS) += trusted.o +-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ + obj-$(CONFIG_KEYS_COMPAT) += compat.o + obj-$(CONFIG_PROC_FS) += proc.o + obj-$(CONFIG_SYSCTL) += sysctl.o ++ ++# ++# Key types ++# ++obj-$(CONFIG_TRUSTED_KEYS) += trusted.o ++obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ +-- +1.7.9.1 + + +From b78b34f3950b08d1def84449e10e4560d7cee280 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:08 +0000 +Subject: KEYS: Create a key type that can be used for general cryptographic + operations + +Create a key type that can be used for general cryptographic operations, such +as encryption, decryption, signature generation and signature verification. + +The key type is "crypto" and can provide access to a variety of cryptographic +algorithms. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + Documentation/security/keys-crypto.txt | 181 +++++++++++++++++++++++++ + include/keys/crypto-subtype.h | 56 ++++++++ + include/keys/crypto-type.h | 25 ++++ + security/keys/Kconfig | 8 + + security/keys/Makefile | 3 + + security/keys/crypto_keys.h | 28 ++++ + security/keys/crypto_type.c | 228 ++++++++++++++++++++++++++++++++ + 7 files changed, 529 insertions(+), 0 deletions(-) + create mode 100644 Documentation/security/keys-crypto.txt + create mode 100644 include/keys/crypto-subtype.h + create mode 100644 include/keys/crypto-type.h + create mode 100644 security/keys/crypto_keys.h + create mode 100644 security/keys/crypto_type.c + +diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt +new file mode 100644 +index 0000000..97dee80 +--- /dev/null ++++ b/Documentation/security/keys-crypto.txt +@@ -0,0 +1,181 @@ ++ ====================== ++ CRYPTOGRAPHIC KEY TYPE ++ ====================== ++ ++Contents: ++ ++ - Overview. ++ - Key identification. ++ - Accessing crypto keys. ++ - Implementing crypto parsers. ++ - Implementing crypto subtypes. ++ ++ ++======== ++OVERVIEW ++======== ++ ++The "crypto" key type is designed to be a container for cryptographic keys, ++without imposing any particular restrictions on the form of the cryptography or ++the key. ++ ++The crypto key is given a subtype that defines what sort of data is associated ++with the key and provides operations to describe and destroy it. However, no ++requirement is made that the key data actually be loaded into the key. ++ ++The crypto key also has a number of data parsers registered with it. The data ++parsers are responsible for extracing information the blobs of data passed to ++the instantiator function. The first data parser that recognises the blob gets ++to set the subtype of the key and define the operations that can be done on ++that key. ++ ++Completely in-kernel key retention and operation subtypes and parsers can be ++defined, but it would also be possible to provide access to cryptographic ++hardware (such as a TPM) that might be used to both retain the relevant key and ++perform operations using that key. In such a case, the crypto key would then ++merely be an interface to the TPM driver. ++ ++ ++================== ++KEY IDENTIFICATION ++================== ++ ++Because the identity of a key is not necessarily known and may not be easily ++calculated when a crypto key is allocated, it may not be a simple matter to set ++a key description to something that's useful for determining whether this is ++the key you're looking for. Furthermore, it may be necessary to perform a ++partial match upon the key identity. ++ ++To help with this, when a key is loaded, the parser calculates the key ++fingerprint and stores a copy in the key structure. ++ ++The crypto key type's key matching function then performs more checks than just ++the straightforward comparison of the description with the criterion string: ++ ++ (1) If the criterion string is of the form "id:<hexdigits>" then the match ++ function will examine a key's fingerprint to see if the hex digits given ++ after the "id:" match the tail. For instance: ++ ++ keyctl search @s crypto id:5acc2142 ++ ++ will match a key with fingerprint: ++ ++ 1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142 ++ ++ (2) If the criterion string is of the form "<subtype>:<hexdigits>" then the ++ match will match the ID as in (1), but with the added restriction that ++ only keys of the specified subtype (e.g. dsa or rsa) will be matched. For ++ instance: ++ ++ keyctl search @s crypto dsa:5acc2142 ++ ++Looking in /proc/keys, the last 8 hex digits of the key fingerprint are ++displayed, along with the subtype: ++ ++ 1a39e171 I----- 1 perm 3f010000 0 0 crypto modsign.0: DSA 5acc2142 [] ++ ++ ++===================== ++ACCESSING CRYPTO KEYS ++===================== ++ ++To access crypto keys from within the kernel, the following inclusion is ++required: ++ ++ #include <keys/crypto-type.h> ++ ++This gives access to the key type: ++ ++ struct key_type key_type_crypto; ++ ++ ++=========================== ++IMPLEMENTING CRYPTO PARSERS ++=========================== ++ ++The crypto key type keeps a list of registered data parsers. An example of ++such a parser is one that parses OpenPGP packet formatted data [RFC 4880]. ++ ++During key instantiation each parser in the list is tried until one doesn't ++return -EBADMSG. ++ ++The parser definition structure looks like the following: ++ ++ struct crypto_key_parser { ++ struct module *owner; ++ const char *name; ++ ++ int (*instantiate)(struct key *key, ++ const void *data, size_t datalen); ++ }; ++ ++The owner and name fields should be set to the owning module and the name of ++the parser. ++ ++There are a number of operations defined by the parser. They are all optional, ++but it is expected that at least one will be defined. ++ ++ (1) instantiate(). ++ ++ The arguments are the same as for the instantiate function in the key ++ type. 'key' is the crypto key being instantiated; data and datalen are ++ the instantiation data, presumably containing cryptographic key data, and ++ the length of that data. ++ ++ If the data format is not recognised, -EBADMSG should be returned. If it ++ is recognised, but the key cannot for some reason be set up, some other ++ negative error code should be returned. ++ ++ If the key can be successfully set up, then key->payload should be set to ++ point to the retained data, key->type_data.p[0] should be set to point to ++ the subtype chosen and key->type_data.p[1] should be set to point to a ++ copy of the key's identity string and 0 should be returned. ++ ++ The key's identity string may be partially matched upon. For a public-key ++ algorithm such as RSA and DSA this will likely be a printable hex version ++ of the key's fingerprint. ++ ++Functions are provided to register and unregister parsers: ++ ++ int register_crypto_key_parser(struct crypto_key_parser *parser); ++ void unregister_crypto_key_parser(struct crypto_key_parser *subtype); ++ ++Parsers may not have the same name. The names are only used for displaying in ++debugging messages. ++ ++ ++============================ ++IMPLEMENTING CRYPTO SUBTYPES ++============================ ++ ++The parser selects the appropriate subtype directly and sets it on the key; the ++crypto key then retains a reference on the subtype module (which means the ++parser can be removed thereafter). ++ ++The subtype definition structure looks like the following: ++ ++ struct crypto_key_subtype { ++ struct module *owner; ++ const char *name; ++ ++ void (*describe)(const struct key *key, struct seq_file *m); ++ void (*destroy)(void *payload); ++ }; ++ ++The owner and name fields should be set to the owning module and the name of ++the subtype. ++ ++There are a number of operations defined by the subtype: ++ ++ (1) describe(). ++ ++ Mandatory. This allows the subtype to display something in /proc/keys ++ against the key. For instance the name of the public key algorithm type ++ could be displayed. The key type will display the tail of the key ++ identity string after this. ++ ++ (2) destroy(). ++ ++ Mandatory. This should free the memory associated with the key. The ++ crypto key will look after freeing the fingerprint and releasing the ++ reference on the subtype module. +diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h +new file mode 100644 +index 0000000..fa87555 +--- /dev/null ++++ b/include/keys/crypto-subtype.h +@@ -0,0 +1,56 @@ ++/* Cryptographic key subtype ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#ifndef _KEYS_CRYPTO_SUBTYPE_H ++#define _KEYS_CRYPTO_SUBTYPE_H ++ ++#include <linux/seq_file.h> ++#include <keys/crypto-type.h> ++ ++extern struct key_type key_type_crypto; ++ ++/* ++ * Keys of this type declare a subtype that indicates the handlers and ++ * capabilities. ++ */ ++struct crypto_key_subtype { ++ struct module *owner; ++ const char *name; ++ unsigned short name_len; /* length of name */ ++ ++ void (*describe)(const struct key *key, struct seq_file *m); ++ ++ void (*destroy)(void *payload); ++}; ++ ++/* ++ * Data parser. Called during instantiation and signature verification ++ * initiation. ++ */ ++struct crypto_key_parser { ++ struct list_head link; ++ struct module *owner; ++ const char *name; ++ ++ /* Attempt to instantiate a key from the data blob passed to add_key() ++ * or keyctl_instantiate(). ++ * ++ * Return EBADMSG if not recognised. ++ */ ++ int (*instantiate)(struct key *key, const void *data, size_t datalen); ++}; ++ ++extern int register_crypto_key_parser(struct crypto_key_parser *); ++extern void unregister_crypto_key_parser(struct crypto_key_parser *); ++ ++#endif /* _KEYS_CRYPTO_SUBTYPE_H */ +diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h +new file mode 100644 +index 0000000..47c00c7 +--- /dev/null ++++ b/include/keys/crypto-type.h +@@ -0,0 +1,25 @@ ++/* Cryptographic key type interface ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#ifndef _KEYS_CRYPTO_TYPE_H ++#define _KEYS_CRYPTO_TYPE_H ++ ++#include <linux/key-type.h> ++ ++extern struct key_type key_type_crypto; ++ ++/* ++ * The payload is at the discretion of the subtype. ++ */ ++ ++#endif /* _KEYS_CRYPTO_TYPE_H */ +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index a90d6d3..290c9d3 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -69,3 +69,11 @@ config KEYS_DEBUG_PROC_KEYS + the resulting table. + + If you are unsure as to whether this is required, answer N. ++ ++config CRYPTO_KEY_TYPE ++ tristate "Cryptographic key type" ++ depends on KEYS ++ help ++ This option provides support for a type of key that holds the keys ++ required for cryptographic operations such as encryption, decryption, ++ signature generation and signature verification. +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 504aaa0..67fceaa 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -24,3 +24,6 @@ obj-$(CONFIG_SYSCTL) += sysctl.o + # + obj-$(CONFIG_TRUSTED_KEYS) += trusted.o + obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ ++obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o ++ ++crypto_keys-y := crypto_type.o +diff --git a/security/keys/crypto_keys.h b/security/keys/crypto_keys.h +new file mode 100644 +index 0000000..a339ce0 +--- /dev/null ++++ b/security/keys/crypto_keys.h +@@ -0,0 +1,28 @@ ++/* Internal crypto type stuff ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++static inline ++struct crypto_key_subtype *crypto_key_subtype(const struct key *key) ++{ ++ return key->type_data.p[0]; ++} ++ ++static inline char *crypto_key_id(const struct key *key) ++{ ++ return key->type_data.p[1]; ++} ++ ++ ++/* ++ * crypto_type.c ++ */ ++extern struct list_head crypto_key_parsers; ++extern struct rw_semaphore crypto_key_parsers_sem; +diff --git a/security/keys/crypto_type.c b/security/keys/crypto_type.c +new file mode 100644 +index 0000000..33d279b +--- /dev/null ++++ b/security/keys/crypto_type.c +@@ -0,0 +1,228 @@ ++/* Cryptographic key type ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++#include <keys/crypto-subtype.h> ++#include <linux/seq_file.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include "crypto_keys.h" ++ ++MODULE_LICENSE("GPL"); ++ ++LIST_HEAD(crypto_key_parsers); ++DECLARE_RWSEM(crypto_key_parsers_sem); ++ ++/* ++ * Match crypto_keys on (part of) their name ++ * We have some shorthand methods for matching keys. We allow: ++ * ++ * "<desc>" - request a key by description ++ * "id:<id>" - request a key matching the ID ++ * "<subtype>:<id>" - request a key of a subtype ++ */ ++static int crypto_key_match(const struct key *key, const void *description) ++{ ++ const struct crypto_key_subtype *subtype = crypto_key_subtype(key); ++ const char *spec = description; ++ const char *id, *kid; ++ ptrdiff_t speclen; ++ size_t idlen, kidlen; ++ ++ if (!subtype || !spec || !*spec) ++ return 0; ++ ++ /* See if the full key description matches as is */ ++ if (key->description && strcmp(key->description, description) == 0) ++ return 1; ++ ++ /* All tests from here on break the criterion description into a ++ * specifier, a colon and then an identifier. ++ */ ++ id = strchr(spec, ':'); ++ if (!id) ++ return 0; ++ ++ speclen = id - spec; ++ id++; ++ ++ /* Anything after here requires a partial match on the ID string */ ++ kid = crypto_key_id(key); ++ if (!kid) ++ return 0; ++ ++ idlen = strlen(id); ++ kidlen = strlen(kid); ++ if (idlen > kidlen) ++ return 0; ++ ++ kid += kidlen - idlen; ++ if (strcasecmp(id, kid) != 0) ++ return 0; ++ ++ if (speclen == 2 && ++ memcmp(spec, "id", 2) == 0) ++ return 1; ++ ++ if (speclen == subtype->name_len && ++ memcmp(spec, subtype->name, speclen) == 0) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * Describe the crypto key ++ */ ++static void crypto_key_describe(const struct key *key, struct seq_file *m) ++{ ++ const struct crypto_key_subtype *subtype = crypto_key_subtype(key); ++ const char *kid = crypto_key_id(key); ++ size_t n; ++ ++ seq_puts(m, key->description); ++ ++ if (subtype) { ++ seq_puts(m, ": "); ++ subtype->describe(key, m); ++ ++ if (kid) { ++ seq_putc(m, ' '); ++ n = strlen(kid); ++ if (n <= 8) ++ seq_puts(m, kid); ++ else ++ seq_puts(m, kid + n - 8); ++ } ++ ++ seq_puts(m, " ["); ++ /* put something here to indicate the key's capabilities */ ++ seq_putc(m, ']'); ++ } ++} ++ ++/* ++ * Instantiate a crypto_key defined key ++ */ ++static int crypto_key_instantiate(struct key *key, ++ const void *data, size_t datalen) ++{ ++ struct crypto_key_parser *parser; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (datalen == 0) ++ return -EINVAL; ++ ++ down_read(&crypto_key_parsers_sem); ++ ++ ret = -EBADMSG; ++ list_for_each_entry(parser, &crypto_key_parsers, link) { ++ pr_debug("Trying parser '%s'\n", parser->name); ++ ++ ret = parser->instantiate(key, data, datalen); ++ if (ret != -EBADMSG) { ++ pr_debug("Parser recognised the format (ret %d)\n", ++ ret); ++ break; ++ } ++ } ++ ++ up_read(&crypto_key_parsers_sem); ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; ++} ++ ++/* ++ * dispose of the data dangling from the corpse of a crypto key ++ */ ++static void crypto_key_destroy(struct key *key) ++{ ++ struct crypto_key_subtype *subtype = crypto_key_subtype(key); ++ if (subtype) { ++ subtype->destroy(key->payload.data); ++ module_put(subtype->owner); ++ key->type_data.p[0] = NULL; ++ } ++ kfree(key->type_data.p[1]); ++ key->type_data.p[1] = NULL; ++} ++ ++struct key_type key_type_crypto = { ++ .name = "crypto", ++ .instantiate = crypto_key_instantiate, ++ .match = crypto_key_match, ++ .destroy = crypto_key_destroy, ++ .describe = crypto_key_describe, ++}; ++EXPORT_SYMBOL_GPL(key_type_crypto); ++ ++/** ++ * register_crypto_key_parser - Register a crypto key blob parser ++ * @parser: The parser to register ++ */ ++int register_crypto_key_parser(struct crypto_key_parser *parser) ++{ ++ struct crypto_key_parser *cursor; ++ int ret; ++ ++ down_write(&crypto_key_parsers_sem); ++ ++ list_for_each_entry(cursor, &crypto_key_parsers, link) { ++ if (strcmp(cursor->name, parser->name) == 0) { ++ pr_err("Crypto key parser '%s' already registered\n", ++ parser->name); ++ ret = -EEXIST; ++ goto out; ++ } ++ } ++ ++ list_add_tail(&parser->link, &crypto_key_parsers); ++ ++ pr_notice("Crypto key parser '%s' registered\n", parser->name); ++ ret = 0; ++ ++out: ++ up_write(&crypto_key_parsers_sem); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(register_crypto_key_parser); ++ ++/** ++ * unregister_crypto_key_parser - Unregister a crypto key blob parser ++ * @parser: The parser to unregister ++ */ ++void unregister_crypto_key_parser(struct crypto_key_parser *parser) ++{ ++ down_write(&crypto_key_parsers_sem); ++ list_del(&parser->link); ++ up_write(&crypto_key_parsers_sem); ++ ++ pr_notice("Crypto key parser '%s' unregistered\n", parser->name); ++} ++EXPORT_SYMBOL_GPL(unregister_crypto_key_parser); ++ ++/* ++ * Module stuff ++ */ ++static int __init crypto_key_init(void) ++{ ++ return register_key_type(&key_type_crypto); ++} ++ ++static void __exit crypto_key_cleanup(void) ++{ ++ unregister_key_type(&key_type_crypto); ++} ++ ++module_init(crypto_key_init); ++module_exit(crypto_key_cleanup); +-- +1.7.9.1 + + +From 9d66ee5300d0d1391367dd002eba6663aaf33760 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:09 +0000 +Subject: KEYS: Add signature verification facility + +Add a facility whereby a key subtype may be asked to verify a signature against +the data it is purported to have signed. + +This adds four routines: + + (1) struct crypto_key_verify_context * + verify_sig_begin(struct key *keyring, const void *sig, size_t siglen); + + This sets up a verification context for the given signature using + information in that signature to select a key from the specified keyring + and to request a hash algorithm from the crypto layer. + + (2) int verify_sig_add_data(struct crypto_key_verify_context *ctx, + const void *data, size_t datalen); + + Incrementally supply data to be signed. May be called multiple times. + + (3) int verify_sig_end(struct crypto_key_verify_context *ctx, + const void *sig, size_t siglen); + + Complete the verification process and return the result. -EKEYREJECTED + will indicate that the verification failed and 0 will indicate success. + Other errors are also possible. + + (4) void verify_sig_cancel(struct crypto_key_verify_context *ctx); + + Cancel the verification process. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + Documentation/security/keys-crypto.txt | 101 +++++++++++++++++++++++++++++ + include/keys/crypto-subtype.h | 21 ++++++ + include/keys/crypto-type.h | 9 +++ + security/keys/Makefile | 2 +- + security/keys/crypto_verify.c | 111 ++++++++++++++++++++++++++++++++ + 5 files changed, 243 insertions(+), 1 deletions(-) + create mode 100644 security/keys/crypto_verify.c + +diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt +index 97dee80..a964717 100644 +--- a/Documentation/security/keys-crypto.txt ++++ b/Documentation/security/keys-crypto.txt +@@ -7,6 +7,7 @@ Contents: + - Overview. + - Key identification. + - Accessing crypto keys. ++ - Signature verification. + - Implementing crypto parsers. + - Implementing crypto subtypes. + +@@ -89,6 +90,65 @@ This gives access to the key type: + struct key_type key_type_crypto; + + ++SIGNATURE VERIFICATION ++---------------------- ++ ++The four operations that can perform cryptographic signature verification, ++using one of a set of keys to provide the public key: ++ ++ (1) Begin verification procedure. ++ ++ struct crypto_key_verify_context * ++ verify_sig_begin(struct key *keyring, const void *sig, size_t siglen); ++ ++ This function sets up a verification context from the information in the ++ signature and looks for a suitable key in the keyring. The signature blob ++ must be presented again at the end of the procedure. The keys will be ++ checked against parameters in the signature, and if the matching one is ++ not found then -ENOKEY will be returned. ++ ++ The hashing algorithm, if such a thing applies, will be determined from ++ information in the signature and the appropriate crypto module will be ++ used. -ENOPKG will be returned if the hash algorithm is unavailable. ++ ++ The return value is an opaque pointer to be passed to the other functions, ++ or a negative error code. ++ ++ (2) Indicate data to be verified. ++ ++ int verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++ ++ This function is used to shovel data to the verification procedure so that ++ it can load it into the hash, pass it to hardware or whatever is ++ appropriate for the algorithm being employed. ++ ++ The data is not canonicalised for the document type specified in the ++ signature. The caller must do that. ++ ++ It will return 0 if successful and a negative error code if not. ++ ++ (3) Complete the verification process. ++ ++ int verify_sig_end(struct crypto_key_verify_context *ctx, ++ const void *sig, size_t siglen); ++ ++ This function performs the actual signature verification step and cleans ++ up the resources allocated at the beginning. The signature must be ++ presented again as some of the data therein may need to be added to the ++ internal hash. ++ ++ It will return -EKEYREJECTED if the signature didn't match, 0 if ++ successful and may return other errors as appropriate. ++ ++ (4) Cancel the verification process. ++ ++ void verify_sig_cancel(struct crypto_key_verify_context *ctx); ++ ++ This function cleans up the resources allocated at the beginning. This is ++ not necessary if verify_sig_end() was called. ++ ++ + =========================== + IMPLEMENTING CRYPTO PARSERS + =========================== +@@ -96,6 +156,7 @@ IMPLEMENTING CRYPTO PARSERS + The crypto key type keeps a list of registered data parsers. An example of + such a parser is one that parses OpenPGP packet formatted data [RFC 4880]. + ++ + During key instantiation each parser in the list is tried until one doesn't + return -EBADMSG. + +@@ -107,6 +168,8 @@ The parser definition structure looks like the following: + + int (*instantiate)(struct key *key, + const void *data, size_t datalen); ++ struct crypto_key_verify_context *(*verify_sig_begin)( ++ struct key *keyring, const u8 *sig, size_t siglen); + }; + + The owner and name fields should be set to the owning module and the name of +@@ -135,6 +198,44 @@ but it is expected that at least one will be defined. + algorithm such as RSA and DSA this will likely be a printable hex version + of the key's fingerprint. + ++ (2) verify_sig_begin(). ++ ++ This is similar in concept to the instantiate() function, except that it ++ is given a signature blob to parse rather than a key data blob. ++ ++ If the data format is not recognised, -EBADMSG should be returned. If it ++ is recognised, but the signature verification process cannot for some ++ reason be set up, some other negative error code should be returned. ++ -ENOKEY should be used to indicate that no matching key is available and ++ -ENOPKG should be returned if the hash algorithm or the verification ++ algorithm are unavailable. ++ ++ If successful, the parser should allocate a verification context and embed ++ the following struct in it: ++ ++ struct crypto_key_verify_context { ++ struct key *key; ++ int (*add_data)(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++ int (*end)(struct crypto_key_verify_context *ctx, ++ const u8 *sig, size_t siglen); ++ void (*cancel)(struct crypto_key_verify_context *ctx); ++ }; ++ ++ and return a pointer to this to the caller, who will then pass it to the ++ verification operation wrappers described in the "Signature Verification" ++ section. The three operation pointers here correspond exactly to those ++ wrappers and are all mandatory. container_of() should be used to retrieve ++ the actual context. ++ ++ Note that the crypto key type retains a reference on the parser module for ++ the lifetime of this context, though the operation pointers need not point ++ into this module. ++ ++ The parser should also record a pointer to the key selected and take a ++ reference on that key with key_get(). ++ ++ + Functions are provided to register and unregister parsers: + + int register_crypto_key_parser(struct crypto_key_parser *parser); +diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h +index fa87555..f2b927a 100644 +--- a/include/keys/crypto-subtype.h ++++ b/include/keys/crypto-subtype.h +@@ -20,6 +20,20 @@ + extern struct key_type key_type_crypto; + + /* ++ * Context base for signature verification methods. Allocated by the subtype ++ * and presumably embedded in something appropriate. ++ */ ++struct crypto_key_verify_context { ++ struct key *key; ++ struct crypto_key_parser *parser; ++ int (*add_data)(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++ int (*end)(struct crypto_key_verify_context *ctx, ++ const u8 *sig, size_t siglen); ++ void (*cancel)(struct crypto_key_verify_context *ctx); ++}; ++ ++/* + * Keys of this type declare a subtype that indicates the handlers and + * capabilities. + */ +@@ -48,6 +62,13 @@ struct crypto_key_parser { + * Return EBADMSG if not recognised. + */ + int (*instantiate)(struct key *key, const void *data, size_t datalen); ++ ++ /* Attempt to recognise a signature blob and find a matching key. ++ * ++ * Return EBADMSG if not recognised. ++ */ ++ struct crypto_key_verify_context *(*verify_sig_begin)( ++ struct key *keyring, const u8 *sig, size_t siglen); + }; + + extern int register_crypto_key_parser(struct crypto_key_parser *); +diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h +index 47c00c7..6b93366 100644 +--- a/include/keys/crypto-type.h ++++ b/include/keys/crypto-type.h +@@ -18,6 +18,15 @@ + + extern struct key_type key_type_crypto; + ++struct crypto_key_verify_context; ++extern struct crypto_key_verify_context *verify_sig_begin( ++ struct key *key, const void *sig, size_t siglen); ++extern int verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++extern int verify_sig_end(struct crypto_key_verify_context *ctx, ++ const void *sig, size_t siglen); ++extern void verify_sig_cancel(struct crypto_key_verify_context *ctx); ++ + /* + * The payload is at the discretion of the subtype. + */ +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 67fceaa..8462904 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -26,4 +26,4 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o + obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ + obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + +-crypto_keys-y := crypto_type.o ++crypto_keys-y := crypto_type.o crypto_verify.o +diff --git a/security/keys/crypto_verify.c b/security/keys/crypto_verify.c +new file mode 100644 +index 0000000..65f734c +--- /dev/null ++++ b/security/keys/crypto_verify.c +@@ -0,0 +1,111 @@ ++/* Signature verification with a crypto key ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#include <keys/crypto-subtype.h> ++#include <linux/module.h> ++#include "crypto_keys.h" ++ ++/** ++ * verify_sig_begin - Initiate the use of a crypto key to verify a signature ++ * @keyring: The public keys to verify against ++ * @sig: The signature data ++ * @siglen: The signature length ++ * ++ * Returns a context or an error. ++ */ ++struct crypto_key_verify_context *verify_sig_begin( ++ struct key *keyring, const void *sig, size_t siglen) ++{ ++ struct crypto_key_verify_context *ret; ++ struct crypto_key_parser *parser; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (siglen == 0 || !sig) ++ return ERR_PTR(-EINVAL); ++ ++ down_read(&crypto_key_parsers_sem); ++ ++ ret = ERR_PTR(-EBADMSG); ++ list_for_each_entry(parser, &crypto_key_parsers, link) { ++ if (parser->verify_sig_begin) { ++ if (!try_module_get(parser->owner)) ++ continue; ++ ++ pr_debug("Trying parser '%s'\n", parser->name); ++ ++ ret = parser->verify_sig_begin(keyring, sig, siglen); ++ if (IS_ERR(ret)) ++ module_put(parser->owner); ++ else ++ ret->parser = parser; ++ if (ret != ERR_PTR(-EBADMSG)) { ++ pr_debug("Parser recognised the format" ++ " (ret %ld)\n", ++ PTR_ERR(ret)); ++ break; ++ } ++ } ++ } ++ ++ up_read(&crypto_key_parsers_sem); ++ pr_devel("<==%s() = %p\n", __func__, ret); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(verify_sig_begin); ++ ++/** ++ * verify_sig_add_data - Incrementally provide data to be verified ++ * @ctx: The context from verify_sig_begin() ++ * @data: Data ++ * @datalen: The amount of @data ++ * ++ * This may be called multiple times. ++ */ ++int verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen) ++{ ++ return ctx->add_data(ctx, data, datalen); ++} ++EXPORT_SYMBOL_GPL(verify_sig_add_data); ++ ++/** ++ * verify_sig_end - Finalise signature verification and return result ++ * @ctx: The context from verify_sig_begin() ++ * @sig: The signature data ++ * @siglen: The signature length ++ */ ++int verify_sig_end(struct crypto_key_verify_context *ctx, ++ const void *sig, size_t siglen) ++{ ++ struct crypto_key_parser *parser = ctx->parser; ++ int ret; ++ ++ ret = ctx->end(ctx, sig, siglen); ++ module_put(parser->owner); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(verify_sig_end); ++ ++/** ++ * verify_sig_end - Cancel signature verification ++ * @ctx: The context from verify_sig_begin() ++ */ ++void verify_sig_cancel(struct crypto_key_verify_context *ctx) ++{ ++ struct crypto_key_parser *parser = ctx->parser; ++ ++ ctx->cancel(ctx); ++ module_put(parser->owner); ++} ++EXPORT_SYMBOL_GPL(verify_sig_cancel); +-- +1.7.9.1 + + +From 8842a89fac8ac5a9691fb8ff381cdf98e23e8029 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:10 +0000 +Subject: KEYS: Asymmetric public-key algorithm crypto key subtype + +Add a subtype for supporting asymmetric public-key encryption algorithms such +as DSA (FIPS-186) and RSA (PKCS#1 / RFC1337). + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/Kconfig | 9 ++++ + security/keys/Makefile | 1 + + security/keys/public_key.c | 55 +++++++++++++++++++++++ + security/keys/public_key.h | 106 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 171 insertions(+), 0 deletions(-) + create mode 100644 security/keys/public_key.c + create mode 100644 security/keys/public_key.h + +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index 290c9d3..07c7f3b 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -77,3 +77,12 @@ config CRYPTO_KEY_TYPE + This option provides support for a type of key that holds the keys + required for cryptographic operations such as encryption, decryption, + signature generation and signature verification. ++ ++config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE ++ tristate "Asymmetric public-key crypto algorithm subtype" ++ depends on CRYPTO_KEY_TYPE ++ help ++ This option provides support for asymmetric public key type handling. ++ If signature generation and/or verification are to be used, ++ appropriate hash algorithms (such as SHA-1) must be available. ++ ENOPKG will be reported if the requisite algorithm is unavailable. +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 8462904..dc3281f 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -25,5 +25,6 @@ obj-$(CONFIG_SYSCTL) += sysctl.o + obj-$(CONFIG_TRUSTED_KEYS) += trusted.o + obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ + obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o ++obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o + + crypto_keys-y := crypto_type.o crypto_verify.o +diff --git a/security/keys/public_key.c b/security/keys/public_key.c +new file mode 100644 +index 0000000..c00ddac +--- /dev/null ++++ b/security/keys/public_key.c +@@ -0,0 +1,55 @@ ++/* Asymmetric public key crypto subtype ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "PKEY: "fmt ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include "public_key.h" ++ ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Provide a part of a description of the key for /proc/keys. ++ */ ++static void public_key_describe(const struct key *crypto_key, ++ struct seq_file *m) ++{ ++ struct public_key *key = crypto_key->payload.data; ++ ++ if (key) ++ seq_puts(m, key->algo->name); ++} ++ ++/* ++ * Destroy a public key algorithm key ++ */ ++static void public_key_destroy(void *payload) ++{ ++ struct public_key *key = payload; ++ int i; ++ ++ if (key) { ++ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) ++ mpi_free(key->mpi[i]); ++ kfree(key); ++ } ++} ++ ++/* ++ * Public key algorithm crypto key subtype ++ */ ++struct crypto_key_subtype public_key_crypto_key_subtype = { ++ .owner = THIS_MODULE, ++ .name = "public_key", ++ .describe = public_key_describe, ++ .destroy = public_key_destroy, ++}; ++EXPORT_SYMBOL_GPL(public_key_crypto_key_subtype); +diff --git a/security/keys/public_key.h b/security/keys/public_key.h +new file mode 100644 +index 0000000..81ed603 +--- /dev/null ++++ b/security/keys/public_key.h +@@ -0,0 +1,106 @@ ++/* Asymmetric public-key algorithm definitions ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_PUBLIC_KEY_H ++#define _LINUX_PUBLIC_KEY_H ++ ++#include <linux/mpi.h> ++#include <crypto/hash.h> ++#include <keys/crypto-subtype.h> ++ ++struct public_key; ++struct public_key_signature; ++ ++enum pkey_hash_algo { ++ PKEY_HASH_MD5, ++ PKEY_HASH_SHA1, ++ PKEY_HASH_RIPE_MD_160, ++ PKEY_HASH_SHA256, ++ PKEY_HASH_SHA384, ++ PKEY_HASH_SHA512, ++ PKEY_HASH_SHA224, ++ PKEY_HASH__LAST ++}; ++ ++/* ++ * Public key type definition ++ */ ++struct public_key_algorithm { ++ const char *name; ++ u8 n_pub_mpi; /* Number of MPIs in public key */ ++ u8 n_sec_mpi; /* Number of MPIs in secret key */ ++ u8 n_sig_mpi; /* Number of MPIs in a signature */ ++ int (*verify)(const struct public_key *key, ++ const struct public_key_signature *sig); ++}; ++ ++/* ++ * Asymmetric public key data ++ */ ++struct public_key { ++ const struct public_key_algorithm *algo; ++ u8 capabilities; ++#define PKEY_CAN_ENCRYPT 0x01 ++#define PKEY_CAN_DECRYPT 0x02 ++#define PKEY_CAN_ENCDEC (PKEY_CAN_ENCRYPT | PKEY_CAN_DECRYPT) ++#define PKEY_CAN_SIGN 0x04 ++#define PKEY_CAN_VERIFY 0x08 ++#define PKEY_CAN_SIGVER (PKEY_CAN_SIGN | PKEY_CAN_VERIFY) ++ union { ++ MPI mpi[5]; ++ struct { ++ MPI p; /* DSA prime */ ++ MPI q; /* DSA group order */ ++ MPI g; /* DSA group generator */ ++ MPI y; /* DSA public-key value = g^x mod p */ ++ MPI x; /* DSA secret exponent (if present) */ ++ } dsa; ++ struct { ++ MPI n; /* RSA public modulus */ ++ MPI e; /* RSA public encryption exponent */ ++ MPI d; /* RSA secret encryption exponent (if present) */ ++ MPI p; /* RSA secret prime (if present) */ ++ MPI q; /* RSA secret prime (if present) */ ++ } rsa; ++ }; ++ ++ u8 key_id[8]; /* ID of this key pair */ ++ u8 key_id_size; /* Number of bytes in key_id */ ++}; ++ ++/* ++ * Asymmetric public key algorithm signature data ++ */ ++struct public_key_signature { ++ struct crypto_key_verify_context base; ++ u8 *digest; ++ enum pkey_hash_algo pkey_hash_algo : 8; ++ u8 signed_hash_msw[2]; ++ u8 digest_size; /* Number of bytes in digest */ ++ union { ++ MPI mpi[2]; ++ struct { ++ MPI s; /* m^d mod n */ ++ } rsa; ++ struct { ++ MPI r; ++ MPI s; ++ } dsa; ++ }; ++ struct shash_desc hash; /* This must go last! */ ++}; ++ ++extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( ++ struct key *crypto_key, const u8 *sigdata, size_t siglen); ++ ++extern struct crypto_key_subtype public_key_crypto_key_subtype; ++ ++#endif /* _LINUX_PUBLIC_KEY_H */ +-- +1.7.9.1 + + +From 6fc88dcf4610907920e8ec8fc9d11610a23b12ae Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:11 +0000 +Subject: KEYS: RSA signature verification algorithm + +Implement the RSA algorithm (PKCS#1 / RFC3447). At this time, only signature +verification is supported. This uses the asymmetric public key subtype to hold +its key data. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/Kconfig | 6 + + security/keys/Makefile | 1 + + security/keys/crypto_rsa.c | 282 ++++++++++++++++++++++++++++++++++++++++++++ + security/keys/public_key.h | 2 + + 4 files changed, 291 insertions(+), 0 deletions(-) + create mode 100644 security/keys/crypto_rsa.c + +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index 07c7f3b..65d640b 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -86,3 +86,9 @@ config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE + If signature generation and/or verification are to be used, + appropriate hash algorithms (such as SHA-1) must be available. + ENOPKG will be reported if the requisite algorithm is unavailable. ++ ++config CRYPTO_KEY_PKEY_ALGO_RSA ++ tristate "RSA public-key algorithm" ++ depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE ++ help ++ This option enables support for the RSA algorithm (PKCS#1, RFC3447). +diff --git a/security/keys/Makefile b/security/keys/Makefile +index dc3281f..59e7180 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -26,5 +26,6 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o + obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ + obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o ++obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o + + crypto_keys-y := crypto_type.o crypto_verify.o +diff --git a/security/keys/crypto_rsa.c b/security/keys/crypto_rsa.c +new file mode 100644 +index 0000000..beb5181 +--- /dev/null ++++ b/security/keys/crypto_rsa.c +@@ -0,0 +1,282 @@ ++/* RSA asymmetric public-key algorithm [RFC3447] ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "RSA: "fmt ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include "public_key.h" ++ ++MODULE_LICENSE("GPL"); ++ ++#define kenter(FMT, ...) \ ++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) ++#define kleave(FMT, ...) \ ++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) ++ ++/* ++ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. ++ */ ++static const u8 RSA_digest_info_MD5[] = { ++ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, ++ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ ++ 0x05, 0x00, 0x04, 0x10 ++}; ++ ++static const u8 RSA_digest_info_SHA1[] = { ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x0E, 0x03, 0x02, 0x1A, ++ 0x05, 0x00, 0x04, 0x14 ++}; ++ ++static const u8 RSA_digest_info_RIPE_MD_160[] = { ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x24, 0x03, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x14 ++}; ++ ++static const u8 RSA_digest_info_SHA224[] = { ++ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, ++ 0x05, 0x00, 0x04, 0x1C ++}; ++ ++static const u8 RSA_digest_info_SHA256[] = { ++ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x20 ++}; ++ ++static const u8 RSA_digest_info_SHA384[] = { ++ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, ++ 0x05, 0x00, 0x04, 0x30 ++}; ++ ++static const u8 RSA_digest_info_SHA512[] = { ++ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x05, 0x00, 0x04, 0x40 ++}; ++ ++static const struct { ++ const u8 const *data; ++ size_t size; ++} RSA_ASN1_templates[PKEY_HASH__LAST] = { ++#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } ++ [PKEY_HASH_MD5] = _(MD5), ++ [PKEY_HASH_SHA1] = _(SHA1), ++ [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), ++ [PKEY_HASH_SHA256] = _(SHA256), ++ [PKEY_HASH_SHA384] = _(SHA384), ++ [PKEY_HASH_SHA512] = _(SHA512), ++ [PKEY_HASH_SHA224] = _(SHA224), ++#undef _ ++}; ++ ++/* ++ * RSAVP1() function [RFC3447 sec 5.2.2] ++ */ ++static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) ++{ ++ MPI m; ++ int ret; ++ ++ /* (1) Validate 0 <= s < n */ ++ if (mpi_cmp_ui(s, 0) < 0) { ++ kleave(" = -EBADMSG [s < 0]"); ++ return -EBADMSG; ++ } ++ if (mpi_cmp(s, key->rsa.n) >= 0) { ++ kleave(" = -EBADMSG [s >= n]"); ++ return -EBADMSG; ++ } ++ ++ m = mpi_alloc(0); ++ if (!m) ++ return -ENOMEM; ++ ++ /* (2) m = s^e mod n */ ++ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); ++ if (ret < 0) { ++ mpi_free(m); ++ return ret; ++ } ++ ++ *_m = m; ++ return 0; ++} ++ ++/* ++ * Integer to Octet String conversion [RFC3447 sec 4.1] ++ */ ++static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) ++{ ++ unsigned X_size, x_size; ++ int X_sign; ++ u8 *X; ++ ++ /* Make sure the string is the right length. The number should begin ++ * with { 0x00, 0x01, ... } so we have to account for 15 leading zero ++ * bits not being reported by MPI. ++ */ ++ x_size = mpi_get_nbits(x); ++ pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); ++ if (x_size != xLen * 8 - 15) ++ return -ERANGE; ++ ++ X = mpi_get_buffer(x, &X_size, &X_sign); ++ if (!X) ++ return -ENOMEM; ++ if (X_sign < 0) { ++ kfree(X); ++ return -EBADMSG; ++ } ++ if (X_size != xLen - 1) { ++ kfree(X); ++ return -EBADMSG; ++ } ++ ++ *_X = X; ++ return 0; ++} ++ ++/* ++ * Perform the RSA signature verification. ++ * @H: Value of hash of data and metadata ++ * @EM: The computed signature value ++ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) ++ * @hash_size: The size of H ++ * @asn1_template: The DigestInfo ASN.1 template ++ * @asn1_size: Size of asm1_template[] ++ */ ++static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, ++ const u8 *asn1_template, size_t asn1_size) ++{ ++ unsigned PS_end, T_offset, i; ++ ++ kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); ++ ++ if (k < 2 + 1 + asn1_size + hash_size) ++ return -EBADMSG; ++ ++ /* Decode the EMSA-PKCS1-v1_5 */ ++ if (EM[1] != 0x01) { ++ kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); ++ return -EBADMSG; ++ } ++ ++ T_offset = k - (asn1_size + hash_size); ++ PS_end = T_offset - 1; ++ if (EM[PS_end] != 0x00) { ++ kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); ++ return -EBADMSG; ++ } ++ ++ for (i = 2; i < PS_end; i++) { ++ if (EM[i] != 0xff) { ++ kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); ++ return -EBADMSG; ++ } ++ } ++ ++ if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { ++ kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); ++ return -EBADMSG; ++ } ++ ++ if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { ++ kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); ++ return -EKEYREJECTED; ++ } ++ ++ kleave(" = 0"); ++ return 0; ++} ++ ++/* ++ * Perform the verification step [RFC3447 sec 8.2.2]. ++ */ ++static int RSA_verify_signature(const struct public_key *key, ++ const struct public_key_signature *sig) ++{ ++ size_t tsize; ++ int ret; ++ ++ /* Variables as per RFC3447 sec 8.2.2 */ ++ const u8 *H = sig->digest; ++ u8 *EM = NULL; ++ MPI m = NULL; ++ size_t k; ++ ++ kenter(""); ++ ++ /* (1) Check the signature size against the public key modulus size */ ++ k = (mpi_get_nbits(key->rsa.n) + 7) / 8; ++ ++ tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; ++ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); ++ if (tsize != k) { ++ ret = -EBADMSG; ++ goto error; ++ } ++ ++ /* (2b) Apply the RSAVP1 verification primitive to the public key */ ++ ret = RSAVP1(key, sig->rsa.s, &m); ++ if (ret < 0) ++ goto error; ++ ++ /* (2c) Convert the message representative (m) to an encoded message ++ * (EM) of length k octets. ++ * ++ * NOTE! The leading zero byte is suppressed by MPI, so we pass a ++ * pointer to the _preceding_ byte to RSA_verify()! ++ */ ++ ret = RSA_I2OSP(m, k, &EM); ++ if (ret < 0) ++ goto error; ++ ++#if 0 ++ { ++ int i; ++ printk("H: "); ++ for (i = 0; i < sig->digest_size; i++) ++ printk("%02x", H[i]); ++ printk("\n"); ++ } ++ ++ { ++ int i; ++ printk("EM: 00"); ++ for (i = 0; i < k - 1; i++) ++ printk("%02x", EM[i]); ++ printk("\n"); ++ } ++#endif ++ ++ ret = RSA_verify(H, EM - 1, k, sig->digest_size, ++ RSA_ASN1_templates[sig->pkey_hash_algo].data, ++ RSA_ASN1_templates[sig->pkey_hash_algo].size); ++ ++error: ++ kfree(EM); ++ mpi_free(m); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++const struct public_key_algorithm RSA_public_key_algorithm = { ++ .name = "RSA", ++ .n_pub_mpi = 2, ++ .n_sec_mpi = 3, ++ .n_sig_mpi = 1, ++ .verify = RSA_verify_signature, ++}; ++EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); +diff --git a/security/keys/public_key.h b/security/keys/public_key.h +index 81ed603..7913615 100644 +--- a/security/keys/public_key.h ++++ b/security/keys/public_key.h +@@ -42,6 +42,8 @@ struct public_key_algorithm { + const struct public_key_signature *sig); + }; + ++extern const struct public_key_algorithm RSA_public_key_algorithm; ++ + /* + * Asymmetric public key data + */ +-- +1.7.9.1 + + +From 82b8d487e66a5218ca9f91ca406db97b2113da60 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:11 +0000 +Subject: PGPLIB: PGP definitions (RFC 4880) + +Provide some useful PGP definitions from RFC 4880. These describe details of +public key crypto as used by crypto keys for things like signature +verification. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + include/linux/pgp.h | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 206 insertions(+), 0 deletions(-) + create mode 100644 include/linux/pgp.h + +diff --git a/include/linux/pgp.h b/include/linux/pgp.h +new file mode 100644 +index 0000000..1359f64 +--- /dev/null ++++ b/include/linux/pgp.h +@@ -0,0 +1,206 @@ ++/* PGP definitions (RFC 4880) ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_PGP_H ++#define _LINUX_PGP_H ++ ++#include <linux/types.h> ++ ++struct pgp_key_ID { ++ u8 id[8]; ++}; ++ ++struct pgp_time { ++ u8 time[4]; ++}; ++ ++/* ++ * PGP public-key algorithm identifiers [RFC4880: 9.1] ++ */ ++enum pgp_pubkey_algo { ++ PGP_PUBKEY_RSA_ENC_OR_SIG = 1, ++ PGP_PUBKEY_RSA_ENC_ONLY = 2, ++ PGP_PUBKEY_RSA_SIG_ONLY = 3, ++ PGP_PUBKEY_ELGAMAL = 16, ++ PGP_PUBKEY_DSA = 17, ++ PGP_PUBKEY__LAST ++}; ++ ++/* ++ * PGP symmetric-key algorithm identifiers [RFC4880: 9.2] ++ */ ++enum pgp_symkey_algo { ++ PGP_SYMKEY_PLAINTEXT = 0, ++ PGP_SYMKEY_IDEA = 1, ++ PGP_SYMKEY_3DES = 2, ++ PGP_SYMKEY_CAST5 = 3, ++ PGP_SYMKEY_BLOWFISH = 4, ++ PGP_SYMKEY_AES_128KEY = 7, ++ PGP_SYMKEY_AES_192KEY = 8, ++ PGP_SYMKEY_AES_256KEY = 9, ++ PGP_SYMKEY_TWOFISH_256KEY = 10, ++}; ++ ++/* ++ * PGP compression algorithm identifiers [RFC4880: 9.3] ++ */ ++enum pgp_compr_algo { ++ PGP_COMPR_UNCOMPRESSED = 0, ++ PGP_COMPR_ZIP = 1, ++ PGP_COMPR_ZLIB = 2, ++ PGP_COMPR_BZIP2 = 3, ++}; ++ ++/* ++ * PGP hash algorithm identifiers [RFC4880: 9.4] ++ */ ++enum pgp_hash_algo { ++ PGP_HASH_MD5 = 1, ++ PGP_HASH_SHA1 = 2, ++ PGP_HASH_RIPE_MD_160 = 3, ++ PGP_HASH_SHA256 = 8, ++ PGP_HASH_SHA384 = 9, ++ PGP_HASH_SHA512 = 10, ++ PGP_HASH_SHA224 = 11, ++ PGP_HASH__LAST ++}; ++ ++extern const char *const pgp_hash_algorithms[PGP_HASH__LAST]; ++ ++/* ++ * PGP packet type tags [RFC4880: 4.3]. ++ */ ++enum pgp_packet_tag { ++ PGP_PKT_RESERVED = 0, ++ PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, ++ PGP_PKT_SIGNATURE = 2, ++ PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, ++ PGP_PKT_ONEPASS_SIGNATURE = 4, ++ PGP_PKT_SECRET_KEY = 5, ++ PGP_PKT_PUBLIC_KEY = 6, ++ PGP_PKT_SECRET_SUBKEY = 7, ++ PGP_PKT_COMPRESSED_DATA = 8, ++ PGP_PKT_SYM_ENC_DATA = 9, ++ PGP_PKT_MARKER = 10, ++ PGP_PKT_LITERAL_DATA = 11, ++ PGP_PKT_TRUST = 12, ++ PGP_PKT_USER_ID = 13, ++ PGP_PKT_PUBLIC_SUBKEY = 14, ++ PGP_PKT_USER_ATTRIBUTE = 17, ++ PGP_PKT_SYM_ENC_AND_INTEG_DATA = 18, ++ PGP_PKT_MODIFY_DETECT_CODE = 19, ++ PGP_PKT_PRIVATE_0 = 60, ++ PGP_PKT_PRIVATE_3 = 63, ++ PGP_PKT__HIGHEST = 63 ++}; ++ ++/* ++ * Signature (tag 2) packet [RFC4880: 5.2]. ++ */ ++enum pgp_signature_version { ++ PGP_SIG_VERSION_3 = 3, ++ PGP_SIG_VERSION_4 = 4, ++}; ++ ++enum pgp_signature_type { ++ PGP_SIG_BINARY_DOCUMENT_SIG = 0x00, ++ PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG = 0x01, ++ PGP_SIG_STANDALONE_SIG = 0x02, ++ PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY = 0x10, ++ PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY = 0x11, ++ PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY = 0x12, ++ PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY = 0x13, ++ PGP_SIG_SUBKEY_BINDING_SIG = 0x18, ++ PGP_SIG_PRIMARY_KEY_BINDING_SIG = 0x19, ++ PGP_SIG_DIRECTLY_ON_KEY = 0x1F, ++ PGP_SIG_KEY_REVOCATION_SIG = 0x20, ++ PGP_SIG_SUBKEY_REVOCATION_SIG = 0x28, ++ PGP_SIG_CERT_REVOCATION_SIG = 0x30, ++ PGP_SIG_TIMESTAMP_SIG = 0x40, ++ PGP_SIG_THIRD_PARTY_CONFIRM_SIG = 0x50, ++}; ++ ++struct pgp_signature_v3_packet { ++ enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */ ++ u8 length_of_hashed; /* == 5 */ ++ struct { ++ enum pgp_signature_type signature_type : 8; ++ struct pgp_time creation_time; ++ } hashed; ++ struct pgp_key_ID issuer; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ enum pgp_hash_algo hash_algo : 8; ++} __packed; ++ ++struct pgp_signature_v4_packet { ++ enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_4 */ ++ enum pgp_signature_type signature_type : 8; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ enum pgp_hash_algo hash_algo : 8; ++} __packed; ++ ++/* ++ * V4 signature subpacket types [RFC4880: 5.2.3.1]. ++ */ ++enum pgp_sig_subpkt_type { ++ PGP_SIG_CREATION_TIME = 2, ++ PGP_SIG_EXPIRATION_TIME = 3, ++ PGP_SIG_EXPORTABLE_CERT = 4, ++ PGP_SIG_TRUST_SIG = 5, ++ PGP_SIG_REGEXP = 6, ++ PGP_SIG_REVOCABLE = 7, ++ PGP_SIG_KEY_EXPIRATION_TIME = 9, ++ PGP_SIG_PREF_SYM_ALGO = 11, ++ PGP_SIG_REVOCATION_KEY = 12, ++ PGP_SIG_ISSUER = 16, ++ PGP_SIG_NOTATION_DATA = 20, ++ PGP_SIG_PREF_HASH_ALGO = 21, ++ PGP_SIG_PREF_COMPR_ALGO = 22, ++ PGP_SIG_KEY_SERVER_PREFS = 23, ++ PGP_SIG_PREF_KEY_SERVER = 24, ++ PGP_SIG_PRIMARY_USER_ID = 25, ++ PGP_SIG_POLICY_URI = 26, ++ PGP_SIG_KEY_FLAGS = 27, ++ PGP_SIG_SIGNERS_USER_ID = 28, ++ PGP_SIG_REASON_FOR_REVOCATION = 29, ++ PGP_SIG_FEATURES = 30, ++ PGP_SIG_TARGET = 31, ++ PGP_SIG_EMBEDDED_SIG = 32, ++ PGP_SIG__LAST ++}; ++ ++#define PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK 0x80 ++ ++/* ++ * Key (tag 5, 6, 7 and 14) packet ++ */ ++enum pgp_key_version { ++ PGP_KEY_VERSION_2 = 2, ++ PGP_KEY_VERSION_3 = 3, ++ PGP_KEY_VERSION_4 = 4, ++}; ++ ++struct pgp_key_v3_packet { ++ enum pgp_key_version version : 8; ++ struct pgp_time creation_time; ++ u8 expiry[2]; /* 0 or time in days till expiry */ ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ u8 key_material[0]; ++} __packed; ++ ++struct pgp_key_v4_packet { ++ enum pgp_key_version version : 8; ++ struct pgp_time creation_time; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ u8 key_material[0]; ++} __packed; ++ ++#endif /* _LINUX_PGP_H */ +-- +1.7.9.1 + + +From 570b106e22577e362c2772bdbfa1049c894b5cfb Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:12 +0000 +Subject: PGPLIB: Basic packet parser + +Provide a simple parser that extracts the packets from a PGP packet blob and +passes the desirous ones to the given processor function: + + struct pgp_parse_context { + u64 types_of_interest; + int (*process_packet)(struct pgp_parse_context *context, + enum pgp_packet_tag type, + u8 headerlen, + const u8 *data, + size_t datalen); + }; + + int pgp_parse_packets(const u8 *data, size_t datalen, + struct pgp_parse_context *ctx); + +This is configured on with CONFIG_PGP_LIBRARY. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + include/linux/pgp.h | 25 ++++ + security/keys/Kconfig | 6 + + security/keys/Makefile | 1 + + security/keys/pgp_library.c | 254 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 286 insertions(+), 0 deletions(-) + create mode 100644 security/keys/pgp_library.c + +diff --git a/include/linux/pgp.h b/include/linux/pgp.h +index 1359f64..235270a 100644 +--- a/include/linux/pgp.h ++++ b/include/linux/pgp.h +@@ -203,4 +203,29 @@ struct pgp_key_v4_packet { + u8 key_material[0]; + } __packed; + ++/* ++ * PGP library packet parser ++ */ ++struct pgp_parse_context { ++ u64 types_of_interest; ++ int (*process_packet)(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen); ++}; ++ ++extern int pgp_parse_packets(const u8 *data, size_t datalen, ++ struct pgp_parse_context *ctx); ++ ++struct pgp_parse_pubkey { ++ enum pgp_key_version version : 8; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ time_t creation_time; ++ time_t expires_at; ++}; ++ ++extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, ++ struct pgp_parse_pubkey *pk); ++ + #endif /* _LINUX_PGP_H */ +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index 65d640b..aa3954c 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -92,3 +92,9 @@ config CRYPTO_KEY_PKEY_ALGO_RSA + depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE + help + This option enables support for the RSA algorithm (PKCS#1, RFC3447). ++ ++config PGP_LIBRARY ++ tristate "PGP parsing library" ++ help ++ This option enables a library that provides a number of simple ++ utility functions for parsing PGP (RFC 4880) packet-based messages. +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 59e7180..2dbbe6c 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -27,5 +27,6 @@ obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ + obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o + obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o ++obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o + + crypto_keys-y := crypto_type.o crypto_verify.o +diff --git a/security/keys/pgp_library.c b/security/keys/pgp_library.c +new file mode 100644 +index 0000000..685660f +--- /dev/null ++++ b/security/keys/pgp_library.c +@@ -0,0 +1,254 @@ ++/* PGP packet parser (RFC 4880) ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++#define pr_fmt(fmt) "PGP: "fmt ++#include <linux/pgp.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++MODULE_LICENSE("GPL"); ++ ++const char *const pgp_hash_algorithms[PGP_HASH__LAST] = { ++ [PGP_HASH_MD5] = "md5", ++ [PGP_HASH_SHA1] = "sha1", ++ [PGP_HASH_RIPE_MD_160] = "rmd160", ++ [PGP_HASH_SHA256] = "sha256", ++ [PGP_HASH_SHA384] = "sha384", ++ [PGP_HASH_SHA512] = "sha512", ++ [PGP_HASH_SHA224] = "sha224", ++}; ++EXPORT_SYMBOL_GPL(pgp_hash_algorithms); ++ ++/** ++ * pgp_parse_packet_header - Parse a PGP packet header ++ * @_data: Start of the PGP packet (updated to PGP packet data) ++ * @_datalen: Amount of data remaining in buffer (decreased) ++ * @_type: Where the packet type will be returned ++ * @_headerlen: Where the header length will be returned ++ * ++ * Parse a set of PGP packet header [RFC 4880: 4.2]. ++ * ++ * Returns packet data size on success; non-zero on error. If successful, ++ * *_data and *_datalen will have been updated and *_headerlen will be set to ++ * hold the length of the packet header. ++ */ ++ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, ++ enum pgp_packet_tag *_type, ++ u8 *_headerlen) ++{ ++ enum pgp_packet_tag type; ++ const u8 *data = *_data; ++ size_t size, datalen = *_datalen; ++ ++ pr_devel("-->pgp_parse_packet_header(,%zu,,)", datalen); ++ ++ if (datalen < 2) ++ goto short_packet; ++ ++ pr_devel("pkthdr %02x, %02x\n", data[0], data[1]); ++ ++ type = *data++; ++ datalen--; ++ if (!(type & 0x80)) { ++ pr_debug("Packet type does not have MSB set\n"); ++ return -EBADMSG; ++ } ++ type &= ~0x80; ++ ++ if (type & 0x40) { ++ /* New packet length format */ ++ type &= ~0x40; ++ pr_devel("new format: t=%u\n", type); ++ switch (data[0]) { ++ case 0x00 ... 0xbf: ++ /* One-byte length */ ++ size = data[0]; ++ data++; ++ datalen--; ++ *_headerlen = 2; ++ break; ++ case 0xc0 ... 0xdf: ++ /* Two-byte length */ ++ if (datalen < 2) ++ goto short_packet; ++ size = (data[0] - 192) * 256; ++ size += data[1] + 192; ++ data += 2; ++ datalen -= 2; ++ *_headerlen = 3; ++ break; ++ case 0xff: ++ pr_debug("Five-byte packet length not supported\n"); ++ return -EBADMSG; ++ default: ++ pr_debug("Error parsing packet length\n"); ++ return -EBADMSG; ++ } ++ } else { ++ /* Old packet length format */ ++ u8 length_type = type & 0x03; ++ type >>= 2; ++ pr_devel("old format: t=%u lt=%u\n", type, length_type); ++ ++ switch (length_type) { ++ case 0: ++ /* One-byte length */ ++ size = data[0]; ++ data++; ++ datalen--; ++ *_headerlen = 2; ++ break; ++ case 1: ++ /* Two-byte length */ ++ if (datalen < 2) ++ goto short_packet; ++ size = data[0] << 8; ++ size |= data[1]; ++ data += 2; ++ datalen -= 2; ++ *_headerlen = 3; ++ break; ++ case 2: ++ /* Four-byte length */ ++ if (datalen < 4) ++ goto short_packet; ++ size = data[0] << 24; ++ size |= data[1] << 16; ++ size |= data[2] << 8; ++ size |= data[3]; ++ data += 4; ++ datalen -= 4; ++ *_headerlen = 5; ++ break; ++ default: ++ pr_debug("Indefinite length packet not supported\n"); ++ return -EBADMSG; ++ } ++ } ++ ++ pr_devel("datalen=%zu size=%zu", datalen, size); ++ if (datalen < size) ++ goto short_packet; ++ ++ *_data = data; ++ *_datalen = datalen; ++ *_type = type; ++ pr_devel("Found packet type=%u size=%zd\n", type, size); ++ return size; ++ ++short_packet: ++ pr_debug("Attempt to parse short packet\n"); ++ return -EBADMSG; ++} ++ ++/** ++ * pgp_parse_packets - Parse a set of PGP packets ++ * @_data: Data to be parsed (updated) ++ * @_datalen: Amount of data (updated) ++ * @ctx: Parsing context ++ * ++ * Parse a set of PGP packets [RFC 4880: 4]. ++ */ ++int pgp_parse_packets(const u8 *data, size_t datalen, ++ struct pgp_parse_context *ctx) ++{ ++ enum pgp_packet_tag type; ++ ssize_t pktlen; ++ u8 headerlen; ++ int ret; ++ ++ while (datalen > 2) { ++ pktlen = pgp_parse_packet_header(&data, &datalen, &type, ++ &headerlen); ++ if (pktlen < 0) ++ return pktlen; ++ ++ if ((ctx->types_of_interest >> type) & 1) { ++ ret = ctx->process_packet(ctx, type, headerlen, ++ data, pktlen); ++ if (ret < 0) ++ return ret; ++ } ++ data += pktlen; ++ datalen -= pktlen; ++ } ++ ++ if (datalen != 0) { ++ pr_debug("Excess octets in packet stream\n"); ++ return -EBADMSG; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_packets); ++ ++/** ++ * pgp_parse_public_key - Parse the common part of a PGP pubkey packet ++ * @_data: Content of packet (updated) ++ * @_datalen: Length of packet remaining (updated) ++ * @pk: Public key data ++ * ++ * Parse the common data struct for a PGP pubkey packet [RFC 4880: 5.5.2]. ++ */ ++int pgp_parse_public_key(const u8 **_data, size_t *_datalen, ++ struct pgp_parse_pubkey *pk) ++{ ++ const u8 *data = *_data; ++ size_t datalen = *_datalen; ++ __be32 tmp; ++ ++ if (datalen < 12) { ++ pr_debug("Public key packet too short\n"); ++ return -EBADMSG; ++ } ++ ++ pk->version = *data++; ++ switch (pk->version) { ++ case PGP_KEY_VERSION_2: ++ case PGP_KEY_VERSION_3: ++ case PGP_KEY_VERSION_4: ++ break; ++ default: ++ pr_debug("Public key packet with unhandled version %d\n", ++ pk->version); ++ return -EBADMSG; ++ } ++ ++ tmp = *data++ << 24; ++ tmp |= *data++ << 16; ++ tmp |= *data++ << 8; ++ tmp |= *data++; ++ pk->creation_time = tmp; ++ if (pk->version == PGP_KEY_VERSION_4) { ++ pk->expires_at = 0; /* Have to get it from the selfsignature */ ++ } else { ++ unsigned short ndays; ++ ndays = *data++ << 8; ++ ndays |= *data++; ++ if (ndays) ++ pk->expires_at = pk->creation_time + ndays * 86400UL; ++ else ++ pk->expires_at = 0; ++ datalen -= 2; ++ } ++ ++ pk->pubkey_algo = *data++; ++ datalen -= 6; ++ ++ pr_devel("%x,%x,%lx,%lx", ++ pk->version, pk->pubkey_algo, pk->creation_time, ++ pk->expires_at); ++ ++ *_data = data; ++ *_datalen = datalen; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_public_key); +-- +1.7.9.1 + + +From 194b547524cc4abf00e357948d949871d42bed84 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:13 +0000 +Subject: PGPLIB: Signature parser + +Provide some PGP signature parsing helpers: + + (1) A function to parse V4 signature subpackets and pass the desired ones to + a processor function: + + int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, + struct pgp_parse_sig_context *ctx); + + (2) A function to parse out basic signature parameters from any PGP signature + such that the algorithms and public key can be selected: + + int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, + struct pgp_sig_parameters *p); + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + include/linux/pgp.h | 24 ++++ + security/keys/pgp_library.c | 277 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 301 insertions(+), 0 deletions(-) + +diff --git a/include/linux/pgp.h b/include/linux/pgp.h +index 235270a..ab1a8fa 100644 +--- a/include/linux/pgp.h ++++ b/include/linux/pgp.h +@@ -228,4 +228,28 @@ struct pgp_parse_pubkey { + extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, + struct pgp_parse_pubkey *pk); + ++struct pgp_parse_sig_context { ++ unsigned long types_of_interest[128 / BITS_PER_LONG]; ++ int (*process_packet)(struct pgp_parse_sig_context *context, ++ enum pgp_sig_subpkt_type type, ++ const u8 *data, ++ size_t datalen); ++}; ++ ++extern int pgp_parse_sig_packets(const u8 *data, size_t datalen, ++ struct pgp_parse_sig_context *ctx); ++ ++struct pgp_sig_parameters { ++ enum pgp_signature_type signature_type : 8; ++ union { ++ struct pgp_key_ID issuer; ++ __be32 issuer32[2]; ++ }; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ enum pgp_hash_algo hash_algo : 8; ++}; ++ ++extern int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, ++ struct pgp_sig_parameters *p); ++ + #endif /* _LINUX_PGP_H */ +diff --git a/security/keys/pgp_library.c b/security/keys/pgp_library.c +index 685660f..f6b831f 100644 +--- a/security/keys/pgp_library.c ++++ b/security/keys/pgp_library.c +@@ -252,3 +252,280 @@ int pgp_parse_public_key(const u8 **_data, size_t *_datalen, + return 0; + } + EXPORT_SYMBOL_GPL(pgp_parse_public_key); ++ ++/** ++ * pgp_parse_sig_subpkt_header - Parse a PGP V4 signature subpacket header ++ * @_data: Start of the subpacket (updated to subpacket data) ++ * @_datalen: Amount of data remaining in buffer (decreased) ++ * @_type: Where the subpacket type will be returned ++ * ++ * Parse a PGP V4 signature subpacket header [RFC 4880: 5.2.3.1]. ++ * ++ * Returns packet data size on success; non-zero on error. If successful, ++ * *_data and *_datalen will have been updated and *_headerlen will be set to ++ * hold the length of the packet header. ++ */ ++ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, ++ enum pgp_sig_subpkt_type *_type) ++{ ++ enum pgp_sig_subpkt_type type; ++ const u8 *data = *_data; ++ size_t size, datalen = *_datalen; ++ ++ pr_devel("-->pgp_parse_sig_subpkt_header(,%zu,,)", datalen); ++ ++ if (datalen < 2) ++ goto short_subpacket; ++ ++ pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]); ++ ++ switch (data[0]) { ++ case 0x00 ... 0xbf: ++ /* One-byte length */ ++ size = data[0]; ++ data++; ++ datalen--; ++ break; ++ case 0xc0 ... 0xfe: ++ /* Two-byte length */ ++ if (datalen < 3) ++ goto short_subpacket; ++ size = (data[0] - 192) * 256; ++ size += data[1] + 192; ++ data += 2; ++ datalen -= 2; ++ break; ++ case 0xff: ++ if (datalen < 6) ++ goto short_subpacket; ++ size = data[1] << 24; ++ size |= data[2] << 16; ++ size |= data[3] << 8; ++ size |= data[4]; ++ data += 5; ++ datalen -= 5; ++ break; ++ } ++ ++ /* The type octet is included in the size */ ++ if (size == 0) { ++ pr_debug("Signature subpacket size can't be zero\n"); ++ return -EBADMSG; ++ } ++ ++ type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; ++ datalen--; ++ size--; ++ ++ pr_devel("datalen=%zu size=%zu", datalen, size); ++ if (datalen < size) ++ goto short_subpacket; ++ ++ *_data = data; ++ *_datalen = datalen; ++ *_type = type; ++ pr_devel("Found subpkt type=%u size=%zd\n", type, size); ++ return size; ++ ++short_subpacket: ++ pr_debug("Attempt to parse short signature subpacket\n"); ++ return -EBADMSG; ++} ++ ++/** ++ * pgp_parse_sig_subpkts - Parse a set of PGP V4 signatute subpackets ++ * @_data: Data to be parsed (updated) ++ * @_datalen: Amount of data (updated) ++ * @ctx: Parsing context ++ * ++ * Parse a set of PGP signature subpackets [RFC 4880: 5.2.3]. ++ */ ++int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, ++ struct pgp_parse_sig_context *ctx) ++{ ++ enum pgp_sig_subpkt_type type; ++ ssize_t pktlen; ++ int ret; ++ ++ pr_devel("-->pgp_parse_sig_subpkts(,%zu,,)", datalen); ++ ++ while (datalen > 2) { ++ pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type); ++ if (pktlen < 0) ++ return pktlen; ++ if (test_bit(type, ctx->types_of_interest)) { ++ ret = ctx->process_packet(ctx, type, data, pktlen); ++ if (ret < 0) ++ return ret; ++ } ++ data += pktlen; ++ datalen -= pktlen; ++ } ++ ++ if (datalen != 0) { ++ pr_debug("Excess octets in signature subpacket stream\n"); ++ return -EBADMSG; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_sig_subpkts); ++ ++struct pgp_parse_sig_params_ctx { ++ struct pgp_parse_sig_context base; ++ struct pgp_sig_parameters *params; ++ bool got_the_issuer; ++}; ++ ++/* ++ * Process a V4 signature subpacket. ++ */ ++static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context, ++ enum pgp_sig_subpkt_type type, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct pgp_parse_sig_params_ctx *ctx = ++ container_of(context, struct pgp_parse_sig_params_ctx, base); ++ ++ if (ctx->got_the_issuer) { ++ pr_debug("V4 signature packet has multiple issuers\n"); ++ return -EBADMSG; ++ } ++ ++ if (datalen != 8) { ++ pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n", ++ datalen); ++ return -EBADMSG; ++ } ++ ++ memcpy(&ctx->params->issuer, data, 8); ++ ctx->got_the_issuer = true; ++ return 0; ++} ++ ++/** ++ * pgp_parse_sig_params - Parse basic parameters from a PGP signature packet ++ * @_data: Content of packet (updated) ++ * @_datalen: Length of packet remaining (updated) ++ * @p: The basic parameters ++ * ++ * Parse the basic parameters from a PGP signature packet [RFC 4880: 5.2] that ++ * are needed to start off a signature verification operation. The only ones ++ * actually necessary are the signature type (which affects how the data is ++ * transformed) and the has algorithm. ++ * ++ * We also extract the public key algorithm and the issuer's key ID as we'll ++ * need those to determine if we actually have the public key available. If ++ * not, then we can't verify the signature anyway. ++ * ++ * Returns 0 if successful or a negative error code. *_data and *_datalen are ++ * updated to point to the 16-bit subset of the hash value and the set of MPIs. ++ */ ++int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, ++ struct pgp_sig_parameters *p) ++{ ++ enum pgp_signature_version version; ++ const u8 *data = *_data; ++ size_t datalen = *_datalen; ++ int ret; ++ ++ pr_devel("-->pgp_parse_sig_params(,%zu,,)", datalen); ++ ++ if (datalen < 1) ++ return -EBADMSG; ++ version = *data; ++ ++ if (version == PGP_SIG_VERSION_3) { ++ const struct pgp_signature_v3_packet *v3 = (const void *)data; ++ ++ if (datalen < sizeof(*v3)) { ++ pr_debug("Short V3 signature packet\n"); ++ return -EBADMSG; ++ } ++ datalen -= sizeof(*v3); ++ data += sizeof(*v3); ++ ++ /* V3 has everything we need in the header */ ++ p->signature_type = v3->hashed.signature_type; ++ p->issuer = v3->issuer; ++ p->pubkey_algo = v3->pubkey_algo; ++ p->hash_algo = v3->hash_algo; ++ ++ } else if (version == PGP_SIG_VERSION_4) { ++ const struct pgp_signature_v4_packet *v4 = (const void *)data; ++ struct pgp_parse_sig_params_ctx ctx = { ++ .base.process_packet = pgp_process_sig_params_subpkt, ++ .params = p, ++ .got_the_issuer = false, ++ }; ++ size_t subdatalen; ++ ++ if (datalen < sizeof(*v4) + 2 + 2 + 2) { ++ pr_debug("Short V4 signature packet\n"); ++ return -EBADMSG; ++ } ++ datalen -= sizeof(*v4); ++ data += sizeof(*v4); ++ ++ /* V4 has most things in the header... */ ++ p->signature_type = v4->signature_type; ++ p->pubkey_algo = v4->pubkey_algo; ++ p->hash_algo = v4->hash_algo; ++ ++ /* ... but we have to get the key ID from the subpackets, of ++ * which there are two sets. */ ++ __set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest); ++ ++ subdatalen = *data++ << 8; ++ subdatalen |= *data++; ++ datalen -= 2; ++ if (subdatalen) { ++ /* Hashed subpackets */ ++ pr_devel("hashed data: %zu (after %zu)\n", ++ subdatalen, sizeof(*v4)); ++ if (subdatalen > datalen + 2 + 2) { ++ pr_debug("Short V4 signature packet [hdata]\n"); ++ return -EBADMSG; ++ } ++ ret = pgp_parse_sig_subpkts(data, subdatalen, ++ &ctx.base); ++ if (ret < 0) ++ return ret; ++ data += subdatalen; ++ datalen += subdatalen; ++ } ++ ++ subdatalen = *data++ << 8; ++ subdatalen |= *data++; ++ datalen -= 2; ++ if (subdatalen) { ++ /* Unhashed subpackets */ ++ pr_devel("unhashed data: %zu\n", subdatalen); ++ if (subdatalen > datalen + 2) { ++ pr_debug("Short V4 signature packet [udata]\n"); ++ return -EBADMSG; ++ } ++ ret = pgp_parse_sig_subpkts(data, subdatalen, ++ &ctx.base); ++ if (ret < 0) ++ return ret; ++ data += subdatalen; ++ datalen += subdatalen; ++ } ++ ++ if (!ctx.got_the_issuer) { ++ pr_debug("V4 signature packet lacks issuer\n"); ++ return -EBADMSG; ++ } ++ } else { ++ pr_debug("Signature packet with unhandled version %d\n", ++ version); ++ return -EBADMSG; ++ } ++ ++ *_data = data; ++ *_datalen = datalen; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_sig_params); +-- +1.7.9.1 + + +From ee32f2d2d24a635e7bb46cbd37a0622850f4c66e Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:13 +0000 +Subject: KEYS: PGP data parser + +Implement a PGP data parser for the crypto key type to use when instantiating a +key. + +This parser attempts to parse the instantiation data as a PGP packet sequence +(RFC 4880) and if it parses okay, attempts to extract a public-key algorithm +key or subkey from it. + +If it finds such a key, it will set up a public_key subtype payload with +appropriate handler routines (DSA or RSA) and attach it to the key. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/Kconfig | 12 ++ + security/keys/Makefile | 4 + + security/keys/pgp_key_parser.c | 343 ++++++++++++++++++++++++++++++++++++++++ + security/keys/pgp_parser.h | 23 +++ + 4 files changed, 382 insertions(+), 0 deletions(-) + create mode 100644 security/keys/pgp_key_parser.c + create mode 100644 security/keys/pgp_parser.h + +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index aa3954c..fd53028 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -98,3 +98,15 @@ config PGP_LIBRARY + help + This option enables a library that provides a number of simple + utility functions for parsing PGP (RFC 4880) packet-based messages. ++ ++config CRYPTO_KEY_PGP_PARSER ++ tristate "PGP key blob parser" ++ depends on CRYPTO_KEY_TYPE ++ select CRYPTO_KEY_PUBLIC_KEY_SUBTYPE ++ select PGP_LIBRARY ++ select MD5 # V3 fingerprint generation ++ select SHA1 # V4 fingerprint generation ++ help ++ This option provides support for parsing PGP (RFC 4880) format blobs ++ for key data and provides the ability to instantiate a crypto key ++ from a public key packet found inside the blob. +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 2dbbe6c..416670c 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -28,5 +28,9 @@ obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o + obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o + obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o ++obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o + + crypto_keys-y := crypto_type.o crypto_verify.o ++ ++pgp_parser-y := \ ++ pgp_key_parser.o +diff --git a/security/keys/pgp_key_parser.c b/security/keys/pgp_key_parser.c +new file mode 100644 +index 0000000..4efc4de +--- /dev/null ++++ b/security/keys/pgp_key_parser.c +@@ -0,0 +1,343 @@ ++/* Parser for PGP format key data [RFC 4880] ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "PGP: "fmt ++#include <keys/crypto-subtype.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/mpi.h> ++#include <linux/pgp.h> ++#include <crypto/hash.h> ++#include "public_key.h" ++#include "pgp_parser.h" ++ ++MODULE_LICENSE("GPL"); ++ ++const ++struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST] = { ++#if defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) || \ ++ defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA_MODULE) ++ [PGP_PUBKEY_RSA_ENC_OR_SIG] = &RSA_public_key_algorithm, ++ [PGP_PUBKEY_RSA_ENC_ONLY] = &RSA_public_key_algorithm, ++ [PGP_PUBKEY_RSA_SIG_ONLY] = &RSA_public_key_algorithm, ++#endif ++ [PGP_PUBKEY_ELGAMAL] = NULL, ++ [PGP_PUBKEY_DSA] = NULL, ++}; ++ ++static const u8 pgp_public_key_capabilities[PGP_PUBKEY__LAST] = { ++ [PGP_PUBKEY_RSA_ENC_OR_SIG] = PKEY_CAN_ENCDEC | PKEY_CAN_SIGVER, ++ [PGP_PUBKEY_RSA_ENC_ONLY] = PKEY_CAN_ENCDEC, ++ [PGP_PUBKEY_RSA_SIG_ONLY] = PKEY_CAN_SIGVER, ++ [PGP_PUBKEY_ELGAMAL] = 0, ++ [PGP_PUBKEY_DSA] = 0, ++}; ++ ++static inline void digest_putc(struct shash_desc *digest, uint8_t ch) ++{ ++ crypto_shash_update(digest, &ch, 1); ++} ++ ++struct pgp_key_data_parse_context { ++ struct pgp_parse_context pgp; ++ struct crypto_key_subtype *subtype; ++ char *fingerprint; ++ void *payload; ++}; ++ ++/* ++ * Calculate the public key ID (RFC4880 12.2) ++ */ ++static int pgp_calc_pkey_keyid(struct shash_desc *digest, ++ struct pgp_parse_pubkey *pgp, ++ struct public_key *key) ++{ ++ unsigned nb[ARRAY_SIZE(key->mpi)]; ++ unsigned nn[ARRAY_SIZE(key->mpi)]; ++ unsigned n; ++ u8 *pp[ARRAY_SIZE(key->mpi)]; ++ u32 a32; ++ int npkey = key->algo->n_pub_mpi; ++ int i, ret = -ENOMEM; ++ ++ kenter(""); ++ ++ n = (pgp->version < PGP_KEY_VERSION_4) ? 8 : 6; ++ for (i = 0; i < npkey; i++) { ++ nb[i] = mpi_get_nbits(key->mpi[i]); ++ pp[i] = mpi_get_buffer(key->mpi[i], nn + i, NULL); ++ if (!pp[i]) ++ goto error; ++ n += 2 + nn[i]; ++ } ++ ++ digest_putc(digest, 0x99); /* ctb */ ++ digest_putc(digest, n >> 8); /* 16-bit header length */ ++ digest_putc(digest, n); ++ digest_putc(digest, pgp->version); ++ ++ a32 = pgp->creation_time; ++ digest_putc(digest, a32 >> 24); ++ digest_putc(digest, a32 >> 16); ++ digest_putc(digest, a32 >> 8); ++ digest_putc(digest, a32 >> 0); ++ ++ if (pgp->version < PGP_KEY_VERSION_4) { ++ u16 a16; ++ ++ if( pgp->expires_at) ++ a16 = (pgp->expires_at - pgp->creation_time) / 86400UL; ++ else ++ a16 = 0; ++ digest_putc(digest, a16 >> 8); ++ digest_putc(digest, a16 >> 0); ++ } ++ ++ digest_putc(digest, pgp->pubkey_algo); ++ ++ for (i = 0; i < npkey; i++) { ++ digest_putc(digest, nb[i] >> 8); ++ digest_putc(digest, nb[i]); ++ crypto_shash_update(digest, pp[i], nn[i]); ++ } ++ ret = 0; ++ ++error: ++ for (i = 0; i < npkey; i++) ++ kfree(pp[i]); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Calculate the public key ID fingerprint ++ */ ++static int pgp_generate_fingerprint(struct pgp_key_data_parse_context *ctx, ++ struct pgp_parse_pubkey *pgp, ++ struct public_key *key) ++{ ++ struct crypto_shash *tfm; ++ struct shash_desc *digest; ++ char *fingerprint; ++ u8 *raw_fingerprint; ++ int digest_size, offset; ++ int ret, i; ++ ++ ret = -ENOMEM; ++ tfm = crypto_alloc_shash(pgp->version < PGP_KEY_VERSION_4 ? ++ "md5" : "sha1", 0, 0); ++ if (!tfm) ++ goto cleanup; ++ ++ digest = kmalloc(sizeof(*digest) + crypto_shash_descsize(tfm), ++ GFP_KERNEL); ++ if (!digest) ++ goto cleanup_tfm; ++ ++ digest->tfm = tfm; ++ digest->flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ ret = crypto_shash_init(digest); ++ if (ret < 0) ++ goto cleanup_hash; ++ ++ ret = pgp_calc_pkey_keyid(digest, pgp, key); ++ if (ret < 0) ++ goto cleanup_hash; ++ ++ digest_size = crypto_shash_digestsize(tfm); ++ ++ raw_fingerprint = kmalloc(digest_size, GFP_KERNEL); ++ if (!raw_fingerprint) ++ goto cleanup_hash; ++ ++ ret = crypto_shash_final(digest, raw_fingerprint); ++ if (ret < 0) ++ goto cleanup_raw_fingerprint; ++ ++ fingerprint = kmalloc(digest_size * 2 + 1, GFP_KERNEL); ++ if (!fingerprint) ++ goto cleanup_raw_fingerprint; ++ ++ offset = digest_size - 8; ++ pr_debug("offset %u/%u\n", offset, digest_size); ++ ++ for (i = 0; i < digest_size; i++) ++ sprintf(fingerprint + i * 2, "%02x", raw_fingerprint[i]); ++ pr_debug("fingerprint %s\n", fingerprint); ++ ++ memcpy(&key->key_id, raw_fingerprint + offset, 8); ++ key->key_id_size = 8; ++ ++ ctx->fingerprint = fingerprint; ++ ret = 0; ++cleanup_raw_fingerprint: ++ kfree(raw_fingerprint); ++cleanup_hash: ++ kfree(digest); ++cleanup_tfm: ++ crypto_free_shash(tfm); ++cleanup: ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Extract a public key or public subkey from the PGP stream. ++ */ ++static int pgp_process_public_key(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ const struct public_key_algorithm *algo; ++ struct pgp_key_data_parse_context *ctx = ++ container_of(context, struct pgp_key_data_parse_context, pgp); ++ struct pgp_parse_pubkey pgp; ++ struct public_key *key; ++ int i, ret; ++ ++ kenter(",%u,%u,,%zu", type, headerlen, datalen); ++ ++ if (ctx->subtype) { ++ kleave(" = -ENOKEY [already]"); ++ return -EBADMSG; ++ } ++ ++ key = kzalloc(sizeof(struct public_key), GFP_KERNEL); ++ if (!key) ++ return -ENOMEM; ++ ++ ret = pgp_parse_public_key(&data, &datalen, &pgp); ++ if (ret < 0) ++ goto cleanup; ++ ++ if (pgp.pubkey_algo >= PGP_PUBKEY__LAST || ++ !pgp_public_key_algorithms[pgp.pubkey_algo]) { ++ pr_debug("Unsupported public key algorithm %u\n", ++ pgp.pubkey_algo); ++ ret = -ENOPKG; ++ goto cleanup; ++ } ++ ++ algo = key->algo = pgp_public_key_algorithms[pgp.pubkey_algo]; ++ ++ /* It's a public key, so that only gives us encrypt and verify ++ * capabilities. ++ */ ++ key->capabilities = pgp_public_key_capabilities[pgp.pubkey_algo] & ++ (PKEY_CAN_ENCRYPT | PKEY_CAN_VERIFY); ++ ++ ret = -ENOMEM; ++ for (i = 0; i < algo->n_pub_mpi; i++) { ++ unsigned int remaining = datalen; ++ ret = -EBADMSG; ++ if (remaining == 0) { ++ pr_debug("short %zu mpi %d\n", datalen, i); ++ goto cleanup; ++ } ++ key->mpi[i] = mpi_read_from_buffer(data, &remaining); ++ if (!key->mpi[i]) ++ goto cleanup; ++ data += remaining; ++ datalen -= remaining; ++ } ++ ++ ret = -EBADMSG; ++ if (datalen != 0) { ++ pr_debug("excess %zu\n", datalen); ++ goto cleanup; ++ } ++ ++ ret = pgp_generate_fingerprint(ctx, &pgp, key); ++ if (ret < 0) ++ goto cleanup; ++ ++ /* We're pinning the module by being linked against it */ ++ __module_get(public_key_crypto_key_subtype.owner); ++ ctx->subtype = &public_key_crypto_key_subtype; ++ ctx->payload = key; ++ kleave(" = 0 [use]"); ++ return 0; ++ ++cleanup: ++ pr_devel("cleanup"); ++ if (key) { ++ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) ++ mpi_free(key->mpi[i]); ++ kfree(key); ++ } ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Attempt to parse the instantiation data blob for a key as a PGP packet ++ * message holding a key. ++ */ ++static int pgp_key_instantiate(struct key *key, ++ const void *data, size_t datalen) ++{ ++ struct pgp_key_data_parse_context ctx; ++ int ret; ++ ++ kenter(""); ++ ++ ret = key_payload_reserve(key, datalen); ++ if (ret < 0) ++ return ret; ++ ++ ctx.pgp.types_of_interest = ++ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY); ++ ctx.pgp.process_packet = pgp_process_public_key; ++ ctx.subtype = NULL; ++ ctx.fingerprint = NULL; ++ ctx.payload = NULL; ++ ++ ret = pgp_parse_packets(data, datalen, &ctx.pgp); ++ if (ret < 0) { ++ if (ctx.payload) ++ ctx.subtype->destroy(ctx.payload); ++ if (ctx.subtype) ++ module_put(ctx.subtype->owner); ++ kfree(ctx.fingerprint); ++ key_payload_reserve(key, 0); ++ return ret; ++ } ++ ++ key->type_data.p[0] = ctx.subtype; ++ key->type_data.p[1] = ctx.fingerprint; ++ key->payload.data = ctx.payload; ++ return 0; ++} ++ ++static struct crypto_key_parser pgp_key_parser = { ++ .owner = THIS_MODULE, ++ .name = "pgp", ++ .instantiate = pgp_key_instantiate, ++}; ++ ++/* ++ * Module stuff ++ */ ++static int __init pgp_key_init(void) ++{ ++ return register_crypto_key_parser(&pgp_key_parser); ++} ++ ++static void __exit pgp_key_exit(void) ++{ ++ unregister_crypto_key_parser(&pgp_key_parser); ++} ++ ++module_init(pgp_key_init); ++module_exit(pgp_key_exit); +diff --git a/security/keys/pgp_parser.h b/security/keys/pgp_parser.h +new file mode 100644 +index 0000000..1cda231 +--- /dev/null ++++ b/security/keys/pgp_parser.h +@@ -0,0 +1,23 @@ ++/* PGP crypto data parser internal definitions ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/pgp.h> ++ ++#define kenter(FMT, ...) \ ++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) ++#define kleave(FMT, ...) \ ++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) ++ ++/* ++ * pgp_key_parser.c ++ */ ++extern const ++struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; +-- +1.7.9.1 + + +From 0e862034535288f2ee5653563178f6a6b99f8c47 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:14 +0000 +Subject: KEYS: PGP-based public key signature verification + +Provide handlers for PGP-based public-key algorithm signature verification. +This does most of the work involved in signature verification as most of it is +public-key algorithm agnostic. The public-key verification algorithm itself +is just the last little bit and is supplied the complete hash data to process. + +This requires glue logic putting on top to make use of it - something the next +patch provides. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/Makefile | 3 +- + security/keys/pgp_parser.h | 6 + + security/keys/pgp_pubkey_sig.c | 323 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 331 insertions(+), 1 deletions(-) + create mode 100644 security/keys/pgp_pubkey_sig.c + +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 416670c..24e83a2 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -33,4 +33,5 @@ obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o + crypto_keys-y := crypto_type.o crypto_verify.o + + pgp_parser-y := \ +- pgp_key_parser.o ++ pgp_key_parser.o \ ++ pgp_pubkey_sig.o +diff --git a/security/keys/pgp_parser.h b/security/keys/pgp_parser.h +index 1cda231..a6192ce 100644 +--- a/security/keys/pgp_parser.h ++++ b/security/keys/pgp_parser.h +@@ -21,3 +21,9 @@ + */ + extern const + struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; ++ ++/* ++ * pgp_pubkey_sig.c ++ */ ++extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( ++ struct key *crypto_key, const u8 *sigdata, size_t siglen); +diff --git a/security/keys/pgp_pubkey_sig.c b/security/keys/pgp_pubkey_sig.c +new file mode 100644 +index 0000000..b4b7cb0 +--- /dev/null ++++ b/security/keys/pgp_pubkey_sig.c +@@ -0,0 +1,323 @@ ++/* Handling for PGP public key signature data [RFC 4880] ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "PGPSIG: "fmt ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pgp.h> ++#include "public_key.h" ++#include "pgp_parser.h" ++ ++const struct { ++ enum pkey_hash_algo algo : 8; ++} pgp_pubkey_hash[PGP_HASH__LAST] = { ++ [PGP_HASH_MD5].algo = PKEY_HASH_MD5, ++ [PGP_HASH_SHA1].algo = PKEY_HASH_SHA1, ++ [PGP_HASH_RIPE_MD_160].algo = PKEY_HASH_RIPE_MD_160, ++ [PGP_HASH_SHA256].algo = PKEY_HASH_SHA256, ++ [PGP_HASH_SHA384].algo = PKEY_HASH_SHA384, ++ [PGP_HASH_SHA512].algo = PKEY_HASH_SHA512, ++ [PGP_HASH_SHA224].algo = PKEY_HASH_SHA224, ++}; ++ ++static int pgp_pkey_verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++static int pgp_pkey_verify_sig_end(struct crypto_key_verify_context *ctx, ++ const u8 *sig, size_t siglen); ++static void pgp_pkey_verify_sig_cancel(struct crypto_key_verify_context *ctx); ++ ++struct pgp_pkey_sig_parse_context { ++ struct pgp_parse_context pgp; ++ struct pgp_sig_parameters params; ++}; ++ ++static int pgp_pkey_parse_signature(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct pgp_pkey_sig_parse_context *ctx = ++ container_of(context, struct pgp_pkey_sig_parse_context, pgp); ++ ++ return pgp_parse_sig_params(&data, &datalen, &ctx->params); ++} ++ ++/* ++ * Begin the process of verifying a DSA signature. ++ * ++ * This involves allocating the hash into which first the data and then the ++ * metadata will be put, and parsing the signature to check that it matches the ++ * key. ++ */ ++struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( ++ struct key *crypto_key, const u8 *sigdata, size_t siglen) ++{ ++ struct pgp_pkey_sig_parse_context p; ++ struct public_key_signature *sig; ++ struct crypto_shash *tfm; ++ const struct public_key *key = crypto_key->payload.data; ++ size_t digest_size, desc_size; ++ int ret; ++ ++ kenter("{%d},,%zu", key_serial(crypto_key), siglen); ++ ++ if (!key) { ++ kleave(" = -ENOKEY [no public key]"); ++ return ERR_PTR(-ENOKEY); ++ } ++ ++ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); ++ p.pgp.process_packet = pgp_pkey_parse_signature; ++ ret = pgp_parse_packets(sigdata, siglen, &p.pgp); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ if (p.params.pubkey_algo >= PGP_PUBKEY__LAST || ++ !pgp_public_key_algorithms[p.params.pubkey_algo]) { ++ pr_debug("Unsupported public key algorithm %u\n", ++ p.params.pubkey_algo); ++ return ERR_PTR(-ENOKEY); ++ } ++ ++ if (pgp_public_key_algorithms[p.params.pubkey_algo] != key->algo) { ++ kleave(" = -ENOKEY [wrong pk algo]"); ++ return ERR_PTR(-ENOKEY); ++ } ++ ++ if (!(key->capabilities & PKEY_CAN_VERIFY)) { ++ kleave(" = -EKEYREJECTED [key can't verify]"); ++ return ERR_PTR(-EKEYREJECTED); ++ } ++ ++ if (p.params.hash_algo >= PGP_HASH__LAST || ++ !pgp_hash_algorithms[p.params.hash_algo]) { ++ kleave(" = -ENOPKG [hash]"); ++ return ERR_PTR(-ENOPKG); ++ } ++ ++ pr_debug("Signature generated with %s hash\n", ++ pgp_hash_algorithms[p.params.hash_algo]); ++ ++ if (memcmp(&p.params.issuer, key->key_id, 8) != 0) { ++ kleave(" = -ENOKEY [wrong key ID]"); ++ return ERR_PTR(-ENOKEY); ++ } ++ ++ if (p.params.signature_type != PGP_SIG_BINARY_DOCUMENT_SIG && ++ p.params.signature_type != PGP_SIG_STANDALONE_SIG) { ++ /* We don't want to canonicalise */ ++ kleave(" = -EOPNOTSUPP [canon]"); ++ return ERR_PTR(-EOPNOTSUPP); ++ } ++ ++ /* Allocate the hashing algorithm we're going to need and find out how ++ * big the hash operational data will be. ++ */ ++ tfm = crypto_alloc_shash(pgp_hash_algorithms[p.params.hash_algo], 0, 0); ++ if (IS_ERR(tfm)) ++ return PTR_ERR(tfm) == -ENOENT ? ++ ERR_PTR(-ENOPKG) : ERR_CAST(tfm); ++ ++ desc_size = crypto_shash_descsize(tfm); ++ digest_size = crypto_shash_digestsize(tfm); ++ ++ /* We allocate the hash operational data storage on the end of our ++ * context data. ++ */ ++ sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); ++ if (!sig) { ++ crypto_free_shash(tfm); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sig->base.key = crypto_key; ++ sig->base.add_data = pgp_pkey_verify_sig_add_data; ++ sig->base.end = pgp_pkey_verify_sig_end; ++ sig->base.cancel = pgp_pkey_verify_sig_cancel; ++ sig->pkey_hash_algo = pgp_pubkey_hash[p.params.hash_algo].algo; ++ sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; ++ sig->digest_size = digest_size; ++ sig->hash.tfm = tfm; ++ sig->hash.flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ ++ ret = crypto_shash_init(&sig->hash); ++ if (ret < 0) { ++ crypto_free_shash(sig->hash.tfm); ++ kfree(sig); ++ return ERR_PTR(ret); ++ } ++ ++ key_get(sig->base.key); ++ kleave(" = %p", sig); ++ return &sig->base; ++} ++ ++/* ++ * Load data into the hash ++ */ ++static int pgp_pkey_verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen) ++{ ++ struct public_key_signature *sig = ++ container_of(ctx, struct public_key_signature, base); ++ ++ return crypto_shash_update(&sig->hash, data, datalen); ++} ++ ++struct pgp_pkey_sig_digest_context { ++ struct pgp_parse_context pgp; ++ const struct public_key *key; ++ struct public_key_signature *sig; ++}; ++ ++/* ++ * Extract required metadata from the signature packet and add what we need to ++ * to the hash. ++ */ ++static int pgp_pkey_digest_signature(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct pgp_pkey_sig_digest_context *ctx = ++ container_of(context, struct pgp_pkey_sig_digest_context, pgp); ++ enum pgp_signature_version version; ++ int i; ++ ++ kenter(",%u,%u,,%zu", type, headerlen, datalen); ++ ++ version = *data; ++ if (version == PGP_SIG_VERSION_3) { ++ /* We just include an excerpt of the metadata from a V3 ++ * signature. ++ */ ++ crypto_shash_update(&ctx->sig->hash, data + 1, 5); ++ data += sizeof(struct pgp_signature_v3_packet); ++ datalen -= sizeof(struct pgp_signature_v3_packet); ++ } else if (version == PGP_SIG_VERSION_4) { ++ /* We add the whole metadata header and some of the hashed data ++ * for a V4 signature, plus a trailer. ++ */ ++ size_t hashedsz, unhashedsz; ++ u8 trailer[6]; ++ ++ hashedsz = 4 + 2 + (data[4] << 8) + data[5]; ++ crypto_shash_update(&ctx->sig->hash, data, hashedsz); ++ ++ trailer[0] = version; ++ trailer[1] = 0xffU; ++ trailer[2] = hashedsz >> 24; ++ trailer[3] = hashedsz >> 16; ++ trailer[4] = hashedsz >> 8; ++ trailer[5] = hashedsz; ++ ++ crypto_shash_update(&ctx->sig->hash, trailer, 6); ++ data += hashedsz; ++ datalen -= hashedsz; ++ ++ unhashedsz = 2 + (data[0] << 8) + data[1]; ++ data += unhashedsz; ++ datalen -= unhashedsz; ++ } ++ ++ if (datalen <= 2) { ++ kleave(" = -EBADMSG"); ++ return -EBADMSG; ++ } ++ ++ /* There's a quick check on the hash available. */ ++ ctx->sig->signed_hash_msw[0] = *data++; ++ ctx->sig->signed_hash_msw[1] = *data++; ++ datalen -= 2; ++ ++ /* And then the cryptographic data, which we'll need for the ++ * algorithm. ++ */ ++ for (i = 0; i < ctx->key->algo->n_sig_mpi; i++) { ++ unsigned int remaining = datalen; ++ if (remaining == 0) { ++ pr_debug("short %zu mpi %d\n", datalen, i); ++ return -EBADMSG; ++ } ++ ctx->sig->mpi[i] = mpi_read_from_buffer(data, &remaining); ++ if (!ctx->sig->mpi[i]) ++ return -ENOMEM; ++ data += remaining; ++ datalen -= remaining; ++ } ++ ++ if (datalen != 0) { ++ kleave(" = -EBADMSG [trailer %zu]", datalen); ++ return -EBADMSG; ++ } ++ ++ kleave(" = 0"); ++ return 0; ++} ++ ++/* ++ * The data is now all loaded into the hash; load the metadata, finalise the ++ * hash and perform the verification step. ++ */ ++static int pgp_pkey_verify_sig_end(struct crypto_key_verify_context *ctx, ++ const u8 *sigdata, size_t siglen) ++{ ++ struct public_key_signature *sig = ++ container_of(ctx, struct public_key_signature, base); ++ const struct public_key *key = sig->base.key->payload.data; ++ struct pgp_pkey_sig_digest_context p; ++ int ret; ++ ++ kenter(""); ++ ++ /* Firstly we add metadata, starting with some of the data from the ++ * signature packet */ ++ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); ++ p.pgp.process_packet = pgp_pkey_digest_signature; ++ p.key = key; ++ p.sig = sig; ++ ret = pgp_parse_packets(sigdata, siglen, &p.pgp); ++ if (ret < 0) ++ goto error_free_ctx; ++ ++ crypto_shash_final(&sig->hash, sig->digest); ++ ++ ret = key->algo->verify(key, sig); ++ ++error_free_ctx: ++ pgp_pkey_verify_sig_cancel(ctx); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Cancel an in-progress data loading ++ */ ++static void pgp_pkey_verify_sig_cancel(struct crypto_key_verify_context *ctx) ++{ ++ struct public_key_signature *sig = ++ container_of(ctx, struct public_key_signature, base); ++ int i; ++ ++ kenter(""); ++ ++ /* !!! Do we need to tell the crypto layer to cancel too? */ ++ crypto_free_shash(sig->hash.tfm); ++ key_put(sig->base.key); ++ for (i = 0; i < ARRAY_SIZE(sig->mpi); i++) ++ mpi_free(sig->mpi[i]); ++ kfree(sig); ++ ++ kleave(""); ++} +-- +1.7.9.1 + + +From b8d572f41734596c3abbd15b1d2e30f5fa603c01 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:15 +0000 +Subject: KEYS: PGP format signature parser + +Implement a signature parser that will attempt to parse a signature blob as a +PGP packet format message. If it can, it will find an appropriate crypto key +and set the public-key algorithm according to the data in the signature. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/Makefile | 1 + + security/keys/pgp_key_parser.c | 1 + + security/keys/pgp_parser.h | 6 ++ + security/keys/pgp_sig_parser.c | 104 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 112 insertions(+), 0 deletions(-) + create mode 100644 security/keys/pgp_sig_parser.c + +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 24e83a2..9aa48fe 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -34,4 +34,5 @@ crypto_keys-y := crypto_type.o crypto_verify.o + + pgp_parser-y := \ + pgp_key_parser.o \ ++ pgp_sig_parser.o \ + pgp_pubkey_sig.o +diff --git a/security/keys/pgp_key_parser.c b/security/keys/pgp_key_parser.c +index 4efc4de..1407e2e 100644 +--- a/security/keys/pgp_key_parser.c ++++ b/security/keys/pgp_key_parser.c +@@ -324,6 +324,7 @@ static struct crypto_key_parser pgp_key_parser = { + .owner = THIS_MODULE, + .name = "pgp", + .instantiate = pgp_key_instantiate, ++ .verify_sig_begin = pgp_verify_sig_begin, + }; + + /* +diff --git a/security/keys/pgp_parser.h b/security/keys/pgp_parser.h +index a6192ce..73c900e 100644 +--- a/security/keys/pgp_parser.h ++++ b/security/keys/pgp_parser.h +@@ -23,6 +23,12 @@ extern const + struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; + + /* ++ * pgp_sig_parser.c ++ */ ++extern struct crypto_key_verify_context *pgp_verify_sig_begin( ++ struct key *keyring, const u8 *sig, size_t siglen); ++ ++/* + * pgp_pubkey_sig.c + */ + extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( +diff --git a/security/keys/pgp_sig_parser.c b/security/keys/pgp_sig_parser.c +new file mode 100644 +index 0000000..b72c505 +--- /dev/null ++++ b/security/keys/pgp_sig_parser.c +@@ -0,0 +1,104 @@ ++/* Handling for PGP public key signature data [RFC 4880] ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#define pr_fmt(fmt) "PGPSIG: "fmt ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/pgp.h> ++#include "public_key.h" ++#include "pgp_parser.h" ++ ++struct PGP_sig_parse_context { ++ struct pgp_parse_context pgp; ++ struct pgp_sig_parameters params; ++ bool found_sig; ++}; ++ ++/* ++ * Look inside signature sections for a key ID ++ */ ++static int pgp_process_signature(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct PGP_sig_parse_context *ctx = ++ container_of(context, struct PGP_sig_parse_context, pgp); ++ ++ ctx->found_sig = true; ++ return pgp_parse_sig_params(&data, &datalen, &ctx->params); ++} ++ ++/* ++ * Attempt to find a key to use for PGP signature verification, starting off by ++ * looking in the supplied keyring. ++ * ++ * The function may also look for other key sources such as a TPM. If an ++ * alternative key is found it can be added to the keyring for future ++ * reference. ++ */ ++static struct key *find_key_for_pgp_sig(struct key *keyring, ++ const u8 *sig, size_t siglen) ++{ ++ struct PGP_sig_parse_context p; ++ key_ref_t key; ++ char criterion[3 + 8 * 2 + 1]; ++ int ret; ++ ++ if (!keyring) ++ return ERR_PTR(-ENOKEY); ++ ++ /* Need to find the key ID */ ++ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); ++ p.pgp.process_packet = pgp_process_signature; ++ p.found_sig = false; ++ ret = pgp_parse_packets(sig, siglen, &p.pgp); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ if (!p.found_sig) ++ return ERR_PTR(-EINVAL); ++ ++ sprintf(criterion, "id:%08x%08x", ++ be32_to_cpu(p.params.issuer32[0]), ++ be32_to_cpu(p.params.issuer32[1])); ++ ++ pr_debug("Look up: %s\n", criterion); ++ ++ key = keyring_search(make_key_ref(keyring, 1), ++ &key_type_crypto, criterion); ++ if (IS_ERR(key)) ++ return ERR_CAST(key); ++ ++ pr_debug("Found key %x\n", key_serial(key_ref_to_ptr(key))); ++ return key_ref_to_ptr(key); ++} ++ ++/* ++ * Attempt to parse a signature as a PGP packet format blob and find a ++ * matching key. ++ */ ++struct crypto_key_verify_context *pgp_verify_sig_begin( ++ struct key *keyring, const u8 *sig, size_t siglen) ++{ ++ struct crypto_key_verify_context *ctx; ++ struct key *key; ++ ++ key = find_key_for_pgp_sig(keyring, sig, siglen); ++ if (IS_ERR(key)) ++ return ERR_CAST(key); ++ ++ /* We only handle in-kernel public key signatures for the moment */ ++ ctx = pgp_pkey_verify_sig_begin(key, sig, siglen); ++ key_put(key); ++ return ctx; ++} +-- +1.7.9.1 + + +From e25da6c545204746a8011dc27ce179816f715449 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:16 +0000 +Subject: KEYS: Provide a function to load keys from a PGP keyring blob + +Provide a function to load keys from a PGP keyring blob for use in initialising +the module signing key keyring: + + int load_PGP_keys(const u8 *pgpdata, size_t pgpdatalen, + struct key *keyring, const char *descprefix); + +The keys are labelled with descprefix plus a number to uniquify them. The keys +will actually be identified by the ID calculated from the PGP data rather than +by the description, so this shouldn't be a problem. + +The keys are attached to the keyring supplied. + +Looking as root in /proc/keys after the module signing keyring has been loaded: + +24460d1c I----- 1 perm 3f010000 0 0 crypto modsign.0: dsa 5acc2142 [] +3ca85723 I----- 1 perm 1f010000 0 0 keyring .module_sign: 1/4 + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + Documentation/security/keys-crypto.txt | 20 +++++++ + include/keys/crypto-type.h | 3 + + security/keys/Kconfig | 9 +++ + security/keys/Makefile | 1 + + security/keys/pgp_preload.c | 90 ++++++++++++++++++++++++++++++++ + 5 files changed, 123 insertions(+), 0 deletions(-) + create mode 100644 security/keys/pgp_preload.c + +diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt +index a964717..ba2ab55 100644 +--- a/Documentation/security/keys-crypto.txt ++++ b/Documentation/security/keys-crypto.txt +@@ -10,6 +10,7 @@ Contents: + - Signature verification. + - Implementing crypto parsers. + - Implementing crypto subtypes. ++ - Initial PGP key preloading. + + + ======== +@@ -280,3 +281,22 @@ There are a number of operations defined by the subtype: + Mandatory. This should free the memory associated with the key. The + crypto key will look after freeing the fingerprint and releasing the + reference on the subtype module. ++ ++ ++======================= ++INITIAL PGP KEY LOADING ++======================= ++ ++A function is provided to perform an initial load of a set of public keys bound ++into a PGP packet format blob: ++ ++ int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, ++ struct key *keyring, const char *descprefix); ++ ++This takes the blob of data defined by pgpdata and pgpdatalen, extracts keys ++from them and adds them to the specified keyring. The keys are labelled with ++descprefix plus a simple uniquifier - it is not expected that the description ++will be used to identify the key. The description is required to prevent all ++but the last key being discarded when the keys are linked into the keyring. ++ ++This function is only available during initial kernel set up. +diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h +index 6b93366..710e77f 100644 +--- a/include/keys/crypto-type.h ++++ b/include/keys/crypto-type.h +@@ -31,4 +31,7 @@ extern void verify_sig_cancel(struct crypto_key_verify_context *ctx); + * The payload is at the discretion of the subtype. + */ + ++extern __init int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, ++ struct key *keyring, const char *descprefix); ++ + #endif /* _KEYS_CRYPTO_TYPE_H */ +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index fd53028..5e77c2a 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -110,3 +110,12 @@ config CRYPTO_KEY_PGP_PARSER + This option provides support for parsing PGP (RFC 4880) format blobs + for key data and provides the ability to instantiate a crypto key + from a public key packet found inside the blob. ++ ++config PGP_PRELOAD ++ bool "PGP public key preloading facility" ++ select PGP_LIBRARY ++ select CRYPTO_KEY_PGP_PARSER ++ help ++ This option provides a facility for the kernel to preload PGP-wrapped ++ bundles of keys during boot. It is used by module signing to load ++ the module signing keys for example. +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 9aa48fe..5a43bdb 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o + obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o + obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o ++obj-$(CONFIG_PGP_PRELOAD) += pgp_preload.o + obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o + + crypto_keys-y := crypto_type.o crypto_verify.o +diff --git a/security/keys/pgp_preload.c b/security/keys/pgp_preload.c +new file mode 100644 +index 0000000..25154e3 +--- /dev/null ++++ b/security/keys/pgp_preload.c +@@ -0,0 +1,90 @@ ++/* Cryptographic key request handling ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#include <linux/module.h> ++#include <linux/key.h> ++#include <linux/pgp.h> ++#include "crypto_keys.h" ++ ++struct preload_pgp_keys_context { ++ struct pgp_parse_context pgp; ++ key_ref_t keyring; ++ char descbuf[20]; ++ u8 key_n; ++ u8 dsize; ++}; ++ ++/* ++ * Extract a public key or subkey from the PGP stream. ++ */ ++static int __init found_pgp_key(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, u8 headerlen, ++ const u8 *data, size_t datalen) ++{ ++ struct preload_pgp_keys_context *ctx = ++ container_of(context, struct preload_pgp_keys_context, pgp); ++ key_ref_t key; ++ ++ sprintf(ctx->descbuf + ctx->dsize, "%d", ctx->key_n++); ++ ++ key = key_create_or_update(ctx->keyring, "crypto", ctx->descbuf, ++ data - headerlen, datalen + headerlen, ++ KEY_POS_ALL | KEY_USR_VIEW, ++ KEY_ALLOC_NOT_IN_QUOTA); ++ ++ if (IS_ERR(key)) ++ return PTR_ERR(key); ++ ++ pr_notice("Loaded %s key: %s\n", ++ key_ref_to_ptr(key)->description, ++ crypto_key_id(key_ref_to_ptr(key))); ++ ++ key_ref_put(key); ++ return 0; ++} ++ ++/** ++ * preload_pgp_keys - Load keys from a PGP keyring blob ++ * @pgpdata: The PGP keyring blob containing the keys. ++ * @pgpdatalen: The size of the @pgpdata blob. ++ * @keyring: The keyring to add the new keys to. ++ * @descprefix: The key description prefix. ++ * ++ * Preload a pack of keys from a PGP keyring blob. ++ * ++ * The keys are given description of @descprefix + the number of the key in the ++ * list. Since keys can be matched on their key IDs independently of the key ++ * description, the description is mostly irrelevant apart from the fact that ++ * keys of the same description displace one another from a keyring. ++ * ++ * The caller should override the current creds if they want the keys to be ++ * owned by someone other than the current process's owner. Keys will not be ++ * accounted towards the owner's quota. ++ * ++ * This function may only be called whilst the kernel is booting. ++ */ ++int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, ++ struct key *keyring, const char *descprefix) ++{ ++ struct preload_pgp_keys_context ctx; ++ ++ ctx.pgp.types_of_interest = ++ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY); ++ ctx.pgp.process_packet = found_pgp_key; ++ ctx.keyring = make_key_ref(keyring, 1); ++ ctx.key_n = 0; ++ ctx.dsize = strlen(descprefix); ++ strcpy(ctx.descbuf, descprefix); ++ ++ return pgp_parse_packets(pgpdata, pgpdatalen, &ctx.pgp); ++} +-- +1.7.9.1 + + +From dad531381fad892fda776ddb354e1eb936b46b62 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:16 +0000 +Subject: MODSIGN: Add indications of module ELF types + +Add per-arch indications of module ELF types and relocation table entry types. + +Signed-Off-By: David Howells <dhowells@redhat.com> +--- + arch/alpha/include/asm/module.h | 3 +++ + arch/arm/include/asm/module.h | 5 +++++ + arch/cris/include/asm/module.h | 5 +++++ + arch/h8300/include/asm/module.h | 5 +++++ + arch/ia64/include/asm/module.h | 5 +++++ + arch/m32r/include/asm/module.h | 5 +++++ + arch/m68k/include/asm/module.h | 5 +++++ + arch/mips/include/asm/module.h | 12 ++++++++++-- + arch/parisc/include/asm/module.h | 8 ++++++++ + arch/powerpc/include/asm/module.h | 10 ++++++++++ + arch/s390/include/asm/module.h | 3 +++ + include/asm-generic/module.h | 10 ++++++++++ + 12 files changed, 74 insertions(+), 2 deletions(-) + +diff --git a/arch/alpha/include/asm/module.h b/arch/alpha/include/asm/module.h +index 7b63743..3d5a3ea 100644 +--- a/arch/alpha/include/asm/module.h ++++ b/arch/alpha/include/asm/module.h +@@ -6,6 +6,7 @@ struct mod_arch_specific + unsigned int gotsecindex; + }; + ++#define MODULES_ARE_ELF64 + #define Elf_Sym Elf64_Sym + #define Elf_Shdr Elf64_Shdr + #define Elf_Ehdr Elf64_Ehdr +@@ -13,6 +14,8 @@ struct mod_arch_specific + #define Elf_Dyn Elf64_Dyn + #define Elf_Rel Elf64_Rel + #define Elf_Rela Elf64_Rela ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) + + #define ARCH_SHF_SMALL SHF_ALPHA_GPREL + +diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h +index 6c6809f..f47d9cd 100644 +--- a/arch/arm/include/asm/module.h ++++ b/arch/arm/include/asm/module.h +@@ -1,9 +1,14 @@ + #ifndef _ASM_ARM_MODULE_H + #define _ASM_ARM_MODULE_H + ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + + struct unwind_table; + +diff --git a/arch/cris/include/asm/module.h b/arch/cris/include/asm/module.h +index 7ee7231..03f7b2e 100644 +--- a/arch/cris/include/asm/module.h ++++ b/arch/cris/include/asm/module.h +@@ -3,7 +3,12 @@ + /* cris is simple */ + struct mod_arch_specific { }; + ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + #endif /* _ASM_CRIS_MODULE_H */ +diff --git a/arch/h8300/include/asm/module.h b/arch/h8300/include/asm/module.h +index 8e46724..5140128 100644 +--- a/arch/h8300/include/asm/module.h ++++ b/arch/h8300/include/asm/module.h +@@ -4,8 +4,13 @@ + * This file contains the H8/300 architecture specific module code. + */ + struct mod_arch_specific { }; ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + + #endif /* _ASM_H8/300_MODULE_H */ +diff --git a/arch/ia64/include/asm/module.h b/arch/ia64/include/asm/module.h +index 908eaef..3c4cd94 100644 +--- a/arch/ia64/include/asm/module.h ++++ b/arch/ia64/include/asm/module.h +@@ -29,9 +29,14 @@ struct mod_arch_specific { + unsigned int next_got_entry; /* index of next available got entry */ + }; + ++#define MODULES_ARE_ELF64 + #define Elf_Shdr Elf64_Shdr + #define Elf_Sym Elf64_Sym + #define Elf_Ehdr Elf64_Ehdr ++#define Elf_Rel Elf64_Rel ++#define Elf_Rela Elf64_Rela ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) + + #define MODULE_PROC_FAMILY "ia64" + #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \ +diff --git a/arch/m32r/include/asm/module.h b/arch/m32r/include/asm/module.h +index eb73ee0..7146455 100644 +--- a/arch/m32r/include/asm/module.h ++++ b/arch/m32r/include/asm/module.h +@@ -3,8 +3,13 @@ + + struct mod_arch_specific { }; + ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + + #endif /* _ASM_M32R_MODULE_H */ +diff --git a/arch/m68k/include/asm/module.h b/arch/m68k/include/asm/module.h +index edffe66..9e2cd74 100644 +--- a/arch/m68k/include/asm/module.h ++++ b/arch/m68k/include/asm/module.h +@@ -36,8 +36,13 @@ struct module; + extern void module_fixup(struct module *mod, struct m68k_fixup_info *start, + struct m68k_fixup_info *end); + ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + + #endif /* _ASM_M68K_MODULE_H */ +diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h +index bc01a02..73c71a2 100644 +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -33,11 +33,15 @@ typedef struct { + } Elf64_Mips_Rela; + + #ifdef CONFIG_32BIT +- ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr + #define Elf_Addr Elf32_Addr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + + #define Elf_Mips_Rel Elf32_Rel + #define Elf_Mips_Rela Elf32_Rela +@@ -48,11 +52,15 @@ typedef struct { + #endif + + #ifdef CONFIG_64BIT +- ++#define MODULES_ARE_ELF64 + #define Elf_Shdr Elf64_Shdr + #define Elf_Sym Elf64_Sym + #define Elf_Ehdr Elf64_Ehdr + #define Elf_Addr Elf64_Addr ++#define Elf_Rel Elf64_Rel ++#define Elf_Rela Elf64_Rela ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) + + #define Elf_Mips_Rel Elf64_Mips_Rel + #define Elf_Mips_Rela Elf64_Mips_Rela +diff --git a/arch/parisc/include/asm/module.h b/arch/parisc/include/asm/module.h +index 1f41234..3e13f69 100644 +--- a/arch/parisc/include/asm/module.h ++++ b/arch/parisc/include/asm/module.h +@@ -4,17 +4,25 @@ + * This file contains the parisc architecture specific module code. + */ + #ifdef CONFIG_64BIT ++#define MODULES_ARE_ELF64 + #define Elf_Shdr Elf64_Shdr + #define Elf_Sym Elf64_Sym + #define Elf_Ehdr Elf64_Ehdr + #define Elf_Addr Elf64_Addr ++#define Elf_Rel Elf64_Rel + #define Elf_Rela Elf64_Rela ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) + #else ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr + #define Elf_Addr Elf32_Addr ++#define Elf_Rel Elf32_Rel + #define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + #endif + + struct unwind_table; +diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h +index 0192a4e..e949704 100644 +--- a/arch/powerpc/include/asm/module.h ++++ b/arch/powerpc/include/asm/module.h +@@ -60,16 +60,26 @@ struct mod_arch_specific { + */ + + #ifdef __powerpc64__ ++# define MODULES_ARE_ELF64 + # define Elf_Shdr Elf64_Shdr + # define Elf_Sym Elf64_Sym + # define Elf_Ehdr Elf64_Ehdr ++# define Elf_Rel Elf64_Rel ++# define Elf_Rela Elf64_Rela ++# define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++# define ELF_R_SYM(X) ELF64_R_SYM(X) + # ifdef MODULE + asm(".section .stubs,\"ax\",@nobits; .align 3; .previous"); + # endif + #else ++# define MODULES_ARE_ELF32 + # define Elf_Shdr Elf32_Shdr + # define Elf_Sym Elf32_Sym + # define Elf_Ehdr Elf32_Ehdr ++# define Elf_Rel Elf32_Rel ++# define Elf_Rela Elf32_Rela ++# define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++# define ELF_R_SYM(X) ELF32_R_SYM(X) + # ifdef MODULE + asm(".section .plt,\"ax\",@nobits; .align 3; .previous"); + asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous"); +diff --git a/arch/s390/include/asm/module.h b/arch/s390/include/asm/module.h +index 1cc1c5a..b64dab0 100644 +--- a/arch/s390/include/asm/module.h ++++ b/arch/s390/include/asm/module.h +@@ -29,14 +29,17 @@ struct mod_arch_specific + }; + + #ifdef __s390x__ ++#define MODULES_ARE_ELF64 + #define ElfW(x) Elf64_ ## x + #define ELFW(x) ELF64_ ## x + #else ++#define MODULES_ARE_ELF32 + #define ElfW(x) Elf32_ ## x + #define ELFW(x) ELF32_ ## x + #endif + + #define Elf_Addr ElfW(Addr) ++#define Elf_Rel ElfW(Rel) + #define Elf_Rela ElfW(Rela) + #define Elf_Shdr ElfW(Shdr) + #define Elf_Sym ElfW(Sym) +diff --git a/include/asm-generic/module.h b/include/asm-generic/module.h +index ed5b44d..e053617b 100644 +--- a/include/asm-generic/module.h ++++ b/include/asm-generic/module.h +@@ -10,13 +10,23 @@ struct mod_arch_specific + }; + + #ifdef CONFIG_64BIT ++#define MODULES_ARE_ELF64 + #define Elf_Shdr Elf64_Shdr + #define Elf_Sym Elf64_Sym + #define Elf_Ehdr Elf64_Ehdr ++#define Elf_Rel Elf64_Rel ++#define Elf_Rela Elf64_Rela ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) + #else ++#define MODULES_ARE_ELF32 + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + #endif + + #endif /* __ASM_GENERIC_MODULE_H */ +-- +1.7.9.1 + + + +From a66294fc859a6a9374a6d873d8a6ca3ec683538f Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:17 +0000 +Subject: MODSIGN: Module ELF verifier + +Do preliminary verification of the ELF structure of a module. This is used to +make sure that the ELF structure can then be used to check the module signature +and access the module data without breaking the module loader. + +If the module's ELF metadata is determined to be bad, then ELIBBAD will be +returned and a message will be logged to the kernel log. + +Signed-Off-By: David Howells <dhowells@redhat.com> + +Rebased-to-3.3-rc6: Josh Boyer <jwboyer@redhat.com> +--- + init/Kconfig | 11 ++ + kernel/Makefile | 2 + + kernel/module-verify-elf.c | 344 ++++++++++++++++++++++++++++++++++++++++++++ + kernel/module-verify.c | 41 ++++++ + kernel/module-verify.h | 53 +++++++ + kernel/module.c | 6 + + 6 files changed, 457 insertions(+), 0 deletions(-) + create mode 100644 kernel/module-verify-elf.c + create mode 100644 kernel/module-verify.c + create mode 100644 kernel/module-verify.h + +diff --git a/init/Kconfig b/init/Kconfig +index 3f42cd6..61b5f03 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1418,6 +1418,17 @@ config MODULE_SRCVERSION_ALL + the version). With this option, such a "srcversion" field + will be created for all modules. If unsure, say N. + ++config MODULE_VERIFY_ELF ++ bool "Module ELF structure verification" ++ depends on MODULES ++ help ++ Check ELF structure of modules upon load ++ ++config MODULE_VERIFY ++ bool ++ depends on MODULES ++ default y if MODULE_VERIFY_ELF ++ + endif # MODULES + + config INIT_ALL_POSSIBLE +diff --git a/kernel/Makefile b/kernel/Makefile +index 2d9de86..77b7a39 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -52,6 +52,8 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o + obj-$(CONFIG_PROVE_LOCKING) += spinlock.o + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += module.o ++obj-$(CONFIG_MODULE_VERIFY) += module-verify.o ++obj-$(CONFIG_MODULE_VERIFY_ELF) += module-verify-elf.o + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +diff --git a/kernel/module-verify-elf.c b/kernel/module-verify-elf.c +new file mode 100644 +index 0000000..4dea8d0 +--- /dev/null ++++ b/kernel/module-verify-elf.c +@@ -0,0 +1,344 @@ ++/* module-verify-elf.c: module ELF verifier ++ * ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/elf.h> ++#include <linux/ctype.h> ++#include "module-verify.h" ++ ++#if 0 ++#define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__) ++#else ++#define _debug(FMT, ...) do {} while (0) ++#endif ++ ++/* ++ * verify the ELF structure of a module ++ */ ++int module_verify_elf(struct module_verify_data *mvdata) ++{ ++ const struct elf_note *note; ++ const Elf_Ehdr *hdr = mvdata->hdr; ++ const Elf_Shdr *section, *section2, *secstop; ++ const Elf_Rela *relas, *rela, *relastop; ++ const Elf_Rel *rels, *rel, *relstop; ++ const Elf_Sym *symbol, *symstop; ++ const void *start, *p, *stop; ++ const char *q, *qs; ++ size_t size, sssize, *secsize, tmp, tmp2; ++ long last; ++ int line; ++ ++ size = mvdata->size; ++ mvdata->nsects = hdr->e_shnum; ++ ++#define elfcheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while(0) ++ ++#define seccheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while(0) ++ ++#define symcheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0) ++ ++#define relcheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto relcheck_error; } } while(0) ++ ++#define relacheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto relacheck_error; } } while(0) ++ ++#define notecheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto notecheck_error; } } while(0) ++ ++ /* validate the ELF header */ ++ elfcheck(hdr->e_ehsize < size); ++ /*elfcheck(hdr->e_entry == 0);*/ ++ elfcheck(hdr->e_phoff == 0); ++ elfcheck(hdr->e_phnum == 0); ++ ++ elfcheck(hdr->e_shnum < SHN_LORESERVE); ++ elfcheck(hdr->e_shoff < size); ++ elfcheck(hdr->e_shoff >= hdr->e_ehsize); ++ elfcheck((hdr->e_shoff & (sizeof(long) - 1)) == 0); ++ elfcheck(hdr->e_shstrndx > 0); ++ elfcheck(hdr->e_shstrndx < hdr->e_shnum); ++ elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr)); ++ ++ tmp = (size_t) hdr->e_shentsize * (size_t) hdr->e_shnum; ++ elfcheck(tmp <= size - hdr->e_shoff); ++ ++ /* allocate a table to hold in-file section sizes */ ++ mvdata->secsizes = kcalloc(hdr->e_shnum, sizeof(size_t), GFP_KERNEL); ++ if (!mvdata->secsizes) ++ return -ENOMEM; ++ ++ /* validate the ELF section headers */ ++ mvdata->sections = mvdata->buffer + hdr->e_shoff; ++ secstop = mvdata->sections + mvdata->nsects; ++ ++ sssize = mvdata->sections[hdr->e_shstrndx].sh_size; ++ elfcheck(sssize > 0); ++ ++ section = mvdata->sections; ++ seccheck(section->sh_type == SHT_NULL); ++ seccheck(section->sh_size == 0); ++ seccheck(section->sh_offset == 0); ++ ++ secsize = mvdata->secsizes + 1; ++ for (section++; section < secstop; secsize++, section++) { ++ seccheck(section->sh_name < sssize); ++ seccheck(section->sh_link < hdr->e_shnum); ++ ++ if (section->sh_entsize > 0) ++ seccheck(section->sh_size % section->sh_entsize == 0); ++ ++ seccheck(section->sh_offset >= hdr->e_ehsize); ++ seccheck(section->sh_offset < size); ++ ++ /* determine the section's in-file size */ ++ tmp = size - section->sh_offset; ++ if (section->sh_offset < hdr->e_shoff) ++ tmp = hdr->e_shoff - section->sh_offset; ++ ++ for (section2 = mvdata->sections + 1; ++ section2 < secstop; ++ section2++) { ++ if (section->sh_offset < section2->sh_offset) { ++ tmp2 = section2->sh_offset - ++ section->sh_offset; ++ if (tmp2 < tmp) ++ tmp = tmp2; ++ } ++ } ++ *secsize = tmp; ++ ++ _debug("Section %ld: %zx bytes at %lx\n", ++ section - mvdata->sections, ++ *secsize, ++ (unsigned long) section->sh_offset); ++ ++ /* perform section type specific checks */ ++ switch (section->sh_type) { ++ case SHT_NOBITS: ++ break; ++ ++ case SHT_REL: ++ seccheck(section->sh_entsize == sizeof(Elf_Rel)); ++ goto more_rel_checks; ++ ++ case SHT_RELA: ++ seccheck(section->sh_entsize == sizeof(Elf_Rela)); ++ more_rel_checks: ++ seccheck(section->sh_info > 0); ++ seccheck(section->sh_info < hdr->e_shnum); ++ goto more_sec_checks; ++ ++ case SHT_SYMTAB: ++ seccheck(section->sh_entsize == sizeof(Elf_Sym)); ++ goto more_sec_checks; ++ ++ default: ++ more_sec_checks: ++ /* most types of section must be contained entirely ++ * within the file */ ++ seccheck(section->sh_size <= *secsize); ++ break; ++ } ++ } ++ ++ /* validate the ELF section names */ ++ section = &mvdata->sections[hdr->e_shstrndx]; ++ ++ seccheck(section->sh_offset != hdr->e_shoff); ++ ++ mvdata->secstrings = mvdata->buffer + section->sh_offset; ++ ++ last = -1; ++ for (section = mvdata->sections + 1; section < secstop; section++) { ++ const char *secname; ++ tmp = sssize - section->sh_name; ++ secname = mvdata->secstrings + section->sh_name; ++ seccheck(secname[0] != 0); ++ if (section->sh_name > last) ++ last = section->sh_name; ++ } ++ ++ if (last > -1) { ++ tmp = sssize - last; ++ elfcheck(memchr(mvdata->secstrings + last, 0, tmp) != NULL); ++ } ++ ++ /* look for various sections in the module */ ++ for (section = mvdata->sections + 1; section < secstop; section++) { ++ switch (section->sh_type) { ++ case SHT_SYMTAB: ++ if (strcmp(mvdata->secstrings + section->sh_name, ++ ".symtab") == 0 ++ ) { ++ seccheck(mvdata->symbols == NULL); ++ mvdata->symbols = ++ mvdata->buffer + section->sh_offset; ++ mvdata->nsyms = ++ section->sh_size / sizeof(Elf_Sym); ++ seccheck(section->sh_size > 0); ++ } ++ break; ++ ++ case SHT_STRTAB: ++ if (strcmp(mvdata->secstrings + section->sh_name, ++ ".strtab") == 0 ++ ) { ++ seccheck(mvdata->strings == NULL); ++ mvdata->strings = ++ mvdata->buffer + section->sh_offset; ++ sssize = mvdata->nstrings = section->sh_size; ++ seccheck(section->sh_size > 0); ++ } ++ break; ++ } ++ } ++ ++ if (!mvdata->symbols) { ++ printk("Couldn't locate module symbol table\n"); ++ goto format_error; ++ } ++ ++ if (!mvdata->strings) { ++ printk("Couldn't locate module strings table\n"); ++ goto format_error; ++ } ++ ++ /* validate the symbol table */ ++ symstop = mvdata->symbols + mvdata->nsyms; ++ ++ symbol = mvdata->symbols; ++ symcheck(ELF_ST_TYPE(symbol[0].st_info) == STT_NOTYPE); ++ symcheck(symbol[0].st_shndx == SHN_UNDEF); ++ symcheck(symbol[0].st_value == 0); ++ symcheck(symbol[0].st_size == 0); ++ ++ last = -1; ++ for (symbol++; symbol < symstop; symbol++) { ++ symcheck(symbol->st_name < sssize); ++ if (symbol->st_name > last) ++ last = symbol->st_name; ++ symcheck(symbol->st_shndx < mvdata->nsects || ++ symbol->st_shndx >= SHN_LORESERVE); ++ } ++ ++ if (last > -1) { ++ tmp = sssize - last; ++ elfcheck(memchr(mvdata->strings + last, 0, tmp) != NULL); ++ } ++ ++ /* validate each relocation table and note list as best we can */ ++ for (section = mvdata->sections + 1; section < secstop; section++) { ++ section2 = mvdata->sections + section->sh_info; ++ start = mvdata->buffer + section->sh_offset; ++ stop = start + section->sh_size; ++ ++ switch (section->sh_type) { ++ case SHT_REL: ++ rels = start; ++ relstop = stop; ++ ++ for (rel = rels; rel < relstop; rel++) { ++ relcheck(rel->r_offset < section2->sh_size); ++ relcheck(ELF_R_SYM(rel->r_info) < ++ mvdata->nsyms); ++ } ++ ++ break; ++ ++ case SHT_RELA: ++ relas = start; ++ relastop = stop; ++ ++ for (rela = relas; rela < relastop; rela++) { ++ relacheck(rela->r_offset < section2->sh_size); ++ relacheck(ELF_R_SYM(rela->r_info) < ++ mvdata->nsyms); ++ } ++ ++ break; ++ ++ case SHT_NOTE: ++ p = start; ++ while (p < stop) { ++ note = p; ++ notecheck(stop - p >= sizeof(*note)); ++ p += sizeof(*note); ++ tmp = note->n_namesz; ++ if (tmp > 0) { ++ notecheck(stop - p >= tmp); ++ qs = p + tmp - 1; ++ notecheck(*qs == '\0'); ++ for (q = p; q < qs; q++) ++ notecheck(*q != '\0'); ++ tmp = roundup(tmp, 4); ++ notecheck(stop - p >= tmp); ++ p += tmp; ++ } ++ tmp = note->n_descsz; ++ if (tmp > 0) { ++ notecheck(stop - p >= tmp); ++ tmp = roundup(tmp, 4); ++ notecheck(stop - p >= tmp); ++ p += tmp; ++ } ++ } ++ seccheck(p == stop); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ _debug("ELF okay\n"); ++ return 0; ++ ++elfcheck_error: ++ printk("Verify ELF error (assertion %d)\n", line); ++ goto format_error; ++ ++seccheck_error: ++ printk("Verify ELF error [sec %ld] (assertion %d)\n", ++ (long)(section - mvdata->sections), line); ++ goto format_error; ++ ++symcheck_error: ++ printk("Verify ELF error [sym %ld] (assertion %d)\n", ++ (long)(symbol - mvdata->symbols), line); ++ goto format_error; ++ ++relcheck_error: ++ printk("Verify ELF error [sec %ld rel %ld] (assertion %d)\n", ++ (long)(section - mvdata->sections), ++ (long)(rel - rels), line); ++ goto format_error; ++ ++relacheck_error: ++ printk("Verify ELF error [sec %ld rela %ld] (assertion %d)\n", ++ (long)(section - mvdata->sections), ++ (long)(rela - relas), line); ++ goto format_error; ++ ++notecheck_error: ++ printk("Verify ELF error [sec %ld note %ld] (assertion %d)\n", ++ (long)(section - mvdata->sections), ++ (long)(p - start), line); ++ goto format_error; ++ ++format_error: ++ return -ELIBBAD; ++} +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +new file mode 100644 +index 0000000..875279f +--- /dev/null ++++ b/kernel/module-verify.c +@@ -0,0 +1,41 @@ ++/* module-verify.c: module verifier ++ * ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include "module-verify.h" ++ ++/* ++ * verify a module's integrity ++ * - check the ELF is viable ++ */ ++int module_verify(const Elf_Ehdr *hdr, size_t size) ++{ ++ struct module_verify_data mvdata; ++ int ret; ++ ++ memset(&mvdata, 0, sizeof(mvdata)); ++ mvdata.buffer = hdr; ++ mvdata.hdr = hdr; ++ mvdata.size = size; ++ ++ ret = module_verify_elf(&mvdata); ++ if (ret < 0) { ++ if (ret == -ELIBBAD) ++ printk("Module failed ELF checks\n"); ++ goto error; ++ } ++ ++error: ++ kfree(mvdata.secsizes); ++ kfree(mvdata.canonlist); ++ return ret; ++} +diff --git a/kernel/module-verify.h b/kernel/module-verify.h +new file mode 100644 +index 0000000..20884fc +--- /dev/null ++++ b/kernel/module-verify.h +@@ -0,0 +1,53 @@ ++/* module-verify.h: module verification definitions ++ * ++ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <linux/types.h> ++#include <asm/module.h> ++ ++#ifdef CONFIG_MODULE_VERIFY ++struct module_verify_data { ++ const void *buffer; /* module buffer */ ++ const Elf_Ehdr *hdr; /* ELF header */ ++ const Elf_Shdr *sections; /* ELF section table */ ++ const Elf_Sym *symbols; /* ELF symbol table */ ++ const char *secstrings; /* ELF section string table */ ++ const char *strings; /* ELF string table */ ++ size_t *secsizes; /* section size list */ ++ size_t size; /* module object size */ ++ size_t nsects; /* number of sections */ ++ size_t nsyms; /* number of symbols */ ++ size_t nstrings; /* size of strings section */ ++ size_t signed_size; /* count of bytes contributed to digest */ ++ int *canonlist; /* list of canonicalised sections */ ++ int *canonmap; /* section canonicalisation map */ ++ int ncanon; /* number of canonicalised sections */ ++ int sig_index; /* module signature section index */ ++ uint8_t xcsum; /* checksum of bytes contributed to digest */ ++ uint8_t csum; /* checksum of bytes representing a section */ ++}; ++ ++/* ++ * module-verify.c ++ */ ++extern int module_verify(const Elf_Ehdr *hdr, size_t size); ++ ++/* ++ * module-verify-elf.c ++ */ ++#ifdef CONFIG_MODULE_VERIFY_ELF ++extern int module_verify_elf(struct module_verify_data *mvdata); ++#else ++#define module_verify_elf(m) (0) ++#endif ++ ++#else ++#define module_verify(h, s) (0) ++#endif +diff --git a/kernel/module.c b/kernel/module.c +index 2c93276..54d6910 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -58,6 +58,7 @@ + #include <linux/jump_label.h> + #include <linux/pfn.h> + #include <linux/bsearch.h> ++#include "module-verify.h" + + #define CREATE_TRACE_POINTS + #include <trace/events/module.h> +@@ -2404,6 +2405,11 @@ static int copy_and_check(struct load_info *info, + goto free_hdr; + } + ++ /* Verify the module's contents */ ++ err = module_verify(hdr, len); ++ if (err < 0) ++ goto free_hdr; ++ + info->hdr = hdr; + info->len = len; + return 0; +-- +1.7.9.1 + + +From 1ecd333ad910d539e75f8f85d1fb1e3d87547c4e Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 7 Dec 2011 14:07:18 +0000 +Subject: MODSIGN: Apply signature checking to modules on module load + +Apply signature checking to modules on module load, checking the signature +against the ring of public keys compiled into the kernel (if enabled by +CONFIG_MODULE_SIG). Turning on signature checking will also force the module's +ELF metadata to be verified first. + +These patches have been in use by RHEL and Fedora kernels for years, and so +have been thoroughly tested. The signed modules survive both the debuginfo +separation performed by rpmbuild and the strip performed when modules are being +reduced as much as possible before being included in an initial ramdisk +composition. Signed modules have been tested to work with LE and BE, 32- and +64-bit arch kernels, including i386, x86_64, ppc64, ia64, s390 and s390x. + +There are several reasons why these patches are useful, amongst which are: + + (1) to protect against accidentally-corrupted modules causing damage; + + (2) to protect against maliciously modified modules causing damage; + + (3) to allow a sysadmin (or more likely an IT department) to enforce a policy + that only known and approved modules shall be loaded onto machines which + they're expected to support; + + (4) to allow other support providers to do likewise, or at least to _detect_ + the fact that unsupported modules are loaded; + + (5) to allow the detection of modules replaced by a second-order distro or a + preloaded Linux purveyor. + +These patches have two main appeals: (a) preventing malicious modules from +being loaded, and (b) reducing support workload by pointing out modules on a +crashing box that aren't what they're expected to be. + +Now, this is not a complete solution by any means: the core kernel is not +protected, and nor are /dev/mem or /dev/kmem, but it denies (or at least +controls) one relatively simple attack vector. + +This facility is optional: the builder of a kernel is by no means under any +requirement to actually enable it, let alone force the set of loadable modules +to be restricted to just those that the builder provides (there are degrees of +restriction available). + +Use of the module signing facility is documentated in: + + Documentation/module-signing.txt + +which I've included here for reference: + + ============================== + KERNEL MODULE SIGNING FACILITY + ============================== + +The module signing facilitiy applies cryptographic signature checking to +modules on module load, checking the signature against a ring of public keys +compiled into the kernel. GPG is used to do the cryptographic work and +determines the format of the signature and key data. The facility uses GPG's +MPI library to handle the huge numbers involved. + +This facility is enabled through CONFIG_MODULE_SIG. Turning on signature +checking will also force the module's ELF metadata to be verified before the +signature is checked. + +===================== +SUPPLYING PUBLIC KEYS +===================== + +A set of public keys must be supplied at main kernel compile time. This is +done by taking a GPG public key file, running it through the kernel's bin2c +program and writing the result over crypto/signature/key.h. To automate this +process, something like this could be done: + + cat >genkey <<EOF + %pubring kernel.pub + %secring kernel.sec + Key-Type: DSA + Key-Length: 512 + Name-Real: A. N. Other + Name-Comment: Kernel Module GPG key + %commit + EOF + make scripts/bin2c + gpg --homedir . --batch --gen-key genkey + +The above generates fresh keys using /dev/random. If there's insufficient data +in /dev/random, more can be provided more by running: + + rngd -r /dev/urandom + +in the background. + +Note: + + (1) That "keyname" is the name of the key in the keyring. This differentiates + it from any other keys that may be added to the keyring. + + (2) That no GPG password is used in the above scriptlet. + + (3) It may be desirable to shred and delete the private key file after signing + the modules. + +============== +MODULE SIGNING +============== + +Modules will then be signed automatically. The kernel make command line can +include the following options: + + (*) MODSECKEY=<secret-key-ring-path> + + This indicates the whereabouts of the GPG keyring that is the source of + the secret key to be used. The default is "./kernel.sec". + + (*) MODPUBKEY=<public-key-ring-path> + + This indicates the whereabouts of the GPG keyring that is the source of + the public key to be used. The default is "./kernel.pub". + + (*) MODKEYNAME=<key-name> + + The name of the key pair to be used from the aforementioned keyrings. + This defaults to being unset, thus leaving the choice of default key to + gpg. + + (*) KEYFLAGS="gpg-options" + + Override the complete gpg command line, including the preceding three + options. The default options supplied to gpg are: + + --no-default-keyring + --secret-keyring $(MODSECKEY) + --keyring $(MODPUBKEY) + --no-default-keyring + --homedir . + --no-options + --no-auto-check-trustdb + --no-permission-warning + + with: + + --default-key $(MODKEYNAME) + + being added if requested. + +The resulting module.ko file will be the signed module. + +======================== +STRIPPING SIGNED MODULES +======================== + +Signed modules may be safely stripped as the signature only covers those parts +of the module the kernel actually uses and any ELF metadata required to deal +with them. Any necessary ELF metadata that is affected by stripping is +canonicalised by the sig generator and the sig checker to hide strip effects. + +This permits the debuginfo to be detached from the module and placed in another +spot so that gdb can find it when referring to that module without the need for +multiple signed versions of the module. Such is done by rpmbuild when +producing RPMs. + +It also permits the module to be stripped as far as possible for when modules +are being reduced prior to being included in an initial ramdisk composition. + +====================== +LOADING SIGNED MODULES +====================== + +Modules are loaded with insmod, exactly as for unsigned modules. The signature +is inserted into the module object file as an ELF section called ".module_sig". +The signature checker will spot it and apply signature checking. + +========================================= +NON-VALID SIGNATURES AND UNSIGNED MODULES +========================================= + +If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on +the kernel command line, the kernel will _only_ load validly signed modules +for which it has a public key. Otherwise, it will also load modules that are +unsigned. Any module for which the kernel has a key, but which proves to have +a signature mismatch will not be permitted to load (returning EKEYREJECTED). + +This table indicates the behaviours of the various situations: + + MODULE STATE PERMISSIVE MODE ENFORCING MODE + =============================== =============== =============== + Unsigned Ok EKEYREJECTED + Signed, no public key ENOKEY ENOKEY + Validly signed, public key Ok Ok + Invalidly signed, public key EKEYREJECTED EKEYREJECTED + Validly signed, expired key EKEYEXPIRED EKEYEXPIRED + Corrupt signature ELIBBAD ELIBBAD + Corrupt ELF ELIBBAD ELIBBAD + +Signed-Off-By: David Howells <dhowells@redhat.com> + +Rebased-to-3.3-rc6-by: Josh Boyer <jwboyer@redhat.com> +--- + .gitignore | 15 + + Documentation/module-signing.txt | 186 ++++++++ + Makefile | 1 + + include/linux/elfnote.h | 4 + + include/linux/modsign.h | 27 ++ + include/linux/module.h | 3 + + init/Kconfig | 56 +++- + kernel/Makefile | 2 + + kernel/modsign-pubkey.c | 44 ++ + kernel/module-verify-sig.c | 526 ++++++++++++++++++++++ + kernel/module-verify.c | 5 +- + kernel/module-verify.h | 19 +- + kernel/module.c | 21 +- + scripts/Makefile.modpost | 85 ++++- + scripts/mod/.gitignore | 1 + + scripts/mod/Makefile | 2 +- + scripts/mod/mod-extract.c | 913 ++++++++++++++++++++++++++++++++++++++ + scripts/mod/modsign-note.sh | 16 + + 18 files changed, 1914 insertions(+), 12 deletions(-) + create mode 100644 Documentation/module-signing.txt + create mode 100644 include/linux/modsign.h + create mode 100644 kernel/modsign-pubkey.c + create mode 100644 kernel/module-verify-sig.c + create mode 100644 scripts/mod/mod-extract.c + create mode 100644 scripts/mod/modsign-note.sh + +diff --git a/.gitignore b/.gitignore +index 57af07c..841a17ee 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,6 +14,9 @@ + *.o.* + *.a + *.s ++*.ko.unsigned ++*.ko.digest ++*.ko.digest.sig + *.ko + *.so + *.so.dbg +@@ -84,3 +87,15 @@ GTAGS + *.orig + *~ + \#*# ++ ++# ++# GPG leavings from module signing ++# ++trustdb.gpg ++random_seed ++kernel.pub ++kernel.sec ++extract.pub ++secring.gpg ++pubring.gpg ++crypto/signature/key.h +diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt +new file mode 100644 +index 0000000..300b91a +--- /dev/null ++++ b/Documentation/module-signing.txt +@@ -0,0 +1,186 @@ ++ ============================== ++ KERNEL MODULE SIGNING FACILITY ++ ============================== ++ ++The module signing facility applies cryptographic signature checking to modules ++on module load, checking the signature against a ring of public keys compiled ++into the kernel. GPG is used to do the cryptographic work and determines the ++format of the signature and key data. The facility uses GPG's MPI library to ++handle the huge numbers involved. ++ ++This facility is enabled through CONFIG_MODULE_SIG. Turning on signature ++checking will also force the module's ELF metadata to be verified before the ++signature is checked. ++ ++The signature checker in the kernel is capable of handling multiple keys of ++either DSA or RSA type, and can support any of MD5, RIPE-MD-160, SHA-1, ++SHA-224, SHA-256, SHA-384 and SHA-512 hashes - PROVIDED(!) the requisite ++algorithms are compiled into the kernel. ++ ++(!) NOTE: Modules may only be verified initially with algorithms compiled into ++the kernel. Further algorithm modules may be loaded and used - but these must ++first pass a verification step using already loaded/compiled-in algorithms. ++ ++ ++===================== ++SUPPLYING PUBLIC KEYS ++===================== ++ ++A set of public keys must be supplied at kernel image build time. This is done ++by taking a GPG public key file and placing it in the base of the kernel ++directory in a file called kernel.pub. ++ ++For example, a throwaway key could be generated automatically by something like ++the following: ++ ++ cat >genkey <<EOF ++ %pubring kernel.pub ++ %secring kernel.sec ++ Key-Type: DSA ++ Key-Length: 512 ++ Name-Real: A. N. Other ++ Name-Comment: Kernel Module GPG key ++ %commit ++ EOF ++ gpg --homedir . --batch --gen-key genkey ++ ++The above generates fresh keys using /dev/random. If there's insufficient data ++in /dev/random, more can be provided more by running: ++ ++ rngd -r /dev/urandom ++ ++in the background. ++ ++Note that no GPG password is used in the above scriptlet. ++ ++The kernel.pub file is compiled into the kernel directly by the assembler by ++means of an ".incbin" directive in kernel/modsign-pubkey.c. ++ ++Once the kernel is running, the keys are visible to root as kernel crypto keys ++in /proc/keys in a keyring called .module_sign: ++ ++335ab517 I----- 1 perm 1f030000 0 0 keyring .module_sign: 2/4 ++38d7d169 I----- 1 perm 3f010000 0 0 crypto modsign.0: rsa 57532ca5 [] ++195fa736 I----- 1 perm 3f010000 0 0 crypto modsign.1: dsa 5acc2142 [] ++ ++This keyring can be listed with the keyctl program. See: ++ ++ Documentation/security/keys-crypto.txt ++ ++for more information of crypto keys. ++ ++ ++============================ ++SELECTING THE HASH ALGORITHM ++============================ ++ ++The hash algorithm to be used is selected by a multiple choice configuration ++item that enables one of the following variables: ++ ++ CONFIG_SIG_SHA1 ++ CONFIG_SIG_SHA224 ++ CONFIG_SIG_SHA256 ++ CONFIG_SIG_SHA384 ++ CONFIG_SIG_SHA512 ++ ++These cause an appropriate "--digest-algo=" parameter to be passed to gpg when ++signing a module and force the appropriate hash algorithm to be compiled ++directly into the kernel rather than being built as a module. ++ ++ ++============== ++MODULE SIGNING ++============== ++ ++Modules will then be signed automatically. The kernel make command line can ++include the following options: ++ ++ (*) MODSECKEY=<secret-key-ring-path> ++ ++ This indicates the whereabouts of the GPG keyring that is the source of ++ the secret key to be used. The default is "./kernel.sec". ++ ++ (*) MODPUBKEY=<public-key-ring-path> ++ ++ This indicates the whereabouts of the GPG keyring that is the source of ++ the public key to be used. The default is "./kernel.pub". ++ ++ (*) MODKEYNAME=<key-name> ++ ++ The name of the key pair to be used from the aforementioned keyrings. ++ This defaults to being unset, thus leaving the choice of default key to ++ gpg. ++ ++ (*) KEYFLAGS="gpg-options" ++ ++ Override the complete gpg command line, including the preceding three ++ options. The default options supplied to gpg are: ++ ++ --no-default-keyring ++ --secret-keyring $(MODSECKEY) ++ --keyring $(MODPUBKEY) ++ --no-default-keyring ++ --homedir . ++ --no-options ++ --no-auto-check-trustdb ++ --no-permission-warning ++ --digest-algo=<hash-algorithm> ++ ++ with: ++ ++ --default-key $(MODKEYNAME) ++ ++ being added if requested. ++ ++The resulting module.ko file will be the signed module. ++ ++ ++======================== ++STRIPPING SIGNED MODULES ++======================== ++ ++Signed modules may be safely stripped as the signature only covers those parts ++of the module the kernel actually uses and any ELF metadata required to deal ++with them. Any necessary ELF metadata that is affected by stripping is ++canonicalised by the sig generator and the sig checker to hide strip effects. ++ ++This permits the debuginfo to be detached from the module and placed in another ++spot so that gdb can find it when referring to that module without the need for ++multiple signed versions of the module. Such is done by rpmbuild when ++producing RPMs. ++ ++It also permits the module to be stripped as far as possible for when modules ++are being reduced prior to being included in an initial ramdisk composition. ++ ++ ++====================== ++LOADING SIGNED MODULES ++====================== ++ ++Modules are loaded with insmod, exactly as for unsigned modules. The signature ++is inserted into the module object file as an ELF section called ".module_sig". ++The signature checker will detect it and apply signature checking. ++ ++ ++========================================= ++NON-VALID SIGNATURES AND UNSIGNED MODULES ++========================================= ++ ++If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on ++the kernel command line, the kernel will _only_ load validly signed modules ++for which it has a public key. Otherwise, it will also load modules that are ++unsigned. Any module for which the kernel has a key, but which proves to have ++a signature mismatch will not be permitted to load (returning EKEYREJECTED). ++ ++This table indicates the behaviours of the various situations: ++ ++ MODULE STATE PERMISSIVE MODE ENFORCING MODE ++ ======================================= =============== =============== ++ Unsigned Ok EKEYREJECTED ++ Signed, no public key ENOKEY ENOKEY ++ Validly signed, public key Ok Ok ++ Invalidly signed, public key EKEYREJECTED EKEYREJECTED ++ Validly signed, expired key EKEYEXPIRED EKEYEXPIRED ++ Signed, hash algorithm unavailable ENOPKG ENOPKG ++ Corrupt signature EBADMSG EBADMSG ++ Corrupt ELF ELIBBAD ELIBBAD +diff --git a/Makefile b/Makefile +index 66d13c9..8ba824f 100644 +--- a/Makefile ++++ b/Makefile +@@ -1407,6 +1407,7 @@ clean: $(clean-dirs) + $(call cmd,rmfiles) + @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ + \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ ++ -o -name '*.ko.*' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ + -o -name '*.symtypes' -o -name 'modules.order' \ + -o -name modules.builtin -o -name '.tmp_*.o.*' \ +diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h +index 278e3ef..949d494 100644 +--- a/include/linux/elfnote.h ++++ b/include/linux/elfnote.h +@@ -58,6 +58,7 @@ + ELFNOTE_END + + #else /* !__ASSEMBLER__ */ ++#include <linux/stringify.h> + #include <linux/elf.h> + /* + * Use an anonymous structure which matches the shape of +@@ -93,6 +94,9 @@ + + #define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc) + #define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc) ++ ++#define ELFNOTE_NAME(name) __stringify(name) ++#define ELFNOTE_SECTION(name) ".note."ELFNOTE_NAME(name) + #endif /* __ASSEMBLER__ */ + + #endif /* _LINUX_ELFNOTE_H */ +diff --git a/include/linux/modsign.h b/include/linux/modsign.h +new file mode 100644 +index 0000000..c5ac87a +--- /dev/null ++++ b/include/linux/modsign.h +@@ -0,0 +1,27 @@ ++/* Module signing definitions ++ * ++ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_MODSIGN_H ++#define _LINUX_MODSIGN_H ++ ++#ifdef CONFIG_MODULE_SIG ++ ++#include <linux/elfnote.h> ++ ++/* ++ * The parameters of the ELF note used to carry the signature ++ */ ++#define MODSIGN_NOTE_NAME module.sig ++#define MODSIGN_NOTE_TYPE 100 ++ ++#endif ++ ++#endif /* _LINUX_MODSIGN_H */ +diff --git a/include/linux/module.h b/include/linux/module.h +index 4598bf0..2bd03f1 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -294,6 +294,9 @@ struct module + + unsigned int taints; /* same bits as kernel:tainted */ + ++ /* Is this module GPG signed */ ++ int gpgsig_ok; ++ + #ifdef CONFIG_GENERIC_BUG + /* Support for BUG */ + unsigned num_bugs; +diff --git a/init/Kconfig b/init/Kconfig +index 61b5f03..b21dcae 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1424,10 +1424,64 @@ config MODULE_VERIFY_ELF + help + Check ELF structure of modules upon load + ++config MODULE_SIG ++ bool "Module signature verification (EXPERIMENTAL)" ++ depends on MODULES && EXPERIMENTAL ++ select CRYPTO_KEY_TYPE ++ select CRYPTO_KEY_PKEY_ALGO_DSA ++ select CRYPTO_KEY_PKEY_ALGO_RSA ++ select PGP_PARSER ++ select PGP_PRELOAD ++ select MODULE_VERIFY_ELF ++ help ++ Check modules for valid signatures upon load. For more information ++ see: ++ ++ Documentation/module-signing.txt ++ ++choice ++ prompt "Which hash algorithm should modules be signed with?" ++ depends on MODULE_SIG ++ help ++ This determines which sort of hashing algorithm will be used during ++ signature generation. This algorithm _must_ be built into the kernel ++ directly so that signature verification can take place. It is not ++ possible to load a signed module containing the algorithm to check ++ the signature on that module. ++ ++config MODULE_SIG_SHA1 ++ bool "Sign modules with SHA-1" ++ select CRYPTO_SHA1 ++ ++config MODULE_SIG_SHA224 ++ bool "Sign modules with SHA-224" ++ select CRYPTO_SHA224 ++ ++config MODULE_SIG_SHA256 ++ bool "Sign modules with SHA-256" ++ select CRYPTO_SHA256 ++ ++config MODULE_SIG_SHA384 ++ bool "Sign modules with SHA-384" ++ select CRYPTO_SHA384 ++ ++config MODULE_SIG_SHA512 ++ bool "Sign modules with SHA-512" ++ select CRYPTO_SHA512 ++ ++endchoice ++ ++config MODULE_SIG_FORCE ++ bool "Required modules to be validly signed (EXPERIMENTAL)" ++ depends on MODULE_SIG ++ help ++ Reject unsigned modules or signed modules for which we don't have a ++ key. ++ + config MODULE_VERIFY + bool + depends on MODULES +- default y if MODULE_VERIFY_ELF ++ default y if MODULE_VERIFY_ELF || MODULE_SIG + + endif # MODULES + +diff --git a/kernel/Makefile b/kernel/Makefile +index 77b7a39..9732e11 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -54,6 +54,8 @@ obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += module.o + obj-$(CONFIG_MODULE_VERIFY) += module-verify.o + obj-$(CONFIG_MODULE_VERIFY_ELF) += module-verify-elf.o ++obj-$(CONFIG_MODULE_SIG) += module-verify-sig.o modsign-pubkey.o ++kernel/modsign-pubkey.o: kernel.pub + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +diff --git a/kernel/modsign-pubkey.c b/kernel/modsign-pubkey.c +new file mode 100644 +index 0000000..df55565 +--- /dev/null ++++ b/kernel/modsign-pubkey.c +@@ -0,0 +1,44 @@ ++/* Public keys for module signature verification ++ * ++ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <keys/crypto-type.h> ++#include "module-verify.h" ++ ++extern __initdata const u8 modsign_public_keys[]; ++extern __initdata const u8 modsign_public_keys_end[]; ++asm(".section .init.data,\"aw\"\n" ++ "modsign_public_keys:\n" ++ ".incbin \"kernel.pub\"\n" ++ "modsign_public_keys_end:" ++ ); ++ ++/* ++ * We need to make sure ccache doesn't cache the .o file as it doesn't notice ++ * if kernel.pub changes. ++ */ ++static __initdata const char annoy_ccache[] = __TIME__ "foo"; ++ ++/* ++ * Load the compiled-in keys ++ */ ++static __init int modsign_pubkey_init(void) ++{ ++ pr_notice("Load module verification keys\n"); ++ ++ if (preload_pgp_keys(modsign_public_keys, ++ modsign_public_keys_end - modsign_public_keys, ++ modsign_keyring, "modsign.") < 0) ++ panic("Can't load module signing keys\n"); ++ ++ return 0; ++} ++late_initcall(modsign_pubkey_init); +diff --git a/kernel/module-verify-sig.c b/kernel/module-verify-sig.c +new file mode 100644 +index 0000000..ced5681 +--- /dev/null ++++ b/kernel/module-verify-sig.c +@@ -0,0 +1,526 @@ ++/* Module signature checker ++ * ++ * Copyright (C) 2004,2011 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * - Derived from GregKH's RSA module signer ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/elf.h> ++#include <linux/sched.h> ++#include <linux/cred.h> ++#include <linux/modsign.h> ++#include <keys/keyring-type.h> ++#include "module-verify.h" ++ ++#undef MODSIGN_DEBUG ++ ++struct key *modsign_keyring; ++ ++int modsign_debug; ++core_param(modsign_debug, modsign_debug, bool, 0644); ++ ++#define _debug(FMT, ...) \ ++ do { \ ++ if (unlikely(modsign_debug)) \ ++ pr_debug(FMT, ##__VA_ARGS__); \ ++ } while(0) ++ ++#ifdef MODSIGN_DEBUG ++#define count_and_csum(C, __p, __n) \ ++do { \ ++ int __loop; \ ++ for (__loop = 0; __loop < __n; __loop++) { \ ++ (C)->csum += __p[__loop]; \ ++ (C)->xcsum += __p[__loop]; \ ++ } \ ++ (C)->signed_size += __n; \ ++} while (0) ++#else ++#define count_and_csum(C, __p, __n) \ ++do { \ ++ (C)->signed_size += __n; \ ++} while (0) ++#endif ++ ++#define crypto_digest_update_data(C, PTR, N) \ ++do { \ ++ uint8_t *__p = (uint8_t *)(PTR); \ ++ size_t __n = (N); \ ++ count_and_csum((C), __p, __n); \ ++ verify_sig_add_data((C)->mod_sig, __p, __n); \ ++} while (0) ++ ++#define crypto_digest_update_val(C, VAL) \ ++do { \ ++ uint8_t *__p = (uint8_t *)&(VAL); \ ++ size_t __n = sizeof(VAL); \ ++ count_and_csum((C), __p, __n); \ ++ verify_sig_add_data((C)->mod_sig, __p, __n); \ ++} while (0) ++ ++static int module_verify_canonicalise(struct module_verify_data *mvdata); ++ ++static int extract_elf_rela(struct module_verify_data *mvdata, ++ int secix, ++ const Elf_Rela *relatab, size_t nrels, ++ const char *sh_name); ++ ++static int extract_elf_rel(struct module_verify_data *mvdata, ++ int secix, ++ const Elf_Rel *reltab, size_t nrels, ++ const char *sh_name); ++ ++#ifdef CONFIG_MODULE_SIG_FORCE ++static int signedonly = 1; ++#else ++static int signedonly; ++#endif ++ ++static int __init sign_setup(char *str) ++{ ++ signedonly = 1; ++ return 0; ++} ++__setup("enforcemodulesig", sign_setup); ++ ++static const char modsign_note_name[] = ELFNOTE_NAME(MODSIGN_NOTE_NAME); ++static const char modsign_note_section[] = ELFNOTE_SECTION(MODSIGN_NOTE_NAME); ++ ++/* ++ * verify a module's signature ++ */ ++int module_verify_signature(struct module_verify_data *mvdata, ++ int *_gpgsig_ok) ++{ ++ struct crypto_key_verify_context *mod_sig; ++ const struct elf_note *note; ++ const Elf_Shdr *sechdrs = mvdata->sections; ++ const char *secstrings = mvdata->secstrings; ++ const char *sig; ++ unsigned note_size, sig_size, note_namesz; ++ int loop, ret; ++ ++ _debug("looking for sig section '%s'\n", modsign_note_section); ++ ++ for (loop = 1; loop < mvdata->nsects; loop++) { ++ switch (sechdrs[loop].sh_type) { ++ case SHT_NOTE: ++ if (strcmp(mvdata->secstrings + sechdrs[loop].sh_name, ++ modsign_note_section) == 0) ++ mvdata->sig_index = loop; ++ break; ++ } ++ } ++ ++ if (mvdata->sig_index <= 0) ++ goto no_signature; ++ ++ note = mvdata->buffer + sechdrs[mvdata->sig_index].sh_offset; ++ note_size = sechdrs[mvdata->sig_index].sh_size; ++ ++ /* there should be one note of the appropriate type */ ++ if (note_size < sizeof(*note) + 2 * 4) ++ goto format_error_no_free; ++ note_namesz = note->n_namesz; ++ sig_size = note->n_descsz; ++ if (note_namesz != sizeof(modsign_note_name)) ++ goto format_error_no_free; ++ if (note->n_type != MODSIGN_NOTE_TYPE) ++ goto format_error_no_free; ++ if (memcmp(note + 1, modsign_note_name, note_namesz) != 0) ++ goto format_error_no_free; ++ sig = (void *)(note + 1) + roundup(note_namesz, 4); ++ ++ _debug("sig in section %d (size %d)\n", ++ mvdata->sig_index, sig_size); ++ _debug("%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ sig[0], sig[1], sig[2], sig[3], ++ sig[4], sig[5], sig[6], sig[7]); ++ ++ /* produce a canonicalisation map for the sections */ ++ ret = module_verify_canonicalise(mvdata); ++ if (ret < 0) ++ return ret; ++ ++ /* Find the crypto key for the module signature ++ * - !!! if this tries to load the required hash algorithm module, ++ * we will deadlock!!! ++ */ ++ mod_sig = verify_sig_begin(modsign_keyring, sig, sig_size); ++ if (IS_ERR(mod_sig)) { ++ pr_err("Couldn't initiate module signature verification: %ld\n", ++ PTR_ERR(mod_sig)); ++ return PTR_ERR(mod_sig); ++ } ++ ++ mvdata->mod_sig = mod_sig; ++ ++#ifdef MODSIGN_DEBUG ++ mvdata->xcsum = 0; ++#endif ++ ++ /* load data from each relevant section into the digest */ ++ for (loop = 0; loop < mvdata->ncanon; loop++) { ++ int sect = mvdata->canonlist[loop]; ++ unsigned long sh_type = sechdrs[sect].sh_type; ++ unsigned long sh_info = sechdrs[sect].sh_info; ++ unsigned long sh_size = sechdrs[sect].sh_size; ++ unsigned long sh_flags = sechdrs[sect].sh_flags; ++ const char *sh_name = secstrings + sechdrs[sect].sh_name; ++ const void *data = mvdata->buffer + sechdrs[sect].sh_offset; ++ ++#ifdef MODSIGN_DEBUG ++ mvdata->csum = 0; ++#endif ++ ++ /* it would be nice to include relocation sections, but the act ++ * of adding a signature to the module seems changes their ++ * contents, because the symtab gets changed when sections are ++ * added or removed */ ++ if (sh_type == SHT_REL || sh_type == SHT_RELA) { ++ uint32_t xsh_info = mvdata->canonmap[sh_info]; ++ ++ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); ++ crypto_digest_update_val(mvdata, xsh_info); ++ ++ if (sh_type == SHT_RELA) ++ ret = extract_elf_rela( ++ mvdata, sect, ++ data, ++ sh_size / sizeof(Elf_Rela), ++ sh_name); ++ else ++ ret = extract_elf_rel( ++ mvdata, sect, ++ data, ++ sh_size / sizeof(Elf_Rel), ++ sh_name); ++ ++ if (ret < 0) ++ goto format_error; ++ continue; ++ } ++ ++ /* include the headers of BSS sections */ ++ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { ++ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); ++ goto digested; ++ } ++ ++ /* include allocatable loadable sections */ ++ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) ++ goto include_section; ++ ++ continue; ++ ++ include_section: ++ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); ++ ++ crypto_digest_update_data(mvdata, data, sh_size); ++ ++ digested: ++ _debug("%08zx %02x digested the %s section, size %ld\n", ++ mvdata->signed_size, mvdata->csum, sh_name, sh_size); ++ } ++ ++ _debug("Contributed %zu bytes to the digest (csum 0x%02x)\n", ++ mvdata->signed_size, mvdata->xcsum); ++ ++ /* do the actual signature verification */ ++ ret = verify_sig_end(mvdata->mod_sig, sig, sig_size); ++ mvdata->mod_sig = NULL; ++ ++ _debug("verify-sig : %d\n", ret); ++ ++ switch (ret) { ++ case 0: /* good signature */ ++ *_gpgsig_ok = 1; ++ break; ++ case -EKEYREJECTED: /* signature mismatch or number format error */ ++ pr_err("Module signature verification failed\n"); ++ break; ++ case -ENOKEY: /* signed, but we don't have the public key */ ++ pr_err("Module signed with unknown public key\n"); ++ break; ++ default: /* other error (probably ENOMEM) */ ++ break; ++ } ++ ++ return ret; ++ ++format_error: ++ verify_sig_cancel(mvdata->mod_sig); ++ mvdata->mod_sig = NULL; ++format_error_no_free: ++ pr_err("Module format error encountered\n"); ++ return -ELIBBAD; ++ ++ /* deal with the case of an unsigned module */ ++no_signature: ++ _debug("no signature found\n"); ++ if (!signedonly) ++ return 0; ++ pr_err("An attempt to load unsigned module was rejected\n"); ++ return -EKEYREJECTED; ++} ++ ++/* ++ * canonicalise the section table index numbers ++ */ ++static int module_verify_canonicalise(struct module_verify_data *mvdata) ++{ ++ int canon, loop, changed, tmp; ++ ++ /* produce a list of index numbers of sections that contribute ++ * to the kernel's module image ++ */ ++ mvdata->canonlist = ++ kmalloc(sizeof(int) * mvdata->nsects * 2, GFP_KERNEL); ++ if (!mvdata->canonlist) ++ return -ENOMEM; ++ ++ mvdata->canonmap = mvdata->canonlist + mvdata->nsects; ++ canon = 0; ++ ++ for (loop = 1; loop < mvdata->nsects; loop++) { ++ const Elf_Shdr *section = mvdata->sections + loop; ++ ++ if (loop == mvdata->sig_index) ++ continue; ++ ++ /* we only need to canonicalise allocatable sections */ ++ if (section->sh_flags & SHF_ALLOC) ++ mvdata->canonlist[canon++] = loop; ++ else if ((section->sh_type == SHT_REL || ++ section->sh_type == SHT_RELA) && ++ mvdata->sections[section->sh_info].sh_flags & SHF_ALLOC) ++ mvdata->canonlist[canon++] = loop; ++ } ++ ++ /* canonicalise the index numbers of the contributing section */ ++ do { ++ changed = 0; ++ ++ for (loop = 0; loop < canon - 1; loop++) { ++ const char *x, *y; ++ ++ x = mvdata->secstrings + ++ mvdata->sections[mvdata->canonlist[loop + 0]].sh_name; ++ y = mvdata->secstrings + ++ mvdata->sections[mvdata->canonlist[loop + 1]].sh_name; ++ ++ if (strcmp(x, y) > 0) { ++ tmp = mvdata->canonlist[loop + 0]; ++ mvdata->canonlist[loop + 0] = ++ mvdata->canonlist[loop + 1]; ++ mvdata->canonlist[loop + 1] = tmp; ++ changed = 1; ++ } ++ } ++ ++ } while (changed); ++ ++ for (loop = 0; loop < canon; loop++) ++ mvdata->canonmap[mvdata->canonlist[loop]] = loop + 1; ++ mvdata->ncanon = canon; ++ return 0; ++} ++ ++/* ++ * extract an ELF RELA table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static int extract_elf_rela(struct module_verify_data *mvdata, ++ int secix, ++ const Elf_Rela *relatab, size_t nrels, ++ const char *sh_name) ++{ ++ struct { ++#if defined(MODULES_ARE_ELF32) ++ uint32_t r_offset; ++ uint32_t r_addend; ++ uint32_t st_value; ++ uint32_t st_size; ++ uint16_t st_shndx; ++ uint8_t r_type; ++ uint8_t st_info; ++ uint8_t st_other; ++#elif defined(MODULES_ARE_ELF64) ++ uint64_t r_offset; ++ uint64_t r_addend; ++ uint64_t st_value; ++ uint64_t st_size; ++ uint32_t r_type; ++ uint16_t st_shndx; ++ uint8_t st_info; ++ uint8_t st_other; ++#else ++#error unsupported module type ++#endif ++ } __attribute__((packed)) relocation; ++ ++ const Elf_Rela *reloc; ++ const Elf_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ int st_shndx; ++ ++ reloc = &relatab[loop]; ++ ++ /* decode the relocation */ ++ relocation.r_offset = reloc->r_offset; ++ relocation.r_addend = reloc->r_addend; ++ relocation.r_type = ELF_R_TYPE(reloc->r_info); ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = symbol->st_shndx; ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects) ++ relocation.st_shndx = mvdata->canonmap[st_shndx]; ++ ++ crypto_digest_update_val(mvdata, relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = mvdata->strings + symbol->st_name; ++ crypto_digest_update_data(mvdata, ++ name, strlen(name) + 1); ++ } ++ } ++ ++ _debug("%08zx %02x digested the %s section, nrels %zu\n", ++ mvdata->signed_size, mvdata->csum, sh_name, nrels); ++ ++ return 0; ++} ++ ++/* ++ * extract an ELF REL table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static int extract_elf_rel(struct module_verify_data *mvdata, ++ int secix, ++ const Elf_Rel *reltab, size_t nrels, ++ const char *sh_name) ++{ ++ struct { ++#if defined(MODULES_ARE_ELF32) ++ uint32_t r_offset; ++ uint32_t st_value; ++ uint32_t st_size; ++ uint16_t st_shndx; ++ uint8_t r_type; ++ uint8_t st_info; ++ uint8_t st_other; ++#elif defined(MODULES_ARE_ELF64) ++ uint64_t r_offset; ++ uint64_t st_value; ++ uint64_t st_size; ++ uint32_t r_type; ++ uint16_t st_shndx; ++ uint8_t st_info; ++ uint8_t st_other; ++#else ++#error unsupported module type ++#endif ++ } __attribute__((packed)) relocation; ++ ++ const Elf_Rel *reloc; ++ const Elf_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ int st_shndx; ++ ++ reloc = &reltab[loop]; ++ ++ /* decode the relocation */ ++ relocation.r_offset = reloc->r_offset; ++ relocation.r_type = ELF_R_TYPE(reloc->r_info); ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = symbol->st_shndx; ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects) ++ relocation.st_shndx = mvdata->canonmap[st_shndx]; ++ ++ crypto_digest_update_val(mvdata, relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = mvdata->strings + symbol->st_name; ++ crypto_digest_update_data(mvdata, ++ name, strlen(name) + 1); ++ } ++ } ++ ++ _debug("%08zx %02x digested the %s section, nrels %zu\n", ++ mvdata->signed_size, mvdata->csum, sh_name, nrels); ++ ++ return 0; ++} ++ ++/* ++ * Load the compiled-in keys ++ */ ++static __init int module_verify_init(void) ++{ ++ pr_notice("Initialise module verification\n"); ++ ++ modsign_keyring = key_alloc(&key_type_keyring, ".module_sign", ++ 0, 0, current_cred(), ++ (KEY_POS_ALL & ~KEY_POS_SETATTR) | ++ KEY_USR_VIEW | KEY_USR_READ, ++ KEY_ALLOC_NOT_IN_QUOTA); ++ if (IS_ERR(modsign_keyring)) ++ panic("Can't allocate module signing keyring\n"); ++ ++ if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0) ++ panic("Can't instantiate module signing keyring\n"); ++ ++ return 0; ++} ++ ++/* ++ * Must be initialised before we try and load the keys into the keyring. ++ */ ++device_initcall(module_verify_init); +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 875279f..64c5813 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -16,8 +16,9 @@ + /* + * verify a module's integrity + * - check the ELF is viable ++ * - check the module's signature + */ +-int module_verify(const Elf_Ehdr *hdr, size_t size) ++int module_verify(const Elf_Ehdr *hdr, size_t size, int *_gpgsig_ok) + { + struct module_verify_data mvdata; + int ret; +@@ -34,6 +35,8 @@ int module_verify(const Elf_Ehdr *hdr, size_t size) + goto error; + } + ++ ret = module_verify_signature(&mvdata, _gpgsig_ok); ++ + error: + kfree(mvdata.secsizes); + kfree(mvdata.canonlist); +diff --git a/kernel/module-verify.h b/kernel/module-verify.h +index 20884fc..0ccdb71 100644 +--- a/kernel/module-verify.h ++++ b/kernel/module-verify.h +@@ -10,10 +10,13 @@ + */ + + #include <linux/types.h> ++#include <linux/elf.h> ++#include <keys/crypto-type.h> + #include <asm/module.h> + + #ifdef CONFIG_MODULE_VERIFY + struct module_verify_data { ++ struct crypto_key_verify_context *mod_sig; /* Module signing context */ + const void *buffer; /* module buffer */ + const Elf_Ehdr *hdr; /* ELF header */ + const Elf_Shdr *sections; /* ELF section table */ +@@ -37,7 +40,7 @@ struct module_verify_data { + /* + * module-verify.c + */ +-extern int module_verify(const Elf_Ehdr *hdr, size_t size); ++extern int module_verify(const Elf_Ehdr *hdr, size_t size, int *_gpgsig_ok); + + /* + * module-verify-elf.c +@@ -48,6 +51,18 @@ extern int module_verify_elf(struct module_verify_data *mvdata); + #define module_verify_elf(m) (0) + #endif + ++/* ++ * module-verify-sig.c ++ */ ++#ifdef CONFIG_MODULE_SIG ++extern struct key *modsign_keyring; ++ ++extern int module_verify_signature(struct module_verify_data *mvdata, ++ int *_gpgsig_ok); ++#else ++#define module_verify_signature(m, g) (0) ++#endif ++ + #else +-#define module_verify(h, s) (0) ++#define module_verify(h, s, g) (0) + #endif +diff --git a/kernel/module.c b/kernel/module.c +index 54d6910..bb38584 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2372,7 +2372,8 @@ static inline void kmemleak_load_module(const struct module *mod, + /* Sets info->hdr and info->len. */ + static int copy_and_check(struct load_info *info, + const void __user *umod, unsigned long len, +- const char __user *uargs) ++ const char __user *uargs, ++ int *_gpgsig_ok) + { + int err; + Elf_Ehdr *hdr; +@@ -2406,7 +2407,7 @@ static int copy_and_check(struct load_info *info, + } + + /* Verify the module's contents */ +- err = module_verify(hdr, len); ++ err = module_verify(hdr, len, _gpgsig_ok); + if (err < 0) + goto free_hdr; + +@@ -2752,7 +2753,8 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr, + return 0; + } + +-static struct module *layout_and_allocate(struct load_info *info) ++static struct module *layout_and_allocate(struct load_info *info, ++ int gpgsig_ok) + { + /* Module within temporary copy. */ + struct module *mod; +@@ -2762,6 +2764,7 @@ static struct module *layout_and_allocate(struct load_info *info) + mod = setup_load_info(info); + if (IS_ERR(mod)) + return mod; ++ mod->gpgsig_ok = gpgsig_ok; + + err = check_modinfo(mod, info); + if (err) +@@ -2845,17 +2848,18 @@ static struct module *load_module(void __user *umod, + struct load_info info = { NULL, }; + struct module *mod; + long err; ++ int gpgsig_ok; + + pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", + umod, len, uargs); + + /* Copy in the blobs from userspace, check they are vaguely sane. */ +- err = copy_and_check(&info, umod, len, uargs); ++ err = copy_and_check(&info, umod, len, uargs, &gpgsig_ok); + if (err) + return ERR_PTR(err); + + /* Figure out module layout, and allocate all the memory. */ +- mod = layout_and_allocate(&info); ++ mod = layout_and_allocate(&info, gpgsig_ok); + if (IS_ERR(mod)) { + err = PTR_ERR(mod); + goto free_copy; +@@ -3491,8 +3495,13 @@ void print_modules(void) + printk(KERN_DEFAULT "Modules linked in:"); + /* Most callers should already have preempt disabled, but make sure */ + preempt_disable(); +- list_for_each_entry_rcu(mod, &modules, list) ++ list_for_each_entry_rcu(mod, &modules, list) { + printk(" %s%s", mod->name, module_flags(mod, buf)); ++#ifdef CONFIG_MODULE_SIG ++ if (!mod->gpgsig_ok) ++ printk("(U)"); ++#endif ++ } + preempt_enable(); + if (last_unloaded_module[0]) + printk(" [last unloaded: %s]", last_unloaded_module); +diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost +index 08dce14..b436b04 100644 +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -14,7 +14,8 @@ + # 3) create one <module>.mod.c file pr. module + # 4) create one Module.symvers file with CRC for all exported symbols + # 5) compile all <module>.mod.c files +-# 6) final link of the module to a <module.ko> file ++# 6) final link of the module to a <module.ko> (or <module.unsigned>) file ++# 7) signs the modules to a <module.ko> file + + # Step 3 is used to place certain information in the module's ELF + # section, including information such as: +@@ -32,6 +33,8 @@ + # Step 4 is solely used to allow module versioning in external modules, + # where the CRC of each module is retrieved from the Module.symvers file. + ++# Step 7 is dependent on CONFIG_MODULE_SIG being enabled. ++ + # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined + # symbols in the final module linking stage + # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. +@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE + targets += $(modules:.ko=.mod.o) + + # Step 6), final link of the modules ++ifneq ($(CONFIG_MODULE_SIG),y) + quiet_cmd_ld_ko_o = LD [M] $@ + cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ +@@ -125,7 +129,86 @@ $(modules): %.ko :%.o %.mod.o FORCE + $(call if_changed,ld_ko_o) + + targets += $(modules) ++else ++quiet_cmd_ld_ko_unsigned_o = LD [M] $@ ++ cmd_ld_ko_unsigned_o = \ ++ $(LD) -r $(LDFLAGS) \ ++ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ ++ -o $@ $(filter-out FORCE,$^) \ ++ $(if $(AFTER_LINK),; $(AFTER_LINK)) ++ ++$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE ++ $(call if_changed,ld_ko_unsigned_o) ++ ++targets += $(modules:.ko=.ko.unsigned) ++ ++# Step 7), sign the modules ++MODSECKEY = ./kernel.sec ++MODPUBKEY = ./kernel.pub ++KEYFLAGS = --no-default-keyring --secret-keyring $(MODSECKEY) --keyring $(MODPUBKEY) --no-default-keyring --homedir . --no-options --no-auto-check-trustdb --no-permission-warning ++ ++ifdef CONFIG_MODULE_SIG_SHA1 ++KEYFLAGS += --digest-algo=SHA1 ++else ++ifdef CONFIG_MODULE_SIG_SHA224 ++KEYFLAGS += --digest-algo=SHA224 ++else ++ifdef CONFIG_MODULE_SIG_SHA256 ++KEYFLAGS += --digest-algo=SHA256 ++else ++ifdef CONFIG_MODULE_SIG_SHA384 ++KEYFLAGS += --digest-algo=SHA384 ++else ++ifdef CONFIG_MODULE_SIG_SHA512 ++KEYFLAGS += --digest-algo=SHA512 ++else ++endif ++endif ++endif ++endif ++endif ++ ++ifdef MODKEYNAME ++KEYFLAGS += --default-key $(MODKEYNAME) ++endif + ++ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) ++ifeq ($(KBUILD_SRC),) ++ # no O= is being used ++ SCRIPTS_DIR := scripts ++else ++ SCRIPTS_DIR := $(KBUILD_SRC)/scripts ++endif ++SIGN_MODULES := 1 ++else ++SIGN_MODULES := 0 ++endif ++ ++# only sign if it's an in-tree module ++ifneq ($(KBUILD_EXTMOD),) ++SIGN_MODULES := 0 ++endif ++ ++ifeq ($(SIGN_MODULES),1) ++quiet_cmd_sign_ko_ko_unsigned = SIGN [M] $@ ++ cmd_sign_ko_ko_unsigned = \ ++ scripts/mod/mod-extract $< $@.digest && \ ++ rm -f $@.digest.sig && \ ++ gpg --batch --no-greeting $(KEYFLAGS) -b $@.digest && \ ++ sh $(SCRIPTS_DIR)/mod/modsign-note.sh $@.digest.sig | \ ++ $(CC) -x assembler-with-cpp $(c_flags) $(CFLAGS_MODULE) -c -o $@.note.o - && \ ++ $(LD) -r $(LDFLAGS) -o $@ $< $@.note.o ++else ++quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@ ++ cmd_sign_ko_ko_unsigned = \ ++ cp $< $@ ++endif ++ ++$(modules): %.ko :%.ko.unsigned FORCE ++ $(call if_changed,sign_ko_ko_unsigned) ++ ++targets += $(modules) ++endif + + # Add FORCE to the prequisites of a target to force it to be always rebuilt. + # --------------------------------------------------------------------------- +diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore +index e9b7abe..223dfd6 100644 +--- a/scripts/mod/.gitignore ++++ b/scripts/mod/.gitignore +@@ -1,4 +1,5 @@ + elfconfig.h + mk_elfconfig + modpost ++mod-extract + +diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile +index ff954f8..4654e3b 100644 +--- a/scripts/mod/Makefile ++++ b/scripts/mod/Makefile +@@ -1,4 +1,4 @@ +-hostprogs-y := modpost mk_elfconfig ++hostprogs-y := modpost mk_elfconfig mod-extract + always := $(hostprogs-y) empty.o + + modpost-objs := modpost.o file2alias.o sumversion.o +diff --git a/scripts/mod/mod-extract.c b/scripts/mod/mod-extract.c +new file mode 100644 +index 0000000..0c0e3e3 +--- /dev/null ++++ b/scripts/mod/mod-extract.c +@@ -0,0 +1,913 @@ ++/* mod-extract.c: module extractor for signing ++ * ++ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdint.h> ++#include <stdarg.h> ++#include <string.h> ++#include <unistd.h> ++#include <fcntl.h> ++#include <sys/mman.h> ++#include <sys/stat.h> ++#include <elf.h> ++#include <asm/byteorder.h> ++ ++static void extract_elf64(void *buffer, size_t size, Elf64_Ehdr *hdr); ++static void extract_elf32(void *buffer, size_t size, Elf32_Ehdr *hdr); ++ ++struct byteorder { ++ uint16_t (*get16)(const uint16_t *); ++ uint32_t (*get32)(const uint32_t *); ++ uint64_t (*get64)(const uint64_t *); ++ void (*set16)(uint16_t *, uint16_t); ++ void (*set32)(uint32_t *, uint32_t); ++ void (*set64)(uint64_t *, uint64_t); ++}; ++ ++static uint16_t get16_le(const uint16_t *p) { return __le16_to_cpu(*p); } ++static uint32_t get32_le(const uint32_t *p) { return __le32_to_cpu(*p); } ++static uint64_t get64_le(const uint64_t *p) { return __le64_to_cpu(*p); } ++static uint16_t get16_be(const uint16_t *p) { return __be16_to_cpu(*p); } ++static uint32_t get32_be(const uint32_t *p) { return __be32_to_cpu(*p); } ++static uint64_t get64_be(const uint64_t *p) { return __be64_to_cpu(*p); } ++ ++static void set16_le(uint16_t *p, uint16_t n) { *p = __cpu_to_le16(n); } ++static void set32_le(uint32_t *p, uint32_t n) { *p = __cpu_to_le32(n); } ++static void set64_le(uint64_t *p, uint64_t n) { *p = __cpu_to_le64(n); } ++static void set16_be(uint16_t *p, uint16_t n) { *p = __cpu_to_be16(n); } ++static void set32_be(uint32_t *p, uint32_t n) { *p = __cpu_to_be32(n); } ++static void set64_be(uint64_t *p, uint64_t n) { *p = __cpu_to_be64(n); } ++ ++static const struct byteorder byteorder_le = { ++ get16_le, get32_le, get64_le, ++ set16_le, set32_le, set64_le ++}; ++static const struct byteorder byteorder_be = { ++ get16_be, get32_be, get64_be, ++ set16_be, set32_be, set64_be ++}; ++static const struct byteorder *order; ++ ++static inline uint16_t get16(const uint16_t *p) { return order->get16(p); } ++static inline uint32_t get32(const uint32_t *p) { return order->get32(p); } ++static inline uint64_t get64(const uint64_t *p) { return order->get64(p); } ++static inline void set16(uint16_t *p, uint16_t n) { order->set16(p, n); } ++static inline void set32(uint32_t *p, uint32_t n) { order->set32(p, n); } ++static inline void set64(uint64_t *p, uint64_t n) { order->set64(p, n); } ++ ++static FILE *outfd; ++static uint8_t csum, xcsum; ++ ++static void write_out(const void *data, size_t size) ++{ ++ const uint8_t *p = data; ++ size_t loop; ++ ++ for (loop = 0; loop < size; loop++) { ++ csum += p[loop]; ++ xcsum += p[loop]; ++ } ++ ++ if (fwrite(data, 1, size, outfd) != size) { ++ perror("write"); ++ exit(1); ++ } ++} ++ ++#define write_out_val(VAL) write_out(&(VAL), sizeof(VAL)) ++ ++static int is_verbose; ++ ++static __attribute__((format(printf, 1, 2))) ++void verbose(const char *fmt, ...) ++{ ++ va_list va; ++ ++ if (is_verbose) { ++ va_start(va, fmt); ++ vprintf(fmt, va); ++ va_end(va); ++ } ++} ++ ++static __attribute__((noreturn)) ++void usage(void) ++{ ++ fprintf(stderr, "Usage: mod-extract [-v] <modulefile> <extractfile>\n"); ++ exit(2); ++} ++ ++/* ++ * ++ */ ++int main(int argc, char **argv) ++{ ++ struct stat st; ++ Elf32_Ehdr *hdr32; ++ Elf64_Ehdr *hdr64; ++ size_t len; ++ void *buffer; ++ int fd, be, b64; ++ ++ while (argc > 1 && strcmp("-v", argv[1]) == 0) { ++ argv++; ++ argc--; ++ is_verbose++; ++ } ++ ++ if (argc != 3) ++ usage(); ++ ++ /* map the module into memory */ ++ fd = open(argv[1], O_RDONLY); ++ if (fd < 0) { ++ perror("open input"); ++ exit(1); ++ } ++ ++ if (fstat(fd, &st) < 0) { ++ perror("fstat"); ++ exit(1); ++ } ++ ++ len = st.st_size; ++ ++ buffer = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); ++ if (buffer == MAP_FAILED) { ++ perror("mmap"); ++ exit(1); ++ } ++ ++ if (close(fd) < 0) { ++ perror("close input"); ++ exit(1); ++ } ++ ++ /* check it's an ELF object */ ++ hdr32 = buffer; ++ hdr64 = buffer; ++ ++ if (hdr32->e_ident[EI_MAG0] != ELFMAG0 || ++ hdr32->e_ident[EI_MAG1] != ELFMAG1 || ++ hdr32->e_ident[EI_MAG2] != ELFMAG2 || ++ hdr32->e_ident[EI_MAG3] != ELFMAG3 ++ ) { ++ fprintf(stderr, "Module does not appear to be ELF\n"); ++ exit(3); ++ } ++ ++ /* determine endianness and word size */ ++ b64 = (hdr32->e_ident[EI_CLASS] == ELFCLASS64); ++ be = (hdr32->e_ident[EI_DATA] == ELFDATA2MSB); ++ order = be ? &byteorder_be : &byteorder_le; ++ ++ verbose("Module is %s-bit %s-endian\n", ++ b64 ? "64" : "32", ++ be ? "big" : "little"); ++ ++ /* open the output file */ ++ outfd = fopen(argv[2], "w"); ++ if (!outfd) { ++ perror("open output"); ++ exit(1); ++ } ++ ++ /* perform the extraction */ ++ if (b64) ++ extract_elf64(buffer, len, hdr64); ++ else ++ extract_elf32(buffer, len, hdr32); ++ ++ /* done */ ++ if (fclose(outfd) == EOF) { ++ perror("close output"); ++ exit(1); ++ } ++ ++ return 0; ++} ++ ++/* ++ * extract a RELA table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf64_rela(const void *buffer, int secix, int targetix, ++ const Elf64_Rela *relatab, size_t nrels, ++ const Elf64_Sym *symbols, size_t nsyms, ++ const Elf64_Shdr *sections, size_t nsects, int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ uint64_t r_offset; ++ uint64_t r_addend; ++ uint64_t st_value; ++ uint64_t st_size; ++ uint32_t r_type; ++ uint16_t st_shndx; ++ uint8_t st_info; ++ uint8_t st_other; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf64_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf64_Section st_shndx; ++ Elf64_Xword r_info; ++ ++ /* decode the relocation */ ++ r_info = get64(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ relocation.r_addend = relatab[loop].r_addend; ++ set32(&relocation.r_type, ELF64_R_TYPE(r_info)); ++ ++ if (ELF64_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n", ++ (size_t)ELF64_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF64_R_SYM(r_info)]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract a REL table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf64_rel(const void *buffer, int secix, int targetix, ++ const Elf64_Rel *relatab, size_t nrels, ++ const Elf64_Sym *symbols, size_t nsyms, ++ const Elf64_Shdr *sections, size_t nsects, int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ uint64_t r_offset; ++ uint64_t st_value; ++ uint64_t st_size; ++ uint32_t r_type; ++ uint16_t st_shndx; ++ uint8_t st_info; ++ uint8_t st_other; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf64_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf64_Section st_shndx; ++ Elf64_Xword r_info; ++ ++ /* decode the relocation */ ++ r_info = get64(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ set32(&relocation.r_type, ELF64_R_TYPE(r_info)); ++ ++ if (ELF64_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n", ++ (size_t)ELF64_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF64_R_SYM(r_info)]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract the data from a 64-bit module ++ */ ++static void extract_elf64(void *buffer, size_t len, Elf64_Ehdr *hdr) ++{ ++ const Elf64_Sym *symbols; ++ Elf64_Shdr *sections; ++ const char *secstrings, *strings; ++ size_t nsyms, nstrings; ++ int loop, shnum, *canonlist, *canonmap, canon, changed, tmp; ++ ++ sections = buffer + get64(&hdr->e_shoff); ++ secstrings = buffer + get64(§ions[get16(&hdr->e_shstrndx)].sh_offset); ++ shnum = get16(&hdr->e_shnum); ++ ++ /* find the symbol table and the string table and produce a list of ++ * index numbers of sections that contribute to the kernel's module ++ * image ++ */ ++ canonlist = calloc(sizeof(int), shnum * 2); ++ if (!canonlist) { ++ perror("calloc"); ++ exit(1); ++ } ++ canonmap = canonlist + shnum; ++ canon = 0; ++ ++ symbols = NULL; ++ strings = NULL; ++ nstrings = 0; ++ nsyms = 0; ++ ++ for (loop = 1; loop < shnum; loop++) { ++ const char *sh_name = secstrings + get32(§ions[loop].sh_name); ++ Elf64_Word sh_type = get32(§ions[loop].sh_type); ++ Elf64_Xword sh_size = get64(§ions[loop].sh_size); ++ Elf64_Xword sh_flags = get64(§ions[loop].sh_flags); ++ Elf64_Word sh_info = get32(§ions[loop].sh_info); ++ Elf64_Off sh_offset = get64(§ions[loop].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ /* quick sanity check */ ++ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { ++ fprintf(stderr, "Section goes beyond EOF\n"); ++ exit(3); ++ } ++ ++ /* we only need to canonicalise allocatable sections */ ++ if (sh_flags & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ else if ((sh_type == SHT_REL || sh_type == SHT_RELA) && ++ get64(§ions[sh_info].sh_flags) & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ ++ /* keep track of certain special sections */ ++ switch (sh_type) { ++ case SHT_SYMTAB: ++ if (strcmp(sh_name, ".symtab") == 0) { ++ symbols = data; ++ nsyms = sh_size / sizeof(Elf64_Sym); ++ } ++ break; ++ ++ case SHT_STRTAB: ++ if (strcmp(sh_name, ".strtab") == 0) { ++ strings = data; ++ nstrings = sh_size; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (!symbols) { ++ fprintf(stderr, "Couldn't locate symbol table\n"); ++ exit(3); ++ } ++ ++ if (!strings) { ++ fprintf(stderr, "Couldn't locate strings table\n"); ++ exit(3); ++ } ++ ++ /* canonicalise the index numbers of the contributing section */ ++ do { ++ changed = 0; ++ ++ for (loop = 0; loop < canon - 1; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name); ++ const char *y = secstrings + get32(§ions[canonlist[loop + 1]].sh_name); ++ if (strcmp(x, y) > 0) { ++ tmp = canonlist[loop + 0]; ++ canonlist[loop + 0] = canonlist[loop + 1]; ++ canonlist[loop + 1] = tmp; ++ changed = 1; ++ } ++ } ++ ++ } while (changed); ++ ++ for (loop = 0; loop < canon; loop++) ++ canonmap[canonlist[loop]] = loop + 1; ++ ++ if (is_verbose > 1) { ++ printf("\nSection canonicalisation map:\n"); ++ for (loop = 1; loop < shnum; loop++) { ++ const char *x = secstrings + get32(§ions[loop].sh_name); ++ printf("%4d %s\n", canonmap[loop], x); ++ } ++ ++ printf("\nAllocated section list in canonical order:\n"); ++ for (loop = 0; loop < canon; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name); ++ printf("%4d %s\n", canonlist[loop], x); ++ } ++ } ++ ++ /* iterate through the section table looking for sections we want to ++ * contribute to the signature */ ++ verbose("\n"); ++ verbose("CAN FILE POS CS SECT NAME\n"); ++ verbose("=== ======== == ==== ==============================\n"); ++ ++ for (loop = 0; loop < canon; loop++) { ++ int sect = canonlist[loop]; ++ const char *sh_name = secstrings + get32(§ions[sect].sh_name); ++ Elf64_Word sh_type = get32(§ions[sect].sh_type); ++ Elf64_Xword sh_size = get64(§ions[sect].sh_size); ++ Elf64_Xword sh_flags = get64(§ions[sect].sh_flags); ++ Elf64_Word sh_info = get32(§ions[sect].sh_info); ++ Elf64_Off sh_offset = get64(§ions[sect].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ csum = 0; ++ ++ /* include canonicalised relocation sections */ ++ if (sh_type == SHT_REL || sh_type == SHT_RELA) { ++ Elf32_Word canon_sh_info; ++ ++ if (sh_info <= 0 && sh_info >= hdr->e_shnum) { ++ fprintf(stderr, ++ "Invalid ELF - REL/RELA sh_info does" ++ " not refer to a valid section\n"); ++ exit(3); ++ } ++ ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ set32(&canon_sh_info, canonmap[sh_info]); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ write_out_val(canon_sh_info); ++ ++ if (sh_type == SHT_RELA) ++ extract_elf64_rela(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf64_Rela), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ else ++ extract_elf64_rel(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf64_Rel), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ continue; ++ } ++ ++ /* include the headers of BSS sections */ ++ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ /* include allocatable loadable sections */ ++ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) ++ goto include_section; ++ ++ /* not this section */ ++ continue; ++ ++ include_section: ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ /* write out the section data */ ++ write_out(data, sh_size); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ verbose("%08lx (%lu bytes csum 0x%02x)\n", ++ ftell(outfd), ftell(outfd), xcsum); ++} ++ ++/* ++ * extract a RELA table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf32_rela(const void *buffer, int secix, int targetix, ++ const Elf32_Rela *relatab, size_t nrels, ++ const Elf32_Sym *symbols, size_t nsyms, ++ const Elf32_Shdr *sections, size_t nsects, ++ int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ uint32_t r_offset; ++ uint32_t r_addend; ++ uint32_t st_value; ++ uint32_t st_size; ++ uint16_t st_shndx; ++ uint8_t r_type; ++ uint8_t st_info; ++ uint8_t st_other; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf32_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf32_Section st_shndx; ++ Elf32_Word r_info; ++ ++ /* decode the relocation */ ++ r_info = get32(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ relocation.r_addend = relatab[loop].r_addend; ++ relocation.r_type = ELF32_R_TYPE(r_info); ++ ++ if (ELF32_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n", ++ ELF32_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF32_R_SYM(r_info)]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract a REL table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf32_rel(const void *buffer, int secix, int targetix, ++ const Elf32_Rel *relatab, size_t nrels, ++ const Elf32_Sym *symbols, size_t nsyms, ++ const Elf32_Shdr *sections, size_t nsects, ++ int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ uint32_t r_offset; ++ uint32_t st_value; ++ uint32_t st_size; ++ uint16_t st_shndx; ++ uint8_t r_type; ++ uint8_t st_info; ++ uint8_t st_other; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf32_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf32_Section st_shndx; ++ Elf32_Word r_info; ++ ++ /* decode the relocation */ ++ r_info = get32(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ relocation.r_type = ELF32_R_TYPE(r_info); ++ ++ if (ELF32_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n", ++ ELF32_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF32_R_SYM(r_info)]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract the data from a 32-bit module ++ */ ++static void extract_elf32(void *buffer, size_t len, Elf32_Ehdr *hdr) ++{ ++ const Elf32_Sym *symbols; ++ Elf32_Shdr *sections; ++ const char *secstrings, *strings; ++ size_t nsyms, nstrings; ++ int loop, shnum, *canonlist, *canonmap, canon, changed, tmp; ++ ++ sections = buffer + get32(&hdr->e_shoff); ++ secstrings = buffer + get32(§ions[get16(&hdr->e_shstrndx)].sh_offset); ++ shnum = get16(&hdr->e_shnum); ++ ++ /* find the symbol table and the string table and produce a list of ++ * index numbers of sections that contribute to the kernel's module ++ * image ++ */ ++ canonlist = calloc(sizeof(int), shnum * 2); ++ if (!canonlist) { ++ perror("calloc"); ++ exit(1); ++ } ++ canonmap = canonlist + shnum; ++ canon = 0; ++ ++ symbols = NULL; ++ strings = NULL; ++ nstrings = 0; ++ nsyms = 0; ++ ++ for (loop = 1; loop < shnum; loop++) { ++ const char *sh_name = secstrings + get32(§ions[loop].sh_name); ++ Elf32_Word sh_type = get32(§ions[loop].sh_type); ++ Elf32_Xword sh_size = get32(§ions[loop].sh_size); ++ Elf32_Xword sh_flags = get32(§ions[loop].sh_flags); ++ Elf64_Word sh_info = get32(§ions[loop].sh_info); ++ Elf32_Off sh_offset = get32(§ions[loop].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ /* quick sanity check */ ++ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { ++ fprintf(stderr, "Section goes beyond EOF\n"); ++ exit(3); ++ } ++ ++ /* we only need to canonicalise allocatable sections */ ++ if (sh_flags & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ else if ((sh_type == SHT_REL || sh_type == SHT_RELA) && ++ get32(§ions[sh_info].sh_flags) & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ ++ /* keep track of certain special sections */ ++ switch (sh_type) { ++ case SHT_SYMTAB: ++ if (strcmp(sh_name, ".symtab") == 0) { ++ symbols = data; ++ nsyms = sh_size / sizeof(Elf32_Sym); ++ } ++ break; ++ ++ case SHT_STRTAB: ++ if (strcmp(sh_name, ".strtab") == 0) { ++ strings = data; ++ nstrings = sh_size; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (!symbols) { ++ fprintf(stderr, "Couldn't locate symbol table\n"); ++ exit(3); ++ } ++ ++ if (!strings) { ++ fprintf(stderr, "Couldn't locate strings table\n"); ++ exit(3); ++ } ++ ++ /* canonicalise the index numbers of the contributing section */ ++ do { ++ changed = 0; ++ ++ for (loop = 0; loop < canon - 1; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name); ++ const char *y = secstrings + get32(§ions[canonlist[loop + 1]].sh_name); ++ if (strcmp(x, y) > 0) { ++ tmp = canonlist[loop + 0]; ++ canonlist[loop + 0] = canonlist[loop + 1]; ++ canonlist[loop + 1] = tmp; ++ changed = 1; ++ } ++ } ++ ++ } while (changed); ++ ++ for (loop = 0; loop < canon; loop++) ++ canonmap[canonlist[loop]] = loop + 1; ++ ++ if (is_verbose > 1) { ++ printf("\nSection canonicalisation map:\n"); ++ for (loop = 1; loop < shnum; loop++) { ++ const char *x = secstrings + get32(§ions[loop].sh_name); ++ printf("%4d %s\n", canonmap[loop], x); ++ } ++ ++ printf("\nAllocated section list in canonical order:\n"); ++ for (loop = 0; loop < canon; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name); ++ printf("%4d %s\n", canonlist[loop], x); ++ } ++ } ++ ++ /* iterate through the section table looking for sections we want to ++ * contribute to the signature */ ++ verbose("\n"); ++ verbose("CAN FILE POS CS SECT NAME\n"); ++ verbose("=== ======== == ==== ==============================\n"); ++ ++ for (loop = 0; loop < canon; loop++) { ++ int sect = canonlist[loop]; ++ const char *sh_name = secstrings + get32(§ions[sect].sh_name); ++ Elf32_Word sh_type = get32(§ions[sect].sh_type); ++ Elf32_Xword sh_size = get32(§ions[sect].sh_size); ++ Elf32_Xword sh_flags = get32(§ions[sect].sh_flags); ++ Elf32_Word sh_info = get32(§ions[sect].sh_info); ++ Elf32_Off sh_offset = get32(§ions[sect].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ csum = 0; ++ ++ /* quick sanity check */ ++ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { ++ fprintf(stderr, "section goes beyond EOF\n"); ++ exit(3); ++ } ++ ++ /* include canonicalised relocation sections */ ++ if (sh_type == SHT_REL || sh_type == SHT_RELA) { ++ Elf32_Word canon_sh_info; ++ ++ if (sh_info <= 0 && sh_info >= hdr->e_shnum) { ++ fprintf(stderr, ++ "Invalid ELF - REL/RELA sh_info does" ++ " not refer to a valid section\n"); ++ exit(3); ++ } ++ ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ set32(&canon_sh_info, canonmap[sh_info]); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ write_out_val(canon_sh_info); ++ ++ if (sh_type == SHT_RELA) ++ extract_elf32_rela(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf32_Rela), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ else ++ extract_elf32_rel(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf32_Rel), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ continue; ++ } ++ ++ /* include the headers of BSS sections */ ++ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ /* include allocatable loadable sections */ ++ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) ++ goto include_section; ++ ++ /* not this section */ ++ continue; ++ ++ include_section: ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ /* write out the section data */ ++ write_out(data, sh_size); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ verbose("%08lx (%lu bytes csum 0x%02x)\n", ++ ftell(outfd), ftell(outfd), xcsum); ++} +diff --git a/scripts/mod/modsign-note.sh b/scripts/mod/modsign-note.sh +new file mode 100644 +index 0000000..bca67c0 +--- /dev/null ++++ b/scripts/mod/modsign-note.sh +@@ -0,0 +1,16 @@ ++#!/bin/sh ++# ++# Generate a module signature note source file ++# ++# mod-sign.sh <sig-file> ><note-src-file> ++# ++ ++SIG=$1 ++ ++cat <<EOF ++#include <linux/modsign.h> ++ ++ELFNOTE(MODSIGN_NOTE_NAME, MODSIGN_NOTE_TYPE, .incbin "$SIG") ++EOF ++ ++exit 0 +-- +1.7.9.1 + +From 31e77b71e584a702c8e44b83f6af03bb8511cf8d Mon Sep 17 00:00:00 2001 +From: Josh Boyer <jwboyer@redhat.com> +Date: Tue, 6 Mar 2012 12:56:49 -0500 +Subject: [PATCH] Make sure MPILIB is selected for stuff that uses it... + +security/built-in.o: In function `public_key_destroy': +/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/public_key.c:41: undefined reference to `mpi_free' +security/built-in.o: In function `RSA_verify_signature': +/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:222: undefined reference to `mpi_get_nbits' +/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:224: undefined reference to `mpi_get_nbits' + +security/built-in.o: In function `RSAVP1': +/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:93: undefined reference to `mpi_cmp_ui' +/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:97: undefined reference to `mpi_cmp' + +Signed-off-by: Josh Boyer <jwboyer@redhat.com> +--- + security/keys/Kconfig | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index 5e77c2a..e40f9b68 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -89,12 +89,14 @@ config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE + + config CRYPTO_KEY_PKEY_ALGO_RSA + tristate "RSA public-key algorithm" ++ select MPILIB_EXTRA + depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE + help + This option enables support for the RSA algorithm (PKCS#1, RFC3447). + + config PGP_LIBRARY + tristate "PGP parsing library" ++ select MPILIB + help + This option enables a library that provides a number of simple + utility functions for parsing PGP (RFC 4880) packet-based messages. +-- +1.7.9.1 + |