diff options
| author | James Morris <james.l.morris@oracle.com> | 2015-08-13 22:08:39 -0400 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2015-08-13 22:08:39 -0400 |
| commit | e4fc02f24c223ee8d668bf2d39bb8a2dbd61b40e (patch) | |
| tree | 8ad26407ec8b8898f6ff5f396ff628919a56c624 | |
| parent | aa62efff65ba572814511efa68cb158fe9e960c4 (diff) | |
| parent | e9a5e8cc55286941503f36c5b7485a5aa923b3f1 (diff) | |
Merge tag 'modsign-pkcs7-20150812-3' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into next
35 files changed, 1597 insertions, 928 deletions
diff --git a/.gitignore b/.gitignore index 4ad4a98b884b..17fa24dd7e46 100644 --- a/.gitignore +++ b/.gitignore | |||
| @@ -97,6 +97,7 @@ GTAGS | |||
| 97 | # Leavings from module signing | 97 | # Leavings from module signing |
| 98 | # | 98 | # |
| 99 | extra_certificates | 99 | extra_certificates |
| 100 | signing_key.pem | ||
| 100 | signing_key.priv | 101 | signing_key.priv |
| 101 | signing_key.x509 | 102 | signing_key.x509 |
| 102 | x509.genkey | 103 | x509.genkey |
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt index 6466704d47b5..0ff6a466a05b 100644 --- a/Documentation/kbuild/kbuild.txt +++ b/Documentation/kbuild/kbuild.txt | |||
| @@ -174,6 +174,11 @@ The output directory is often set using "O=..." on the commandline. | |||
| 174 | 174 | ||
| 175 | The value can be overridden in which case the default value is ignored. | 175 | The value can be overridden in which case the default value is ignored. |
| 176 | 176 | ||
| 177 | KBUILD_SIGN_PIN | ||
| 178 | -------------------------------------------------- | ||
| 179 | This variable allows a passphrase or PIN to be passed to the sign-file | ||
| 180 | utility when signing kernel modules, if the private key requires such. | ||
| 181 | |||
| 177 | KBUILD_MODPOST_WARN | 182 | KBUILD_MODPOST_WARN |
| 178 | -------------------------------------------------- | 183 | -------------------------------------------------- |
| 179 | KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined | 184 | KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined |
diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt index c72702ec1ded..02a9baf1c72f 100644 --- a/Documentation/module-signing.txt +++ b/Documentation/module-signing.txt | |||
| @@ -89,6 +89,32 @@ This has a number of options available: | |||
| 89 | their signatures checked without causing a dependency loop. | 89 | their signatures checked without causing a dependency loop. |
| 90 | 90 | ||
| 91 | 91 | ||
| 92 | (4) "File name or PKCS#11 URI of module signing key" (CONFIG_MODULE_SIG_KEY) | ||
| 93 | |||
| 94 | Setting this option to something other than its default of | ||
| 95 | "signing_key.pem" will disable the autogeneration of signing keys and | ||
| 96 | allow the kernel modules to be signed with a key of your choosing. | ||
| 97 | The string provided should identify a file containing both a private | ||
| 98 | key and its corresponding X.509 certificate in PEM form, or — on | ||
| 99 | systems where the OpenSSL ENGINE_pkcs11 is functional — a PKCS#11 URI | ||
| 100 | as defined by RFC7512. In the latter case, the PKCS#11 URI should | ||
| 101 | reference both a certificate and a private key. | ||
| 102 | |||
| 103 | If the PEM file containing the private key is encrypted, or if the | ||
| 104 | PKCS#11 token requries a PIN, this can be provided at build time by | ||
| 105 | means of the KBUILD_SIGN_PIN variable. | ||
| 106 | |||
| 107 | |||
| 108 | (5) "Additional X.509 keys for default system keyring" (CONFIG_SYSTEM_TRUSTED_KEYS) | ||
| 109 | |||
| 110 | This option can be set to the filename of a PEM-encoded file containing | ||
| 111 | additional certificates which will be included in the system keyring by | ||
| 112 | default. | ||
| 113 | |||
| 114 | Note that enabling module signing adds a dependency on the OpenSSL devel | ||
| 115 | packages to the kernel build processes for the tool that does the signing. | ||
| 116 | |||
| 117 | |||
| 92 | ======================= | 118 | ======================= |
| 93 | GENERATING SIGNING KEYS | 119 | GENERATING SIGNING KEYS |
| 94 | ======================= | 120 | ======================= |
| @@ -100,11 +126,11 @@ it can be deleted or stored securely. The public key gets built into the | |||
| 100 | kernel so that it can be used to check the signatures as the modules are | 126 | kernel so that it can be used to check the signatures as the modules are |
| 101 | loaded. | 127 | loaded. |
| 102 | 128 | ||
| 103 | Under normal conditions, the kernel build will automatically generate a new | 129 | Under normal conditions, when CONFIG_MODULE_SIG_KEY is unchanged from its |
| 104 | keypair using openssl if one does not exist in the files: | 130 | default, the kernel build will automatically generate a new keypair using |
| 131 | openssl if one does not exist in the file: | ||
| 105 | 132 | ||
| 106 | signing_key.priv | 133 | signing_key.pem |
| 107 | signing_key.x509 | ||
| 108 | 134 | ||
| 109 | during the building of vmlinux (the public part of the key needs to be built | 135 | during the building of vmlinux (the public part of the key needs to be built |
| 110 | into vmlinux) using parameters in the: | 136 | into vmlinux) using parameters in the: |
| @@ -135,8 +161,12 @@ kernel sources tree and the openssl command. The following is an example to | |||
| 135 | generate the public/private key files: | 161 | generate the public/private key files: |
| 136 | 162 | ||
| 137 | openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \ | 163 | openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \ |
| 138 | -config x509.genkey -outform DER -out signing_key.x509 \ | 164 | -config x509.genkey -outform PEM -out kernel_key.pem \ |
| 139 | -keyout signing_key.priv | 165 | -keyout kernel_key.pem |
| 166 | |||
| 167 | The full pathname for the resulting kernel_key.pem file can then be specified | ||
| 168 | in the CONFIG_MODULE_SIG_KEY option, and the certificate and key therein will | ||
| 169 | be used instead of an autogenerated keypair. | ||
| 140 | 170 | ||
| 141 | 171 | ||
| 142 | ========================= | 172 | ========================= |
| @@ -152,10 +182,9 @@ in a keyring called ".system_keyring" that can be seen by: | |||
| 152 | 302d2d52 I------ 1 perm 1f010000 0 0 asymmetri Fedora kernel signing key: d69a84e6bce3d216b979e9505b3e3ef9a7118079: X509.RSA a7118079 [] | 182 | 302d2d52 I------ 1 perm 1f010000 0 0 asymmetri Fedora kernel signing key: d69a84e6bce3d216b979e9505b3e3ef9a7118079: X509.RSA a7118079 [] |
| 153 | ... | 183 | ... |
| 154 | 184 | ||
| 155 | Beyond the public key generated specifically for module signing, any file | 185 | Beyond the public key generated specifically for module signing, additional |
| 156 | placed in the kernel source root directory or the kernel build root directory | 186 | trusted certificates can be provided in a PEM-encoded file referenced by the |
| 157 | whose name is suffixed with ".x509" will be assumed to be an X.509 public key | 187 | CONFIG_SYSTEM_TRUSTED_KEYS configuration option. |
| 158 | and will be added to the keyring. | ||
| 159 | 188 | ||
| 160 | Further, the architecture code may take public keys from a hardware store and | 189 | Further, the architecture code may take public keys from a hardware store and |
| 161 | add those in also (e.g. from the UEFI key database). | 190 | add those in also (e.g. from the UEFI key database). |
| @@ -181,7 +210,7 @@ To manually sign a module, use the scripts/sign-file tool available in | |||
| 181 | the Linux kernel source tree. The script requires 4 arguments: | 210 | the Linux kernel source tree. The script requires 4 arguments: |
| 182 | 211 | ||
| 183 | 1. The hash algorithm (e.g., sha256) | 212 | 1. The hash algorithm (e.g., sha256) |
| 184 | 2. The private key filename | 213 | 2. The private key filename or PKCS#11 URI |
| 185 | 3. The public key filename | 214 | 3. The public key filename |
| 186 | 4. The kernel module to be signed | 215 | 4. The kernel module to be signed |
| 187 | 216 | ||
| @@ -194,6 +223,9 @@ The hash algorithm used does not have to match the one configured, but if it | |||
| 194 | doesn't, you should make sure that hash algorithm is either built into the | 223 | doesn't, you should make sure that hash algorithm is either built into the |
| 195 | kernel or can be loaded without requiring itself. | 224 | kernel or can be loaded without requiring itself. |
| 196 | 225 | ||
| 226 | If the private key requires a passphrase or PIN, it can be provided in the | ||
| 227 | $KBUILD_SIGN_PIN environment variable. | ||
| 228 | |||
| 197 | 229 | ||
| 198 | ============================ | 230 | ============================ |
| 199 | SIGNED MODULES AND STRIPPING | 231 | SIGNED MODULES AND STRIPPING |
| @@ -870,10 +870,10 @@ INITRD_COMPRESS-$(CONFIG_RD_LZ4) := lz4 | |||
| 870 | # export INITRD_COMPRESS := $(INITRD_COMPRESS-y) | 870 | # export INITRD_COMPRESS := $(INITRD_COMPRESS-y) |
| 871 | 871 | ||
| 872 | ifdef CONFIG_MODULE_SIG_ALL | 872 | ifdef CONFIG_MODULE_SIG_ALL |
| 873 | MODSECKEY = ./signing_key.priv | 873 | MODSECKEY = $(CONFIG_MODULE_SIG_KEY) |
| 874 | MODPUBKEY = ./signing_key.x509 | 874 | MODPUBKEY = ./signing_key.x509 |
| 875 | export MODPUBKEY | 875 | export MODPUBKEY |
| 876 | mod_sign_cmd = perl $(srctree)/scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODSECKEY) $(MODPUBKEY) | 876 | mod_sign_cmd = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODSECKEY) $(MODPUBKEY) |
| 877 | else | 877 | else |
| 878 | mod_sign_cmd = true | 878 | mod_sign_cmd = true |
| 879 | endif | 879 | endif |
| @@ -1173,8 +1173,8 @@ MRPROPER_DIRS += include/config usr/include include/generated \ | |||
| 1173 | arch/*/include/generated .tmp_objdiff | 1173 | arch/*/include/generated .tmp_objdiff |
| 1174 | MRPROPER_FILES += .config .config.old .version .old_version \ | 1174 | MRPROPER_FILES += .config .config.old .version .old_version \ |
| 1175 | Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ | 1175 | Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ |
| 1176 | signing_key.priv signing_key.x509 x509.genkey \ | 1176 | signing_key.pem signing_key.priv signing_key.x509 \ |
| 1177 | extra_certificates signing_key.x509.keyid \ | 1177 | x509.genkey extra_certificates signing_key.x509.keyid \ |
| 1178 | signing_key.x509.signer vmlinux-gdb.py | 1178 | signing_key.x509.signer vmlinux-gdb.py |
| 1179 | 1179 | ||
| 1180 | # clean - Delete most, but leave enough to build external modules | 1180 | # clean - Delete most, but leave enough to build external modules |
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index ca83f7ac388b..fab22e72808c 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
| @@ -536,7 +536,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) | |||
| 536 | int ret; | 536 | int ret; |
| 537 | 537 | ||
| 538 | ret = verify_pefile_signature(kernel, kernel_len, | 538 | ret = verify_pefile_signature(kernel, kernel_len, |
| 539 | system_trusted_keyring, &trusted); | 539 | system_trusted_keyring, |
| 540 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
| 541 | &trusted); | ||
| 540 | if (ret < 0) | 542 | if (ret < 0) |
| 541 | return ret; | 543 | return ret; |
| 542 | if (!trusted) | 544 | if (!trusted) |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e47fcd9ac5e8..cd1406f9b14a 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
| @@ -15,15 +15,21 @@ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o | |||
| 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o | 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o |
| 16 | x509_key_parser-y := \ | 16 | x509_key_parser-y := \ |
| 17 | x509-asn1.o \ | 17 | x509-asn1.o \ |
| 18 | x509_akid-asn1.o \ | ||
| 18 | x509_rsakey-asn1.o \ | 19 | x509_rsakey-asn1.o \ |
| 19 | x509_cert_parser.o \ | 20 | x509_cert_parser.o \ |
| 20 | x509_public_key.o | 21 | x509_public_key.o |
| 21 | 22 | ||
| 22 | $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h | 23 | $(obj)/x509_cert_parser.o: \ |
| 24 | $(obj)/x509-asn1.h \ | ||
| 25 | $(obj)/x509_akid-asn1.h \ | ||
| 26 | $(obj)/x509_rsakey-asn1.h | ||
| 23 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h | 27 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h |
| 28 | $(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h | ||
| 24 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | 29 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h |
| 25 | 30 | ||
| 26 | clean-files += x509-asn1.c x509-asn1.h | 31 | clean-files += x509-asn1.c x509-asn1.h |
| 32 | clean-files += x509_akid-asn1.c x509_akid-asn1.h | ||
| 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 33 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
| 28 | 34 | ||
| 29 | # | 35 | # |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index b0e4ed23d668..1916680ad81b 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | #include <keys/asymmetric-subtype.h> | 13 | #include <keys/asymmetric-subtype.h> |
| 14 | #include <keys/asymmetric-parser.h> | 14 | #include <keys/asymmetric-parser.h> |
| 15 | #include <crypto/public_key.h> | ||
| 15 | #include <linux/seq_file.h> | 16 | #include <linux/seq_file.h> |
| 16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| @@ -20,6 +21,16 @@ | |||
| 20 | 21 | ||
| 21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
| 22 | 23 | ||
| 24 | const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { | ||
| 25 | [VERIFYING_MODULE_SIGNATURE] = "mod sig", | ||
| 26 | [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig", | ||
| 27 | [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig", | ||
| 28 | [VERIFYING_KEY_SIGNATURE] = "key sig", | ||
| 29 | [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig", | ||
| 30 | [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig", | ||
| 31 | }; | ||
| 32 | EXPORT_SYMBOL_GPL(key_being_used_for); | ||
| 33 | |||
| 23 | static LIST_HEAD(asymmetric_key_parsers); | 34 | static LIST_HEAD(asymmetric_key_parsers); |
| 24 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
| 25 | 36 | ||
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1 index a5a14ef28c86..1eca740b816a 100644 --- a/crypto/asymmetric_keys/pkcs7.asn1 +++ b/crypto/asymmetric_keys/pkcs7.asn1 | |||
| @@ -1,14 +1,14 @@ | |||
| 1 | PKCS7ContentInfo ::= SEQUENCE { | 1 | PKCS7ContentInfo ::= SEQUENCE { |
| 2 | contentType ContentType, | 2 | contentType ContentType ({ pkcs7_check_content_type }), |
| 3 | content [0] EXPLICIT SignedData OPTIONAL | 3 | content [0] EXPLICIT SignedData OPTIONAL |
| 4 | } | 4 | } |
| 5 | 5 | ||
| 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) |
| 7 | 7 | ||
| 8 | SignedData ::= SEQUENCE { | 8 | SignedData ::= SEQUENCE { |
| 9 | version INTEGER, | 9 | version INTEGER ({ pkcs7_note_signeddata_version }), |
| 10 | digestAlgorithms DigestAlgorithmIdentifiers, | 10 | digestAlgorithms DigestAlgorithmIdentifiers, |
| 11 | contentInfo ContentInfo, | 11 | contentInfo ContentInfo ({ pkcs7_note_content }), |
| 12 | certificates CHOICE { | 12 | certificates CHOICE { |
| 13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, | 13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, |
| 14 | certSequence [2] IMPLICIT Certificates | 14 | certSequence [2] IMPLICIT Certificates |
| @@ -21,7 +21,7 @@ SignedData ::= SEQUENCE { | |||
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | ContentInfo ::= SEQUENCE { | 23 | ContentInfo ::= SEQUENCE { |
| 24 | contentType ContentType, | 24 | contentType ContentType ({ pkcs7_note_OID }), |
| 25 | content [0] EXPLICIT Data OPTIONAL | 25 | content [0] EXPLICIT Data OPTIONAL |
| 26 | } | 26 | } |
| 27 | 27 | ||
| @@ -68,8 +68,8 @@ SignerInfos ::= CHOICE { | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | SignerInfo ::= SEQUENCE { | 70 | SignerInfo ::= SEQUENCE { |
| 71 | version INTEGER, | 71 | version INTEGER ({ pkcs7_note_signerinfo_version }), |
| 72 | issuerAndSerialNumber IssuerAndSerialNumber, | 72 | sid SignerIdentifier, -- CMS variant, not PKCS#7 |
| 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), | 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), |
| 74 | authenticatedAttributes CHOICE { | 74 | authenticatedAttributes CHOICE { |
| 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute | 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute |
| @@ -88,6 +88,12 @@ SignerInfo ::= SEQUENCE { | |||
| 88 | } OPTIONAL | 88 | } OPTIONAL |
| 89 | } ({ pkcs7_note_signed_info }) | 89 | } ({ pkcs7_note_signed_info }) |
| 90 | 90 | ||
| 91 | SignerIdentifier ::= CHOICE { | ||
| 92 | -- RFC5652 sec 5.3 | ||
| 93 | issuerAndSerialNumber IssuerAndSerialNumber, | ||
| 94 | subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier | ||
| 95 | } | ||
| 96 | |||
| 91 | IssuerAndSerialNumber ::= SEQUENCE { | 97 | IssuerAndSerialNumber ::= SEQUENCE { |
| 92 | issuer Name ({ pkcs7_sig_note_issuer }), | 98 | issuer Name ({ pkcs7_sig_note_issuer }), |
| 93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | 99 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) |
| @@ -95,6 +101,8 @@ IssuerAndSerialNumber ::= SEQUENCE { | |||
| 95 | 101 | ||
| 96 | CertificateSerialNumber ::= INTEGER | 102 | CertificateSerialNumber ::= INTEGER |
| 97 | 103 | ||
| 104 | SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid }) | ||
| 105 | |||
| 98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | 106 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute |
| 99 | 107 | ||
| 100 | AuthenticatedAttribute ::= SEQUENCE { | 108 | AuthenticatedAttribute ::= SEQUENCE { |
| @@ -103,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE { | |||
| 103 | } | 111 | } |
| 104 | 112 | ||
| 105 | UnauthenticatedAttribute ::= SEQUENCE { | 113 | UnauthenticatedAttribute ::= SEQUENCE { |
| 106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | 114 | type OBJECT IDENTIFIER, |
| 107 | values SET OF ANY | 115 | values SET OF ANY |
| 108 | } | 116 | } |
| 109 | 117 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index 3d13b042da73..e2d0edbbc71a 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
| @@ -14,16 +14,26 @@ | |||
| 14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/key-type.h> | 16 | #include <linux/key-type.h> |
| 17 | #include <keys/asymmetric-type.h> | ||
| 17 | #include <crypto/pkcs7.h> | 18 | #include <crypto/pkcs7.h> |
| 18 | #include <keys/user-type.h> | 19 | #include <keys/user-type.h> |
| 19 | #include <keys/system_keyring.h> | 20 | #include <keys/system_keyring.h> |
| 20 | #include "pkcs7_parser.h" | 21 | #include "pkcs7_parser.h" |
| 21 | 22 | ||
| 23 | MODULE_LICENSE("GPL"); | ||
| 24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | ||
| 25 | |||
| 26 | static unsigned pkcs7_usage; | ||
| 27 | module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO); | ||
| 28 | MODULE_PARM_DESC(pkcs7_usage, | ||
| 29 | "Usage to specify when verifying the PKCS#7 message"); | ||
| 30 | |||
| 22 | /* | 31 | /* |
| 23 | * Preparse a PKCS#7 wrapped and validated data blob. | 32 | * Preparse a PKCS#7 wrapped and validated data blob. |
| 24 | */ | 33 | */ |
| 25 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) |
| 26 | { | 35 | { |
| 36 | enum key_being_used_for usage = pkcs7_usage; | ||
| 27 | struct pkcs7_message *pkcs7; | 37 | struct pkcs7_message *pkcs7; |
| 28 | const void *data, *saved_prep_data; | 38 | const void *data, *saved_prep_data; |
| 29 | size_t datalen, saved_prep_datalen; | 39 | size_t datalen, saved_prep_datalen; |
| @@ -32,6 +42,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
| 32 | 42 | ||
| 33 | kenter(""); | 43 | kenter(""); |
| 34 | 44 | ||
| 45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
| 46 | pr_err("Invalid usage type %d\n", usage); | ||
| 47 | return -EINVAL; | ||
| 48 | } | ||
| 49 | |||
| 35 | saved_prep_data = prep->data; | 50 | saved_prep_data = prep->data; |
| 36 | saved_prep_datalen = prep->datalen; | 51 | saved_prep_datalen = prep->datalen; |
| 37 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | 52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); |
| @@ -40,7 +55,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
| 40 | goto error; | 55 | goto error; |
| 41 | } | 56 | } |
| 42 | 57 | ||
| 43 | ret = pkcs7_verify(pkcs7); | 58 | ret = pkcs7_verify(pkcs7, usage); |
| 44 | if (ret < 0) | 59 | if (ret < 0) |
| 45 | goto error_free; | 60 | goto error_free; |
| 46 | 61 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 3bd5a1e4c493..e6298b7a945a 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
| @@ -33,6 +33,9 @@ struct pkcs7_parse_context { | |||
| 33 | unsigned raw_serial_size; | 33 | unsigned raw_serial_size; |
| 34 | unsigned raw_issuer_size; | 34 | unsigned raw_issuer_size; |
| 35 | const void *raw_issuer; | 35 | const void *raw_issuer; |
| 36 | const void *raw_skid; | ||
| 37 | unsigned raw_skid_size; | ||
| 38 | bool expect_skid; | ||
| 36 | }; | 39 | }; |
| 37 | 40 | ||
| 38 | /* | 41 | /* |
| @@ -78,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7) | |||
| 78 | } | 81 | } |
| 79 | EXPORT_SYMBOL_GPL(pkcs7_free_message); | 82 | EXPORT_SYMBOL_GPL(pkcs7_free_message); |
| 80 | 83 | ||
| 84 | /* | ||
| 85 | * Check authenticatedAttributes are provided or not provided consistently. | ||
| 86 | */ | ||
| 87 | static int pkcs7_check_authattrs(struct pkcs7_message *msg) | ||
| 88 | { | ||
| 89 | struct pkcs7_signed_info *sinfo; | ||
| 90 | bool want; | ||
| 91 | |||
| 92 | sinfo = msg->signed_infos; | ||
| 93 | if (sinfo->authattrs) { | ||
| 94 | want = true; | ||
| 95 | msg->have_authattrs = true; | ||
| 96 | } | ||
| 97 | |||
| 98 | for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) | ||
| 99 | if (!!sinfo->authattrs != want) | ||
| 100 | goto inconsistent; | ||
| 101 | return 0; | ||
| 102 | |||
| 103 | inconsistent: | ||
| 104 | pr_warn("Inconsistently supplied authAttrs\n"); | ||
| 105 | return -EINVAL; | ||
| 106 | } | ||
| 107 | |||
| 81 | /** | 108 | /** |
| 82 | * pkcs7_parse_message - Parse a PKCS#7 message | 109 | * pkcs7_parse_message - Parse a PKCS#7 message |
| 83 | * @data: The raw binary ASN.1 encoded message to be parsed | 110 | * @data: The raw binary ASN.1 encoded message to be parsed |
| @@ -110,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | |||
| 110 | goto out; | 137 | goto out; |
| 111 | } | 138 | } |
| 112 | 139 | ||
| 140 | ret = pkcs7_check_authattrs(ctx->msg); | ||
| 141 | if (ret < 0) | ||
| 142 | goto out; | ||
| 143 | |||
| 113 | msg = ctx->msg; | 144 | msg = ctx->msg; |
| 114 | ctx->msg = NULL; | 145 | ctx->msg = NULL; |
| 115 | 146 | ||
| @@ -226,6 +257,100 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | |||
| 226 | } | 257 | } |
| 227 | 258 | ||
| 228 | /* | 259 | /* |
| 260 | * We only support signed data [RFC2315 sec 9]. | ||
| 261 | */ | ||
| 262 | int pkcs7_check_content_type(void *context, size_t hdrlen, | ||
| 263 | unsigned char tag, | ||
| 264 | const void *value, size_t vlen) | ||
| 265 | { | ||
| 266 | struct pkcs7_parse_context *ctx = context; | ||
| 267 | |||
| 268 | if (ctx->last_oid != OID_signed_data) { | ||
| 269 | pr_warn("Only support pkcs7_signedData type\n"); | ||
| 270 | return -EINVAL; | ||
| 271 | } | ||
| 272 | |||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* | ||
| 277 | * Note the SignedData version | ||
| 278 | */ | ||
| 279 | int pkcs7_note_signeddata_version(void *context, size_t hdrlen, | ||
| 280 | unsigned char tag, | ||
| 281 | const void *value, size_t vlen) | ||
| 282 | { | ||
| 283 | struct pkcs7_parse_context *ctx = context; | ||
| 284 | unsigned version; | ||
| 285 | |||
| 286 | if (vlen != 1) | ||
| 287 | goto unsupported; | ||
| 288 | |||
| 289 | ctx->msg->version = version = *(const u8 *)value; | ||
| 290 | switch (version) { | ||
| 291 | case 1: | ||
| 292 | /* PKCS#7 SignedData [RFC2315 sec 9.1] | ||
| 293 | * CMS ver 1 SignedData [RFC5652 sec 5.1] | ||
| 294 | */ | ||
| 295 | break; | ||
| 296 | case 3: | ||
| 297 | /* CMS ver 3 SignedData [RFC2315 sec 5.1] */ | ||
| 298 | break; | ||
| 299 | default: | ||
| 300 | goto unsupported; | ||
| 301 | } | ||
| 302 | |||
| 303 | return 0; | ||
| 304 | |||
| 305 | unsupported: | ||
| 306 | pr_warn("Unsupported SignedData version\n"); | ||
| 307 | return -EINVAL; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Note the SignerInfo version | ||
| 312 | */ | ||
| 313 | int pkcs7_note_signerinfo_version(void *context, size_t hdrlen, | ||
| 314 | unsigned char tag, | ||
| 315 | const void *value, size_t vlen) | ||
| 316 | { | ||
| 317 | struct pkcs7_parse_context *ctx = context; | ||
| 318 | unsigned version; | ||
| 319 | |||
| 320 | if (vlen != 1) | ||
| 321 | goto unsupported; | ||
| 322 | |||
| 323 | version = *(const u8 *)value; | ||
| 324 | switch (version) { | ||
| 325 | case 1: | ||
| 326 | /* PKCS#7 SignerInfo [RFC2315 sec 9.2] | ||
| 327 | * CMS ver 1 SignerInfo [RFC5652 sec 5.3] | ||
| 328 | */ | ||
| 329 | if (ctx->msg->version != 1) | ||
| 330 | goto version_mismatch; | ||
| 331 | ctx->expect_skid = false; | ||
| 332 | break; | ||
| 333 | case 3: | ||
| 334 | /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */ | ||
| 335 | if (ctx->msg->version == 1) | ||
| 336 | goto version_mismatch; | ||
| 337 | ctx->expect_skid = true; | ||
| 338 | break; | ||
| 339 | default: | ||
| 340 | goto unsupported; | ||
| 341 | } | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | |||
| 345 | unsupported: | ||
| 346 | pr_warn("Unsupported SignerInfo version\n"); | ||
| 347 | return -EINVAL; | ||
| 348 | version_mismatch: | ||
| 349 | pr_warn("SignedData-SignerInfo version mismatch\n"); | ||
| 350 | return -EBADMSG; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 229 | * Extract a certificate and store it in the context. | 354 | * Extract a certificate and store it in the context. |
| 230 | */ | 355 | */ |
| 231 | int pkcs7_extract_cert(void *context, size_t hdrlen, | 356 | int pkcs7_extract_cert(void *context, size_t hdrlen, |
| @@ -284,6 +409,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen, | |||
| 284 | } | 409 | } |
| 285 | 410 | ||
| 286 | /* | 411 | /* |
| 412 | * Note the content type. | ||
| 413 | */ | ||
| 414 | int pkcs7_note_content(void *context, size_t hdrlen, | ||
| 415 | unsigned char tag, | ||
| 416 | const void *value, size_t vlen) | ||
| 417 | { | ||
| 418 | struct pkcs7_parse_context *ctx = context; | ||
| 419 | |||
| 420 | if (ctx->last_oid != OID_data && | ||
| 421 | ctx->last_oid != OID_msIndirectData) { | ||
| 422 | pr_warn("Unsupported data type %d\n", ctx->last_oid); | ||
| 423 | return -EINVAL; | ||
| 424 | } | ||
| 425 | |||
| 426 | ctx->msg->data_type = ctx->last_oid; | ||
| 427 | return 0; | ||
| 428 | } | ||
| 429 | |||
| 430 | /* | ||
| 287 | * Extract the data from the message and store that and its content type OID in | 431 | * Extract the data from the message and store that and its content type OID in |
| 288 | * the context. | 432 | * the context. |
| 289 | */ | 433 | */ |
| @@ -298,45 +442,119 @@ int pkcs7_note_data(void *context, size_t hdrlen, | |||
| 298 | ctx->msg->data = value; | 442 | ctx->msg->data = value; |
| 299 | ctx->msg->data_len = vlen; | 443 | ctx->msg->data_len = vlen; |
| 300 | ctx->msg->data_hdrlen = hdrlen; | 444 | ctx->msg->data_hdrlen = hdrlen; |
| 301 | ctx->msg->data_type = ctx->last_oid; | ||
| 302 | return 0; | 445 | return 0; |
| 303 | } | 446 | } |
| 304 | 447 | ||
| 305 | /* | 448 | /* |
| 306 | * Parse authenticated attributes | 449 | * Parse authenticated attributes. |
| 307 | */ | 450 | */ |
| 308 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, | 451 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, |
| 309 | unsigned char tag, | 452 | unsigned char tag, |
| 310 | const void *value, size_t vlen) | 453 | const void *value, size_t vlen) |
| 311 | { | 454 | { |
| 312 | struct pkcs7_parse_context *ctx = context; | 455 | struct pkcs7_parse_context *ctx = context; |
| 456 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
| 457 | enum OID content_type; | ||
| 313 | 458 | ||
| 314 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | 459 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); |
| 315 | 460 | ||
| 316 | switch (ctx->last_oid) { | 461 | switch (ctx->last_oid) { |
| 462 | case OID_contentType: | ||
| 463 | if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set)) | ||
| 464 | goto repeated; | ||
| 465 | content_type = look_up_OID(value, vlen); | ||
| 466 | if (content_type != ctx->msg->data_type) { | ||
| 467 | pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n", | ||
| 468 | ctx->msg->data_type, sinfo->index, | ||
| 469 | content_type); | ||
| 470 | return -EBADMSG; | ||
| 471 | } | ||
| 472 | return 0; | ||
| 473 | |||
| 474 | case OID_signingTime: | ||
| 475 | if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set)) | ||
| 476 | goto repeated; | ||
| 477 | /* Should we check that the signing time is consistent | ||
| 478 | * with the signer's X.509 cert? | ||
| 479 | */ | ||
| 480 | return x509_decode_time(&sinfo->signing_time, | ||
| 481 | hdrlen, tag, value, vlen); | ||
| 482 | |||
| 317 | case OID_messageDigest: | 483 | case OID_messageDigest: |
| 484 | if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set)) | ||
| 485 | goto repeated; | ||
| 318 | if (tag != ASN1_OTS) | 486 | if (tag != ASN1_OTS) |
| 319 | return -EBADMSG; | 487 | return -EBADMSG; |
| 320 | ctx->sinfo->msgdigest = value; | 488 | sinfo->msgdigest = value; |
| 321 | ctx->sinfo->msgdigest_len = vlen; | 489 | sinfo->msgdigest_len = vlen; |
| 490 | return 0; | ||
| 491 | |||
| 492 | case OID_smimeCapabilites: | ||
| 493 | if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) | ||
| 494 | goto repeated; | ||
| 495 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
| 496 | pr_warn("S/MIME Caps only allowed with Authenticode\n"); | ||
| 497 | return -EKEYREJECTED; | ||
| 498 | } | ||
| 499 | return 0; | ||
| 500 | |||
| 501 | /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE | ||
| 502 | * char URLs and cont[1] 8-bit char URLs. | ||
| 503 | * | ||
| 504 | * Microsoft StatementType seems to contain a list of OIDs that | ||
| 505 | * are also used as extendedKeyUsage types in X.509 certs. | ||
| 506 | */ | ||
| 507 | case OID_msSpOpusInfo: | ||
| 508 | if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) | ||
| 509 | goto repeated; | ||
| 510 | goto authenticode_check; | ||
| 511 | case OID_msStatementType: | ||
| 512 | if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set)) | ||
| 513 | goto repeated; | ||
| 514 | authenticode_check: | ||
| 515 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
| 516 | pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n"); | ||
| 517 | return -EKEYREJECTED; | ||
| 518 | } | ||
| 519 | /* I'm not sure how to validate these */ | ||
| 322 | return 0; | 520 | return 0; |
| 323 | default: | 521 | default: |
| 324 | return 0; | 522 | return 0; |
| 325 | } | 523 | } |
| 524 | |||
| 525 | repeated: | ||
| 526 | /* We permit max one item per AuthenticatedAttribute and no repeats */ | ||
| 527 | pr_warn("Repeated/multivalue AuthAttrs not permitted\n"); | ||
| 528 | return -EKEYREJECTED; | ||
| 326 | } | 529 | } |
| 327 | 530 | ||
| 328 | /* | 531 | /* |
| 329 | * Note the set of auth attributes for digestion purposes [RFC2315 9.3] | 532 | * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3] |
| 330 | */ | 533 | */ |
| 331 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, | 534 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, |
| 332 | unsigned char tag, | 535 | unsigned char tag, |
| 333 | const void *value, size_t vlen) | 536 | const void *value, size_t vlen) |
| 334 | { | 537 | { |
| 335 | struct pkcs7_parse_context *ctx = context; | 538 | struct pkcs7_parse_context *ctx = context; |
| 539 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
| 540 | |||
| 541 | if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || | ||
| 542 | !test_bit(sinfo_has_message_digest, &sinfo->aa_set) || | ||
| 543 | (ctx->msg->data_type == OID_msIndirectData && | ||
| 544 | !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) { | ||
| 545 | pr_warn("Missing required AuthAttr\n"); | ||
| 546 | return -EBADMSG; | ||
| 547 | } | ||
| 548 | |||
| 549 | if (ctx->msg->data_type != OID_msIndirectData && | ||
| 550 | test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) { | ||
| 551 | pr_warn("Unexpected Authenticode AuthAttr\n"); | ||
| 552 | return -EBADMSG; | ||
| 553 | } | ||
| 336 | 554 | ||
| 337 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ | 555 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ |
| 338 | ctx->sinfo->authattrs = value - (hdrlen - 1); | 556 | sinfo->authattrs = value - (hdrlen - 1); |
| 339 | ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); | 557 | sinfo->authattrs_len = vlen + (hdrlen - 1); |
| 340 | return 0; | 558 | return 0; |
| 341 | } | 559 | } |
| 342 | 560 | ||
| @@ -367,6 +585,22 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen, | |||
| 367 | } | 585 | } |
| 368 | 586 | ||
| 369 | /* | 587 | /* |
| 588 | * Note the issuing cert's subjectKeyIdentifier | ||
| 589 | */ | ||
| 590 | int pkcs7_sig_note_skid(void *context, size_t hdrlen, | ||
| 591 | unsigned char tag, | ||
| 592 | const void *value, size_t vlen) | ||
| 593 | { | ||
| 594 | struct pkcs7_parse_context *ctx = context; | ||
| 595 | |||
| 596 | pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | ||
| 597 | |||
| 598 | ctx->raw_skid = value; | ||
| 599 | ctx->raw_skid_size = vlen; | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | /* | ||
| 370 | * Note the signature data | 604 | * Note the signature data |
| 371 | */ | 605 | */ |
| 372 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, | 606 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, |
| @@ -398,14 +632,27 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, | |||
| 398 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | 632 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
| 399 | struct asymmetric_key_id *kid; | 633 | struct asymmetric_key_id *kid; |
| 400 | 634 | ||
| 635 | if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) { | ||
| 636 | pr_warn("Authenticode requires AuthAttrs\n"); | ||
| 637 | return -EBADMSG; | ||
| 638 | } | ||
| 639 | |||
| 401 | /* Generate cert issuer + serial number key ID */ | 640 | /* Generate cert issuer + serial number key ID */ |
| 402 | kid = asymmetric_key_generate_id(ctx->raw_serial, | 641 | if (!ctx->expect_skid) { |
| 403 | ctx->raw_serial_size, | 642 | kid = asymmetric_key_generate_id(ctx->raw_serial, |
| 404 | ctx->raw_issuer, | 643 | ctx->raw_serial_size, |
| 405 | ctx->raw_issuer_size); | 644 | ctx->raw_issuer, |
| 645 | ctx->raw_issuer_size); | ||
| 646 | } else { | ||
| 647 | kid = asymmetric_key_generate_id(ctx->raw_skid, | ||
| 648 | ctx->raw_skid_size, | ||
| 649 | "", 0); | ||
| 650 | } | ||
| 406 | if (IS_ERR(kid)) | 651 | if (IS_ERR(kid)) |
| 407 | return PTR_ERR(kid); | 652 | return PTR_ERR(kid); |
| 408 | 653 | ||
| 654 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); | ||
| 655 | |||
| 409 | sinfo->signing_cert_id = kid; | 656 | sinfo->signing_cert_id = kid; |
| 410 | sinfo->index = ++ctx->sinfo_index; | 657 | sinfo->index = ++ctx->sinfo_index; |
| 411 | *ctx->ppsinfo = sinfo; | 658 | *ctx->ppsinfo = sinfo; |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index efc7dc9b8f9c..a66b19ebcf47 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
| @@ -21,9 +21,9 @@ | |||
| 21 | struct pkcs7_signed_info { | 21 | struct pkcs7_signed_info { |
| 22 | struct pkcs7_signed_info *next; | 22 | struct pkcs7_signed_info *next; |
| 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ | 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ |
| 24 | unsigned index; | 24 | unsigned index; |
| 25 | bool trusted; | 25 | bool trusted; |
| 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ | 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ |
| 27 | 27 | ||
| 28 | /* Message digest - the digest of the Content Data (or NULL) */ | 28 | /* Message digest - the digest of the Content Data (or NULL) */ |
| 29 | const void *msgdigest; | 29 | const void *msgdigest; |
| @@ -32,8 +32,18 @@ struct pkcs7_signed_info { | |||
| 32 | /* Authenticated Attribute data (or NULL) */ | 32 | /* Authenticated Attribute data (or NULL) */ |
| 33 | unsigned authattrs_len; | 33 | unsigned authattrs_len; |
| 34 | const void *authattrs; | 34 | const void *authattrs; |
| 35 | unsigned long aa_set; | ||
| 36 | #define sinfo_has_content_type 0 | ||
| 37 | #define sinfo_has_signing_time 1 | ||
| 38 | #define sinfo_has_message_digest 2 | ||
| 39 | #define sinfo_has_smime_caps 3 | ||
| 40 | #define sinfo_has_ms_opus_info 4 | ||
| 41 | #define sinfo_has_ms_statement_type 5 | ||
| 42 | time64_t signing_time; | ||
| 35 | 43 | ||
| 36 | /* Issuing cert serial number and issuer's name */ | 44 | /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1] |
| 45 | * or issuing cert's SKID [CMS ver 3]. | ||
| 46 | */ | ||
| 37 | struct asymmetric_key_id *signing_cert_id; | 47 | struct asymmetric_key_id *signing_cert_id; |
| 38 | 48 | ||
| 39 | /* Message signature. | 49 | /* Message signature. |
| @@ -50,6 +60,8 @@ struct pkcs7_message { | |||
| 50 | struct x509_certificate *certs; /* Certificate list */ | 60 | struct x509_certificate *certs; /* Certificate list */ |
| 51 | struct x509_certificate *crl; /* Revocation list */ | 61 | struct x509_certificate *crl; /* Revocation list */ |
| 52 | struct pkcs7_signed_info *signed_infos; | 62 | struct pkcs7_signed_info *signed_infos; |
| 63 | u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */ | ||
| 64 | bool have_authattrs; /* T if have authattrs */ | ||
| 53 | 65 | ||
| 54 | /* Content Data (or NULL) */ | 66 | /* Content Data (or NULL) */ |
| 55 | enum OID data_type; /* Type of Data */ | 67 | enum OID data_type; /* Type of Data */ |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 1d29376072da..90d6d47965b0 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
| @@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 54 | /* Look to see if this certificate is present in the trusted | 54 | /* Look to see if this certificate is present in the trusted |
| 55 | * keys. | 55 | * keys. |
| 56 | */ | 56 | */ |
| 57 | key = x509_request_asymmetric_key(trust_keyring, x509->id, | 57 | key = x509_request_asymmetric_key(trust_keyring, |
| 58 | x509->id, x509->skid, | ||
| 58 | false); | 59 | false); |
| 59 | if (!IS_ERR(key)) { | 60 | if (!IS_ERR(key)) { |
| 60 | /* One of the X.509 certificates in the PKCS#7 message | 61 | /* One of the X.509 certificates in the PKCS#7 message |
| @@ -85,8 +86,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 85 | /* No match - see if the root certificate has a signer amongst the | 86 | /* No match - see if the root certificate has a signer amongst the |
| 86 | * trusted keys. | 87 | * trusted keys. |
| 87 | */ | 88 | */ |
| 88 | if (last && last->authority) { | 89 | if (last && (last->akid_id || last->akid_skid)) { |
| 89 | key = x509_request_asymmetric_key(trust_keyring, last->authority, | 90 | key = x509_request_asymmetric_key(trust_keyring, |
| 91 | last->akid_id, | ||
| 92 | last->akid_skid, | ||
| 90 | false); | 93 | false); |
| 91 | if (!IS_ERR(key)) { | 94 | if (!IS_ERR(key)) { |
| 92 | x509 = last; | 95 | x509 = last; |
| @@ -103,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
| 103 | */ | 106 | */ |
| 104 | key = x509_request_asymmetric_key(trust_keyring, | 107 | key = x509_request_asymmetric_key(trust_keyring, |
| 105 | sinfo->signing_cert_id, | 108 | sinfo->signing_cert_id, |
| 109 | NULL, | ||
| 106 | false); | 110 | false); |
| 107 | if (!IS_ERR(key)) { | 111 | if (!IS_ERR(key)) { |
| 108 | pr_devel("sinfo %u: Direct signer is key %x\n", | 112 | pr_devel("sinfo %u: Direct signer is key %x\n", |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index cd455450b069..d20c0b4b880e 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
| @@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
| 70 | * message digest attribute amongst them which corresponds to the | 70 | * message digest attribute amongst them which corresponds to the |
| 71 | * digest we just calculated. | 71 | * digest we just calculated. |
| 72 | */ | 72 | */ |
| 73 | if (sinfo->msgdigest) { | 73 | if (sinfo->authattrs) { |
| 74 | u8 tag; | 74 | u8 tag; |
| 75 | 75 | ||
| 76 | if (!sinfo->msgdigest) { | ||
| 77 | pr_warn("Sig %u: No messageDigest\n", sinfo->index); | ||
| 78 | ret = -EKEYREJECTED; | ||
| 79 | goto error; | ||
| 80 | } | ||
| 81 | |||
| 76 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | 82 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { |
| 77 | pr_debug("Sig %u: Invalid digest size (%u)\n", | 83 | pr_debug("Sig %u: Invalid digest size (%u)\n", |
| 78 | sinfo->index, sinfo->msgdigest_len); | 84 | sinfo->index, sinfo->msgdigest_len); |
| @@ -170,6 +176,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 170 | struct pkcs7_signed_info *sinfo) | 176 | struct pkcs7_signed_info *sinfo) |
| 171 | { | 177 | { |
| 172 | struct x509_certificate *x509 = sinfo->signer, *p; | 178 | struct x509_certificate *x509 = sinfo->signer, *p; |
| 179 | struct asymmetric_key_id *auth; | ||
| 173 | int ret; | 180 | int ret; |
| 174 | 181 | ||
| 175 | kenter(""); | 182 | kenter(""); |
| @@ -187,11 +194,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 187 | goto maybe_missing_crypto_in_x509; | 194 | goto maybe_missing_crypto_in_x509; |
| 188 | 195 | ||
| 189 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
| 190 | if (x509->authority) | 197 | if (x509->akid_id) |
| 191 | pr_debug("- authkeyid %*phN\n", | 198 | pr_debug("- authkeyid.id %*phN\n", |
| 192 | x509->authority->len, x509->authority->data); | 199 | x509->akid_id->len, x509->akid_id->data); |
| 193 | 200 | if (x509->akid_skid) | |
| 194 | if (!x509->authority || | 201 | pr_debug("- authkeyid.skid %*phN\n", |
| 202 | x509->akid_skid->len, x509->akid_skid->data); | ||
| 203 | |||
| 204 | if ((!x509->akid_id && !x509->akid_skid) || | ||
| 195 | strcmp(x509->subject, x509->issuer) == 0) { | 205 | strcmp(x509->subject, x509->issuer) == 0) { |
| 196 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
| 197 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
| @@ -215,21 +225,42 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
| 215 | /* Look through the X.509 certificates in the PKCS#7 message's | 225 | /* Look through the X.509 certificates in the PKCS#7 message's |
| 216 | * list to see if the next one is there. | 226 | * list to see if the next one is there. |
| 217 | */ | 227 | */ |
| 218 | pr_debug("- want %*phN\n", | 228 | auth = x509->akid_id; |
| 219 | x509->authority->len, x509->authority->data); | 229 | if (auth) { |
| 220 | for (p = pkcs7->certs; p; p = p->next) { | 230 | pr_debug("- want %*phN\n", auth->len, auth->data); |
| 221 | if (!p->skid) | 231 | for (p = pkcs7->certs; p; p = p->next) { |
| 222 | continue; | 232 | pr_debug("- cmp [%u] %*phN\n", |
| 223 | pr_debug("- cmp [%u] %*phN\n", | 233 | p->index, p->id->len, p->id->data); |
| 224 | p->index, p->skid->len, p->skid->data); | 234 | if (asymmetric_key_id_same(p->id, auth)) |
| 225 | if (asymmetric_key_id_same(p->skid, x509->authority)) | 235 | goto found_issuer_check_skid; |
| 226 | goto found_issuer; | 236 | } |
| 237 | } else { | ||
| 238 | auth = x509->akid_skid; | ||
| 239 | pr_debug("- want %*phN\n", auth->len, auth->data); | ||
| 240 | for (p = pkcs7->certs; p; p = p->next) { | ||
| 241 | if (!p->skid) | ||
| 242 | continue; | ||
| 243 | pr_debug("- cmp [%u] %*phN\n", | ||
| 244 | p->index, p->skid->len, p->skid->data); | ||
| 245 | if (asymmetric_key_id_same(p->skid, auth)) | ||
| 246 | goto found_issuer; | ||
| 247 | } | ||
| 227 | } | 248 | } |
| 228 | 249 | ||
| 229 | /* We didn't find the root of this chain */ | 250 | /* We didn't find the root of this chain */ |
| 230 | pr_debug("- top\n"); | 251 | pr_debug("- top\n"); |
| 231 | return 0; | 252 | return 0; |
| 232 | 253 | ||
| 254 | found_issuer_check_skid: | ||
| 255 | /* We matched issuer + serialNumber, but if there's an | ||
| 256 | * authKeyId.keyId, that must match the CA subjKeyId also. | ||
| 257 | */ | ||
| 258 | if (x509->akid_skid && | ||
| 259 | !asymmetric_key_id_same(p->skid, x509->akid_skid)) { | ||
| 260 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", | ||
| 261 | sinfo->index, x509->index, p->index); | ||
| 262 | return -EKEYREJECTED; | ||
| 263 | } | ||
| 233 | found_issuer: | 264 | found_issuer: |
| 234 | pr_debug("- subject %s\n", p->subject); | 265 | pr_debug("- subject %s\n", p->subject); |
| 235 | if (p->seen) { | 266 | if (p->seen) { |
| @@ -289,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 289 | pr_devel("Using X.509[%u] for sig %u\n", | 320 | pr_devel("Using X.509[%u] for sig %u\n", |
| 290 | sinfo->signer->index, sinfo->index); | 321 | sinfo->signer->index, sinfo->index); |
| 291 | 322 | ||
| 323 | /* Check that the PKCS#7 signing time is valid according to the X.509 | ||
| 324 | * certificate. We can't, however, check against the system clock | ||
| 325 | * since that may not have been set yet and may be wrong. | ||
| 326 | */ | ||
| 327 | if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) { | ||
| 328 | if (sinfo->signing_time < sinfo->signer->valid_from || | ||
| 329 | sinfo->signing_time > sinfo->signer->valid_to) { | ||
| 330 | pr_warn("Message signed outside of X.509 validity window\n"); | ||
| 331 | return -EKEYREJECTED; | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 292 | /* Verify the PKCS#7 binary against the key */ | 335 | /* Verify the PKCS#7 binary against the key */ |
| 293 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | 336 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); |
| 294 | if (ret < 0) | 337 | if (ret < 0) |
| @@ -303,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 303 | /** | 346 | /** |
| 304 | * pkcs7_verify - Verify a PKCS#7 message | 347 | * pkcs7_verify - Verify a PKCS#7 message |
| 305 | * @pkcs7: The PKCS#7 message to be verified | 348 | * @pkcs7: The PKCS#7 message to be verified |
| 349 | * @usage: The use to which the key is being put | ||
| 306 | * | 350 | * |
| 307 | * Verify a PKCS#7 message is internally consistent - that is, the data digest | 351 | * Verify a PKCS#7 message is internally consistent - that is, the data digest |
| 308 | * matches the digest in the AuthAttrs and any signature in the message or one | 352 | * matches the digest in the AuthAttrs and any signature in the message or one |
| @@ -314,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 314 | * | 358 | * |
| 315 | * Returns, in order of descending priority: | 359 | * Returns, in order of descending priority: |
| 316 | * | 360 | * |
| 361 | * (*) -EKEYREJECTED if a key was selected that had a usage restriction at | ||
| 362 | * odds with the specified usage, or: | ||
| 363 | * | ||
| 317 | * (*) -EKEYREJECTED if a signature failed to match for which we found an | 364 | * (*) -EKEYREJECTED if a signature failed to match for which we found an |
| 318 | * appropriate X.509 certificate, or: | 365 | * appropriate X.509 certificate, or: |
| 319 | * | 366 | * |
| @@ -325,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
| 325 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified | 372 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified |
| 326 | * (note that a signature chain may be of zero length), or: | 373 | * (note that a signature chain may be of zero length), or: |
| 327 | */ | 374 | */ |
| 328 | int pkcs7_verify(struct pkcs7_message *pkcs7) | 375 | int pkcs7_verify(struct pkcs7_message *pkcs7, |
| 376 | enum key_being_used_for usage) | ||
| 329 | { | 377 | { |
| 330 | struct pkcs7_signed_info *sinfo; | 378 | struct pkcs7_signed_info *sinfo; |
| 331 | struct x509_certificate *x509; | 379 | struct x509_certificate *x509; |
| @@ -334,12 +382,48 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
| 334 | 382 | ||
| 335 | kenter(""); | 383 | kenter(""); |
| 336 | 384 | ||
| 385 | switch (usage) { | ||
| 386 | case VERIFYING_MODULE_SIGNATURE: | ||
| 387 | if (pkcs7->data_type != OID_data) { | ||
| 388 | pr_warn("Invalid module sig (not pkcs7-data)\n"); | ||
| 389 | return -EKEYREJECTED; | ||
| 390 | } | ||
| 391 | if (pkcs7->have_authattrs) { | ||
| 392 | pr_warn("Invalid module sig (has authattrs)\n"); | ||
| 393 | return -EKEYREJECTED; | ||
| 394 | } | ||
| 395 | break; | ||
| 396 | case VERIFYING_FIRMWARE_SIGNATURE: | ||
| 397 | if (pkcs7->data_type != OID_data) { | ||
| 398 | pr_warn("Invalid firmware sig (not pkcs7-data)\n"); | ||
| 399 | return -EKEYREJECTED; | ||
| 400 | } | ||
| 401 | if (!pkcs7->have_authattrs) { | ||
| 402 | pr_warn("Invalid firmware sig (missing authattrs)\n"); | ||
| 403 | return -EKEYREJECTED; | ||
| 404 | } | ||
| 405 | break; | ||
| 406 | case VERIFYING_KEXEC_PE_SIGNATURE: | ||
| 407 | if (pkcs7->data_type != OID_msIndirectData) { | ||
| 408 | pr_warn("Invalid kexec sig (not Authenticode)\n"); | ||
| 409 | return -EKEYREJECTED; | ||
| 410 | } | ||
| 411 | /* Authattr presence checked in parser */ | ||
| 412 | break; | ||
| 413 | case VERIFYING_UNSPECIFIED_SIGNATURE: | ||
| 414 | if (pkcs7->data_type != OID_data) { | ||
| 415 | pr_warn("Invalid unspecified sig (not pkcs7-data)\n"); | ||
| 416 | return -EKEYREJECTED; | ||
| 417 | } | ||
| 418 | break; | ||
| 419 | default: | ||
| 420 | return -EINVAL; | ||
| 421 | } | ||
| 422 | |||
| 337 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | 423 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { |
| 338 | ret = x509_get_sig_params(x509); | 424 | ret = x509_get_sig_params(x509); |
| 339 | if (ret < 0) | 425 | if (ret < 0) |
| 340 | return ret; | 426 | return ret; |
| 341 | pr_debug("X.509[%u] %*phN\n", | ||
| 342 | n, x509->authority->len, x509->authority->data); | ||
| 343 | } | 427 | } |
| 344 | 428 | ||
| 345 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 429 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
| @@ -359,3 +443,28 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
| 359 | return enopkg; | 443 | return enopkg; |
| 360 | } | 444 | } |
| 361 | EXPORT_SYMBOL_GPL(pkcs7_verify); | 445 | EXPORT_SYMBOL_GPL(pkcs7_verify); |
| 446 | |||
| 447 | /** | ||
| 448 | * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message | ||
| 449 | * @pkcs7: The PKCS#7 message | ||
| 450 | * @data: The data to be verified | ||
| 451 | * @datalen: The amount of data | ||
| 452 | * | ||
| 453 | * Supply the detached data needed to verify a PKCS#7 message. Note that no | ||
| 454 | * attempt to retain/pin the data is made. That is left to the caller. The | ||
| 455 | * data will not be modified by pkcs7_verify() and will not be freed when the | ||
| 456 | * PKCS#7 message is freed. | ||
| 457 | * | ||
| 458 | * Returns -EINVAL if data is already supplied in the message, 0 otherwise. | ||
| 459 | */ | ||
| 460 | int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, | ||
| 461 | const void *data, size_t datalen) | ||
| 462 | { | ||
| 463 | if (pkcs7->data) { | ||
| 464 | pr_debug("Data already supplied\n"); | ||
| 465 | return -EINVAL; | ||
| 466 | } | ||
| 467 | pkcs7->data = data; | ||
| 468 | pkcs7->data_len = datalen; | ||
| 469 | return 0; | ||
| 470 | } | ||
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 2f6e4fb1a1ea..81efccbe22d5 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
| @@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo); | |||
| 39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { | 39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { |
| 40 | [PKEY_ID_PGP] = "PGP", | 40 | [PKEY_ID_PGP] = "PGP", |
| 41 | [PKEY_ID_X509] = "X509", | 41 | [PKEY_ID_X509] = "X509", |
| 42 | [PKEY_ID_PKCS7] = "PKCS#7", | ||
| 42 | }; | 43 | }; |
| 43 | EXPORT_SYMBOL_GPL(pkey_id_type_name); | 44 | EXPORT_SYMBOL_GPL(pkey_id_type_name); |
| 44 | 45 | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 2421f46184ce..897b734dabf9 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
| @@ -393,6 +393,7 @@ error_no_desc: | |||
| 393 | * @pebuf: Buffer containing the PE binary image | 393 | * @pebuf: Buffer containing the PE binary image |
| 394 | * @pelen: Length of the binary image | 394 | * @pelen: Length of the binary image |
| 395 | * @trust_keyring: Signing certificates to use as starting points | 395 | * @trust_keyring: Signing certificates to use as starting points |
| 396 | * @usage: The use to which the key is being put. | ||
| 396 | * @_trusted: Set to true if trustworth, false otherwise | 397 | * @_trusted: Set to true if trustworth, false otherwise |
| 397 | * | 398 | * |
| 398 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | 399 | * Validate that the certificate chain inside the PKCS#7 message inside the PE |
| @@ -417,7 +418,9 @@ error_no_desc: | |||
| 417 | * May also return -ENOMEM. | 418 | * May also return -ENOMEM. |
| 418 | */ | 419 | */ |
| 419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 420 | int verify_pefile_signature(const void *pebuf, unsigned pelen, |
| 420 | struct key *trusted_keyring, bool *_trusted) | 421 | struct key *trusted_keyring, |
| 422 | enum key_being_used_for usage, | ||
| 423 | bool *_trusted) | ||
| 421 | { | 424 | { |
| 422 | struct pkcs7_message *pkcs7; | 425 | struct pkcs7_message *pkcs7; |
| 423 | struct pefile_context ctx; | 426 | struct pefile_context ctx; |
| @@ -462,7 +465,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
| 462 | if (ret < 0) | 465 | if (ret < 0) |
| 463 | goto error; | 466 | goto error; |
| 464 | 467 | ||
| 465 | ret = pkcs7_verify(pkcs7); | 468 | ret = pkcs7_verify(pkcs7, usage); |
| 466 | if (ret < 0) | 469 | if (ret < 0) |
| 467 | goto error; | 470 | goto error; |
| 468 | 471 | ||
diff --git a/crypto/asymmetric_keys/x509_akid.asn1 b/crypto/asymmetric_keys/x509_akid.asn1 new file mode 100644 index 000000000000..1a33231a75a8 --- /dev/null +++ b/crypto/asymmetric_keys/x509_akid.asn1 | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | -- X.509 AuthorityKeyIdentifier | ||
| 2 | -- rfc5280 section 4.2.1.1 | ||
| 3 | |||
| 4 | AuthorityKeyIdentifier ::= SEQUENCE { | ||
| 5 | keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, | ||
| 6 | authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, | ||
| 7 | authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL | ||
| 8 | } | ||
| 9 | |||
| 10 | KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid }) | ||
| 11 | |||
| 12 | CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial }) | ||
| 13 | |||
| 14 | GeneralNames ::= SEQUENCE OF GeneralName | ||
| 15 | |||
| 16 | GeneralName ::= CHOICE { | ||
| 17 | otherName [0] ANY, | ||
| 18 | rfc822Name [1] IA5String, | ||
| 19 | dNSName [2] IA5String, | ||
| 20 | x400Address [3] ANY, | ||
| 21 | directoryName [4] Name ({ x509_akid_note_name }), | ||
| 22 | ediPartyName [5] ANY, | ||
| 23 | uniformResourceIdentifier [6] IA5String, | ||
| 24 | iPAddress [7] OCTET STRING, | ||
| 25 | registeredID [8] OBJECT IDENTIFIER | ||
| 26 | } | ||
| 27 | |||
| 28 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
| 29 | |||
| 30 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
| 31 | |||
| 32 | AttributeValueAssertion ::= SEQUENCE { | ||
| 33 | attributeType OBJECT IDENTIFIER ({ x509_note_OID }), | ||
| 34 | attributeValue ANY ({ x509_extract_name_segment }) | ||
| 35 | } | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index a668d90302d3..af71878dc15b 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "public_key.h" | 18 | #include "public_key.h" |
| 19 | #include "x509_parser.h" | 19 | #include "x509_parser.h" |
| 20 | #include "x509-asn1.h" | 20 | #include "x509-asn1.h" |
| 21 | #include "x509_akid-asn1.h" | ||
| 21 | #include "x509_rsakey-asn1.h" | 22 | #include "x509_rsakey-asn1.h" |
| 22 | 23 | ||
| 23 | struct x509_parse_context { | 24 | struct x509_parse_context { |
| @@ -35,6 +36,10 @@ struct x509_parse_context { | |||
| 35 | u16 o_offset; /* Offset of organizationName (O) */ | 36 | u16 o_offset; /* Offset of organizationName (O) */ |
| 36 | u16 cn_offset; /* Offset of commonName (CN) */ | 37 | u16 cn_offset; /* Offset of commonName (CN) */ |
| 37 | u16 email_offset; /* Offset of emailAddress */ | 38 | u16 email_offset; /* Offset of emailAddress */ |
| 39 | unsigned raw_akid_size; | ||
| 40 | const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ | ||
| 41 | const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ | ||
| 42 | unsigned akid_raw_issuer_size; | ||
| 38 | }; | 43 | }; |
| 39 | 44 | ||
| 40 | /* | 45 | /* |
| @@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert) | |||
| 48 | kfree(cert->subject); | 53 | kfree(cert->subject); |
| 49 | kfree(cert->id); | 54 | kfree(cert->id); |
| 50 | kfree(cert->skid); | 55 | kfree(cert->skid); |
| 51 | kfree(cert->authority); | 56 | kfree(cert->akid_id); |
| 57 | kfree(cert->akid_skid); | ||
| 52 | kfree(cert->sig.digest); | 58 | kfree(cert->sig.digest); |
| 53 | mpi_free(cert->sig.rsa.s); | 59 | mpi_free(cert->sig.rsa.s); |
| 54 | kfree(cert); | 60 | kfree(cert); |
| @@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
| 85 | if (ret < 0) | 91 | if (ret < 0) |
| 86 | goto error_decode; | 92 | goto error_decode; |
| 87 | 93 | ||
| 94 | /* Decode the AuthorityKeyIdentifier */ | ||
| 95 | if (ctx->raw_akid) { | ||
| 96 | pr_devel("AKID: %u %*phN\n", | ||
| 97 | ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); | ||
| 98 | ret = asn1_ber_decoder(&x509_akid_decoder, ctx, | ||
| 99 | ctx->raw_akid, ctx->raw_akid_size); | ||
| 100 | if (ret < 0) { | ||
| 101 | pr_warn("Couldn't decode AuthKeyIdentifier\n"); | ||
| 102 | goto error_decode; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 88 | /* Decode the public key */ | 106 | /* Decode the public key */ |
| 89 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, | 107 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, |
| 90 | ctx->key, ctx->key_size); | 108 | ctx->key, ctx->key_size); |
| @@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
| 422 | struct x509_parse_context *ctx = context; | 440 | struct x509_parse_context *ctx = context; |
| 423 | struct asymmetric_key_id *kid; | 441 | struct asymmetric_key_id *kid; |
| 424 | const unsigned char *v = value; | 442 | const unsigned char *v = value; |
| 425 | int i; | ||
| 426 | 443 | ||
| 427 | pr_debug("Extension: %u\n", ctx->last_oid); | 444 | pr_debug("Extension: %u\n", ctx->last_oid); |
| 428 | 445 | ||
| @@ -437,9 +454,7 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
| 437 | 454 | ||
| 438 | ctx->cert->raw_skid_size = vlen; | 455 | ctx->cert->raw_skid_size = vlen; |
| 439 | ctx->cert->raw_skid = v; | 456 | ctx->cert->raw_skid = v; |
| 440 | kid = asymmetric_key_generate_id(ctx->cert->raw_subject, | 457 | kid = asymmetric_key_generate_id(v, vlen, "", 0); |
| 441 | ctx->cert->raw_subject_size, | ||
| 442 | v, vlen); | ||
| 443 | if (IS_ERR(kid)) | 458 | if (IS_ERR(kid)) |
| 444 | return PTR_ERR(kid); | 459 | return PTR_ERR(kid); |
| 445 | ctx->cert->skid = kid; | 460 | ctx->cert->skid = kid; |
| @@ -449,117 +464,113 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
| 449 | 464 | ||
| 450 | if (ctx->last_oid == OID_authorityKeyIdentifier) { | 465 | if (ctx->last_oid == OID_authorityKeyIdentifier) { |
| 451 | /* Get hold of the CA key fingerprint */ | 466 | /* Get hold of the CA key fingerprint */ |
| 452 | if (ctx->cert->authority || vlen < 5) | 467 | ctx->raw_akid = v; |
| 453 | return -EBADMSG; | 468 | ctx->raw_akid_size = vlen; |
| 454 | |||
| 455 | /* Authority Key Identifier must be a Constructed SEQUENCE */ | ||
| 456 | if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) | ||
| 457 | return -EBADMSG; | ||
| 458 | |||
| 459 | /* Authority Key Identifier is not indefinite length */ | ||
| 460 | if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) | ||
| 461 | return -EBADMSG; | ||
| 462 | |||
| 463 | if (vlen < ASN1_INDEFINITE_LENGTH) { | ||
| 464 | /* Short Form length */ | ||
| 465 | if (v[1] != vlen - 2 || | ||
| 466 | v[2] != SEQ_TAG_KEYID || | ||
| 467 | v[3] > vlen - 4) | ||
| 468 | return -EBADMSG; | ||
| 469 | |||
| 470 | vlen = v[3]; | ||
| 471 | v += 4; | ||
| 472 | } else { | ||
| 473 | /* Long Form length */ | ||
| 474 | size_t seq_len = 0; | ||
| 475 | size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; | ||
| 476 | |||
| 477 | if (sub > 2) | ||
| 478 | return -EBADMSG; | ||
| 479 | |||
| 480 | /* calculate the length from subsequent octets */ | ||
| 481 | v += 2; | ||
| 482 | for (i = 0; i < sub; i++) { | ||
| 483 | seq_len <<= 8; | ||
| 484 | seq_len |= v[i]; | ||
| 485 | } | ||
| 486 | |||
| 487 | if (seq_len != vlen - 2 - sub || | ||
| 488 | v[sub] != SEQ_TAG_KEYID || | ||
| 489 | v[sub + 1] > vlen - 4 - sub) | ||
| 490 | return -EBADMSG; | ||
| 491 | |||
| 492 | vlen = v[sub + 1]; | ||
| 493 | v += (sub + 2); | ||
| 494 | } | ||
| 495 | |||
| 496 | kid = asymmetric_key_generate_id(ctx->cert->raw_issuer, | ||
| 497 | ctx->cert->raw_issuer_size, | ||
| 498 | v, vlen); | ||
| 499 | if (IS_ERR(kid)) | ||
| 500 | return PTR_ERR(kid); | ||
| 501 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
| 502 | ctx->cert->authority = kid; | ||
| 503 | return 0; | 469 | return 0; |
| 504 | } | 470 | } |
| 505 | 471 | ||
| 506 | return 0; | 472 | return 0; |
| 507 | } | 473 | } |
| 508 | 474 | ||
| 509 | /* | 475 | /** |
| 510 | * Record a certificate time. | 476 | * x509_decode_time - Decode an X.509 time ASN.1 object |
| 477 | * @_t: The time to fill in | ||
| 478 | * @hdrlen: The length of the object header | ||
| 479 | * @tag: The object tag | ||
| 480 | * @value: The object value | ||
| 481 | * @vlen: The size of the object value | ||
| 482 | * | ||
| 483 | * Decode an ASN.1 universal time or generalised time field into a struct the | ||
| 484 | * kernel can handle and check it for validity. The time is decoded thus: | ||
| 485 | * | ||
| 486 | * [RFC5280 §4.1.2.5] | ||
| 487 | * CAs conforming to this profile MUST always encode certificate validity | ||
| 488 | * dates through the year 2049 as UTCTime; certificate validity dates in | ||
| 489 | * 2050 or later MUST be encoded as GeneralizedTime. Conforming | ||
| 490 | * applications MUST be able to process validity dates that are encoded in | ||
| 491 | * either UTCTime or GeneralizedTime. | ||
| 511 | */ | 492 | */ |
| 512 | static int x509_note_time(struct tm *tm, size_t hdrlen, | 493 | int x509_decode_time(time64_t *_t, size_t hdrlen, |
| 513 | unsigned char tag, | 494 | unsigned char tag, |
| 514 | const unsigned char *value, size_t vlen) | 495 | const unsigned char *value, size_t vlen) |
| 515 | { | 496 | { |
| 497 | static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, | ||
| 498 | 31, 31, 30, 31, 30, 31 }; | ||
| 516 | const unsigned char *p = value; | 499 | const unsigned char *p = value; |
| 500 | unsigned year, mon, day, hour, min, sec, mon_len; | ||
| 517 | 501 | ||
| 518 | #define dec2bin(X) ((X) - '0') | 502 | #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) |
| 519 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) | 503 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) |
| 520 | 504 | ||
| 521 | if (tag == ASN1_UNITIM) { | 505 | if (tag == ASN1_UNITIM) { |
| 522 | /* UTCTime: YYMMDDHHMMSSZ */ | 506 | /* UTCTime: YYMMDDHHMMSSZ */ |
| 523 | if (vlen != 13) | 507 | if (vlen != 13) |
| 524 | goto unsupported_time; | 508 | goto unsupported_time; |
| 525 | tm->tm_year = DD2bin(p); | 509 | year = DD2bin(p); |
| 526 | if (tm->tm_year >= 50) | 510 | if (year >= 50) |
| 527 | tm->tm_year += 1900; | 511 | year += 1900; |
| 528 | else | 512 | else |
| 529 | tm->tm_year += 2000; | 513 | year += 2000; |
| 530 | } else if (tag == ASN1_GENTIM) { | 514 | } else if (tag == ASN1_GENTIM) { |
| 531 | /* GenTime: YYYYMMDDHHMMSSZ */ | 515 | /* GenTime: YYYYMMDDHHMMSSZ */ |
| 532 | if (vlen != 15) | 516 | if (vlen != 15) |
| 533 | goto unsupported_time; | 517 | goto unsupported_time; |
| 534 | tm->tm_year = DD2bin(p) * 100 + DD2bin(p); | 518 | year = DD2bin(p) * 100 + DD2bin(p); |
| 519 | if (year >= 1950 && year <= 2049) | ||
| 520 | goto invalid_time; | ||
| 535 | } else { | 521 | } else { |
| 536 | goto unsupported_time; | 522 | goto unsupported_time; |
| 537 | } | 523 | } |
| 538 | 524 | ||
| 539 | tm->tm_year -= 1900; | 525 | mon = DD2bin(p); |
| 540 | tm->tm_mon = DD2bin(p) - 1; | 526 | day = DD2bin(p); |
| 541 | tm->tm_mday = DD2bin(p); | 527 | hour = DD2bin(p); |
| 542 | tm->tm_hour = DD2bin(p); | 528 | min = DD2bin(p); |
| 543 | tm->tm_min = DD2bin(p); | 529 | sec = DD2bin(p); |
| 544 | tm->tm_sec = DD2bin(p); | ||
| 545 | 530 | ||
| 546 | if (*p != 'Z') | 531 | if (*p != 'Z') |
| 547 | goto unsupported_time; | 532 | goto unsupported_time; |
| 548 | 533 | ||
| 534 | mon_len = month_lengths[mon]; | ||
| 535 | if (mon == 2) { | ||
| 536 | if (year % 4 == 0) { | ||
| 537 | mon_len = 29; | ||
| 538 | if (year % 100 == 0) { | ||
| 539 | year /= 100; | ||
| 540 | if (year % 4 != 0) | ||
| 541 | mon_len = 28; | ||
| 542 | } | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | if (year < 1970 || | ||
| 547 | mon < 1 || mon > 12 || | ||
| 548 | day < 1 || day > mon_len || | ||
| 549 | hour < 0 || hour > 23 || | ||
| 550 | min < 0 || min > 59 || | ||
| 551 | sec < 0 || sec > 59) | ||
| 552 | goto invalid_time; | ||
| 553 | |||
| 554 | *_t = mktime64(year, mon, day, hour, min, sec); | ||
| 549 | return 0; | 555 | return 0; |
| 550 | 556 | ||
| 551 | unsupported_time: | 557 | unsupported_time: |
| 552 | pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", | 558 | pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", |
| 553 | tag, (int)vlen, (int)vlen, value); | 559 | tag, (int)vlen, value); |
| 560 | return -EBADMSG; | ||
| 561 | invalid_time: | ||
| 562 | pr_debug("Got invalid time [tag %02x]: '%*phN'\n", | ||
| 563 | tag, (int)vlen, value); | ||
| 554 | return -EBADMSG; | 564 | return -EBADMSG; |
| 555 | } | 565 | } |
| 566 | EXPORT_SYMBOL_GPL(x509_decode_time); | ||
| 556 | 567 | ||
| 557 | int x509_note_not_before(void *context, size_t hdrlen, | 568 | int x509_note_not_before(void *context, size_t hdrlen, |
| 558 | unsigned char tag, | 569 | unsigned char tag, |
| 559 | const void *value, size_t vlen) | 570 | const void *value, size_t vlen) |
| 560 | { | 571 | { |
| 561 | struct x509_parse_context *ctx = context; | 572 | struct x509_parse_context *ctx = context; |
| 562 | return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); | 573 | return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); |
| 563 | } | 574 | } |
| 564 | 575 | ||
| 565 | int x509_note_not_after(void *context, size_t hdrlen, | 576 | int x509_note_not_after(void *context, size_t hdrlen, |
| @@ -567,5 +578,71 @@ int x509_note_not_after(void *context, size_t hdrlen, | |||
| 567 | const void *value, size_t vlen) | 578 | const void *value, size_t vlen) |
| 568 | { | 579 | { |
| 569 | struct x509_parse_context *ctx = context; | 580 | struct x509_parse_context *ctx = context; |
| 570 | return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); | 581 | return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); |
| 582 | } | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Note a key identifier-based AuthorityKeyIdentifier | ||
| 586 | */ | ||
| 587 | int x509_akid_note_kid(void *context, size_t hdrlen, | ||
| 588 | unsigned char tag, | ||
| 589 | const void *value, size_t vlen) | ||
| 590 | { | ||
| 591 | struct x509_parse_context *ctx = context; | ||
| 592 | struct asymmetric_key_id *kid; | ||
| 593 | |||
| 594 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); | ||
| 595 | |||
| 596 | if (ctx->cert->akid_skid) | ||
| 597 | return 0; | ||
| 598 | |||
| 599 | kid = asymmetric_key_generate_id(value, vlen, "", 0); | ||
| 600 | if (IS_ERR(kid)) | ||
| 601 | return PTR_ERR(kid); | ||
| 602 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
| 603 | ctx->cert->akid_skid = kid; | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Note a directoryName in an AuthorityKeyIdentifier | ||
| 609 | */ | ||
| 610 | int x509_akid_note_name(void *context, size_t hdrlen, | ||
| 611 | unsigned char tag, | ||
| 612 | const void *value, size_t vlen) | ||
| 613 | { | ||
| 614 | struct x509_parse_context *ctx = context; | ||
| 615 | |||
| 616 | pr_debug("AKID: name: %*phN\n", (int)vlen, value); | ||
| 617 | |||
| 618 | ctx->akid_raw_issuer = value; | ||
| 619 | ctx->akid_raw_issuer_size = vlen; | ||
| 620 | return 0; | ||
| 621 | } | ||
| 622 | |||
| 623 | /* | ||
| 624 | * Note a serial number in an AuthorityKeyIdentifier | ||
| 625 | */ | ||
| 626 | int x509_akid_note_serial(void *context, size_t hdrlen, | ||
| 627 | unsigned char tag, | ||
| 628 | const void *value, size_t vlen) | ||
| 629 | { | ||
| 630 | struct x509_parse_context *ctx = context; | ||
| 631 | struct asymmetric_key_id *kid; | ||
| 632 | |||
| 633 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); | ||
| 634 | |||
| 635 | if (!ctx->akid_raw_issuer || ctx->cert->akid_id) | ||
| 636 | return 0; | ||
| 637 | |||
| 638 | kid = asymmetric_key_generate_id(value, | ||
| 639 | vlen, | ||
| 640 | ctx->akid_raw_issuer, | ||
| 641 | ctx->akid_raw_issuer_size); | ||
| 642 | if (IS_ERR(kid)) | ||
| 643 | return PTR_ERR(kid); | ||
| 644 | |||
| 645 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
| 646 | ctx->cert->akid_id = kid; | ||
| 647 | return 0; | ||
| 571 | } | 648 | } |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 3dfe6b5d6f0b..1de01eaec884 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
| @@ -19,11 +19,12 @@ struct x509_certificate { | |||
| 19 | struct public_key_signature sig; /* Signature parameters */ | 19 | struct public_key_signature sig; /* Signature parameters */ |
| 20 | char *issuer; /* Name of certificate issuer */ | 20 | char *issuer; /* Name of certificate issuer */ |
| 21 | char *subject; /* Name of certificate subject */ | 21 | char *subject; /* Name of certificate subject */ |
| 22 | struct asymmetric_key_id *id; /* Serial number + issuer */ | 22 | struct asymmetric_key_id *id; /* Issuer + Serial number */ |
| 23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ | 23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ |
| 24 | struct asymmetric_key_id *authority; /* Authority key identifier (optional) */ | 24 | struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ |
| 25 | struct tm valid_from; | 25 | struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ |
| 26 | struct tm valid_to; | 26 | time64_t valid_from; |
| 27 | time64_t valid_to; | ||
| 27 | const void *tbs; /* Signed data */ | 28 | const void *tbs; /* Signed data */ |
| 28 | unsigned tbs_size; /* Size of signed data */ | 29 | unsigned tbs_size; /* Size of signed data */ |
| 29 | unsigned raw_sig_size; /* Size of sigature */ | 30 | unsigned raw_sig_size; /* Size of sigature */ |
| @@ -48,6 +49,9 @@ struct x509_certificate { | |||
| 48 | */ | 49 | */ |
| 49 | extern void x509_free_certificate(struct x509_certificate *cert); | 50 | extern void x509_free_certificate(struct x509_certificate *cert); |
| 50 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); | 51 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); |
| 52 | extern int x509_decode_time(time64_t *_t, size_t hdrlen, | ||
| 53 | unsigned char tag, | ||
| 54 | const unsigned char *value, size_t vlen); | ||
| 51 | 55 | ||
| 52 | /* | 56 | /* |
| 53 | * x509_public_key.c | 57 | * x509_public_key.c |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 24f17e6c5904..6d88dd15c98d 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
| @@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup); | |||
| 65 | /** | 65 | /** |
| 66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | 66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. |
| 67 | * @keyring: The keys to search. | 67 | * @keyring: The keys to search. |
| 68 | * @kid: The key ID. | 68 | * @id: The issuer & serialNumber to look for or NULL. |
| 69 | * @skid: The subjectKeyIdentifier to look for or NULL. | ||
| 69 | * @partial: Use partial match if true, exact if false. | 70 | * @partial: Use partial match if true, exact if false. |
| 70 | * | 71 | * |
| 71 | * Find a key in the given keyring by subject name and key ID. These might, | 72 | * Find a key in the given keyring by identifier. The preferred identifier is |
| 72 | * for instance, be the issuer name and the authority key ID of an X.509 | 73 | * the issuer + serialNumber and the fallback identifier is the |
| 73 | * certificate that needs to be verified. | 74 | * subjectKeyIdentifier. If both are given, the lookup is by the former, but |
| 75 | * the latter must also match. | ||
| 74 | */ | 76 | */ |
| 75 | struct key *x509_request_asymmetric_key(struct key *keyring, | 77 | struct key *x509_request_asymmetric_key(struct key *keyring, |
| 76 | const struct asymmetric_key_id *kid, | 78 | const struct asymmetric_key_id *id, |
| 79 | const struct asymmetric_key_id *skid, | ||
| 77 | bool partial) | 80 | bool partial) |
| 78 | { | 81 | { |
| 79 | key_ref_t key; | 82 | struct key *key; |
| 80 | char *id, *p; | 83 | key_ref_t ref; |
| 81 | 84 | const char *lookup; | |
| 85 | char *req, *p; | ||
| 86 | int len; | ||
| 87 | |||
| 88 | if (id) { | ||
| 89 | lookup = id->data; | ||
| 90 | len = id->len; | ||
| 91 | } else { | ||
| 92 | lookup = skid->data; | ||
| 93 | len = skid->len; | ||
| 94 | } | ||
| 95 | |||
| 82 | /* Construct an identifier "id:<keyid>". */ | 96 | /* Construct an identifier "id:<keyid>". */ |
| 83 | p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL); | 97 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); |
| 84 | if (!id) | 98 | if (!req) |
| 85 | return ERR_PTR(-ENOMEM); | 99 | return ERR_PTR(-ENOMEM); |
| 86 | 100 | ||
| 87 | if (partial) { | 101 | if (partial) { |
| @@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring, | |||
| 92 | *p++ = 'x'; | 106 | *p++ = 'x'; |
| 93 | } | 107 | } |
| 94 | *p++ = ':'; | 108 | *p++ = ':'; |
| 95 | p = bin2hex(p, kid->data, kid->len); | 109 | p = bin2hex(p, lookup, len); |
| 96 | *p = 0; | 110 | *p = 0; |
| 97 | 111 | ||
| 98 | pr_debug("Look up: \"%s\"\n", id); | 112 | pr_debug("Look up: \"%s\"\n", req); |
| 99 | 113 | ||
| 100 | key = keyring_search(make_key_ref(keyring, 1), | 114 | ref = keyring_search(make_key_ref(keyring, 1), |
| 101 | &key_type_asymmetric, id); | 115 | &key_type_asymmetric, req); |
| 102 | if (IS_ERR(key)) | 116 | if (IS_ERR(ref)) |
| 103 | pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key)); | 117 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); |
| 104 | kfree(id); | 118 | kfree(req); |
| 105 | 119 | ||
| 106 | if (IS_ERR(key)) { | 120 | if (IS_ERR(ref)) { |
| 107 | switch (PTR_ERR(key)) { | 121 | switch (PTR_ERR(ref)) { |
| 108 | /* Hide some search errors */ | 122 | /* Hide some search errors */ |
| 109 | case -EACCES: | 123 | case -EACCES: |
| 110 | case -ENOTDIR: | 124 | case -ENOTDIR: |
| 111 | case -EAGAIN: | 125 | case -EAGAIN: |
| 112 | return ERR_PTR(-ENOKEY); | 126 | return ERR_PTR(-ENOKEY); |
| 113 | default: | 127 | default: |
| 114 | return ERR_CAST(key); | 128 | return ERR_CAST(ref); |
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | key = key_ref_to_ptr(ref); | ||
| 133 | if (id && skid) { | ||
| 134 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
| 135 | if (!kids->id[1]) { | ||
| 136 | pr_debug("issuer+serial match, but expected SKID missing\n"); | ||
| 137 | goto reject; | ||
| 138 | } | ||
| 139 | if (!asymmetric_key_id_same(skid, kids->id[1])) { | ||
| 140 | pr_debug("issuer+serial match, but SKID does not\n"); | ||
| 141 | goto reject; | ||
| 115 | } | 142 | } |
| 116 | } | 143 | } |
| 144 | |||
| 145 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
| 146 | return key; | ||
| 117 | 147 | ||
| 118 | pr_devel("<==%s() = 0 [%x]\n", __func__, | 148 | reject: |
| 119 | key_serial(key_ref_to_ptr(key))); | 149 | key_put(key); |
| 120 | return key_ref_to_ptr(key); | 150 | return ERR_PTR(-EKEYREJECTED); |
| 121 | } | 151 | } |
| 122 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | 152 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); |
| 123 | 153 | ||
| @@ -227,10 +257,11 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
| 227 | if (!trust_keyring) | 257 | if (!trust_keyring) |
| 228 | return -EOPNOTSUPP; | 258 | return -EOPNOTSUPP; |
| 229 | 259 | ||
| 230 | if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid)) | 260 | if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid)) |
| 231 | return -EPERM; | 261 | return -EPERM; |
| 232 | 262 | ||
| 233 | key = x509_request_asymmetric_key(trust_keyring, cert->authority, | 263 | key = x509_request_asymmetric_key(trust_keyring, |
| 264 | cert->akid_id, cert->akid_skid, | ||
| 234 | false); | 265 | false); |
| 235 | if (!IS_ERR(key)) { | 266 | if (!IS_ERR(key)) { |
| 236 | if (!use_builtin_keys | 267 | if (!use_builtin_keys |
| @@ -271,14 +302,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 271 | } | 302 | } |
| 272 | 303 | ||
| 273 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); | 304 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); |
| 274 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | 305 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
| 275 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | ||
| 276 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | ||
| 277 | cert->valid_from.tm_min, cert->valid_from.tm_sec); | ||
| 278 | pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
| 279 | cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, | ||
| 280 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | ||
| 281 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | ||
| 282 | pr_devel("Cert Signature: %s + %s\n", | 306 | pr_devel("Cert Signature: %s + %s\n", |
| 283 | pkey_algo_name[cert->sig.pkey_algo], | 307 | pkey_algo_name[cert->sig.pkey_algo], |
| 284 | hash_algo_name[cert->sig.pkey_hash_algo]); | 308 | hash_algo_name[cert->sig.pkey_hash_algo]); |
| @@ -287,8 +311,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
| 287 | cert->pub->id_type = PKEY_ID_X509; | 311 | cert->pub->id_type = PKEY_ID_X509; |
| 288 | 312 | ||
| 289 | /* Check the signature on the key if it appears to be self-signed */ | 313 | /* Check the signature on the key if it appears to be self-signed */ |
| 290 | if (!cert->authority || | 314 | if ((!cert->akid_skid && !cert->akid_id) || |
| 291 | asymmetric_key_id_same(cert->skid, cert->authority)) { | 315 | asymmetric_key_id_same(cert->skid, cert->akid_skid) || |
| 316 | asymmetric_key_id_same(cert->id, cert->akid_id)) { | ||
| 292 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 317 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
| 293 | if (ret < 0) | 318 | if (ret < 0) |
| 294 | goto error_free_cert; | 319 | goto error_free_cert; |
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h index 691c79172a26..441aff9b5aa7 100644 --- a/include/crypto/pkcs7.h +++ b/include/crypto/pkcs7.h | |||
| @@ -9,6 +9,11 @@ | |||
| 9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #ifndef _CRYPTO_PKCS7_H | ||
| 13 | #define _CRYPTO_PKCS7_H | ||
| 14 | |||
| 15 | #include <crypto/public_key.h> | ||
| 16 | |||
| 12 | struct key; | 17 | struct key; |
| 13 | struct pkcs7_message; | 18 | struct pkcs7_message; |
| 14 | 19 | ||
| @@ -33,4 +38,10 @@ extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | |||
| 33 | /* | 38 | /* |
| 34 | * pkcs7_verify.c | 39 | * pkcs7_verify.c |
| 35 | */ | 40 | */ |
| 36 | extern int pkcs7_verify(struct pkcs7_message *pkcs7); | 41 | extern int pkcs7_verify(struct pkcs7_message *pkcs7, |
| 42 | enum key_being_used_for usage); | ||
| 43 | |||
| 44 | extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, | ||
| 45 | const void *data, size_t datalen); | ||
| 46 | |||
| 47 | #endif /* _CRYPTO_PKCS7_H */ | ||
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 54add2069901..067c242b1e15 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h | |||
| @@ -33,12 +33,27 @@ extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST]; | |||
| 33 | enum pkey_id_type { | 33 | enum pkey_id_type { |
| 34 | PKEY_ID_PGP, /* OpenPGP generated key ID */ | 34 | PKEY_ID_PGP, /* OpenPGP generated key ID */ |
| 35 | PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ | 35 | PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ |
| 36 | PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ | ||
| 36 | PKEY_ID_TYPE__LAST | 37 | PKEY_ID_TYPE__LAST |
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| 39 | extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; | 40 | extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; |
| 40 | 41 | ||
| 41 | /* | 42 | /* |
| 43 | * The use to which an asymmetric key is being put. | ||
| 44 | */ | ||
| 45 | enum key_being_used_for { | ||
| 46 | VERIFYING_MODULE_SIGNATURE, | ||
| 47 | VERIFYING_FIRMWARE_SIGNATURE, | ||
| 48 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
| 49 | VERIFYING_KEY_SIGNATURE, | ||
| 50 | VERIFYING_KEY_SELF_SIGNATURE, | ||
| 51 | VERIFYING_UNSPECIFIED_SIGNATURE, | ||
| 52 | NR__KEY_BEING_USED_FOR | ||
| 53 | }; | ||
| 54 | extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; | ||
| 55 | |||
| 56 | /* | ||
| 42 | * Cryptographic data for the public-key subtype of the asymmetric key type. | 57 | * Cryptographic data for the public-key subtype of the asymmetric key type. |
| 43 | * | 58 | * |
| 44 | * Note that this may include private part of the key as well as the public | 59 | * Note that this may include private part of the key as well as the public |
| @@ -101,7 +116,8 @@ extern int verify_signature(const struct key *key, | |||
| 101 | 116 | ||
| 102 | struct asymmetric_key_id; | 117 | struct asymmetric_key_id; |
| 103 | extern struct key *x509_request_asymmetric_key(struct key *keyring, | 118 | extern struct key *x509_request_asymmetric_key(struct key *keyring, |
| 104 | const struct asymmetric_key_id *kid, | 119 | const struct asymmetric_key_id *id, |
| 120 | const struct asymmetric_key_id *skid, | ||
| 105 | bool partial); | 121 | bool partial); |
| 106 | 122 | ||
| 107 | #endif /* _LINUX_PUBLIC_KEY_H */ | 123 | #endif /* _LINUX_PUBLIC_KEY_H */ |
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 72665eb80692..b20cd885c1fd 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING | 15 | #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING |
| 16 | 16 | ||
| 17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
| 18 | #include <crypto/public_key.h> | ||
| 18 | 19 | ||
| 19 | extern struct key *system_trusted_keyring; | 20 | extern struct key *system_trusted_keyring; |
| 20 | static inline struct key *get_system_trusted_keyring(void) | 21 | static inline struct key *get_system_trusted_keyring(void) |
| @@ -28,4 +29,10 @@ static inline struct key *get_system_trusted_keyring(void) | |||
| 28 | } | 29 | } |
| 29 | #endif | 30 | #endif |
| 30 | 31 | ||
| 32 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | ||
| 33 | extern int system_verify_data(const void *data, unsigned long len, | ||
| 34 | const void *raw_pkcs7, size_t pkcs7_len, | ||
| 35 | enum key_being_used_for usage); | ||
| 36 | #endif | ||
| 37 | |||
| 31 | #endif /* _KEYS_SYSTEM_KEYRING_H */ | 38 | #endif /* _KEYS_SYSTEM_KEYRING_H */ |
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index c2bbf672b84e..93e0ff92fb9b 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h | |||
| @@ -41,7 +41,7 @@ enum OID { | |||
| 41 | OID_signed_data, /* 1.2.840.113549.1.7.2 */ | 41 | OID_signed_data, /* 1.2.840.113549.1.7.2 */ |
| 42 | /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */ | 42 | /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */ |
| 43 | OID_email_address, /* 1.2.840.113549.1.9.1 */ | 43 | OID_email_address, /* 1.2.840.113549.1.9.1 */ |
| 44 | OID_content_type, /* 1.2.840.113549.1.9.3 */ | 44 | OID_contentType, /* 1.2.840.113549.1.9.3 */ |
| 45 | OID_messageDigest, /* 1.2.840.113549.1.9.4 */ | 45 | OID_messageDigest, /* 1.2.840.113549.1.9.4 */ |
| 46 | OID_signingTime, /* 1.2.840.113549.1.9.5 */ | 46 | OID_signingTime, /* 1.2.840.113549.1.9.5 */ |
| 47 | OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */ | 47 | OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */ |
| @@ -54,6 +54,8 @@ enum OID { | |||
| 54 | 54 | ||
| 55 | /* Microsoft Authenticode & Software Publishing */ | 55 | /* Microsoft Authenticode & Software Publishing */ |
| 56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ | 56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ |
| 57 | OID_msStatementType, /* 1.3.6.1.4.1.311.2.1.11 */ | ||
| 58 | OID_msSpOpusInfo, /* 1.3.6.1.4.1.311.2.1.12 */ | ||
| 57 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ | 59 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ |
| 58 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ | 60 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ |
| 59 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ | 61 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ |
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h index ac34819214f9..da2049b5161c 100644 --- a/include/linux/verify_pefile.h +++ b/include/linux/verify_pefile.h | |||
| @@ -12,7 +12,11 @@ | |||
| 12 | #ifndef _LINUX_VERIFY_PEFILE_H | 12 | #ifndef _LINUX_VERIFY_PEFILE_H |
| 13 | #define _LINUX_VERIFY_PEFILE_H | 13 | #define _LINUX_VERIFY_PEFILE_H |
| 14 | 14 | ||
| 15 | #include <crypto/public_key.h> | ||
| 16 | |||
| 15 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | 17 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, |
| 16 | struct key *trusted_keyring, bool *_trusted); | 18 | struct key *trusted_keyring, |
| 19 | enum key_being_used_for usage, | ||
| 20 | bool *_trusted); | ||
| 17 | 21 | ||
| 18 | #endif /* _LINUX_VERIFY_PEFILE_H */ | 22 | #endif /* _LINUX_VERIFY_PEFILE_H */ |
diff --git a/init/Kconfig b/init/Kconfig index af09b4fb43d2..5d1a703663ad 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -1752,6 +1752,37 @@ config SYSTEM_TRUSTED_KEYRING | |||
| 1752 | 1752 | ||
| 1753 | Keys in this keyring are used by module signature checking. | 1753 | Keys in this keyring are used by module signature checking. |
| 1754 | 1754 | ||
| 1755 | config SYSTEM_TRUSTED_KEYS | ||
| 1756 | string "Additional X.509 keys for default system keyring" | ||
| 1757 | depends on SYSTEM_TRUSTED_KEYRING | ||
| 1758 | help | ||
| 1759 | If set, this option should be the filename of a PEM-formatted file | ||
| 1760 | containing trusted X.509 certificates to be included in the default | ||
| 1761 | system keyring. Any certificate used for module signing is implicitly | ||
| 1762 | also trusted. | ||
| 1763 | |||
| 1764 | NOTE: If you previously provided keys for the system keyring in the | ||
| 1765 | form of DER-encoded *.x509 files in the top-level build directory, | ||
| 1766 | those are no longer used. You will need to set this option instead. | ||
| 1767 | |||
| 1768 | config SYSTEM_DATA_VERIFICATION | ||
| 1769 | def_bool n | ||
| 1770 | select SYSTEM_TRUSTED_KEYRING | ||
| 1771 | select KEYS | ||
| 1772 | select CRYPTO | ||
| 1773 | select ASYMMETRIC_KEY_TYPE | ||
| 1774 | select ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
| 1775 | select PUBLIC_KEY_ALGO_RSA | ||
| 1776 | select ASN1 | ||
| 1777 | select OID_REGISTRY | ||
| 1778 | select X509_CERTIFICATE_PARSER | ||
| 1779 | select PKCS7_MESSAGE_PARSER | ||
| 1780 | help | ||
| 1781 | Provide PKCS#7 message verification using the contents of the system | ||
| 1782 | trusted keyring to provide public keys. This then can be used for | ||
| 1783 | module verification, kexec image verification and firmware blob | ||
| 1784 | verification. | ||
| 1785 | |||
| 1755 | config PROFILING | 1786 | config PROFILING |
| 1756 | bool "Profiling support" | 1787 | bool "Profiling support" |
| 1757 | help | 1788 | help |
| @@ -1860,20 +1891,16 @@ config MODULE_SRCVERSION_ALL | |||
| 1860 | config MODULE_SIG | 1891 | config MODULE_SIG |
| 1861 | bool "Module signature verification" | 1892 | bool "Module signature verification" |
| 1862 | depends on MODULES | 1893 | depends on MODULES |
| 1863 | select SYSTEM_TRUSTED_KEYRING | 1894 | select SYSTEM_DATA_VERIFICATION |
| 1864 | select KEYS | ||
| 1865 | select CRYPTO | ||
| 1866 | select ASYMMETRIC_KEY_TYPE | ||
| 1867 | select ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
| 1868 | select PUBLIC_KEY_ALGO_RSA | ||
| 1869 | select ASN1 | ||
| 1870 | select OID_REGISTRY | ||
| 1871 | select X509_CERTIFICATE_PARSER | ||
| 1872 | help | 1895 | help |
| 1873 | Check modules for valid signatures upon load: the signature | 1896 | Check modules for valid signatures upon load: the signature |
| 1874 | is simply appended to the module. For more information see | 1897 | is simply appended to the module. For more information see |
| 1875 | Documentation/module-signing.txt. | 1898 | Documentation/module-signing.txt. |
| 1876 | 1899 | ||
| 1900 | Note that this option adds the OpenSSL development packages as a | ||
| 1901 | kernel build dependency so that the signing tool can use its crypto | ||
| 1902 | library. | ||
| 1903 | |||
| 1877 | !!!WARNING!!! If you enable this option, you MUST make sure that the | 1904 | !!!WARNING!!! If you enable this option, you MUST make sure that the |
| 1878 | module DOES NOT get stripped after being signed. This includes the | 1905 | module DOES NOT get stripped after being signed. This includes the |
| 1879 | debuginfo strip done by some packagers (such as rpmbuild) and | 1906 | debuginfo strip done by some packagers (such as rpmbuild) and |
| @@ -1938,6 +1965,20 @@ config MODULE_SIG_HASH | |||
| 1938 | default "sha384" if MODULE_SIG_SHA384 | 1965 | default "sha384" if MODULE_SIG_SHA384 |
| 1939 | default "sha512" if MODULE_SIG_SHA512 | 1966 | default "sha512" if MODULE_SIG_SHA512 |
| 1940 | 1967 | ||
| 1968 | config MODULE_SIG_KEY | ||
| 1969 | string "File name or PKCS#11 URI of module signing key" | ||
| 1970 | default "signing_key.pem" | ||
| 1971 | depends on MODULE_SIG | ||
| 1972 | help | ||
| 1973 | Provide the file name of a private key/certificate in PEM format, | ||
| 1974 | or a PKCS#11 URI according to RFC7512. The file should contain, or | ||
| 1975 | the URI should identify, both the certificate and its corresponding | ||
| 1976 | private key. | ||
| 1977 | |||
| 1978 | If this option is unchanged from its default "signing_key.pem", | ||
| 1979 | then the kernel will automatically generate the private key and | ||
| 1980 | certificate as described in Documentation/module-signing.txt | ||
| 1981 | |||
| 1941 | config MODULE_COMPRESS | 1982 | config MODULE_COMPRESS |
| 1942 | bool "Compress modules on installation" | 1983 | bool "Compress modules on installation" |
| 1943 | depends on MODULES | 1984 | depends on MODULES |
diff --git a/kernel/Makefile b/kernel/Makefile index 43c4c920f30a..65ef3846fbe8 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -114,46 +114,74 @@ $(obj)/config_data.h: $(obj)/config_data.gz FORCE | |||
| 114 | 114 | ||
| 115 | ############################################################################### | 115 | ############################################################################### |
| 116 | # | 116 | # |
| 117 | # Roll all the X.509 certificates that we can find together and pull them into | 117 | # When a Kconfig string contains a filename, it is suitable for |
| 118 | # the kernel so that they get loaded into the system trusted keyring during | 118 | # passing to shell commands. It is surrounded by double-quotes, and |
| 119 | # boot. | 119 | # any double-quotes or backslashes within it are escaped by |
| 120 | # backslashes. | ||
| 120 | # | 121 | # |
| 121 | # We look in the source root and the build root for all files whose name ends | 122 | # This is no use for dependencies or $(wildcard). We need to strip the |
| 122 | # in ".x509". Unfortunately, this will generate duplicate filenames, so we | 123 | # surrounding quotes and the escaping from quotes and backslashes, and |
| 123 | # have make canonicalise the pathnames and then sort them to discard the | 124 | # we *do* need to escape any spaces in the string. So, for example: |
| 124 | # duplicates. | 125 | # |
| 126 | # Usage: $(eval $(call config_filename,FOO)) | ||
| 127 | # | ||
| 128 | # Defines FOO_FILENAME based on the contents of the CONFIG_FOO option, | ||
| 129 | # transformed as described above to be suitable for use within the | ||
| 130 | # makefile. | ||
| 131 | # | ||
| 132 | # Also, if the filename is a relative filename and exists in the source | ||
| 133 | # tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to | ||
| 134 | # be prefixed to *both* command invocation and dependencies. | ||
| 135 | # | ||
| 136 | # Note: We also print the filenames in the quiet_cmd_foo text, and | ||
| 137 | # perhaps ought to have a version specially escaped for that purpose. | ||
| 138 | # But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good | ||
| 139 | # enough. It'll strip the quotes in the common case where there's no | ||
| 140 | # space and it's a simple filename, and it'll retain the quotes when | ||
| 141 | # there's a space. There are some esoteric cases in which it'll print | ||
| 142 | # the wrong thing, but we don't really care. The actual dependencies | ||
| 143 | # and commands *do* get it right, with various combinations of single | ||
| 144 | # and double quotes, backslashes and spaces in the filenames. | ||
| 125 | # | 145 | # |
| 126 | ############################################################################### | 146 | ############################################################################### |
| 127 | ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) | 147 | # |
| 128 | X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509) | 148 | quote := $(firstword " ") |
| 129 | X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += $(objtree)/signing_key.x509 | 149 | space := |
| 130 | X509_CERTIFICATES-raw := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \ | 150 | space += |
| 131 | $(or $(realpath $(CERT)),$(CERT)))) | 151 | space_escape := %%%SPACE%%% |
| 132 | X509_CERTIFICATES := $(subst $(realpath $(objtree))/,,$(X509_CERTIFICATES-raw)) | 152 | # |
| 133 | 153 | define config_filename | |
| 134 | ifeq ($(X509_CERTIFICATES),) | 154 | ifneq ($$(CONFIG_$(1)),"") |
| 135 | $(warning *** No X.509 certificates found ***) | 155 | $(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1))))))) |
| 156 | ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME))) | ||
| 157 | else | ||
| 158 | ifeq ($$(wildcard $$($(1)_FILENAME)),) | ||
| 159 | ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),) | ||
| 160 | $(1)_SRCPREFIX := $(srctree)/ | ||
| 136 | endif | 161 | endif |
| 137 | |||
| 138 | ifneq ($(wildcard $(obj)/.x509.list),) | ||
| 139 | ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES)) | ||
| 140 | $(warning X.509 certificate list changed to "$(X509_CERTIFICATES)" from "$(shell cat $(obj)/.x509.list)") | ||
| 141 | $(shell rm $(obj)/.x509.list) | ||
| 142 | endif | 162 | endif |
| 143 | endif | 163 | endif |
| 164 | endif | ||
| 165 | endef | ||
| 166 | # | ||
| 167 | ############################################################################### | ||
| 168 | |||
| 169 | ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) | ||
| 144 | 170 | ||
| 145 | kernel/system_certificates.o: $(obj)/x509_certificate_list | 171 | $(eval $(call config_filename,SYSTEM_TRUSTED_KEYS)) |
| 146 | 172 | ||
| 147 | quiet_cmd_x509certs = CERTS $@ | 173 | # GCC doesn't include .incbin files in -MD generated dependencies (PR#66871) |
| 148 | cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; $(kecho) " - Including cert $(X509)") | 174 | $(obj)/system_certificates.o: $(obj)/x509_certificate_list |
| 149 | 175 | ||
| 150 | targets += $(obj)/x509_certificate_list | 176 | # Cope with signing_key.x509 existing in $(srctree) not $(objtree) |
| 151 | $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list | 177 | AFLAGS_system_certificates.o := -I$(srctree) |
| 152 | $(call if_changed,x509certs) | ||
| 153 | 178 | ||
| 154 | targets += $(obj)/.x509.list | 179 | quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2)) |
| 155 | $(obj)/.x509.list: | 180 | cmd_extract_certs = scripts/extract-cert $(2) $@ || ( rm $@; exit 1) |
| 156 | @echo $(X509_CERTIFICATES) >$@ | 181 | |
| 182 | targets += x509_certificate_list | ||
| 183 | $(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE | ||
| 184 | $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS)) | ||
| 157 | endif | 185 | endif |
| 158 | 186 | ||
| 159 | clean-files := x509_certificate_list .x509.list | 187 | clean-files := x509_certificate_list .x509.list |
| @@ -170,7 +198,11 @@ ifndef CONFIG_MODULE_SIG_HASH | |||
| 170 | $(error Could not determine digest type to use from kernel config) | 198 | $(error Could not determine digest type to use from kernel config) |
| 171 | endif | 199 | endif |
| 172 | 200 | ||
| 173 | signing_key.priv signing_key.x509: x509.genkey | 201 | # We do it this way rather than having a boolean option for enabling an |
| 202 | # external private key, because 'make randconfig' might enable such a | ||
| 203 | # boolean option and we unfortunately can't make it depend on !RANDCONFIG. | ||
| 204 | ifeq ($(CONFIG_MODULE_SIG_KEY),"signing_key.pem") | ||
| 205 | signing_key.pem: x509.genkey | ||
| 174 | @echo "###" | 206 | @echo "###" |
| 175 | @echo "### Now generating an X.509 key pair to be used for signing modules." | 207 | @echo "### Now generating an X.509 key pair to be used for signing modules." |
| 176 | @echo "###" | 208 | @echo "###" |
| @@ -181,8 +213,8 @@ signing_key.priv signing_key.x509: x509.genkey | |||
| 181 | @echo "###" | 213 | @echo "###" |
| 182 | openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ | 214 | openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ |
| 183 | -batch -x509 -config x509.genkey \ | 215 | -batch -x509 -config x509.genkey \ |
| 184 | -outform DER -out signing_key.x509 \ | 216 | -outform PEM -out signing_key.pem \ |
| 185 | -keyout signing_key.priv 2>&1 | 217 | -keyout signing_key.pem 2>&1 |
| 186 | @echo "###" | 218 | @echo "###" |
| 187 | @echo "### Key pair generated." | 219 | @echo "### Key pair generated." |
| 188 | @echo "###" | 220 | @echo "###" |
| @@ -207,3 +239,17 @@ x509.genkey: | |||
| 207 | @echo >>x509.genkey "subjectKeyIdentifier=hash" | 239 | @echo >>x509.genkey "subjectKeyIdentifier=hash" |
| 208 | @echo >>x509.genkey "authorityKeyIdentifier=keyid" | 240 | @echo >>x509.genkey "authorityKeyIdentifier=keyid" |
| 209 | endif | 241 | endif |
| 242 | |||
| 243 | $(eval $(call config_filename,MODULE_SIG_KEY)) | ||
| 244 | |||
| 245 | # If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it | ||
| 246 | ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME))) | ||
| 247 | X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME) | ||
| 248 | endif | ||
| 249 | |||
| 250 | # GCC PR#66871 again. | ||
| 251 | $(obj)/system_certificates.o: signing_key.x509 | ||
| 252 | |||
| 253 | signing_key.x509: scripts/extract-cert include/config/module/sig/key.h $(X509_DEP) | ||
| 254 | $(call cmd,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) | ||
| 255 | endif | ||
diff --git a/kernel/module_signing.c b/kernel/module_signing.c index be5b8fac4bd0..bd62f5cda746 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c | |||
| @@ -10,11 +10,8 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 13 | #include <linux/err.h> | ||
| 14 | #include <crypto/public_key.h> | ||
| 15 | #include <crypto/hash.h> | ||
| 16 | #include <keys/asymmetric-type.h> | ||
| 17 | #include <keys/system_keyring.h> | 13 | #include <keys/system_keyring.h> |
| 14 | #include <crypto/public_key.h> | ||
| 18 | #include "module-internal.h" | 15 | #include "module-internal.h" |
| 19 | 16 | ||
| 20 | /* | 17 | /* |
| @@ -28,170 +25,22 @@ | |||
| 28 | * - Information block | 25 | * - Information block |
| 29 | */ | 26 | */ |
| 30 | struct module_signature { | 27 | struct module_signature { |
| 31 | u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */ | 28 | u8 algo; /* Public-key crypto algorithm [0] */ |
| 32 | u8 hash; /* Digest algorithm [enum hash_algo] */ | 29 | u8 hash; /* Digest algorithm [0] */ |
| 33 | u8 id_type; /* Key identifier type [enum pkey_id_type] */ | 30 | u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ |
| 34 | u8 signer_len; /* Length of signer's name */ | 31 | u8 signer_len; /* Length of signer's name [0] */ |
| 35 | u8 key_id_len; /* Length of key identifier */ | 32 | u8 key_id_len; /* Length of key identifier [0] */ |
| 36 | u8 __pad[3]; | 33 | u8 __pad[3]; |
| 37 | __be32 sig_len; /* Length of signature data */ | 34 | __be32 sig_len; /* Length of signature data */ |
| 38 | }; | 35 | }; |
| 39 | 36 | ||
| 40 | /* | 37 | /* |
| 41 | * Digest the module contents. | ||
| 42 | */ | ||
| 43 | static struct public_key_signature *mod_make_digest(enum hash_algo hash, | ||
| 44 | const void *mod, | ||
| 45 | unsigned long modlen) | ||
| 46 | { | ||
| 47 | struct public_key_signature *pks; | ||
| 48 | struct crypto_shash *tfm; | ||
| 49 | struct shash_desc *desc; | ||
| 50 | size_t digest_size, desc_size; | ||
| 51 | int ret; | ||
| 52 | |||
| 53 | pr_devel("==>%s()\n", __func__); | ||
| 54 | |||
| 55 | /* Allocate the hashing algorithm we're going to need and find out how | ||
| 56 | * big the hash operational data will be. | ||
| 57 | */ | ||
| 58 | tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); | ||
| 59 | if (IS_ERR(tfm)) | ||
| 60 | return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); | ||
| 61 | |||
| 62 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
| 63 | digest_size = crypto_shash_digestsize(tfm); | ||
| 64 | |||
| 65 | /* We allocate the hash operational data storage on the end of our | ||
| 66 | * context data and the digest output buffer on the end of that. | ||
| 67 | */ | ||
| 68 | ret = -ENOMEM; | ||
| 69 | pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); | ||
| 70 | if (!pks) | ||
| 71 | goto error_no_pks; | ||
| 72 | |||
| 73 | pks->pkey_hash_algo = hash; | ||
| 74 | pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; | ||
| 75 | pks->digest_size = digest_size; | ||
| 76 | |||
| 77 | desc = (void *)pks + sizeof(*pks); | ||
| 78 | desc->tfm = tfm; | ||
| 79 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 80 | |||
| 81 | ret = crypto_shash_init(desc); | ||
| 82 | if (ret < 0) | ||
| 83 | goto error; | ||
| 84 | |||
| 85 | ret = crypto_shash_finup(desc, mod, modlen, pks->digest); | ||
| 86 | if (ret < 0) | ||
| 87 | goto error; | ||
| 88 | |||
| 89 | crypto_free_shash(tfm); | ||
| 90 | pr_devel("<==%s() = ok\n", __func__); | ||
| 91 | return pks; | ||
| 92 | |||
| 93 | error: | ||
| 94 | kfree(pks); | ||
| 95 | error_no_pks: | ||
| 96 | crypto_free_shash(tfm); | ||
| 97 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 98 | return ERR_PTR(ret); | ||
| 99 | } | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Extract an MPI array from the signature data. This represents the actual | ||
| 103 | * signature. Each raw MPI is prefaced by a BE 2-byte value indicating the | ||
| 104 | * size of the MPI in bytes. | ||
| 105 | * | ||
| 106 | * RSA signatures only have one MPI, so currently we only read one. | ||
| 107 | */ | ||
| 108 | static int mod_extract_mpi_array(struct public_key_signature *pks, | ||
| 109 | const void *data, size_t len) | ||
| 110 | { | ||
| 111 | size_t nbytes; | ||
| 112 | MPI mpi; | ||
| 113 | |||
| 114 | if (len < 3) | ||
| 115 | return -EBADMSG; | ||
| 116 | nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1]; | ||
| 117 | data += 2; | ||
| 118 | len -= 2; | ||
| 119 | if (len != nbytes) | ||
| 120 | return -EBADMSG; | ||
| 121 | |||
| 122 | mpi = mpi_read_raw_data(data, nbytes); | ||
| 123 | if (!mpi) | ||
| 124 | return -ENOMEM; | ||
| 125 | pks->mpi[0] = mpi; | ||
| 126 | pks->nr_mpi = 1; | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * Request an asymmetric key. | ||
| 132 | */ | ||
| 133 | static struct key *request_asymmetric_key(const char *signer, size_t signer_len, | ||
| 134 | const u8 *key_id, size_t key_id_len) | ||
| 135 | { | ||
| 136 | key_ref_t key; | ||
| 137 | size_t i; | ||
| 138 | char *id, *q; | ||
| 139 | |||
| 140 | pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len); | ||
| 141 | |||
| 142 | /* Construct an identifier. */ | ||
| 143 | id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL); | ||
| 144 | if (!id) | ||
| 145 | return ERR_PTR(-ENOKEY); | ||
| 146 | |||
| 147 | memcpy(id, signer, signer_len); | ||
| 148 | |||
| 149 | q = id + signer_len; | ||
| 150 | *q++ = ':'; | ||
| 151 | *q++ = ' '; | ||
| 152 | for (i = 0; i < key_id_len; i++) { | ||
| 153 | *q++ = hex_asc[*key_id >> 4]; | ||
| 154 | *q++ = hex_asc[*key_id++ & 0x0f]; | ||
| 155 | } | ||
| 156 | |||
| 157 | *q = 0; | ||
| 158 | |||
| 159 | pr_debug("Look up: \"%s\"\n", id); | ||
| 160 | |||
| 161 | key = keyring_search(make_key_ref(system_trusted_keyring, 1), | ||
| 162 | &key_type_asymmetric, id); | ||
| 163 | if (IS_ERR(key)) | ||
| 164 | pr_warn("Request for unknown module key '%s' err %ld\n", | ||
| 165 | id, PTR_ERR(key)); | ||
| 166 | kfree(id); | ||
| 167 | |||
| 168 | if (IS_ERR(key)) { | ||
| 169 | switch (PTR_ERR(key)) { | ||
| 170 | /* Hide some search errors */ | ||
| 171 | case -EACCES: | ||
| 172 | case -ENOTDIR: | ||
| 173 | case -EAGAIN: | ||
| 174 | return ERR_PTR(-ENOKEY); | ||
| 175 | default: | ||
| 176 | return ERR_CAST(key); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); | ||
| 181 | return key_ref_to_ptr(key); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* | ||
| 185 | * Verify the signature on a module. | 38 | * Verify the signature on a module. |
| 186 | */ | 39 | */ |
| 187 | int mod_verify_sig(const void *mod, unsigned long *_modlen) | 40 | int mod_verify_sig(const void *mod, unsigned long *_modlen) |
| 188 | { | 41 | { |
| 189 | struct public_key_signature *pks; | ||
| 190 | struct module_signature ms; | 42 | struct module_signature ms; |
| 191 | struct key *key; | ||
| 192 | const void *sig; | ||
| 193 | size_t modlen = *_modlen, sig_len; | 43 | size_t modlen = *_modlen, sig_len; |
| 194 | int ret; | ||
| 195 | 44 | ||
| 196 | pr_devel("==>%s(,%zu)\n", __func__, modlen); | 45 | pr_devel("==>%s(,%zu)\n", __func__, modlen); |
| 197 | 46 | ||
| @@ -205,46 +54,24 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) | |||
| 205 | if (sig_len >= modlen) | 54 | if (sig_len >= modlen) |
| 206 | return -EBADMSG; | 55 | return -EBADMSG; |
| 207 | modlen -= sig_len; | 56 | modlen -= sig_len; |
| 208 | if ((size_t)ms.signer_len + ms.key_id_len >= modlen) | ||
| 209 | return -EBADMSG; | ||
| 210 | modlen -= (size_t)ms.signer_len + ms.key_id_len; | ||
| 211 | |||
| 212 | *_modlen = modlen; | 57 | *_modlen = modlen; |
| 213 | sig = mod + modlen; | ||
| 214 | |||
| 215 | /* For the moment, only support RSA and X.509 identifiers */ | ||
| 216 | if (ms.algo != PKEY_ALGO_RSA || | ||
| 217 | ms.id_type != PKEY_ID_X509) | ||
| 218 | return -ENOPKG; | ||
| 219 | 58 | ||
| 220 | if (ms.hash >= PKEY_HASH__LAST || | 59 | if (ms.id_type != PKEY_ID_PKCS7) { |
| 221 | !hash_algo_name[ms.hash]) | 60 | pr_err("Module is not signed with expected PKCS#7 message\n"); |
| 222 | return -ENOPKG; | 61 | return -ENOPKG; |
| 223 | |||
| 224 | key = request_asymmetric_key(sig, ms.signer_len, | ||
| 225 | sig + ms.signer_len, ms.key_id_len); | ||
| 226 | if (IS_ERR(key)) | ||
| 227 | return PTR_ERR(key); | ||
| 228 | |||
| 229 | pks = mod_make_digest(ms.hash, mod, modlen); | ||
| 230 | if (IS_ERR(pks)) { | ||
| 231 | ret = PTR_ERR(pks); | ||
| 232 | goto error_put_key; | ||
| 233 | } | 62 | } |
| 234 | 63 | ||
| 235 | ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len, | 64 | if (ms.algo != 0 || |
| 236 | sig_len); | 65 | ms.hash != 0 || |
| 237 | if (ret < 0) | 66 | ms.signer_len != 0 || |
| 238 | goto error_free_pks; | 67 | ms.key_id_len != 0 || |
| 239 | 68 | ms.__pad[0] != 0 || | |
| 240 | ret = verify_signature(key, pks); | 69 | ms.__pad[1] != 0 || |
| 241 | pr_devel("verify_signature() = %d\n", ret); | 70 | ms.__pad[2] != 0) { |
| 71 | pr_err("PKCS#7 signature info has unexpected non-zero params\n"); | ||
| 72 | return -EBADMSG; | ||
| 73 | } | ||
| 242 | 74 | ||
| 243 | error_free_pks: | 75 | return system_verify_data(mod, modlen, mod + modlen, sig_len, |
| 244 | mpi_free(pks->rsa.s); | 76 | VERIFYING_MODULE_SIGNATURE); |
| 245 | kfree(pks); | ||
| 246 | error_put_key: | ||
| 247 | key_put(key); | ||
| 248 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 249 | return ret; | ||
| 250 | } | 77 | } |
diff --git a/kernel/system_certificates.S b/kernel/system_certificates.S index 3e9868d47535..6ba2f75e7ba5 100644 --- a/kernel/system_certificates.S +++ b/kernel/system_certificates.S | |||
| @@ -7,6 +7,9 @@ | |||
| 7 | .globl VMLINUX_SYMBOL(system_certificate_list) | 7 | .globl VMLINUX_SYMBOL(system_certificate_list) |
| 8 | VMLINUX_SYMBOL(system_certificate_list): | 8 | VMLINUX_SYMBOL(system_certificate_list): |
| 9 | __cert_list_start: | 9 | __cert_list_start: |
| 10 | #ifdef CONFIG_MODULE_SIG | ||
| 11 | .incbin "signing_key.x509" | ||
| 12 | #endif | ||
| 10 | .incbin "kernel/x509_certificate_list" | 13 | .incbin "kernel/x509_certificate_list" |
| 11 | __cert_list_end: | 14 | __cert_list_end: |
| 12 | 15 | ||
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 875f64e8935b..2570598b784d 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <keys/asymmetric-type.h> | 17 | #include <keys/asymmetric-type.h> |
| 18 | #include <keys/system_keyring.h> | 18 | #include <keys/system_keyring.h> |
| 19 | #include "module-internal.h" | 19 | #include <crypto/pkcs7.h> |
| 20 | 20 | ||
| 21 | struct key *system_trusted_keyring; | 21 | struct key *system_trusted_keyring; |
| 22 | EXPORT_SYMBOL_GPL(system_trusted_keyring); | 22 | EXPORT_SYMBOL_GPL(system_trusted_keyring); |
| @@ -104,3 +104,54 @@ dodgy_cert: | |||
| 104 | return 0; | 104 | return 0; |
| 105 | } | 105 | } |
| 106 | late_initcall(load_system_certificate_list); | 106 | late_initcall(load_system_certificate_list); |
| 107 | |||
| 108 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Verify a PKCS#7-based signature on system data. | ||
| 112 | * @data: The data to be verified. | ||
| 113 | * @len: Size of @data. | ||
| 114 | * @raw_pkcs7: The PKCS#7 message that is the signature. | ||
| 115 | * @pkcs7_len: The size of @raw_pkcs7. | ||
| 116 | * @usage: The use to which the key is being put. | ||
| 117 | */ | ||
| 118 | int system_verify_data(const void *data, unsigned long len, | ||
| 119 | const void *raw_pkcs7, size_t pkcs7_len, | ||
| 120 | enum key_being_used_for usage) | ||
| 121 | { | ||
| 122 | struct pkcs7_message *pkcs7; | ||
| 123 | bool trusted; | ||
| 124 | int ret; | ||
| 125 | |||
| 126 | pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len); | ||
| 127 | if (IS_ERR(pkcs7)) | ||
| 128 | return PTR_ERR(pkcs7); | ||
| 129 | |||
| 130 | /* The data should be detached - so we need to supply it. */ | ||
| 131 | if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) { | ||
| 132 | pr_err("PKCS#7 signature with non-detached data\n"); | ||
| 133 | ret = -EBADMSG; | ||
| 134 | goto error; | ||
| 135 | } | ||
| 136 | |||
| 137 | ret = pkcs7_verify(pkcs7, usage); | ||
| 138 | if (ret < 0) | ||
| 139 | goto error; | ||
| 140 | |||
| 141 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
| 142 | if (ret < 0) | ||
| 143 | goto error; | ||
| 144 | |||
| 145 | if (!trusted) { | ||
| 146 | pr_err("PKCS#7 signature not signed with a trusted key\n"); | ||
| 147 | ret = -ENOKEY; | ||
| 148 | } | ||
| 149 | |||
| 150 | error: | ||
| 151 | pkcs7_free_message(pkcs7); | ||
| 152 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 153 | return ret; | ||
| 154 | } | ||
| 155 | EXPORT_SYMBOL_GPL(system_verify_data); | ||
| 156 | |||
| 157 | #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ | ||
diff --git a/scripts/Makefile b/scripts/Makefile index 2016a64497ab..1b2661712d44 100644 --- a/scripts/Makefile +++ b/scripts/Makefile | |||
| @@ -16,9 +16,13 @@ hostprogs-$(CONFIG_VT) += conmakehash | |||
| 16 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | 16 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
| 17 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable | 17 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
| 18 | hostprogs-$(CONFIG_ASN1) += asn1_compiler | 18 | hostprogs-$(CONFIG_ASN1) += asn1_compiler |
| 19 | hostprogs-$(CONFIG_MODULE_SIG) += sign-file | ||
| 20 | hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert | ||
| 19 | 21 | ||
| 20 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | 22 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include |
| 21 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | 23 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include |
| 24 | HOSTLOADLIBES_sign-file = -lcrypto | ||
| 25 | HOSTLOADLIBES_extract-cert = -lcrypto | ||
| 22 | 26 | ||
| 23 | always := $(hostprogs-y) $(hostprogs-m) | 27 | always := $(hostprogs-y) $(hostprogs-m) |
| 24 | 28 | ||
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index e48a4e9d8868..07650eeaaf06 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst | |||
| @@ -22,7 +22,7 @@ quiet_cmd_modules_install = INSTALL $@ | |||
| 22 | mkdir -p $(2) ; \ | 22 | mkdir -p $(2) ; \ |
| 23 | cp $@ $(2) ; \ | 23 | cp $@ $(2) ; \ |
| 24 | $(mod_strip_cmd) $(2)/$(notdir $@) ; \ | 24 | $(mod_strip_cmd) $(2)/$(notdir $@) ; \ |
| 25 | $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \ | 25 | $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) && \ |
| 26 | $(mod_compress_cmd) $(2)/$(notdir $@) | 26 | $(mod_compress_cmd) $(2)/$(notdir $@) |
| 27 | 27 | ||
| 28 | # Modules built outside the kernel source tree go into extra by default | 28 | # Modules built outside the kernel source tree go into extra by default |
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index 1c75e22b6385..e000f44e37b8 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <stdio.h> | 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> | 14 | #include <stdlib.h> |
| 15 | #include <stdint.h> | 15 | #include <stdint.h> |
| 16 | #include <stdbool.h> | ||
| 16 | #include <string.h> | 17 | #include <string.h> |
| 17 | #include <ctype.h> | 18 | #include <ctype.h> |
| 18 | #include <unistd.h> | 19 | #include <unistd.h> |
| @@ -293,8 +294,8 @@ static const char *const directives[NR__DIRECTIVES] = { | |||
| 293 | 294 | ||
| 294 | struct action { | 295 | struct action { |
| 295 | struct action *next; | 296 | struct action *next; |
| 297 | char *name; | ||
| 296 | unsigned char index; | 298 | unsigned char index; |
| 297 | char name[]; | ||
| 298 | }; | 299 | }; |
| 299 | 300 | ||
| 300 | static struct action *action_list; | 301 | static struct action *action_list; |
| @@ -305,15 +306,17 @@ struct token { | |||
| 305 | enum token_type token_type : 8; | 306 | enum token_type token_type : 8; |
| 306 | unsigned char size; | 307 | unsigned char size; |
| 307 | struct action *action; | 308 | struct action *action; |
| 308 | const char *value; | 309 | char *content; |
| 309 | struct type *type; | 310 | struct type *type; |
| 310 | }; | 311 | }; |
| 311 | 312 | ||
| 312 | static struct token *token_list; | 313 | static struct token *token_list; |
| 313 | static unsigned nr_tokens; | 314 | static unsigned nr_tokens; |
| 314 | static _Bool verbose; | 315 | static bool verbose_opt; |
| 316 | static bool debug_opt; | ||
| 315 | 317 | ||
| 316 | #define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0) | 318 | #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0) |
| 319 | #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0) | ||
| 317 | 320 | ||
| 318 | static int directive_compare(const void *_key, const void *_pdir) | 321 | static int directive_compare(const void *_key, const void *_pdir) |
| 319 | { | 322 | { |
| @@ -325,11 +328,9 @@ static int directive_compare(const void *_key, const void *_pdir) | |||
| 325 | dlen = strlen(dir); | 328 | dlen = strlen(dir); |
| 326 | clen = (dlen < token->size) ? dlen : token->size; | 329 | clen = (dlen < token->size) ? dlen : token->size; |
| 327 | 330 | ||
| 328 | //debug("cmp(%*.*s,%s) = ", | 331 | //debug("cmp(%s,%s) = ", token->content, dir); |
| 329 | // (int)token->size, (int)token->size, token->value, | ||
| 330 | // dir); | ||
| 331 | 332 | ||
| 332 | val = memcmp(token->value, dir, clen); | 333 | val = memcmp(token->content, dir, clen); |
| 333 | if (val != 0) { | 334 | if (val != 0) { |
| 334 | //debug("%d [cmp]\n", val); | 335 | //debug("%d [cmp]\n", val); |
| 335 | return val; | 336 | return val; |
| @@ -349,7 +350,7 @@ static int directive_compare(const void *_key, const void *_pdir) | |||
| 349 | static void tokenise(char *buffer, char *end) | 350 | static void tokenise(char *buffer, char *end) |
| 350 | { | 351 | { |
| 351 | struct token *tokens; | 352 | struct token *tokens; |
| 352 | char *line, *nl, *p, *q; | 353 | char *line, *nl, *start, *p, *q; |
| 353 | unsigned tix, lineno; | 354 | unsigned tix, lineno; |
| 354 | 355 | ||
| 355 | /* Assume we're going to have half as many tokens as we have | 356 | /* Assume we're going to have half as many tokens as we have |
| @@ -408,11 +409,11 @@ static void tokenise(char *buffer, char *end) | |||
| 408 | break; | 409 | break; |
| 409 | 410 | ||
| 410 | tokens[tix].line = lineno; | 411 | tokens[tix].line = lineno; |
| 411 | tokens[tix].value = p; | 412 | start = p; |
| 412 | 413 | ||
| 413 | /* Handle string tokens */ | 414 | /* Handle string tokens */ |
| 414 | if (isalpha(*p)) { | 415 | if (isalpha(*p)) { |
| 415 | const char **dir; | 416 | const char **dir, *start = p; |
| 416 | 417 | ||
| 417 | /* Can be a directive, type name or element | 418 | /* Can be a directive, type name or element |
| 418 | * name. Find the end of the name. | 419 | * name. Find the end of the name. |
| @@ -423,10 +424,18 @@ static void tokenise(char *buffer, char *end) | |||
| 423 | tokens[tix].size = q - p; | 424 | tokens[tix].size = q - p; |
| 424 | p = q; | 425 | p = q; |
| 425 | 426 | ||
| 427 | tokens[tix].content = malloc(tokens[tix].size + 1); | ||
| 428 | if (!tokens[tix].content) { | ||
| 429 | perror(NULL); | ||
| 430 | exit(1); | ||
| 431 | } | ||
| 432 | memcpy(tokens[tix].content, start, tokens[tix].size); | ||
| 433 | tokens[tix].content[tokens[tix].size] = 0; | ||
| 434 | |||
| 426 | /* If it begins with a lowercase letter then | 435 | /* If it begins with a lowercase letter then |
| 427 | * it's an element name | 436 | * it's an element name |
| 428 | */ | 437 | */ |
| 429 | if (islower(tokens[tix].value[0])) { | 438 | if (islower(tokens[tix].content[0])) { |
| 430 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; | 439 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; |
| 431 | continue; | 440 | continue; |
| 432 | } | 441 | } |
| @@ -455,6 +464,13 @@ static void tokenise(char *buffer, char *end) | |||
| 455 | q++; | 464 | q++; |
| 456 | tokens[tix].size = q - p; | 465 | tokens[tix].size = q - p; |
| 457 | p = q; | 466 | p = q; |
| 467 | tokens[tix].content = malloc(tokens[tix].size + 1); | ||
| 468 | if (!tokens[tix].content) { | ||
| 469 | perror(NULL); | ||
| 470 | exit(1); | ||
| 471 | } | ||
| 472 | memcpy(tokens[tix].content, start, tokens[tix].size); | ||
| 473 | tokens[tix].content[tokens[tix].size] = 0; | ||
| 458 | tokens[tix++].token_type = TOKEN_NUMBER; | 474 | tokens[tix++].token_type = TOKEN_NUMBER; |
| 459 | continue; | 475 | continue; |
| 460 | } | 476 | } |
| @@ -463,6 +479,7 @@ static void tokenise(char *buffer, char *end) | |||
| 463 | if (memcmp(p, "::=", 3) == 0) { | 479 | if (memcmp(p, "::=", 3) == 0) { |
| 464 | p += 3; | 480 | p += 3; |
| 465 | tokens[tix].size = 3; | 481 | tokens[tix].size = 3; |
| 482 | tokens[tix].content = "::="; | ||
| 466 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; | 483 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; |
| 467 | continue; | 484 | continue; |
| 468 | } | 485 | } |
| @@ -472,12 +489,14 @@ static void tokenise(char *buffer, char *end) | |||
| 472 | if (memcmp(p, "({", 2) == 0) { | 489 | if (memcmp(p, "({", 2) == 0) { |
| 473 | p += 2; | 490 | p += 2; |
| 474 | tokens[tix].size = 2; | 491 | tokens[tix].size = 2; |
| 492 | tokens[tix].content = "({"; | ||
| 475 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; | 493 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; |
| 476 | continue; | 494 | continue; |
| 477 | } | 495 | } |
| 478 | if (memcmp(p, "})", 2) == 0) { | 496 | if (memcmp(p, "})", 2) == 0) { |
| 479 | p += 2; | 497 | p += 2; |
| 480 | tokens[tix].size = 2; | 498 | tokens[tix].size = 2; |
| 499 | tokens[tix].content = "})"; | ||
| 481 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; | 500 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; |
| 482 | continue; | 501 | continue; |
| 483 | } | 502 | } |
| @@ -488,22 +507,27 @@ static void tokenise(char *buffer, char *end) | |||
| 488 | switch (*p) { | 507 | switch (*p) { |
| 489 | case '{': | 508 | case '{': |
| 490 | p += 1; | 509 | p += 1; |
| 510 | tokens[tix].content = "{"; | ||
| 491 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; | 511 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; |
| 492 | continue; | 512 | continue; |
| 493 | case '}': | 513 | case '}': |
| 494 | p += 1; | 514 | p += 1; |
| 515 | tokens[tix].content = "}"; | ||
| 495 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; | 516 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; |
| 496 | continue; | 517 | continue; |
| 497 | case '[': | 518 | case '[': |
| 498 | p += 1; | 519 | p += 1; |
| 520 | tokens[tix].content = "["; | ||
| 499 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; | 521 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; |
| 500 | continue; | 522 | continue; |
| 501 | case ']': | 523 | case ']': |
| 502 | p += 1; | 524 | p += 1; |
| 525 | tokens[tix].content = "]"; | ||
| 503 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; | 526 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; |
| 504 | continue; | 527 | continue; |
| 505 | case ',': | 528 | case ',': |
| 506 | p += 1; | 529 | p += 1; |
| 530 | tokens[tix].content = ","; | ||
| 507 | tokens[tix++].token_type = TOKEN_COMMA; | 531 | tokens[tix++].token_type = TOKEN_COMMA; |
| 508 | continue; | 532 | continue; |
| 509 | default: | 533 | default: |
| @@ -518,22 +542,20 @@ static void tokenise(char *buffer, char *end) | |||
| 518 | } | 542 | } |
| 519 | 543 | ||
| 520 | nr_tokens = tix; | 544 | nr_tokens = tix; |
| 521 | debug("Extracted %u tokens\n", nr_tokens); | 545 | verbose("Extracted %u tokens\n", nr_tokens); |
| 522 | 546 | ||
| 523 | #if 0 | 547 | #if 0 |
| 524 | { | 548 | { |
| 525 | int n; | 549 | int n; |
| 526 | for (n = 0; n < nr_tokens; n++) | 550 | for (n = 0; n < nr_tokens; n++) |
| 527 | debug("Token %3u: '%*.*s'\n", | 551 | debug("Token %3u: '%s'\n", n, token_list[n].content); |
| 528 | n, | ||
| 529 | (int)token_list[n].size, (int)token_list[n].size, | ||
| 530 | token_list[n].value); | ||
| 531 | } | 552 | } |
| 532 | #endif | 553 | #endif |
| 533 | } | 554 | } |
| 534 | 555 | ||
| 535 | static void build_type_list(void); | 556 | static void build_type_list(void); |
| 536 | static void parse(void); | 557 | static void parse(void); |
| 558 | static void dump_elements(void); | ||
| 537 | static void render(FILE *out, FILE *hdr); | 559 | static void render(FILE *out, FILE *hdr); |
| 538 | 560 | ||
| 539 | /* | 561 | /* |
| @@ -548,16 +570,27 @@ int main(int argc, char **argv) | |||
| 548 | char *kbuild_verbose; | 570 | char *kbuild_verbose; |
| 549 | int fd; | 571 | int fd; |
| 550 | 572 | ||
| 573 | kbuild_verbose = getenv("KBUILD_VERBOSE"); | ||
| 574 | if (kbuild_verbose) | ||
| 575 | verbose_opt = atoi(kbuild_verbose); | ||
| 576 | |||
| 577 | while (argc > 4) { | ||
| 578 | if (strcmp(argv[1], "-v") == 0) | ||
| 579 | verbose_opt = true; | ||
| 580 | else if (strcmp(argv[1], "-d") == 0) | ||
| 581 | debug_opt = true; | ||
| 582 | else | ||
| 583 | break; | ||
| 584 | memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *)); | ||
| 585 | argc--; | ||
| 586 | } | ||
| 587 | |||
| 551 | if (argc != 4) { | 588 | if (argc != 4) { |
| 552 | fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", | 589 | fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n", |
| 553 | argv[0]); | 590 | argv[0]); |
| 554 | exit(2); | 591 | exit(2); |
| 555 | } | 592 | } |
| 556 | 593 | ||
| 557 | kbuild_verbose = getenv("KBUILD_VERBOSE"); | ||
| 558 | if (kbuild_verbose) | ||
| 559 | verbose = atoi(kbuild_verbose); | ||
| 560 | |||
| 561 | filename = argv[1]; | 594 | filename = argv[1]; |
| 562 | outputname = argv[2]; | 595 | outputname = argv[2]; |
| 563 | headername = argv[3]; | 596 | headername = argv[3]; |
| @@ -608,6 +641,7 @@ int main(int argc, char **argv) | |||
| 608 | tokenise(buffer, buffer + readlen); | 641 | tokenise(buffer, buffer + readlen); |
| 609 | build_type_list(); | 642 | build_type_list(); |
| 610 | parse(); | 643 | parse(); |
| 644 | dump_elements(); | ||
| 611 | 645 | ||
| 612 | out = fopen(outputname, "w"); | 646 | out = fopen(outputname, "w"); |
| 613 | if (!out) { | 647 | if (!out) { |
| @@ -693,7 +727,7 @@ static int type_index_compare(const void *_a, const void *_b) | |||
| 693 | if ((*a)->name->size != (*b)->name->size) | 727 | if ((*a)->name->size != (*b)->name->size) |
| 694 | return (*a)->name->size - (*b)->name->size; | 728 | return (*a)->name->size - (*b)->name->size; |
| 695 | else | 729 | else |
| 696 | return memcmp((*a)->name->value, (*b)->name->value, | 730 | return memcmp((*a)->name->content, (*b)->name->content, |
| 697 | (*a)->name->size); | 731 | (*a)->name->size); |
| 698 | } | 732 | } |
| 699 | 733 | ||
| @@ -706,7 +740,7 @@ static int type_finder(const void *_key, const void *_ti) | |||
| 706 | if (token->size != type->name->size) | 740 | if (token->size != type->name->size) |
| 707 | return token->size - type->name->size; | 741 | return token->size - type->name->size; |
| 708 | else | 742 | else |
| 709 | return memcmp(token->value, type->name->value, | 743 | return memcmp(token->content, type->name->content, |
| 710 | token->size); | 744 | token->size); |
| 711 | } | 745 | } |
| 712 | 746 | ||
| @@ -756,14 +790,11 @@ static void build_type_list(void) | |||
| 756 | 790 | ||
| 757 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); | 791 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); |
| 758 | 792 | ||
| 759 | debug("Extracted %u types\n", nr_types); | 793 | verbose("Extracted %u types\n", nr_types); |
| 760 | #if 0 | 794 | #if 0 |
| 761 | for (n = 0; n < nr_types; n++) { | 795 | for (n = 0; n < nr_types; n++) { |
| 762 | struct type *type = type_index[n]; | 796 | struct type *type = type_index[n]; |
| 763 | debug("- %*.*s\n", | 797 | debug("- %*.*s\n", type->name->content); |
| 764 | (int)type->name->size, | ||
| 765 | (int)type->name->size, | ||
| 766 | type->name->value); | ||
| 767 | } | 798 | } |
| 768 | #endif | 799 | #endif |
| 769 | } | 800 | } |
| @@ -793,15 +824,14 @@ static void parse(void) | |||
| 793 | type->element->type_def = type; | 824 | type->element->type_def = type; |
| 794 | 825 | ||
| 795 | if (cursor != type[1].name) { | 826 | if (cursor != type[1].name) { |
| 796 | fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", | 827 | fprintf(stderr, "%s:%d: Parse error at token '%s'\n", |
| 797 | filename, cursor->line, | 828 | filename, cursor->line, cursor->content); |
| 798 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 799 | exit(1); | 829 | exit(1); |
| 800 | } | 830 | } |
| 801 | 831 | ||
| 802 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); | 832 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); |
| 803 | 833 | ||
| 804 | debug("Extracted %u actions\n", nr_actions); | 834 | verbose("Extracted %u actions\n", nr_actions); |
| 805 | } | 835 | } |
| 806 | 836 | ||
| 807 | static struct element *element_list; | 837 | static struct element *element_list; |
| @@ -862,34 +892,31 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 862 | cursor++; | 892 | cursor++; |
| 863 | break; | 893 | break; |
| 864 | default: | 894 | default: |
| 865 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", | 895 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n", |
| 866 | filename, cursor->line, | 896 | filename, cursor->line, cursor->content); |
| 867 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 868 | exit(1); | 897 | exit(1); |
| 869 | } | 898 | } |
| 870 | 899 | ||
| 871 | if (cursor >= end) | 900 | if (cursor >= end) |
| 872 | goto overrun_error; | 901 | goto overrun_error; |
| 873 | if (cursor->token_type != TOKEN_NUMBER) { | 902 | if (cursor->token_type != TOKEN_NUMBER) { |
| 874 | fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", | 903 | fprintf(stderr, "%s:%d: Missing tag number '%s'\n", |
| 875 | filename, cursor->line, | 904 | filename, cursor->line, cursor->content); |
| 876 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 877 | exit(1); | 905 | exit(1); |
| 878 | } | 906 | } |
| 879 | 907 | ||
| 880 | element->tag &= ~0x1f; | 908 | element->tag &= ~0x1f; |
| 881 | element->tag |= strtoul(cursor->value, &p, 10); | 909 | element->tag |= strtoul(cursor->content, &p, 10); |
| 882 | element->flags |= ELEMENT_TAG_SPECIFIED; | 910 | element->flags |= ELEMENT_TAG_SPECIFIED; |
| 883 | if (p - cursor->value != cursor->size) | 911 | if (p - cursor->content != cursor->size) |
| 884 | abort(); | 912 | abort(); |
| 885 | cursor++; | 913 | cursor++; |
| 886 | 914 | ||
| 887 | if (cursor >= end) | 915 | if (cursor >= end) |
| 888 | goto overrun_error; | 916 | goto overrun_error; |
| 889 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { | 917 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { |
| 890 | fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", | 918 | fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n", |
| 891 | filename, cursor->line, | 919 | filename, cursor->line, cursor->content); |
| 892 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 893 | exit(1); | 920 | exit(1); |
| 894 | } | 921 | } |
| 895 | cursor++; | 922 | cursor++; |
| @@ -989,9 +1016,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 989 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), | 1016 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), |
| 990 | type_finder); | 1017 | type_finder); |
| 991 | if (!ref) { | 1018 | if (!ref) { |
| 992 | fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", | 1019 | fprintf(stderr, "%s:%d: Type '%s' undefined\n", |
| 993 | filename, cursor->line, | 1020 | filename, cursor->line, cursor->content); |
| 994 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 995 | exit(1); | 1021 | exit(1); |
| 996 | } | 1022 | } |
| 997 | cursor->type = *ref; | 1023 | cursor->type = *ref; |
| @@ -1040,9 +1066,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1040 | break; | 1066 | break; |
| 1041 | 1067 | ||
| 1042 | default: | 1068 | default: |
| 1043 | fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", | 1069 | fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n", |
| 1044 | filename, cursor->line, | 1070 | filename, cursor->line, cursor->content); |
| 1045 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1046 | exit(1); | 1071 | exit(1); |
| 1047 | } | 1072 | } |
| 1048 | 1073 | ||
| @@ -1059,20 +1084,18 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1059 | if (cursor >= end) | 1084 | if (cursor >= end) |
| 1060 | goto overrun_error; | 1085 | goto overrun_error; |
| 1061 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { | 1086 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { |
| 1062 | fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", | 1087 | fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n", |
| 1063 | filename, cursor->line, | 1088 | filename, cursor->line, cursor->content); |
| 1064 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1065 | exit(1); | 1089 | exit(1); |
| 1066 | } | 1090 | } |
| 1067 | 1091 | ||
| 1068 | action = malloc(sizeof(struct action) + cursor->size + 1); | 1092 | action = malloc(sizeof(struct action)); |
| 1069 | if (!action) { | 1093 | if (!action) { |
| 1070 | perror(NULL); | 1094 | perror(NULL); |
| 1071 | exit(1); | 1095 | exit(1); |
| 1072 | } | 1096 | } |
| 1073 | action->index = 0; | 1097 | action->index = 0; |
| 1074 | memcpy(action->name, cursor->value, cursor->size); | 1098 | action->name = cursor->content; |
| 1075 | action->name[cursor->size] = 0; | ||
| 1076 | 1099 | ||
| 1077 | for (ppaction = &action_list; | 1100 | for (ppaction = &action_list; |
| 1078 | *ppaction; | 1101 | *ppaction; |
| @@ -1102,9 +1125,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1102 | if (cursor >= end) | 1125 | if (cursor >= end) |
| 1103 | goto overrun_error; | 1126 | goto overrun_error; |
| 1104 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { | 1127 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { |
| 1105 | fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", | 1128 | fprintf(stderr, "%s:%d: Missing close action, got '%s'\n", |
| 1106 | filename, cursor->line, | 1129 | filename, cursor->line, cursor->content); |
| 1107 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1108 | exit(1); | 1130 | exit(1); |
| 1109 | } | 1131 | } |
| 1110 | cursor++; | 1132 | cursor++; |
| @@ -1114,9 +1136,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
| 1114 | return top; | 1136 | return top; |
| 1115 | 1137 | ||
| 1116 | parse_error: | 1138 | parse_error: |
| 1117 | fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", | 1139 | fprintf(stderr, "%s:%d: Unexpected token '%s'\n", |
| 1118 | filename, cursor->line, | 1140 | filename, cursor->line, cursor->content); |
| 1119 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1120 | exit(1); | 1141 | exit(1); |
| 1121 | 1142 | ||
| 1122 | overrun_error: | 1143 | overrun_error: |
| @@ -1134,9 +1155,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end, | |||
| 1134 | struct token *cursor = *_cursor, *name; | 1155 | struct token *cursor = *_cursor, *name; |
| 1135 | 1156 | ||
| 1136 | if (cursor->token_type != TOKEN_OPEN_CURLY) { | 1157 | if (cursor->token_type != TOKEN_OPEN_CURLY) { |
| 1137 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", | 1158 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n", |
| 1138 | filename, cursor->line, | 1159 | filename, cursor->line, cursor->content); |
| 1139 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1140 | exit(1); | 1160 | exit(1); |
| 1141 | } | 1161 | } |
| 1142 | cursor++; | 1162 | cursor++; |
| @@ -1177,9 +1197,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end, | |||
| 1177 | children->flags &= ~ELEMENT_CONDITIONAL; | 1197 | children->flags &= ~ELEMENT_CONDITIONAL; |
| 1178 | 1198 | ||
| 1179 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { | 1199 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { |
| 1180 | fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", | 1200 | fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n", |
| 1181 | filename, cursor->line, | 1201 | filename, cursor->line, cursor->content); |
| 1182 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
| 1183 | exit(1); | 1202 | exit(1); |
| 1184 | } | 1203 | } |
| 1185 | cursor++; | 1204 | cursor++; |
| @@ -1192,6 +1211,52 @@ overrun_error: | |||
| 1192 | exit(1); | 1211 | exit(1); |
| 1193 | } | 1212 | } |
| 1194 | 1213 | ||
| 1214 | static void dump_element(const struct element *e, int level) | ||
| 1215 | { | ||
| 1216 | const struct element *c; | ||
| 1217 | const struct type *t = e->type_def; | ||
| 1218 | const char *name = e->name ? e->name->content : "."; | ||
| 1219 | const char *tname = t && t->name ? t->name->content : "."; | ||
| 1220 | char tag[32]; | ||
| 1221 | |||
| 1222 | if (e->class == 0 && e->method == 0 && e->tag == 0) | ||
| 1223 | strcpy(tag, "<...>"); | ||
| 1224 | else if (e->class == ASN1_UNIV) | ||
| 1225 | sprintf(tag, "%s %s %s", | ||
| 1226 | asn1_classes[e->class], | ||
| 1227 | asn1_methods[e->method], | ||
| 1228 | asn1_universal_tags[e->tag]); | ||
| 1229 | else | ||
| 1230 | sprintf(tag, "%s %s %u", | ||
| 1231 | asn1_classes[e->class], | ||
| 1232 | asn1_methods[e->method], | ||
| 1233 | e->tag); | ||
| 1234 | |||
| 1235 | printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n", | ||
| 1236 | e->flags & ELEMENT_IMPLICIT ? 'I' : '-', | ||
| 1237 | e->flags & ELEMENT_EXPLICIT ? 'E' : '-', | ||
| 1238 | e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-', | ||
| 1239 | e->flags & ELEMENT_SKIPPABLE ? 'S' : '-', | ||
| 1240 | e->flags & ELEMENT_CONDITIONAL ? 'C' : '-', | ||
| 1241 | "-tTqQcaro"[e->compound], | ||
| 1242 | level, "", | ||
| 1243 | tag, | ||
| 1244 | tname, | ||
| 1245 | name, | ||
| 1246 | e->action ? e->action->name : ""); | ||
| 1247 | if (e->compound == TYPE_REF) | ||
| 1248 | dump_element(e->type->type->element, level + 3); | ||
| 1249 | else | ||
| 1250 | for (c = e->children; c; c = c->next) | ||
| 1251 | dump_element(c, level + 3); | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | static void dump_elements(void) | ||
| 1255 | { | ||
| 1256 | if (debug_opt) | ||
| 1257 | dump_element(type_list[0].element, 0); | ||
| 1258 | } | ||
| 1259 | |||
| 1195 | static void render_element(FILE *out, struct element *e, struct element *tag); | 1260 | static void render_element(FILE *out, struct element *e, struct element *tag); |
| 1196 | static void render_out_of_line_list(FILE *out); | 1261 | static void render_out_of_line_list(FILE *out); |
| 1197 | 1262 | ||
| @@ -1293,7 +1358,7 @@ static void render(FILE *out, FILE *hdr) | |||
| 1293 | } | 1358 | } |
| 1294 | 1359 | ||
| 1295 | /* We do two passes - the first one calculates all the offsets */ | 1360 | /* We do two passes - the first one calculates all the offsets */ |
| 1296 | debug("Pass 1\n"); | 1361 | verbose("Pass 1\n"); |
| 1297 | nr_entries = 0; | 1362 | nr_entries = 0; |
| 1298 | root = &type_list[0]; | 1363 | root = &type_list[0]; |
| 1299 | render_element(NULL, root->element, NULL); | 1364 | render_element(NULL, root->element, NULL); |
| @@ -1304,7 +1369,7 @@ static void render(FILE *out, FILE *hdr) | |||
| 1304 | e->flags &= ~ELEMENT_RENDERED; | 1369 | e->flags &= ~ELEMENT_RENDERED; |
| 1305 | 1370 | ||
| 1306 | /* And then we actually render */ | 1371 | /* And then we actually render */ |
| 1307 | debug("Pass 2\n"); | 1372 | verbose("Pass 2\n"); |
| 1308 | fprintf(out, "\n"); | 1373 | fprintf(out, "\n"); |
| 1309 | fprintf(out, "static const unsigned char %s_machine[] = {\n", | 1374 | fprintf(out, "static const unsigned char %s_machine[] = {\n", |
| 1310 | grammar_name); | 1375 | grammar_name); |
| @@ -1390,9 +1455,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
| 1390 | outofline = 1; | 1455 | outofline = 1; |
| 1391 | 1456 | ||
| 1392 | if (e->type_def && out) { | 1457 | if (e->type_def && out) { |
| 1393 | render_more(out, "\t// %*.*s\n", | 1458 | render_more(out, "\t// %s\n", e->type_def->name->content); |
| 1394 | (int)e->type_def->name->size, (int)e->type_def->name->size, | ||
| 1395 | e->type_def->name->value); | ||
| 1396 | } | 1459 | } |
| 1397 | 1460 | ||
| 1398 | /* Render the operation */ | 1461 | /* Render the operation */ |
| @@ -1404,9 +1467,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
| 1404 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,", | 1467 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,", |
| 1405 | cond, act, skippable ? "_OR_SKIP" : ""); | 1468 | cond, act, skippable ? "_OR_SKIP" : ""); |
| 1406 | if (e->name) | 1469 | if (e->name) |
| 1407 | render_more(out, "\t\t// %*.*s", | 1470 | render_more(out, "\t\t// %s", e->name->content); |
| 1408 | (int)e->name->size, (int)e->name->size, | ||
| 1409 | e->name->value); | ||
| 1410 | render_more(out, "\n"); | 1471 | render_more(out, "\n"); |
| 1411 | goto dont_render_tag; | 1472 | goto dont_render_tag; |
| 1412 | 1473 | ||
| @@ -1439,9 +1500,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
| 1439 | 1500 | ||
| 1440 | x = tag ?: e; | 1501 | x = tag ?: e; |
| 1441 | if (x->name) | 1502 | if (x->name) |
| 1442 | render_more(out, "\t\t// %*.*s", | 1503 | render_more(out, "\t\t// %s", x->name->content); |
| 1443 | (int)x->name->size, (int)x->name->size, | ||
| 1444 | x->name->value); | ||
| 1445 | render_more(out, "\n"); | 1504 | render_more(out, "\n"); |
| 1446 | 1505 | ||
| 1447 | /* Render the tag */ | 1506 | /* Render the tag */ |
| @@ -1479,10 +1538,8 @@ dont_render_tag: | |||
| 1479 | * skipability */ | 1538 | * skipability */ |
| 1480 | render_opcode(out, "_jump_target(%u),", e->entry_index); | 1539 | render_opcode(out, "_jump_target(%u),", e->entry_index); |
| 1481 | if (e->type_def && e->type_def->name) | 1540 | if (e->type_def && e->type_def->name) |
| 1482 | render_more(out, "\t\t// --> %*.*s", | 1541 | render_more(out, "\t\t// --> %s", |
| 1483 | (int)e->type_def->name->size, | 1542 | e->type_def->name->content); |
| 1484 | (int)e->type_def->name->size, | ||
| 1485 | e->type_def->name->value); | ||
| 1486 | render_more(out, "\n"); | 1543 | render_more(out, "\n"); |
| 1487 | if (!(e->flags & ELEMENT_RENDERED)) { | 1544 | if (!(e->flags & ELEMENT_RENDERED)) { |
| 1488 | e->flags |= ELEMENT_RENDERED; | 1545 | e->flags |= ELEMENT_RENDERED; |
| @@ -1507,10 +1564,8 @@ dont_render_tag: | |||
| 1507 | * skipability */ | 1564 | * skipability */ |
| 1508 | render_opcode(out, "_jump_target(%u),", e->entry_index); | 1565 | render_opcode(out, "_jump_target(%u),", e->entry_index); |
| 1509 | if (e->type_def && e->type_def->name) | 1566 | if (e->type_def && e->type_def->name) |
| 1510 | render_more(out, "\t\t// --> %*.*s", | 1567 | render_more(out, "\t\t// --> %s", |
| 1511 | (int)e->type_def->name->size, | 1568 | e->type_def->name->content); |
| 1512 | (int)e->type_def->name->size, | ||
| 1513 | e->type_def->name->value); | ||
| 1514 | render_more(out, "\n"); | 1569 | render_more(out, "\n"); |
| 1515 | if (!(e->flags & ELEMENT_RENDERED)) { | 1570 | if (!(e->flags & ELEMENT_RENDERED)) { |
| 1516 | e->flags |= ELEMENT_RENDERED; | 1571 | e->flags |= ELEMENT_RENDERED; |
diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c new file mode 100644 index 000000000000..fd0db015c65c --- /dev/null +++ b/scripts/extract-cert.c | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | /* Extract X.509 certificate in DER form from PKCS#11 or PEM. | ||
| 2 | * | ||
| 3 | * Copyright © 2014 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Copyright © 2015 Intel Corporation. | ||
| 5 | * | ||
| 6 | * Authors: David Howells <dhowells@redhat.com> | ||
| 7 | * David Woodhouse <dwmw2@infradead.org> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public Licence | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the Licence, or (at your option) any later version. | ||
| 13 | */ | ||
| 14 | #define _GNU_SOURCE | ||
| 15 | #include <stdio.h> | ||
| 16 | #include <stdlib.h> | ||
| 17 | #include <stdint.h> | ||
| 18 | #include <stdbool.h> | ||
| 19 | #include <string.h> | ||
| 20 | #include <getopt.h> | ||
| 21 | #include <err.h> | ||
| 22 | #include <arpa/inet.h> | ||
| 23 | #include <openssl/bio.h> | ||
| 24 | #include <openssl/evp.h> | ||
| 25 | #include <openssl/pem.h> | ||
| 26 | #include <openssl/pkcs7.h> | ||
| 27 | #include <openssl/err.h> | ||
| 28 | #include <openssl/engine.h> | ||
| 29 | |||
| 30 | #define PKEY_ID_PKCS7 2 | ||
| 31 | |||
| 32 | static __attribute__((noreturn)) | ||
| 33 | void format(void) | ||
| 34 | { | ||
| 35 | fprintf(stderr, | ||
| 36 | "Usage: scripts/extract-cert <source> <dest>\n"); | ||
| 37 | exit(2); | ||
| 38 | } | ||
| 39 | |||
| 40 | static void display_openssl_errors(int l) | ||
| 41 | { | ||
| 42 | const char *file; | ||
| 43 | char buf[120]; | ||
| 44 | int e, line; | ||
| 45 | |||
| 46 | if (ERR_peek_error() == 0) | ||
| 47 | return; | ||
| 48 | fprintf(stderr, "At main.c:%d:\n", l); | ||
| 49 | |||
| 50 | while ((e = ERR_get_error_line(&file, &line))) { | ||
| 51 | ERR_error_string(e, buf); | ||
| 52 | fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | static void drain_openssl_errors(void) | ||
| 57 | { | ||
| 58 | const char *file; | ||
| 59 | int line; | ||
| 60 | |||
| 61 | if (ERR_peek_error() == 0) | ||
| 62 | return; | ||
| 63 | while (ERR_get_error_line(&file, &line)) {} | ||
| 64 | } | ||
| 65 | |||
| 66 | #define ERR(cond, fmt, ...) \ | ||
| 67 | do { \ | ||
| 68 | bool __cond = (cond); \ | ||
| 69 | display_openssl_errors(__LINE__); \ | ||
| 70 | if (__cond) { \ | ||
| 71 | err(1, fmt, ## __VA_ARGS__); \ | ||
| 72 | } \ | ||
| 73 | } while(0) | ||
| 74 | |||
| 75 | static const char *key_pass; | ||
| 76 | static BIO *wb; | ||
| 77 | static char *cert_dst; | ||
| 78 | int kbuild_verbose; | ||
| 79 | |||
| 80 | static void write_cert(X509 *x509) | ||
| 81 | { | ||
| 82 | char buf[200]; | ||
| 83 | |||
| 84 | if (!wb) { | ||
| 85 | wb = BIO_new_file(cert_dst, "wb"); | ||
| 86 | ERR(!wb, "%s", cert_dst); | ||
| 87 | } | ||
| 88 | X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); | ||
| 89 | ERR(!i2d_X509_bio(wb, x509), cert_dst); | ||
| 90 | if (kbuild_verbose) | ||
| 91 | fprintf(stderr, "Extracted cert: %s\n", buf); | ||
| 92 | } | ||
| 93 | |||
| 94 | int main(int argc, char **argv) | ||
| 95 | { | ||
| 96 | char *cert_src; | ||
| 97 | |||
| 98 | OpenSSL_add_all_algorithms(); | ||
| 99 | ERR_load_crypto_strings(); | ||
| 100 | ERR_clear_error(); | ||
| 101 | |||
| 102 | kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0"); | ||
| 103 | |||
| 104 | key_pass = getenv("KBUILD_SIGN_PIN"); | ||
| 105 | |||
| 106 | if (argc != 3) | ||
| 107 | format(); | ||
| 108 | |||
| 109 | cert_src = argv[1]; | ||
| 110 | cert_dst = argv[2]; | ||
| 111 | |||
| 112 | if (!cert_src[0]) { | ||
| 113 | /* Invoked with no input; create empty file */ | ||
| 114 | FILE *f = fopen(cert_dst, "wb"); | ||
| 115 | ERR(!f, "%s", cert_dst); | ||
| 116 | fclose(f); | ||
| 117 | exit(0); | ||
| 118 | } else if (!strncmp(cert_src, "pkcs11:", 7)) { | ||
| 119 | ENGINE *e; | ||
| 120 | struct { | ||
| 121 | const char *cert_id; | ||
| 122 | X509 *cert; | ||
| 123 | } parms; | ||
| 124 | |||
| 125 | parms.cert_id = cert_src; | ||
| 126 | parms.cert = NULL; | ||
| 127 | |||
| 128 | ENGINE_load_builtin_engines(); | ||
| 129 | drain_openssl_errors(); | ||
| 130 | e = ENGINE_by_id("pkcs11"); | ||
| 131 | ERR(!e, "Load PKCS#11 ENGINE"); | ||
| 132 | if (ENGINE_init(e)) | ||
| 133 | drain_openssl_errors(); | ||
| 134 | else | ||
| 135 | ERR(1, "ENGINE_init"); | ||
| 136 | if (key_pass) | ||
| 137 | ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); | ||
| 138 | ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); | ||
| 139 | ERR(!parms.cert, "Get X.509 from PKCS#11"); | ||
| 140 | write_cert(parms.cert); | ||
| 141 | } else { | ||
| 142 | BIO *b; | ||
| 143 | X509 *x509; | ||
| 144 | |||
| 145 | b = BIO_new_file(cert_src, "rb"); | ||
| 146 | ERR(!b, "%s", cert_src); | ||
| 147 | |||
| 148 | while (1) { | ||
| 149 | x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); | ||
| 150 | if (wb && !x509) { | ||
| 151 | unsigned long err = ERR_peek_last_error(); | ||
| 152 | if (ERR_GET_LIB(err) == ERR_LIB_PEM && | ||
| 153 | ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { | ||
| 154 | ERR_clear_error(); | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | ERR(!x509, "%s", cert_src); | ||
| 159 | write_cert(x509); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | BIO_free(wb); | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
diff --git a/scripts/sign-file b/scripts/sign-file deleted file mode 100755 index 3906ee1e2f76..000000000000 --- a/scripts/sign-file +++ /dev/null | |||
| @@ -1,421 +0,0 @@ | |||
| 1 | #!/usr/bin/perl -w | ||
| 2 | # | ||
| 3 | # Sign a module file using the given key. | ||
| 4 | # | ||
| 5 | |||
| 6 | my $USAGE = | ||
| 7 | "Usage: scripts/sign-file [-v] <hash algo> <key> <x509> <module> [<dest>]\n" . | ||
| 8 | " scripts/sign-file [-v] -s <raw sig> <hash algo> <x509> <module> [<dest>]\n"; | ||
| 9 | |||
| 10 | use strict; | ||
| 11 | use FileHandle; | ||
| 12 | use IPC::Open2; | ||
| 13 | use Getopt::Std; | ||
| 14 | |||
| 15 | my %opts; | ||
| 16 | getopts('vs:', \%opts) or die $USAGE; | ||
| 17 | my $verbose = $opts{'v'}; | ||
| 18 | my $signature_file = $opts{'s'}; | ||
| 19 | |||
| 20 | die $USAGE if ($#ARGV > 4); | ||
| 21 | die $USAGE if (!$signature_file && $#ARGV < 3 || $signature_file && $#ARGV < 2); | ||
| 22 | |||
| 23 | my $dgst = shift @ARGV; | ||
| 24 | my $private_key; | ||
| 25 | if (!$signature_file) { | ||
| 26 | $private_key = shift @ARGV; | ||
| 27 | } | ||
| 28 | my $x509 = shift @ARGV; | ||
| 29 | my $module = shift @ARGV; | ||
| 30 | my ($dest, $keep_orig); | ||
| 31 | if (@ARGV) { | ||
| 32 | $dest = $ARGV[0]; | ||
| 33 | $keep_orig = 1; | ||
| 34 | } else { | ||
| 35 | $dest = $module . "~"; | ||
| 36 | } | ||
| 37 | |||
| 38 | die "Can't read private key\n" if (!$signature_file && !-r $private_key); | ||
| 39 | die "Can't read signature file\n" if ($signature_file && !-r $signature_file); | ||
| 40 | die "Can't read X.509 certificate\n" unless (-r $x509); | ||
| 41 | die "Can't read module\n" unless (-r $module); | ||
| 42 | |||
| 43 | # | ||
| 44 | # Function to read the contents of a file into a variable. | ||
| 45 | # | ||
| 46 | sub read_file($) | ||
| 47 | { | ||
| 48 | my ($file) = @_; | ||
| 49 | my $contents; | ||
| 50 | my $len; | ||
| 51 | |||
| 52 | open(FD, "<$file") || die $file; | ||
| 53 | binmode FD; | ||
| 54 | my @st = stat(FD); | ||
| 55 | die $file if (!@st); | ||
| 56 | $len = read(FD, $contents, $st[7]) || die $file; | ||
| 57 | close(FD) || die $file; | ||
| 58 | die "$file: Wanted length ", $st[7], ", got ", $len, "\n" | ||
| 59 | if ($len != $st[7]); | ||
| 60 | return $contents; | ||
| 61 | } | ||
| 62 | |||
| 63 | ############################################################################### | ||
| 64 | # | ||
| 65 | # First of all, we have to parse the X.509 certificate to find certain details | ||
| 66 | # about it. | ||
| 67 | # | ||
| 68 | # We read the DER-encoded X509 certificate and parse it to extract the Subject | ||
| 69 | # name and Subject Key Identifier. Theis provides the data we need to build | ||
| 70 | # the certificate identifier. | ||
| 71 | # | ||
| 72 | # The signer's name part of the identifier is fabricated from the commonName, | ||
| 73 | # the organizationName or the emailAddress components of the X.509 subject | ||
| 74 | # name. | ||
| 75 | # | ||
| 76 | # The subject key ID is used to select which of that signer's certificates | ||
| 77 | # we're intending to use to sign the module. | ||
| 78 | # | ||
| 79 | ############################################################################### | ||
| 80 | my $x509_certificate = read_file($x509); | ||
| 81 | |||
| 82 | my $UNIV = 0 << 6; | ||
| 83 | my $APPL = 1 << 6; | ||
| 84 | my $CONT = 2 << 6; | ||
| 85 | my $PRIV = 3 << 6; | ||
| 86 | |||
| 87 | my $CONS = 0x20; | ||
| 88 | |||
| 89 | my $BOOLEAN = 0x01; | ||
| 90 | my $INTEGER = 0x02; | ||
| 91 | my $BIT_STRING = 0x03; | ||
| 92 | my $OCTET_STRING = 0x04; | ||
| 93 | my $NULL = 0x05; | ||
| 94 | my $OBJ_ID = 0x06; | ||
| 95 | my $UTF8String = 0x0c; | ||
| 96 | my $SEQUENCE = 0x10; | ||
| 97 | my $SET = 0x11; | ||
| 98 | my $UTCTime = 0x17; | ||
| 99 | my $GeneralizedTime = 0x18; | ||
| 100 | |||
| 101 | my %OIDs = ( | ||
| 102 | pack("CCC", 85, 4, 3) => "commonName", | ||
| 103 | pack("CCC", 85, 4, 6) => "countryName", | ||
| 104 | pack("CCC", 85, 4, 10) => "organizationName", | ||
| 105 | pack("CCC", 85, 4, 11) => "organizationUnitName", | ||
| 106 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", | ||
| 107 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", | ||
| 108 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", | ||
| 109 | pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", | ||
| 110 | pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", | ||
| 111 | pack("CCC", 85, 29, 19) => "basicConstraints" | ||
| 112 | ); | ||
| 113 | |||
| 114 | ############################################################################### | ||
| 115 | # | ||
| 116 | # Extract an ASN.1 element from a string and return information about it. | ||
| 117 | # | ||
| 118 | ############################################################################### | ||
| 119 | sub asn1_extract($$@) | ||
| 120 | { | ||
| 121 | my ($cursor, $expected_tag, $optional) = @_; | ||
| 122 | |||
| 123 | return [ -1 ] | ||
| 124 | if ($cursor->[1] == 0 && $optional); | ||
| 125 | |||
| 126 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" | ||
| 127 | if ($cursor->[1] < 2); | ||
| 128 | |||
| 129 | my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
| 130 | |||
| 131 | if ($expected_tag != -1 && $tag != $expected_tag) { | ||
| 132 | return [ -1 ] | ||
| 133 | if ($optional); | ||
| 134 | die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, | ||
| 135 | " not ", $expected_tag, ")\n"; | ||
| 136 | } | ||
| 137 | |||
| 138 | $cursor->[0] += 2; | ||
| 139 | $cursor->[1] -= 2; | ||
| 140 | |||
| 141 | die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n" | ||
| 142 | if (($tag & 0x1f) == 0x1f); | ||
| 143 | die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n" | ||
| 144 | if ($len == 0x80); | ||
| 145 | |||
| 146 | if ($len > 0x80) { | ||
| 147 | my $l = $len - 0x80; | ||
| 148 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" | ||
| 149 | if ($cursor->[1] < $l); | ||
| 150 | |||
| 151 | if ($l == 0x1) { | ||
| 152 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); | ||
| 153 | } elsif ($l == 0x2) { | ||
| 154 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
| 155 | } elsif ($l == 0x3) { | ||
| 156 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; | ||
| 157 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); | ||
| 158 | } elsif ($l == 0x4) { | ||
| 159 | $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); | ||
| 160 | } else { | ||
| 161 | die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; | ||
| 162 | } | ||
| 163 | |||
| 164 | $cursor->[0] += $l; | ||
| 165 | $cursor->[1] -= $l; | ||
| 166 | } | ||
| 167 | |||
| 168 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" | ||
| 169 | if ($cursor->[1] < $len); | ||
| 170 | |||
| 171 | my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; | ||
| 172 | $cursor->[0] += $len; | ||
| 173 | $cursor->[1] -= $len; | ||
| 174 | |||
| 175 | return $ret; | ||
| 176 | } | ||
| 177 | |||
| 178 | ############################################################################### | ||
| 179 | # | ||
| 180 | # Retrieve the data referred to by a cursor | ||
| 181 | # | ||
| 182 | ############################################################################### | ||
| 183 | sub asn1_retrieve($) | ||
| 184 | { | ||
| 185 | my ($cursor) = @_; | ||
| 186 | my ($offset, $len, $data) = @$cursor; | ||
| 187 | return substr($$data, $offset, $len); | ||
| 188 | } | ||
| 189 | |||
| 190 | ############################################################################### | ||
| 191 | # | ||
| 192 | # Roughly parse the X.509 certificate | ||
| 193 | # | ||
| 194 | ############################################################################### | ||
| 195 | my $cursor = [ 0, length($x509_certificate), \$x509_certificate ]; | ||
| 196 | |||
| 197 | my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); | ||
| 198 | my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 199 | my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); | ||
| 200 | my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); | ||
| 201 | my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 202 | my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 203 | my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 204 | my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 205 | my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 206 | my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); | ||
| 207 | my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); | ||
| 208 | my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); | ||
| 209 | |||
| 210 | my $subject_key_id = (); | ||
| 211 | my $authority_key_id = (); | ||
| 212 | |||
| 213 | # | ||
| 214 | # Parse the extension list | ||
| 215 | # | ||
| 216 | if ($extension_list->[0] != -1) { | ||
| 217 | my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 218 | |||
| 219 | while ($extensions->[1]->[1] > 0) { | ||
| 220 | my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 221 | my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); | ||
| 222 | my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); | ||
| 223 | my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); | ||
| 224 | |||
| 225 | my $raw_oid = asn1_retrieve($x_oid->[1]); | ||
| 226 | next if (!exists($OIDs{$raw_oid})); | ||
| 227 | my $x_type = $OIDs{$raw_oid}; | ||
| 228 | |||
| 229 | my $raw_value = asn1_retrieve($x_val->[1]); | ||
| 230 | |||
| 231 | if ($x_type eq "subjectKeyIdentifier") { | ||
| 232 | my $vcursor = [ 0, length($raw_value), \$raw_value ]; | ||
| 233 | |||
| 234 | $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | ############################################################################### | ||
| 240 | # | ||
| 241 | # Determine what we're going to use as the signer's name. In order of | ||
| 242 | # preference, take one of: commonName, organizationName or emailAddress. | ||
| 243 | # | ||
| 244 | ############################################################################### | ||
| 245 | my $org = ""; | ||
| 246 | my $cn = ""; | ||
| 247 | my $email = ""; | ||
| 248 | |||
| 249 | while ($subject->[1]->[1] > 0) { | ||
| 250 | my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); | ||
| 251 | my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); | ||
| 252 | my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); | ||
| 253 | my $n_val = asn1_extract($attr->[1], -1); | ||
| 254 | |||
| 255 | my $raw_oid = asn1_retrieve($n_oid->[1]); | ||
| 256 | next if (!exists($OIDs{$raw_oid})); | ||
| 257 | my $n_type = $OIDs{$raw_oid}; | ||
| 258 | |||
| 259 | my $raw_value = asn1_retrieve($n_val->[1]); | ||
| 260 | |||
| 261 | if ($n_type eq "organizationName") { | ||
| 262 | $org = $raw_value; | ||
| 263 | } elsif ($n_type eq "commonName") { | ||
| 264 | $cn = $raw_value; | ||
| 265 | } elsif ($n_type eq "emailAddress") { | ||
| 266 | $email = $raw_value; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | my $signers_name = $email; | ||
| 271 | |||
| 272 | if ($org && $cn) { | ||
| 273 | # Don't use the organizationName if the commonName repeats it | ||
| 274 | if (length($org) <= length($cn) && | ||
| 275 | substr($cn, 0, length($org)) eq $org) { | ||
| 276 | $signers_name = $cn; | ||
| 277 | goto got_id_name; | ||
| 278 | } | ||
| 279 | |||
| 280 | # Or a signifcant chunk of it | ||
| 281 | if (length($org) >= 7 && | ||
| 282 | length($cn) >= 7 && | ||
| 283 | substr($cn, 0, 7) eq substr($org, 0, 7)) { | ||
| 284 | $signers_name = $cn; | ||
| 285 | goto got_id_name; | ||
| 286 | } | ||
| 287 | |||
| 288 | $signers_name = $org . ": " . $cn; | ||
| 289 | } elsif ($org) { | ||
| 290 | $signers_name = $org; | ||
| 291 | } elsif ($cn) { | ||
| 292 | $signers_name = $cn; | ||
| 293 | } | ||
| 294 | |||
| 295 | got_id_name: | ||
| 296 | |||
| 297 | die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" | ||
| 298 | if (!$subject_key_id); | ||
| 299 | |||
| 300 | my $key_identifier = asn1_retrieve($subject_key_id->[1]); | ||
| 301 | |||
| 302 | ############################################################################### | ||
| 303 | # | ||
| 304 | # Create and attach the module signature | ||
| 305 | # | ||
| 306 | ############################################################################### | ||
| 307 | |||
| 308 | # | ||
| 309 | # Signature parameters | ||
| 310 | # | ||
| 311 | my $algo = 1; # Public-key crypto algorithm: RSA | ||
| 312 | my $hash = 0; # Digest algorithm | ||
| 313 | my $id_type = 1; # Identifier type: X.509 | ||
| 314 | |||
| 315 | # | ||
| 316 | # Digest the data | ||
| 317 | # | ||
| 318 | my $prologue; | ||
| 319 | if ($dgst eq "sha1") { | ||
| 320 | $prologue = pack("C*", | ||
| 321 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
| 322 | 0x2B, 0x0E, 0x03, 0x02, 0x1A, | ||
| 323 | 0x05, 0x00, 0x04, 0x14); | ||
| 324 | $hash = 2; | ||
| 325 | } elsif ($dgst eq "sha224") { | ||
| 326 | $prologue = pack("C*", | ||
| 327 | 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, | ||
| 328 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, | ||
| 329 | 0x05, 0x00, 0x04, 0x1C); | ||
| 330 | $hash = 7; | ||
| 331 | } elsif ($dgst eq "sha256") { | ||
| 332 | $prologue = pack("C*", | ||
| 333 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, | ||
| 334 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, | ||
| 335 | 0x05, 0x00, 0x04, 0x20); | ||
| 336 | $hash = 4; | ||
| 337 | } elsif ($dgst eq "sha384") { | ||
| 338 | $prologue = pack("C*", | ||
| 339 | 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, | ||
| 340 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, | ||
| 341 | 0x05, 0x00, 0x04, 0x30); | ||
| 342 | $hash = 5; | ||
| 343 | } elsif ($dgst eq "sha512") { | ||
| 344 | $prologue = pack("C*", | ||
| 345 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, | ||
| 346 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, | ||
| 347 | 0x05, 0x00, 0x04, 0x40); | ||
| 348 | $hash = 6; | ||
| 349 | } else { | ||
| 350 | die "Unknown hash algorithm: $dgst\n"; | ||
| 351 | } | ||
| 352 | |||
| 353 | my $signature; | ||
| 354 | if ($signature_file) { | ||
| 355 | $signature = read_file($signature_file); | ||
| 356 | } else { | ||
| 357 | # | ||
| 358 | # Generate the digest and read from openssl's stdout | ||
| 359 | # | ||
| 360 | my $digest; | ||
| 361 | $digest = readpipe("openssl dgst -$dgst -binary $module") || die "openssl dgst"; | ||
| 362 | |||
| 363 | # | ||
| 364 | # Generate the binary signature, which will be just the integer that | ||
| 365 | # comprises the signature with no metadata attached. | ||
| 366 | # | ||
| 367 | my $pid; | ||
| 368 | $pid = open2(*read_from, *write_to, | ||
| 369 | "openssl rsautl -sign -inkey $private_key -keyform PEM") || | ||
| 370 | die "openssl rsautl"; | ||
| 371 | binmode write_to; | ||
| 372 | print write_to $prologue . $digest || die "pipe to openssl rsautl"; | ||
| 373 | close(write_to) || die "pipe to openssl rsautl"; | ||
| 374 | |||
| 375 | binmode read_from; | ||
| 376 | read(read_from, $signature, 4096) || die "pipe from openssl rsautl"; | ||
| 377 | close(read_from) || die "pipe from openssl rsautl"; | ||
| 378 | waitpid($pid, 0) || die; | ||
| 379 | die "openssl rsautl died: $?" if ($? >> 8); | ||
| 380 | } | ||
| 381 | $signature = pack("n", length($signature)) . $signature, | ||
| 382 | |||
| 383 | # | ||
| 384 | # Build the signed binary | ||
| 385 | # | ||
| 386 | my $unsigned_module = read_file($module); | ||
| 387 | |||
| 388 | my $magic_number = "~Module signature appended~\n"; | ||
| 389 | |||
| 390 | my $info = pack("CCCCCxxxN", | ||
| 391 | $algo, $hash, $id_type, | ||
| 392 | length($signers_name), | ||
| 393 | length($key_identifier), | ||
| 394 | length($signature)); | ||
| 395 | |||
| 396 | if ($verbose) { | ||
| 397 | print "Size of unsigned module: ", length($unsigned_module), "\n"; | ||
| 398 | print "Size of signer's name : ", length($signers_name), "\n"; | ||
| 399 | print "Size of key identifier : ", length($key_identifier), "\n"; | ||
| 400 | print "Size of signature : ", length($signature), "\n"; | ||
| 401 | print "Size of information : ", length($info), "\n"; | ||
| 402 | print "Size of magic number : ", length($magic_number), "\n"; | ||
| 403 | print "Signer's name : '", $signers_name, "'\n"; | ||
| 404 | print "Digest : $dgst\n"; | ||
| 405 | } | ||
| 406 | |||
| 407 | open(FD, ">$dest") || die $dest; | ||
| 408 | binmode FD; | ||
| 409 | print FD | ||
| 410 | $unsigned_module, | ||
| 411 | $signers_name, | ||
| 412 | $key_identifier, | ||
| 413 | $signature, | ||
| 414 | $info, | ||
| 415 | $magic_number | ||
| 416 | ; | ||
| 417 | close FD || die $dest; | ||
| 418 | |||
| 419 | if (!$keep_orig) { | ||
| 420 | rename($dest, $module) || die $module; | ||
| 421 | } | ||
diff --git a/scripts/sign-file.c b/scripts/sign-file.c new file mode 100755 index 000000000000..058bba3103e2 --- /dev/null +++ b/scripts/sign-file.c | |||
| @@ -0,0 +1,260 @@ | |||
| 1 | /* Sign a module file using the given key. | ||
| 2 | * | ||
| 3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #define _GNU_SOURCE | ||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <stdint.h> | ||
| 15 | #include <stdbool.h> | ||
| 16 | #include <string.h> | ||
| 17 | #include <getopt.h> | ||
| 18 | #include <err.h> | ||
| 19 | #include <arpa/inet.h> | ||
| 20 | #include <openssl/bio.h> | ||
| 21 | #include <openssl/evp.h> | ||
| 22 | #include <openssl/pem.h> | ||
| 23 | #include <openssl/cms.h> | ||
| 24 | #include <openssl/err.h> | ||
| 25 | #include <openssl/engine.h> | ||
| 26 | |||
| 27 | struct module_signature { | ||
| 28 | uint8_t algo; /* Public-key crypto algorithm [0] */ | ||
| 29 | uint8_t hash; /* Digest algorithm [0] */ | ||
| 30 | uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ | ||
| 31 | uint8_t signer_len; /* Length of signer's name [0] */ | ||
| 32 | uint8_t key_id_len; /* Length of key identifier [0] */ | ||
| 33 | uint8_t __pad[3]; | ||
| 34 | uint32_t sig_len; /* Length of signature data */ | ||
| 35 | }; | ||
| 36 | |||
| 37 | #define PKEY_ID_PKCS7 2 | ||
| 38 | |||
| 39 | static char magic_number[] = "~Module signature appended~\n"; | ||
| 40 | |||
| 41 | static __attribute__((noreturn)) | ||
| 42 | void format(void) | ||
| 43 | { | ||
| 44 | fprintf(stderr, | ||
| 45 | "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n"); | ||
| 46 | exit(2); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void display_openssl_errors(int l) | ||
| 50 | { | ||
| 51 | const char *file; | ||
| 52 | char buf[120]; | ||
| 53 | int e, line; | ||
| 54 | |||
| 55 | if (ERR_peek_error() == 0) | ||
| 56 | return; | ||
| 57 | fprintf(stderr, "At main.c:%d:\n", l); | ||
| 58 | |||
| 59 | while ((e = ERR_get_error_line(&file, &line))) { | ||
| 60 | ERR_error_string(e, buf); | ||
| 61 | fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | static void drain_openssl_errors(void) | ||
| 66 | { | ||
| 67 | const char *file; | ||
| 68 | int line; | ||
| 69 | |||
| 70 | if (ERR_peek_error() == 0) | ||
| 71 | return; | ||
| 72 | while (ERR_get_error_line(&file, &line)) {} | ||
| 73 | } | ||
| 74 | |||
| 75 | #define ERR(cond, fmt, ...) \ | ||
| 76 | do { \ | ||
| 77 | bool __cond = (cond); \ | ||
| 78 | display_openssl_errors(__LINE__); \ | ||
| 79 | if (__cond) { \ | ||
| 80 | err(1, fmt, ## __VA_ARGS__); \ | ||
| 81 | } \ | ||
| 82 | } while(0) | ||
| 83 | |||
| 84 | static const char *key_pass; | ||
| 85 | |||
| 86 | static int pem_pw_cb(char *buf, int len, int w, void *v) | ||
| 87 | { | ||
| 88 | int pwlen; | ||
| 89 | |||
| 90 | if (!key_pass) | ||
| 91 | return -1; | ||
| 92 | |||
| 93 | pwlen = strlen(key_pass); | ||
| 94 | if (pwlen >= len) | ||
| 95 | return -1; | ||
| 96 | |||
| 97 | strcpy(buf, key_pass); | ||
| 98 | |||
| 99 | /* If it's wrong, don't keep trying it. */ | ||
| 100 | key_pass = NULL; | ||
| 101 | |||
| 102 | return pwlen; | ||
| 103 | } | ||
| 104 | |||
| 105 | int main(int argc, char **argv) | ||
| 106 | { | ||
| 107 | struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; | ||
| 108 | char *hash_algo = NULL; | ||
| 109 | char *private_key_name, *x509_name, *module_name, *dest_name; | ||
| 110 | bool save_cms = false, replace_orig; | ||
| 111 | bool sign_only = false; | ||
| 112 | unsigned char buf[4096]; | ||
| 113 | unsigned long module_size, cms_size; | ||
| 114 | unsigned int use_keyid = 0, use_signed_attrs = CMS_NOATTR; | ||
| 115 | const EVP_MD *digest_algo; | ||
| 116 | EVP_PKEY *private_key; | ||
| 117 | CMS_ContentInfo *cms; | ||
| 118 | X509 *x509; | ||
| 119 | BIO *b, *bd = NULL, *bm; | ||
| 120 | int opt, n; | ||
| 121 | |||
| 122 | OpenSSL_add_all_algorithms(); | ||
| 123 | ERR_load_crypto_strings(); | ||
| 124 | ERR_clear_error(); | ||
| 125 | |||
| 126 | key_pass = getenv("KBUILD_SIGN_PIN"); | ||
| 127 | |||
| 128 | do { | ||
| 129 | opt = getopt(argc, argv, "dpk"); | ||
| 130 | switch (opt) { | ||
| 131 | case 'p': save_cms = true; break; | ||
| 132 | case 'd': sign_only = true; save_cms = true; break; | ||
| 133 | case 'k': use_keyid = CMS_USE_KEYID; break; | ||
| 134 | case -1: break; | ||
| 135 | default: format(); | ||
| 136 | } | ||
| 137 | } while (opt != -1); | ||
| 138 | |||
| 139 | argc -= optind; | ||
| 140 | argv += optind; | ||
| 141 | if (argc < 4 || argc > 5) | ||
| 142 | format(); | ||
| 143 | |||
| 144 | hash_algo = argv[0]; | ||
| 145 | private_key_name = argv[1]; | ||
| 146 | x509_name = argv[2]; | ||
| 147 | module_name = argv[3]; | ||
| 148 | if (argc == 5) { | ||
| 149 | dest_name = argv[4]; | ||
| 150 | replace_orig = false; | ||
| 151 | } else { | ||
| 152 | ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0, | ||
| 153 | "asprintf"); | ||
| 154 | replace_orig = true; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* Read the private key and the X.509 cert the PKCS#7 message | ||
| 158 | * will point to. | ||
| 159 | */ | ||
| 160 | if (!strncmp(private_key_name, "pkcs11:", 7)) { | ||
| 161 | ENGINE *e; | ||
| 162 | |||
| 163 | ENGINE_load_builtin_engines(); | ||
| 164 | drain_openssl_errors(); | ||
| 165 | e = ENGINE_by_id("pkcs11"); | ||
| 166 | ERR(!e, "Load PKCS#11 ENGINE"); | ||
| 167 | if (ENGINE_init(e)) | ||
| 168 | drain_openssl_errors(); | ||
| 169 | else | ||
| 170 | ERR(1, "ENGINE_init"); | ||
| 171 | if (key_pass) | ||
| 172 | ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); | ||
| 173 | private_key = ENGINE_load_private_key(e, private_key_name, NULL, | ||
| 174 | NULL); | ||
| 175 | ERR(!private_key, "%s", private_key_name); | ||
| 176 | } else { | ||
| 177 | b = BIO_new_file(private_key_name, "rb"); | ||
| 178 | ERR(!b, "%s", private_key_name); | ||
| 179 | private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL); | ||
| 180 | ERR(!private_key, "%s", private_key_name); | ||
| 181 | BIO_free(b); | ||
| 182 | } | ||
| 183 | |||
| 184 | b = BIO_new_file(x509_name, "rb"); | ||
| 185 | ERR(!b, "%s", x509_name); | ||
| 186 | x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ | ||
| 187 | if (!x509) { | ||
| 188 | ERR(BIO_reset(b) != 1, "%s", x509_name); | ||
| 189 | x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */ | ||
| 190 | if (x509) | ||
| 191 | drain_openssl_errors(); | ||
| 192 | } | ||
| 193 | BIO_free(b); | ||
| 194 | ERR(!x509, "%s", x509_name); | ||
| 195 | |||
| 196 | /* Open the destination file now so that we can shovel the module data | ||
| 197 | * across as we read it. | ||
| 198 | */ | ||
| 199 | if (!sign_only) { | ||
| 200 | bd = BIO_new_file(dest_name, "wb"); | ||
| 201 | ERR(!bd, "%s", dest_name); | ||
| 202 | } | ||
| 203 | |||
| 204 | /* Digest the module data. */ | ||
| 205 | OpenSSL_add_all_digests(); | ||
| 206 | display_openssl_errors(__LINE__); | ||
| 207 | digest_algo = EVP_get_digestbyname(hash_algo); | ||
| 208 | ERR(!digest_algo, "EVP_get_digestbyname"); | ||
| 209 | |||
| 210 | bm = BIO_new_file(module_name, "rb"); | ||
| 211 | ERR(!bm, "%s", module_name); | ||
| 212 | |||
| 213 | /* Load the CMS message from the digest buffer. */ | ||
| 214 | cms = CMS_sign(NULL, NULL, NULL, NULL, | ||
| 215 | CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM); | ||
| 216 | ERR(!cms, "CMS_sign"); | ||
| 217 | |||
| 218 | ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, | ||
| 219 | CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | | ||
| 220 | use_keyid | use_signed_attrs), | ||
| 221 | "CMS_sign_add_signer"); | ||
| 222 | ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, | ||
| 223 | "CMS_final"); | ||
| 224 | |||
| 225 | if (save_cms) { | ||
| 226 | char *cms_name; | ||
| 227 | |||
| 228 | ERR(asprintf(&cms_name, "%s.p7s", module_name) < 0, "asprintf"); | ||
| 229 | b = BIO_new_file(cms_name, "wb"); | ||
| 230 | ERR(!b, "%s", cms_name); | ||
| 231 | ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, "%s", cms_name); | ||
| 232 | BIO_free(b); | ||
| 233 | } | ||
| 234 | |||
| 235 | if (sign_only) | ||
| 236 | return 0; | ||
| 237 | |||
| 238 | /* Append the marker and the PKCS#7 message to the destination file */ | ||
| 239 | ERR(BIO_reset(bm) < 0, "%s", module_name); | ||
| 240 | while ((n = BIO_read(bm, buf, sizeof(buf))), | ||
| 241 | n > 0) { | ||
| 242 | ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); | ||
| 243 | } | ||
| 244 | ERR(n < 0, "%s", module_name); | ||
| 245 | module_size = BIO_number_written(bd); | ||
| 246 | |||
| 247 | ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); | ||
| 248 | cms_size = BIO_number_written(bd) - module_size; | ||
| 249 | sig_info.sig_len = htonl(cms_size); | ||
| 250 | ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); | ||
| 251 | ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name); | ||
| 252 | |||
| 253 | ERR(BIO_free(bd) < 0, "%s", dest_name); | ||
| 254 | |||
| 255 | /* Finally, if we're signing in place, replace the original. */ | ||
| 256 | if (replace_orig) | ||
| 257 | ERR(rename(dest_name, module_name) < 0, "%s", dest_name); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
