diff options
59 files changed, 999 insertions, 745 deletions
diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig index 18c311a..0b9211b 100644 --- a/arch/arm/configs/colibri_pxa270_defconfig +++ b/arch/arm/configs/colibri_pxa270_defconfig @@ -166,7 +166,6 @@ CONFIG_DEBUG_USER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA1=m diff --git a/arch/arm/configs/iop13xx_defconfig b/arch/arm/configs/iop13xx_defconfig index 4fa94a1..652b7bd 100644 --- a/arch/arm/configs/iop13xx_defconfig +++ b/arch/arm/configs/iop13xx_defconfig @@ -95,7 +95,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_NLS=y CONFIG_DEBUG_USER=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_LRW=y CONFIG_CRYPTO_PCBC=m diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig index c3058da..aa3af0a 100644 --- a/arch/arm/configs/iop32x_defconfig +++ b/arch/arm/configs/iop32x_defconfig @@ -108,7 +108,6 @@ CONFIG_DEBUG_USER=y CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL_UART_8250=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_LRW=y CONFIG_CRYPTO_PCBC=m diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index 4bc8700..0ada29d 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -214,7 +214,6 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_USER=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=m diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig index e2f6543..dc5dd5b 100644 --- a/arch/microblaze/configs/mmu_defconfig +++ b/arch/microblaze/configs/mmu_defconfig @@ -87,5 +87,4 @@ CONFIG_KGDB_KDB=y CONFIG_EARLY_PRINTK=y CONFIG_KEYS=y CONFIG_ENCRYPTED_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/microblaze/configs/nommu_defconfig b/arch/microblaze/configs/nommu_defconfig index a29ebd4..4cdaf56 100644 --- a/arch/microblaze/configs/nommu_defconfig +++ b/arch/microblaze/configs/nommu_defconfig @@ -92,7 +92,6 @@ CONFIG_DEBUG_INFO=y CONFIG_EARLY_PRINTK=y CONFIG_KEYS=y CONFIG_ENCRYPTED_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_MD5=y diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index b3e7a1b..e070dac 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -247,7 +247,6 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_DEBUG_LIST=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_NETWORK_XFRM=y diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index 57ed466..6ba9ce9 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -358,7 +358,6 @@ CONFIG_DLM=m CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_CRYPTD=m diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 48e16d9..77e9f50 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -346,7 +346,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DLM=m # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITYFS=y CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_NULL=m diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index fe48220..f9af98f 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig @@ -181,7 +181,6 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig index 4f37a59..a5e85e1 100644 --- a/arch/mips/configs/jazz_defconfig +++ b/arch/mips/configs/jazz_defconfig @@ -362,7 +362,6 @@ CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=m CONFIG_DLM=m -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_LRW=m diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 004cf52..d1f198b 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -412,7 +412,6 @@ CONFIG_DEBUG_FS=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_FIPS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_CRYPTD=m diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index db029f4..82db4e3 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -453,7 +453,6 @@ CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=m CONFIG_DLM=m -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_LRW=m diff --git a/arch/mips/configs/sb1250_swarm_defconfig b/arch/mips/configs/sb1250_swarm_defconfig index 51bab13..7fca09fe 100644 --- a/arch/mips/configs/sb1250_swarm_defconfig +++ b/arch/mips/configs/sb1250_swarm_defconfig @@ -87,7 +87,6 @@ CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_DLM=m CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_AUTHENC=m diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig index 9387cc2..db8f56b 100644 --- a/arch/parisc/configs/712_defconfig +++ b/arch/parisc/configs/712_defconfig @@ -183,7 +183,6 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_DEBUG_RODATA=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_HMAC=y diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig index 0490199..1a4f776 100644 --- a/arch/parisc/configs/a500_defconfig +++ b/arch/parisc/configs/a500_defconfig @@ -193,7 +193,6 @@ CONFIG_HEADERS_CHECK=y CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_HMAC=y diff --git a/arch/parisc/configs/default_defconfig b/arch/parisc/configs/default_defconfig index 4d8127e..310b665 100644 --- a/arch/parisc/configs/default_defconfig +++ b/arch/parisc/configs/default_defconfig @@ -211,7 +211,6 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_MD4=m diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig index 0ffb08f..5b04d70 100644 --- a/arch/parisc/configs/generic-32bit_defconfig +++ b/arch/parisc/configs/generic-32bit_defconfig @@ -301,7 +301,6 @@ CONFIG_RCU_CPU_STALL_INFO=y CONFIG_LATENCYTOP=y CONFIG_LKDTM=m CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_HMAC=y diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig index 9186229..340685c 100644 --- a/arch/powerpc/configs/c2k_defconfig +++ b/arch/powerpc/configs/c2k_defconfig @@ -387,7 +387,6 @@ CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_SPINLOCK=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index e5d2c3d..99ccbeba 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -1175,7 +1175,6 @@ CONFIG_BLK_DEV_IO_TRACE=y CONFIG_XMON=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_NETWORK_XFRM=y diff --git a/arch/score/configs/spct6600_defconfig b/arch/score/configs/spct6600_defconfig index df1edbf..b2d8802 100644 --- a/arch/score/configs/spct6600_defconfig +++ b/arch/score/configs/spct6600_defconfig @@ -70,7 +70,6 @@ CONFIG_NFSD=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_CRYPTO_NULL=y diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig index 37dc936..c1387b7 100644 --- a/arch/tile/configs/tilegx_defconfig +++ b/arch/tile/configs/tilegx_defconfig @@ -374,7 +374,6 @@ CONFIG_DEBUG_CREDENTIALS=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ASYNC_RAID6_TEST=m CONFIG_KGDB=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITYFS=y CONFIG_SECURITY_NETWORK=y diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig index 76a2781..6d9ce8a 100644 --- a/arch/tile/configs/tilepro_defconfig +++ b/arch/tile/configs/tilepro_defconfig @@ -486,7 +486,6 @@ CONFIG_DEBUG_LIST=y CONFIG_DEBUG_CREDENTIALS=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ASYNC_RAID6_TEST=m -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITYFS=y CONFIG_SECURITY_NETWORK=y diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 028be48..a212b68 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -303,7 +303,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_RODATA_TEST is not set CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index cb5b3ab..4f404a6 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -300,7 +300,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y # CONFIG_DEBUG_RODATA_TEST is not set CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SELINUX=y diff --git a/certs/Kconfig b/certs/Kconfig index b030b9c..f0f8a44 100644 --- a/certs/Kconfig +++ b/certs/Kconfig @@ -39,4 +39,20 @@ config SYSTEM_TRUSTED_KEYS form of DER-encoded *.x509 files in the top-level build directory, those are no longer used. You will need to set this option instead. +config SYSTEM_EXTRA_CERTIFICATE + bool "Reserve area for inserting a certificate without recompiling" + depends on SYSTEM_TRUSTED_KEYRING + help + If set, space for an extra certificate will be reserved in the kernel + image. This allows introducing a trusted certificate to the default + system keyring without recompiling the kernel. + +config SYSTEM_EXTRA_CERTIFICATE_SIZE + int "Number of bytes to reserve for the extra certificate" + depends on SYSTEM_EXTRA_CERTIFICATE + default 4096 + help + This is the number of bytes reserved in the kernel image for a + certificate to be inserted. + endmenu diff --git a/certs/Makefile b/certs/Makefile index 28ac694..2773c4a 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -36,29 +36,34 @@ ifndef CONFIG_MODULE_SIG_HASH $(error Could not determine digest type to use from kernel config) endif +redirect_openssl = 2>&1 +quiet_redirect_openssl = 2>&1 +silent_redirect_openssl = 2>/dev/null + # We do it this way rather than having a boolean option for enabling an # external private key, because 'make randconfig' might enable such a # boolean option and we unfortunately can't make it depend on !RANDCONFIG. ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem") $(obj)/signing_key.pem: $(obj)/x509.genkey - @echo "###" - @echo "### Now generating an X.509 key pair to be used for signing modules." - @echo "###" - @echo "### If this takes a long time, you might wish to run rngd in the" - @echo "### background to keep the supply of entropy topped up. It" - @echo "### needs to be run as root, and uses a hardware random" - @echo "### number generator if one is available." - @echo "###" - openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ + @$(kecho) "###" + @$(kecho) "### Now generating an X.509 key pair to be used for signing modules." + @$(kecho) "###" + @$(kecho) "### If this takes a long time, you might wish to run rngd in the" + @$(kecho) "### background to keep the supply of entropy topped up. It" + @$(kecho) "### needs to be run as root, and uses a hardware random" + @$(kecho) "### number generator if one is available." + @$(kecho) "###" + $(Q)openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ -batch -x509 -config $(obj)/x509.genkey \ -outform PEM -out $(obj)/signing_key.pem \ - -keyout $(obj)/signing_key.pem 2>&1 - @echo "###" - @echo "### Key pair generated." - @echo "###" + -keyout $(obj)/signing_key.pem \ + $($(quiet)redirect_openssl) + @$(kecho) "###" + @$(kecho) "### Key pair generated." + @$(kecho) "###" $(obj)/x509.genkey: - @echo Generating X.509 key generation config + @$(kecho) Generating X.509 key generation config @echo >$@ "[ req ]" @echo >>$@ "default_bits = 4096" @echo >>$@ "distinguished_name = req_distinguished_name" diff --git a/certs/system_certificates.S b/certs/system_certificates.S index 9216e8c..c9ceb71 100644 --- a/certs/system_certificates.S +++ b/certs/system_certificates.S @@ -13,6 +13,19 @@ __cert_list_start: .incbin "certs/x509_certificate_list" __cert_list_end: +#ifdef CONFIG_SYSTEM_EXTRA_CERTIFICATE + .globl VMLINUX_SYMBOL(system_extra_cert) + .size system_extra_cert, CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE +VMLINUX_SYMBOL(system_extra_cert): + .fill CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE, 1, 0 + + .align 4 + .globl VMLINUX_SYMBOL(system_extra_cert_used) +VMLINUX_SYMBOL(system_extra_cert_used): + .int 0 + +#endif /* CONFIG_SYSTEM_EXTRA_CERTIFICATE */ + .align 8 .globl VMLINUX_SYMBOL(system_certificate_list_size) VMLINUX_SYMBOL(system_certificate_list_size): diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 2570598..f418032 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -84,12 +84,12 @@ static __init int load_system_certificate_list(void) ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ), KEY_ALLOC_NOT_IN_QUOTA | - KEY_ALLOC_TRUSTED); + KEY_ALLOC_TRUSTED | + KEY_ALLOC_BUILT_IN); if (IS_ERR(key)) { pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", PTR_ERR(key)); } else { - set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags); pr_notice("Loaded X.509 cert '%s'\n", key_ref_to_ptr(key)->description); key_ref_put(key); diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 4870f28..91a7e04 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -12,7 +12,6 @@ if ASYMMETRIC_KEY_TYPE config ASYMMETRIC_PUBLIC_KEY_SUBTYPE tristate "Asymmetric public-key crypto algorithm subtype" select MPILIB - select PUBLIC_KEY_ALGO_RSA select CRYPTO_HASH_INFO help This option provides support for asymmetric public key type handling. @@ -20,12 +19,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE appropriate hash algorithms (such as SHA-1) must be available. ENOPKG will be reported if the requisite algorithm is unavailable. -config PUBLIC_KEY_ALGO_RSA - tristate "RSA public-key algorithm" - select MPILIB - help - This option enables support for the RSA algorithm (PKCS#1, RFC3447). - config X509_CERTIFICATE_PARSER tristate "X.509 certificate parser" depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index cd1406f..f904862 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o asymmetric_keys-y := asymmetric_type.o signature.o obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o -obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o # # X.509 Certificate handling @@ -16,21 +15,18 @@ obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o x509_key_parser-y := \ x509-asn1.o \ x509_akid-asn1.o \ - x509_rsakey-asn1.o \ x509_cert_parser.o \ x509_public_key.o $(obj)/x509_cert_parser.o: \ $(obj)/x509-asn1.h \ - $(obj)/x509_akid-asn1.h \ - $(obj)/x509_rsakey-asn1.h + $(obj)/x509_akid-asn1.h + $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h $(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h -$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h clean-files += x509-asn1.c x509-asn1.h clean-files += x509_akid-asn1.c x509_akid-asn1.h -clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h # # PKCS#7 message handling diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index adcef59..3242cbf 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c @@ -86,25 +86,25 @@ int mscode_note_digest_algo(void *context, size_t hdrlen, oid = look_up_OID(value, vlen); switch (oid) { case OID_md4: - ctx->digest_algo = HASH_ALGO_MD4; + ctx->digest_algo = "md4"; break; case OID_md5: - ctx->digest_algo = HASH_ALGO_MD5; + ctx->digest_algo = "md5"; break; case OID_sha1: - ctx->digest_algo = HASH_ALGO_SHA1; + ctx->digest_algo = "sha1"; break; case OID_sha256: - ctx->digest_algo = HASH_ALGO_SHA256; + ctx->digest_algo = "sha256"; break; case OID_sha384: - ctx->digest_algo = HASH_ALGO_SHA384; + ctx->digest_algo = "sha384"; break; case OID_sha512: - ctx->digest_algo = HASH_ALGO_SHA512; + ctx->digest_algo = "sha512"; break; case OID_sha224: - ctx->digest_algo = HASH_ALGO_SHA224; + ctx->digest_algo = "sha224"; break; case OID__NR: diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 8f3056c..40de03f 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -15,7 +15,7 @@ #include <linux/slab.h> #include <linux/err.h> #include <linux/oid_registry.h> -#include "public_key.h" +#include <crypto/public_key.h> #include "pkcs7_parser.h" #include "pkcs7-asn1.h" @@ -44,7 +44,7 @@ struct pkcs7_parse_context { static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) { if (sinfo) { - mpi_free(sinfo->sig.mpi[0]); + kfree(sinfo->sig.s); kfree(sinfo->sig.digest); kfree(sinfo->signing_cert_id); kfree(sinfo); @@ -87,7 +87,7 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message); static int pkcs7_check_authattrs(struct pkcs7_message *msg) { struct pkcs7_signed_info *sinfo; - bool want; + bool want = false; sinfo = msg->signed_infos; if (sinfo->authattrs) { @@ -218,25 +218,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, switch (ctx->last_oid) { case OID_md4: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4; + ctx->sinfo->sig.hash_algo = "md4"; break; case OID_md5: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5; + ctx->sinfo->sig.hash_algo = "md5"; break; case OID_sha1: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1; + ctx->sinfo->sig.hash_algo = "sha1"; break; case OID_sha256: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; + ctx->sinfo->sig.hash_algo = "sha256"; break; case OID_sha384: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384; + ctx->sinfo->sig.hash_algo = "sha384"; break; case OID_sha512: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512; + ctx->sinfo->sig.hash_algo = "sha512"; break; case OID_sha224: - ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224; + ctx->sinfo->sig.hash_algo = "sha224"; default: printk("Unsupported digest algo: %u\n", ctx->last_oid); return -ENOPKG; @@ -255,7 +255,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, switch (ctx->last_oid) { case OID_rsaEncryption: - ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->sinfo->sig.pkey_algo = "rsa"; break; default: printk("Unsupported pkey algo: %u\n", ctx->last_oid); @@ -614,16 +614,12 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; - MPI mpi; - BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA); - - mpi = mpi_read_raw_data(value, vlen); - if (!mpi) + ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL); + if (!ctx->sinfo->sig.s) return -ENOMEM; - ctx->sinfo->sig.mpi[0] = mpi; - ctx->sinfo->sig.nr_mpi = 1; + ctx->sinfo->sig.s_size = vlen; return 0; } diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 90d6d47..3bbdcc7 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c @@ -17,7 +17,7 @@ #include <linux/asn1.h> #include <linux/key.h> #include <keys/asymmetric-type.h> -#include "public_key.h" +#include <crypto/public_key.h> #include "pkcs7_parser.h" /** diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 325575c..50be2a1 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -16,7 +16,7 @@ #include <linux/err.h> #include <linux/asn1.h> #include <crypto/hash.h> -#include "public_key.h" +#include <crypto/public_key.h> #include "pkcs7_parser.h" /* @@ -31,17 +31,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, void *digest; int ret; - kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo); + kenter(",%u,%s", sinfo->index, sinfo->sig.hash_algo); - if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST || - !hash_algo_name[sinfo->sig.pkey_hash_algo]) + if (!sinfo->sig.hash_algo) return -ENOPKG; /* Allocate the hashing algorithm we're going to need and find out how * big the hash operational data will be. */ - tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo], - 0, 0); + tfm = crypto_alloc_shash(sinfo->sig.hash_algo, 0, 0); if (IS_ERR(tfm)) return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 6db4c01..0f8b264 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -17,32 +17,13 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/seq_file.h> +#include <linux/scatterlist.h> #include <keys/asymmetric-subtype.h> -#include "public_key.h" +#include <crypto/public_key.h> +#include <crypto/akcipher.h> MODULE_LICENSE("GPL"); -const char *const pkey_algo_name[PKEY_ALGO__LAST] = { - [PKEY_ALGO_DSA] = "DSA", - [PKEY_ALGO_RSA] = "RSA", -}; -EXPORT_SYMBOL_GPL(pkey_algo_name); - -const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = { -#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ - defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) - [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, -#endif -}; -EXPORT_SYMBOL_GPL(pkey_algo); - -const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { - [PKEY_ID_PGP] = "PGP", - [PKEY_ID_X509] = "X509", - [PKEY_ID_PKCS7] = "PKCS#7", -}; -EXPORT_SYMBOL_GPL(pkey_id_type_name); - /* * Provide a part of a description of the key for /proc/keys. */ @@ -52,8 +33,7 @@ static void public_key_describe(const struct key *asymmetric_key, struct public_key *key = asymmetric_key->payload.data[asym_crypto]; if (key) - seq_printf(m, "%s.%s", - pkey_id_type_name[key->id_type], key->algo->name); + seq_printf(m, "%s.%s", key->id_type, key->pkey_algo); } /* @@ -62,50 +42,116 @@ static void public_key_describe(const struct key *asymmetric_key, void public_key_destroy(void *payload) { struct public_key *key = payload; - int i; - if (key) { - for (i = 0; i < ARRAY_SIZE(key->mpi); i++) - mpi_free(key->mpi[i]); - kfree(key); - } + if (key) + kfree(key->key); + kfree(key); } EXPORT_SYMBOL_GPL(public_key_destroy); +struct public_key_completion { + struct completion completion; + int err; +}; + +static void public_key_verify_done(struct crypto_async_request *req, int err) +{ + struct public_key_completion *compl = req->data; + + if (err == -EINPROGRESS) + return; + + compl->err = err; + complete(&compl->completion); +} + /* * Verify a signature using a public key. */ -int public_key_verify_signature(const struct public_key *pk, +int public_key_verify_signature(const struct public_key *pkey, const struct public_key_signature *sig) { - const struct public_key_algorithm *algo; - - BUG_ON(!pk); - BUG_ON(!pk->mpi[0]); - BUG_ON(!pk->mpi[1]); + struct public_key_completion compl; + struct crypto_akcipher *tfm; + struct akcipher_request *req; + struct scatterlist sig_sg, digest_sg; + const char *alg_name; + char alg_name_buf[CRYPTO_MAX_ALG_NAME]; + void *output; + unsigned int outlen; + int ret = -ENOMEM; + + pr_devel("==>%s()\n", __func__); + + BUG_ON(!pkey); BUG_ON(!sig); BUG_ON(!sig->digest); - BUG_ON(!sig->mpi[0]); - - algo = pk->algo; - if (!algo) { - if (pk->pkey_algo >= PKEY_ALGO__LAST) - return -ENOPKG; - algo = pkey_algo[pk->pkey_algo]; - if (!algo) - return -ENOPKG; + BUG_ON(!sig->s); + + alg_name = sig->pkey_algo; + if (strcmp(sig->pkey_algo, "rsa") == 0) { + /* The data wangled by the RSA algorithm is typically padded + * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447 + * sec 8.2]. + */ + if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME, + "pkcs1pad(rsa,%s)", sig->hash_algo + ) >= CRYPTO_MAX_ALG_NAME) + return -EINVAL; + alg_name = alg_name_buf; } - if (!algo->verify_signature) - return -ENOTSUPP; - - if (sig->nr_mpi != algo->n_sig_mpi) { - pr_debug("Signature has %u MPI not %u\n", - sig->nr_mpi, algo->n_sig_mpi); - return -EINVAL; + tfm = crypto_alloc_akcipher(alg_name, 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + req = akcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) + goto error_free_tfm; + + ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen); + if (ret) + goto error_free_req; + + outlen = crypto_akcipher_maxsize(tfm); + output = kmalloc(outlen, GFP_KERNEL); + if (!output) + goto error_free_req; + + sg_init_one(&sig_sg, sig->s, sig->s_size); + sg_init_one(&digest_sg, output, outlen); + akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size, + outlen); + init_completion(&compl.completion); + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + public_key_verify_done, &compl); + + /* Perform the verification calculation. This doesn't actually do the + * verification, but rather calculates the hash expected by the + * signature and returns that to us. + */ + ret = crypto_akcipher_verify(req); + if (ret == -EINPROGRESS) { + wait_for_completion(&compl.completion); + ret = compl.err; } - - return algo->verify_signature(pk, sig); + if (ret < 0) + goto out_free_output; + + /* Do the actual verification step. */ + if (req->dst_len != sig->digest_size || + memcmp(sig->digest, output, sig->digest_size) != 0) + ret = -EKEYREJECTED; + +out_free_output: + kfree(output); +error_free_req: + akcipher_request_free(req); +error_free_tfm: + crypto_free_akcipher(tfm); + pr_devel("<==%s() = %d\n", __func__, ret); + return ret; } EXPORT_SYMBOL_GPL(public_key_verify_signature); diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h deleted file mode 100644 index 5c37a22..0000000 --- a/crypto/asymmetric_keys/public_key.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Public key algorithm internals - * - * See Documentation/crypto/asymmetric-keys.txt - * - * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#include <crypto/public_key.h> - -extern struct asymmetric_key_subtype public_key_subtype; - -/* - * Public key algorithm definition. - */ -struct public_key_algorithm { - const char *name; - u8 n_pub_mpi; /* Number of MPIs in public key */ - u8 n_sec_mpi; /* Number of MPIs in secret key */ - u8 n_sig_mpi; /* Number of MPIs in a signature */ - int (*verify_signature)(const struct public_key *key, - const struct public_key_signature *sig); -}; - -extern const struct public_key_algorithm RSA_public_key_algorithm; - -/* - * public_key.c - */ -extern int public_key_verify_signature(const struct public_key *pk, - const struct public_key_signature *sig); diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c deleted file mode 100644 index 508b57b..0000000 --- a/crypto/asymmetric_keys/rsa.c +++ /dev/null @@ -1,278 +0,0 @@ -/* RSA asymmetric public-key algorithm [RFC3447] - * - * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "RSA: "fmt -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <crypto/algapi.h> -#include "public_key.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("RSA Public Key Algorithm"); - -#define kenter(FMT, ...) \ - pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) -#define kleave(FMT, ...) \ - pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) - -/* - * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. - */ -static const u8 RSA_digest_info_MD5[] = { - 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ - 0x05, 0x00, 0x04, 0x10 -}; - -static const u8 RSA_digest_info_SHA1[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, - 0x2B, 0x0E, 0x03, 0x02, 0x1A, - 0x05, 0x00, 0x04, 0x14 -}; - -static const u8 RSA_digest_info_RIPE_MD_160[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, - 0x2B, 0x24, 0x03, 0x02, 0x01, - 0x05, 0x00, 0x04, 0x14 -}; - -static const u8 RSA_digest_info_SHA224[] = { - 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, - 0x05, 0x00, 0x04, 0x1C -}; - -static const u8 RSA_digest_info_SHA256[] = { - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, - 0x05, 0x00, 0x04, 0x20 -}; - -static const u8 RSA_digest_info_SHA384[] = { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, - 0x05, 0x00, 0x04, 0x30 -}; - -static const u8 RSA_digest_info_SHA512[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, - 0x05, 0x00, 0x04, 0x40 -}; - -static const struct { - const u8 *data; - size_t size; -} RSA_ASN1_templates[PKEY_HASH__LAST] = { -#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } - [HASH_ALGO_MD5] = _(MD5), - [HASH_ALGO_SHA1] = _(SHA1), - [HASH_ALGO_RIPE_MD_160] = _(RIPE_MD_160), - [HASH_ALGO_SHA256] = _(SHA256), - [HASH_ALGO_SHA384] = _(SHA384), - [HASH_ALGO_SHA512] = _(SHA512), - [HASH_ALGO_SHA224] = _(SHA224), -#undef _ -}; - -/* - * RSAVP1() function [RFC3447 sec 5.2.2] - */ -static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) -{ - MPI m; - int ret; - - /* (1) Validate 0 <= s < n */ - if (mpi_cmp_ui(s, 0) < 0) { - kleave(" = -EBADMSG [s < 0]"); - return -EBADMSG; - } - if (mpi_cmp(s, key->rsa.n) >= 0) { - kleave(" = -EBADMSG [s >= n]"); - return -EBADMSG; - } - - m = mpi_alloc(0); - if (!m) - return -ENOMEM; - - /* (2) m = s^e mod n */ - ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); - if (ret < 0) { - mpi_free(m); - return ret; - } - - *_m = m; - return 0; -} - -/* - * Integer to Octet String conversion [RFC3447 sec 4.1] - */ -static int RSA_I2OSP(MPI x, size_t xLen, u8 **pX) -{ - unsigned X_size, x_size; - int X_sign; - u8 *X; - - /* Make sure the string is the right length. The number should begin - * with { 0x00, 0x01, ... } so we have to account for 15 leading zero - * bits not being reported by MPI. - */ - x_size = mpi_get_nbits(x); - pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); - if (x_size != xLen * 8 - 15) - return -ERANGE; - - X = mpi_get_buffer(x, &X_size, &X_sign); - if (!X) - return -ENOMEM; - if (X_sign < 0) { - kfree(X); - return -EBADMSG; - } - if (X_size != xLen - 1) { - kfree(X); - return -EBADMSG; - } - - *pX = X; - return 0; -} - -/* - * Perform the RSA signature verification. - * @H: Value of hash of data and metadata - * @EM: The computed signature value - * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) - * @hash_size: The size of H - * @asn1_template: The DigestInfo ASN.1 template - * @asn1_size: Size of asm1_template[] - */ -static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, - const u8 *asn1_template, size_t asn1_size) -{ - unsigned PS_end, T_offset, i; - - kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); - - if (k < 2 + 1 + asn1_size + hash_size) - return -EBADMSG; - - /* Decode the EMSA-PKCS1-v1_5 */ - if (EM[1] != 0x01) { - kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); - return -EBADMSG; - } - - T_offset = k - (asn1_size + hash_size); - PS_end = T_offset - 1; - if (EM[PS_end] != 0x00) { - kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); - return -EBADMSG; - } - - for (i = 2; i < PS_end; i++) { - if (EM[i] != 0xff) { - kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); - return -EBADMSG; - } - } - - if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) { - kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); - return -EBADMSG; - } - - if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) { - kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); - return -EKEYREJECTED; - } - - kleave(" = 0"); - return 0; -} - -/* - * Perform the verification step [RFC3447 sec 8.2.2]. - */ -static int RSA_verify_signature(const struct public_key *key, - const struct public_key_signature *sig) -{ - size_t tsize; - int ret; - - /* Variables as per RFC3447 sec 8.2.2 */ - const u8 *H = sig->digest; - u8 *EM = NULL; - MPI m = NULL; - size_t k; - - kenter(""); - - if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) - return -ENOTSUPP; - - /* (1) Check the signature size against the public key modulus size */ - k = mpi_get_nbits(key->rsa.n); - tsize = mpi_get_nbits(sig->rsa.s); - - /* According to RFC 4880 sec 3.2, length of MPI is computed starting - * from most significant bit. So the RFC 3447 sec 8.2.2 size check - * must be relaxed to conform with shorter signatures - so we fail here - * only if signature length is longer than modulus size. - */ - pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); - if (k < tsize) { - ret = -EBADMSG; - goto error; - } - - /* Round up and convert to octets */ - k = (k + 7) / 8; - - /* (2b) Apply the RSAVP1 verification primitive to the public key */ - ret = RSAVP1(key, sig->rsa.s, &m); - if (ret < 0) - goto error; - - /* (2c) Convert the message representative (m) to an encoded message - * (EM) of length k octets. - * - * NOTE! The leading zero byte is suppressed by MPI, so we pass a - * pointer to the _preceding_ byte to RSA_verify()! - */ - ret = RSA_I2OSP(m, k, &EM); - if (ret < 0) - goto error; - - ret = RSA_verify(H, EM - 1, k, sig->digest_size, - RSA_ASN1_templates[sig->pkey_hash_algo].data, - RSA_ASN1_templates[sig->pkey_hash_algo].size); - -error: - kfree(EM); - mpi_free(m); - kleave(" = %d", ret); - return ret; -} - -const struct public_key_algorithm RSA_public_key_algorithm = { - .name = "RSA", - .n_pub_mpi = 2, - .n_sec_mpi = 3, - .n_sig_mpi = 1, - .verify_signature = RSA_verify_signature, -}; -EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 897b734..7e8c233 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c @@ -328,12 +328,12 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen, void *digest; int ret; - kenter(",%u", ctx->digest_algo); + kenter(",%s", ctx->digest_algo); /* Allocate the hashing algorithm we're going to need and find out how * big the hash operational data will be. */ - tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0); + tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0); if (IS_ERR(tfm)) return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h index 55d5f7e..a133eb8 100644 --- a/crypto/asymmetric_keys/verify_pefile.h +++ b/crypto/asymmetric_keys/verify_pefile.h @@ -28,7 +28,7 @@ struct pefile_context { /* PKCS#7 MS Individual Code Signing content */ const void *digest; /* Digest */ unsigned digest_len; /* Digest length */ - enum hash_algo digest_algo; /* Digest algorithm */ + const char *digest_algo; /* Digest algorithm */ }; #define kenter(FMT, ...) \ diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 021d39c..4a29bac 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -15,11 +15,10 @@ #include <linux/slab.h> #include <linux/err.h> #include <linux/oid_registry.h> -#include "public_key.h" +#include <crypto/public_key.h> #include "x509_parser.h" #include "x509-asn1.h" #include "x509_akid-asn1.h" -#include "x509_rsakey-asn1.h" struct x509_parse_context { struct x509_certificate *cert; /* Certificate being constructed */ @@ -56,7 +55,7 @@ void x509_free_certificate(struct x509_certificate *cert) kfree(cert->akid_id); kfree(cert->akid_skid); kfree(cert->sig.digest); - mpi_free(cert->sig.rsa.s); + kfree(cert->sig.s); kfree(cert); } } @@ -103,12 +102,12 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) } } - /* Decode the public key */ - ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, - ctx->key, ctx->key_size); - if (ret < 0) + cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL); + if (!cert->pub->key) goto error_decode; + cert->pub->keylen = ctx->key_size; + /* Generate cert issuer + serial number key ID */ kid = asymmetric_key_generate_id(cert->raw_serial, cert->raw_serial_size, @@ -124,6 +123,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) return cert; error_decode: + kfree(cert->pub->key); kfree(ctx); error_no_ctx: x509_free_certificate(cert); @@ -188,33 +188,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, return -ENOPKG; /* Unsupported combination */ case OID_md4WithRSAEncryption: - ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5; - ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->cert->sig.hash_algo = "md4"; + ctx->cert->sig.pkey_algo = "rsa"; break; case OID_sha1WithRSAEncryption: - ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1; - ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->cert->sig.hash_algo = "sha1"; + ctx->cert->sig.pkey_algo = "rsa"; break; case OID_sha256WithRSAEncryption: - ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256; - ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->cert->sig.hash_algo = "sha256"; + ctx->cert->sig.pkey_algo = "rsa"; break; case OID_sha384WithRSAEncryption: - ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384; - ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->cert->sig.hash_algo = "sha384"; + ctx->cert->sig.pkey_algo = "rsa"; break; case OID_sha512WithRSAEncryption: - ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512; - ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->cert->sig.hash_algo = "sha512"; + ctx->cert->sig.pkey_algo = "rsa"; break; case OID_sha224WithRSAEncryption: - ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224; - ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA; + ctx->cert->sig.hash_algo = "sha224"; + ctx->cert->sig.pkey_algo = "rsa"; break; } @@ -396,7 +396,7 @@ int x509_extract_key_data(void *context, size_t hdrlen, if (ctx->last_oid != OID_rsaEncryption) return -ENOPKG; - ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA; + ctx->cert->pub->pkey_algo = "rsa"; /* Discard the BIT STRING metadata */ ctx->key = value + 1; @@ -404,29 +404,6 @@ int x509_extract_key_data(void *context, size_t hdrlen, return 0; } -/* - * Extract a RSA public key value - */ -int rsa_extract_mpi(void *context, size_t hdrlen, - unsigned char tag, - const void *value, size_t vlen) -{ - struct x509_parse_context *ctx = context; - MPI mpi; - - if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { - pr_err("Too many public key MPIs in certificate\n"); - return -EBADMSG; - } - - mpi = mpi_read_raw_data(value, vlen); - if (!mpi) - return -ENOMEM; - - ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; - return 0; -} - /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */ #define SEQ_TAG_KEYID (ASN1_CONT << 6) @@ -494,7 +471,7 @@ int x509_decode_time(time64_t *_t, size_t hdrlen, unsigned char tag, const unsigned char *value, size_t vlen) { - static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, + static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; const unsigned char *p = value; unsigned year, mon, day, hour, min, sec, mon_len; @@ -540,17 +517,17 @@ int x509_decode_time(time64_t *_t, size_t hdrlen, if (year % 4 == 0) { mon_len = 29; if (year % 100 == 0) { - year /= 100; - if (year % 4 != 0) - mon_len = 28; + mon_len = 28; + if (year % 400 == 0) + mon_len = 29; } } } if (day < 1 || day > mon_len || - hour > 23 || + hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */ min > 59 || - sec > 59) + sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */ goto invalid_time; *_t = mktime64(year, mon, day, hour, min, sec); diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 9e9e5a6..733c046 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -13,15 +13,11 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/err.h> -#include <linux/mpi.h> -#include <linux/asn1_decoder.h> #include <keys/asymmetric-subtype.h> #include <keys/asymmetric-parser.h> #include <keys/system_keyring.h> #include <crypto/hash.h> #include "asymmetric_keys.h" -#include "public_key.h" #include "x509_parser.h" static bool use_builtin_keys; @@ -167,18 +163,20 @@ int x509_get_sig_params(struct x509_certificate *cert) if (cert->unsupported_crypto) return -ENOPKG; - if (cert->sig.rsa.s) + if (cert->sig.s) return 0; - cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size); - if (!cert->sig.rsa.s) + cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size, + GFP_KERNEL); + if (!cert->sig.s) return -ENOMEM; - cert->sig.nr_mpi = 1; + + cert->sig.s_size = cert->raw_sig_size; /* Allocate the hashing algorithm we're going to need and find out how * big the hash operational data will be. */ - tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0); + tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0); if (IS_ERR(tfm)) { if (PTR_ERR(tfm) == -ENOENT) { cert->unsupported_crypto = true; @@ -293,24 +291,20 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) pr_devel("Cert Issuer: %s\n", cert->issuer); pr_devel("Cert Subject: %s\n", cert->subject); - if (cert->pub->pkey_algo >= PKEY_ALGO__LAST || - cert->sig.pkey_algo >= PKEY_ALGO__LAST || - cert->sig.pkey_hash_algo >= PKEY_HASH__LAST || - !pkey_algo[cert->pub->pkey_algo] || - !pkey_algo[cert->sig.pkey_algo] || - !hash_algo_name[cert->sig.pkey_hash_algo]) { + if (!cert->pub->pkey_algo || + !cert->sig.pkey_algo || + !cert->sig.hash_algo) { ret = -ENOPKG; goto error_free_cert; } - pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); + pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); pr_devel("Cert Signature: %s + %s\n", - pkey_algo_name[cert->sig.pkey_algo], - hash_algo_name[cert->sig.pkey_hash_algo]); + cert->sig.pkey_algo, + cert->sig.hash_algo); - cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; - cert->pub->id_type = PKEY_ID_X509; + cert->pub->id_type = "X509"; /* Check the signature on the key if it appears to be self-signed */ if ((!cert->akid_skid && !cert->akid_id) || diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1 deleted file mode 100644 index 4ec7cc6..0000000 --- a/crypto/asymmetric_keys/x509_rsakey.asn1 +++ /dev/null @@ -1,4 +0,0 @@ -RSAPublicKey ::= SEQUENCE { - modulus INTEGER ({ rsa_extract_mpi }), -- n - publicExponent INTEGER ({ rsa_extract_mpi }) -- e - } diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index 50f5c97..1cea67d 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -18,12 +18,89 @@ #include <linux/module.h> #include <linux/random.h> +/* + * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. + */ +static const u8 rsa_digest_info_md5[] = { + 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */ + 0x05, 0x00, 0x04, 0x10 +}; + +static const u8 rsa_digest_info_sha1[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00, 0x04, 0x14 +}; + +static const u8 rsa_digest_info_rmd160[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x24, 0x03, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x14 +}; + +static const u8 rsa_digest_info_sha224[] = { + 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, + 0x05, 0x00, 0x04, 0x1c +}; + +static const u8 rsa_digest_info_sha256[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x20 +}; + +static const u8 rsa_digest_info_sha384[] = { + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, + 0x05, 0x00, 0x04, 0x30 +}; + +static const u8 rsa_digest_info_sha512[] = { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, + 0x05, 0x00, 0x04, 0x40 +}; + +static const struct rsa_asn1_template { + const char *name; + const u8 *data; + size_t size; +} rsa_asn1_templates[] = { +#define _(X) { #X, rsa_digest_info_##X, sizeof(rsa_digest_info_##X) } + _(md5), + _(sha1), + _(rmd160), + _(sha256), + _(sha384), + _(sha512), + _(sha224), + { NULL } +#undef _ +}; + +static const struct rsa_asn1_template *rsa_lookup_asn1(const char *name) +{ + const struct rsa_asn1_template *p; + + for (p = rsa_asn1_templates; p->name; p++) + if (strcmp(name, p->name) == 0) + return p; + return NULL; +} + struct pkcs1pad_ctx { struct crypto_akcipher *child; - + const char *hash_name; unsigned int key_size; }; +struct pkcs1pad_inst_ctx { + struct crypto_akcipher_spawn spawn; + const char *hash_name; +}; + struct pkcs1pad_request { struct akcipher_request child_req; @@ -339,13 +416,22 @@ static int pkcs1pad_sign(struct akcipher_request *req) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + const struct rsa_asn1_template *digest_info = NULL; int err; - unsigned int ps_end; + unsigned int ps_end, digest_size = 0; if (!ctx->key_size) return -EINVAL; - if (req->src_len > ctx->key_size - 11) + if (ctx->hash_name) { + digest_info = rsa_lookup_asn1(ctx->hash_name); + if (!digest_info) + return -EINVAL; + + digest_size = digest_info->size; + } + + if (req->src_len + digest_size > ctx->key_size - 11) return -EOVERFLOW; if (req->dst_len < ctx->key_size) { @@ -371,11 +457,16 @@ static int pkcs1pad_sign(struct akcipher_request *req) if (!req_ctx->in_buf) return -ENOMEM; - ps_end = ctx->key_size - req->src_len - 2; + ps_end = ctx->key_size - digest_size - req->src_len - 2; req_ctx->in_buf[0] = 0x01; memset(req_ctx->in_buf + 1, 0xff, ps_end - 1); req_ctx->in_buf[ps_end] = 0x00; + if (digest_info) { + memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data, + digest_info->size); + } + pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, ctx->key_size - 1 - req->src_len, req->src); @@ -408,6 +499,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + const struct rsa_asn1_template *digest_info; unsigned int pos; if (err == -EOVERFLOW) @@ -422,20 +514,33 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) goto done; } - if (req_ctx->out_buf[0] != 0x01) { - err = -EINVAL; + err = -EBADMSG; + if (req_ctx->out_buf[0] != 0x01) goto done; - } + for (pos = 1; pos < req_ctx->child_req.dst_len; pos++) if (req_ctx->out_buf[pos] != 0xff) break; + if (pos < 9 || pos == req_ctx->child_req.dst_len || - req_ctx->out_buf[pos] != 0x00) { - err = -EINVAL; + req_ctx->out_buf[pos] != 0x00) goto done; - } pos++; + if (ctx->hash_name) { + digest_info = rsa_lookup_asn1(ctx->hash_name); + if (!digest_info) + goto done; + + if (memcmp(req_ctx->out_buf + pos, digest_info->data, + digest_info->size)) + goto done; + + pos += digest_info->size; + } + + err = 0; + if (req->dst_len < req_ctx->child_req.dst_len - pos) err = -EOVERFLOW; req->dst_len = req_ctx->child_req.dst_len - pos; @@ -444,7 +549,6 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, req->dst_len), req_ctx->out_buf + pos, req->dst_len); - done: kzfree(req_ctx->out_buf); @@ -481,7 +585,7 @@ static int pkcs1pad_verify(struct akcipher_request *req) struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); int err; - if (!ctx->key_size || req->src_len != ctx->key_size) + if (!ctx->key_size || req->src_len < ctx->key_size) return -EINVAL; if (ctx->key_size > PAGE_SIZE) @@ -518,6 +622,7 @@ static int pkcs1pad_verify(struct akcipher_request *req) static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm) { struct akcipher_instance *inst = akcipher_alg_instance(tfm); + struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct crypto_akcipher *child_tfm; @@ -526,7 +631,7 @@ static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm) return PTR_ERR(child_tfm); ctx->child = child_tfm; - + ctx->hash_name = ictx->hash_name; return 0; } @@ -539,10 +644,11 @@ static void pkcs1pad_exit_tfm(struct crypto_akcipher *tfm) static void pkcs1pad_free(struct akcipher_instance *inst) { - struct crypto_akcipher_spawn *spawn = akcipher_instance_ctx(inst); + struct pkcs1pad_inst_ctx *ctx = akcipher_instance_ctx(inst); + struct crypto_akcipher_spawn *spawn = &ctx->spawn; crypto_drop_akcipher(spawn); - + kfree(ctx->hash_name); kfree(inst); } @@ -550,9 +656,11 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) { struct crypto_attr_type *algt; struct akcipher_instance *inst; + struct pkcs1pad_inst_ctx *ctx; struct crypto_akcipher_spawn *spawn; struct akcipher_alg *rsa_alg; const char *rsa_alg_name; + const char *hash_name; int err; algt = crypto_get_attr_type(tb); @@ -566,11 +674,18 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) if (IS_ERR(rsa_alg_name)) return PTR_ERR(rsa_alg_name); - inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + hash_name = crypto_attr_alg_name(tb[2]); + if (IS_ERR(hash_name)) + hash_name = NULL; + + inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); if (!inst) return -ENOMEM; - spawn = akcipher_instance_ctx(inst); + ctx = akcipher_instance_ctx(inst); + spawn = &ctx->spawn; + ctx->hash_name = hash_name ? kstrdup(hash_name, GFP_KERNEL) : NULL; + crypto_set_spawn(&spawn->base, akcipher_crypto_instance(inst)); err = crypto_grab_akcipher(spawn, rsa_alg_name, 0, crypto_requires_sync(algt->type, algt->mask)); @@ -580,15 +695,28 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) rsa_alg = crypto_spawn_akcipher_alg(spawn); err = -ENAMETOOLONG; - if (snprintf(inst->alg.base.cra_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", - rsa_alg->base.cra_name) >= - CRYPTO_MAX_ALG_NAME || - snprintf(inst->alg.base.cra_driver_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", - rsa_alg->base.cra_driver_name) >= - CRYPTO_MAX_ALG_NAME) + + if (!hash_name) { + if (snprintf(inst->alg.base.cra_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_name) >= + CRYPTO_MAX_ALG_NAME || + snprintf(inst->alg.base.cra_driver_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) goto out_drop_alg; + } else { + if (snprintf(inst->alg.base.cra_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)", + rsa_alg->base.cra_name, hash_name) >= + CRYPTO_MAX_ALG_NAME || + snprintf(inst->alg.base.cra_driver_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)", + rsa_alg->base.cra_driver_name, hash_name) >= + CRYPTO_MAX_ALG_NAME) + goto out_free_hash; + } inst->alg.base.cra_flags = rsa_alg->base.cra_flags & CRYPTO_ALG_ASYNC; inst->alg.base.cra_priority = rsa_alg->base.cra_priority; @@ -610,10 +738,12 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) err = akcipher_register_instance(tmpl, inst); if (err) - goto out_drop_alg; + goto out_free_hash; return 0; +out_free_hash: + kfree(ctx->hash_name); out_drop_alg: crypto_drop_akcipher(spawn); out_free_inst: diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index cc2516d..aa730ea 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -14,30 +14,6 @@ #ifndef _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H -#include <linux/mpi.h> -#include <crypto/hash_info.h> - -enum pkey_algo { - PKEY_ALGO_DSA, - PKEY_ALGO_RSA, - PKEY_ALGO__LAST -}; - -extern const char *const pkey_algo_name[PKEY_ALGO__LAST]; -extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST]; - -/* asymmetric key implementation supports only up to SHA224 */ -#define PKEY_HASH__LAST (HASH_ALGO_SHA224 + 1) - -enum pkey_id_type { - PKEY_ID_PGP, /* OpenPGP generated key ID */ - PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ - PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ - PKEY_ID_TYPE__LAST -}; - -extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; - /* * The use to which an asymmetric key is being put. */ @@ -59,31 +35,10 @@ extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; * part. */ struct public_key { - const struct public_key_algorithm *algo; - u8 capabilities; -#define PKEY_CAN_ENCRYPT 0x01 -#define PKEY_CAN_DECRYPT 0x02 -#define PKEY_CAN_SIGN 0x04 -#define PKEY_CAN_VERIFY 0x08 - enum pkey_algo pkey_algo : 8; - enum pkey_id_type id_type : 8; - union { - MPI mpi[5]; - struct { - MPI p; /* DSA prime */ - MPI q; /* DSA group order */ - MPI g; /* DSA group generator */ - MPI y; /* DSA public-key value = g^x mod p */ - MPI x; /* DSA secret exponent (if present) */ - } dsa; - struct { - MPI n; /* RSA public modulus */ - MPI e; /* RSA public encryption exponent */ - MPI d; /* RSA secret encryption exponent (if present) */ - MPI p; /* RSA secret prime (if present) */ - MPI q; /* RSA secret prime (if present) */ - } rsa; - }; + void *key; + u32 keylen; + const char *id_type; + const char *pkey_algo; }; extern void public_key_destroy(void *payload); @@ -92,23 +47,15 @@ extern void public_key_destroy(void *payload); * Public key cryptography signature data */ struct public_key_signature { + u8 *s; /* Signature */ + u32 s_size; /* Number of bytes in signature */ u8 *digest; - u8 digest_size; /* Number of bytes in digest */ - u8 nr_mpi; /* Occupancy of mpi[] */ - enum pkey_algo pkey_algo : 8; - enum hash_algo pkey_hash_algo : 8; - union { - MPI mpi[2]; - struct { - MPI s; /* m^d mod n */ - } rsa; - struct { - MPI r; - MPI s; - } dsa; - }; + u8 digest_size; /* Number of bytes in digest */ + const char *pkey_algo; + const char *hash_algo; }; +extern struct asymmetric_key_subtype public_key_subtype; struct key; extern int verify_signature(const struct key *key, const struct public_key_signature *sig); @@ -119,4 +66,7 @@ extern struct key *x509_request_asymmetric_key(struct key *keyring, const struct asymmetric_key_id *skid, bool partial); +int public_key_verify_signature(const struct public_key *pkey, + const struct public_key_signature *sig); + #endif /* _LINUX_PUBLIC_KEY_H */ diff --git a/include/linux/key.h b/include/linux/key.h index 7321ab8..5f5b112 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -219,6 +219,7 @@ extern struct key *key_alloc(struct key_type *type, #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ #define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */ +#define KEY_ALLOC_BUILT_IN 0x0008 /* Key is built into kernel */ extern void key_revoke(struct key *key); extern void key_invalidate(struct key *key); diff --git a/init/Kconfig b/init/Kconfig index 2232080..af4de4f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1757,9 +1757,9 @@ config SYSTEM_DATA_VERIFICATION select SYSTEM_TRUSTED_KEYRING select KEYS select CRYPTO + select CRYPTO_RSA select ASYMMETRIC_KEY_TYPE select ASYMMETRIC_PUBLIC_KEY_SUBTYPE - select PUBLIC_KEY_ALGO_RSA select ASN1 select OID_REGISTRY select X509_CERTIFICATE_PARSER diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 6528a79..64b9dea 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -11,10 +11,17 @@ #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/string.h> #include <keys/system_keyring.h> #include <crypto/public_key.h> #include "module-internal.h" +enum pkey_id_type { + PKEY_ID_PGP, /* OpenPGP generated key ID */ + PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ + PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ +}; + /* * Module signature information block. * diff --git a/kernel/time/time.c b/kernel/time/time.c index 86751c6..be115b0 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -322,6 +322,13 @@ EXPORT_SYMBOL(timespec_trunc); * -year/100+year/400 terms, and add 10.] * * This algorithm was first published by Gauss (I think). + * + * A leap second can be indicated by calling this function with sec as + * 60 (allowable under ISO 8601). The leap second is treated the same + * as the following second since they don't exist in UNIX time. + * + * An encoding of midnight at the end of the day as 24:00:00 - ie. midnight + * tomorrow - (allowable under ISO 8601) is supported. */ time64_t mktime64(const unsigned int year0, const unsigned int mon0, const unsigned int day, const unsigned int hour, @@ -338,7 +345,7 @@ time64_t mktime64(const unsigned int year0, const unsigned int mon0, return ((((time64_t) (year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499 - )*24 + hour /* now have hours */ + )*24 + hour /* now have hours - midnight tomorrow handled here */ )*60 + min /* now have minutes */ )*60 + sec; /* finally seconds */ } diff --git a/scripts/.gitignore b/scripts/.gitignore index 1f78169..e063daa 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -13,3 +13,4 @@ sortextable asn1_compiler extract-cert sign-file +insert-sys-cert diff --git a/scripts/Makefile b/scripts/Makefile index fd0d53d..822ab4a 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -19,6 +19,7 @@ hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable hostprogs-$(CONFIG_ASN1) += asn1_compiler hostprogs-$(CONFIG_MODULE_SIG) += sign-file hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert +hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl index d476e7d..8227ca1 100755 --- a/scripts/extract-sys-certs.pl +++ b/scripts/extract-sys-certs.pl @@ -91,13 +91,15 @@ print "Have $nr_symbols symbols\n"; die "Can't find system certificate list" unless (exists($symbols{"__cert_list_start"}) && - exists($symbols{"__cert_list_end"})); + exists($symbols{"system_certificate_list_size"})); my $start = Math::BigInt->new($symbols{"__cert_list_start"}); -my $end = Math::BigInt->new($symbols{"__cert_list_end"}); -my $size = $end - $start; +my $end; +my $size; +my $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"}); -printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start; +open FD, "<$vmlinux" || die $vmlinux; +binmode(FD); my $s = undef; foreach my $sec (@sections) { @@ -110,11 +112,24 @@ foreach my $sec (@sections) { next unless ($start >= $s_vma); next if ($start >= $s_vend); - die "Cert object partially overflows section $s_name\n" - if ($end > $s_vend); + die "Certificate list size was not found on the same section\n" + if ($size_sym < $s_vma || $size_sym > $s_vend); die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n" if ($s); + + my $size_off = $size_sym -$s_vma + $s_foff; + my $packed; + die $vmlinux if (!defined(sysseek(FD, $size_off, SEEK_SET))); + sysread(FD, $packed, 8); + $size = unpack 'L!', $packed; + $end = $start + $size; + + printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start; + + die "Cert object partially overflows section $s_name\n" + if ($end > $s_vend); + $s = $sec; } @@ -127,8 +142,6 @@ my $foff = $start - $s->{vma} + $s->{foff}; printf "Certificate list at file offset 0x%x\n", $foff; -open FD, "<$vmlinux" || die $vmlinux; -binmode(FD); die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET))); my $buf = ""; my $len = sysread(FD, $buf, $size); diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c new file mode 100644 index 0000000..8902836 --- /dev/null +++ b/scripts/insert-sys-cert.c @@ -0,0 +1,410 @@ +/* Write the contents of the <certfile> into kernel symbol system_extra_cert + * + * Copyright (C) IBM Corporation, 2015 + * + * Author: Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * Usage: insert-sys-cert [-s <System.map> -b <vmlinux> -c <certfile> + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <elf.h> + +#define CERT_SYM "system_extra_cert" +#define USED_SYM "system_extra_cert_used" +#define LSIZE_SYM "system_certificate_list_size" + +#define info(format, args...) fprintf(stderr, "INFO: " format, ## args) +#define warn(format, args...) fprintf(stdout, "WARNING: " format, ## args) +#define err(format, args...) fprintf(stderr, "ERROR: " format, ## args) + +#if UINTPTR_MAX == 0xffffffff +#define CURRENT_ELFCLASS ELFCLASS32 +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#else +#define CURRENT_ELFCLASS ELFCLASS64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#endif + +static unsigned char endianness(void) +{ + uint16_t two_byte = 0x00FF; + uint8_t low_address = *((uint8_t *)&two_byte); + + if (low_address == 0) + return ELFDATA2MSB; + else + return ELFDATA2LSB; +} + +struct sym { + char *name; + unsigned long address; + unsigned long offset; + void *content; + int size; +}; + +static unsigned long get_offset_from_address(Elf_Ehdr *hdr, unsigned long addr) +{ + Elf_Shdr *x; + unsigned int i, num_sections; + + x = (void *)hdr + hdr->e_shoff; + if (hdr->e_shnum == SHN_UNDEF) + num_sections = x[0].sh_size; + else + num_sections = hdr->e_shnum; + + for (i = 1; i < num_sections; i++) { + unsigned long start = x[i].sh_addr; + unsigned long end = start + x[i].sh_size; + unsigned long offset = x[i].sh_offset; + + if (addr >= start && addr <= end) + return addr - start + offset; + } + return 0; +} + + +#define LINE_SIZE 100 + +static void get_symbol_from_map(Elf_Ehdr *hdr, FILE *f, char *name, + struct sym *s) +{ + char l[LINE_SIZE]; + char *w, *p, *n; + + s->size = 0; + s->address = 0; + s->offset = 0; + if (fseek(f, 0, SEEK_SET) != 0) { + perror("File seek failed"); + exit(EXIT_FAILURE); + } + while (fgets(l, LINE_SIZE, f)) { + p = strchr(l, '\n'); + if (!p) { + err("Missing line ending.\n"); + return; + } + n = strstr(l, name); + if (n) + break; + } + if (!n) { + err("Unable to find symbol: %s\n", name); + return; + } + w = strchr(l, ' '); + if (!w) + return; + + *w = '\0'; + s->address = strtoul(l, NULL, 16); + if (s->address == 0) + return; + s->offset = get_offset_from_address(hdr, s->address); + s->name = name; + s->content = (void *)hdr + s->offset; +} + +static Elf_Sym *find_elf_symbol(Elf_Ehdr *hdr, Elf_Shdr *symtab, char *name) +{ + Elf_Sym *sym, *symtab_start; + char *strtab, *symname; + unsigned int link; + Elf_Shdr *x; + int i, n; + + x = (void *)hdr + hdr->e_shoff; + link = symtab->sh_link; + symtab_start = (void *)hdr + symtab->sh_offset; + n = symtab->sh_size / symtab->sh_entsize; + strtab = (void *)hdr + x[link].sh_offset; + + for (i = 0; i < n; i++) { + sym = &symtab_start[i]; + symname = strtab + sym->st_name; + if (strcmp(symname, name) == 0) + return sym; + } + err("Unable to find symbol: %s\n", name); + return NULL; +} + +static void get_symbol_from_table(Elf_Ehdr *hdr, Elf_Shdr *symtab, + char *name, struct sym *s) +{ + Elf_Shdr *sec; + int secndx; + Elf_Sym *elf_sym; + Elf_Shdr *x; + + x = (void *)hdr + hdr->e_shoff; + s->size = 0; + s->address = 0; + s->offset = 0; + elf_sym = find_elf_symbol(hdr, symtab, name); + if (!elf_sym) + return; + secndx = elf_sym->st_shndx; + if (!secndx) + return; + sec = &x[secndx]; + s->size = elf_sym->st_size; + s->address = elf_sym->st_value; + s->offset = s->address - sec->sh_addr + + sec->sh_offset; + s->name = name; + s->content = (void *)hdr + s->offset; +} + +static Elf_Shdr *get_symbol_table(Elf_Ehdr *hdr) +{ + Elf_Shdr *x; + unsigned int i, num_sections; + + x = (void *)hdr + hdr->e_shoff; + if (hdr->e_shnum == SHN_UNDEF) + num_sections = x[0].sh_size; + else + num_sections = hdr->e_shnum; + + for (i = 1; i < num_sections; i++) + if (x[i].sh_type == SHT_SYMTAB) + return &x[i]; + return NULL; +} + +static void *map_file(char *file_name, int *size) +{ + struct stat st; + void *map; + int fd; + + fd = open(file_name, O_RDWR); + if (fd < 0) { + perror(file_name); + return NULL; + } + if (fstat(fd, &st)) { + perror("Could not determine file size"); + close(fd); + return NULL; + } + *size = st.st_size; + map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + perror("Mapping to memory failed"); + close(fd); + return NULL; + } + close(fd); + return map; +} + +static char *read_file(char *file_name, int *size) +{ + struct stat st; + char *buf; + int fd; + + fd = open(file_name, O_RDONLY); + if (fd < 0) { + perror(file_name); + return NULL; + } + if (fstat(fd, &st)) { + perror("Could not determine file size"); + close(fd); + return NULL; + } + *size = st.st_size; + buf = malloc(*size); + if (!buf) { + perror("Allocating memory failed"); + close(fd); + return NULL; + } + if (read(fd, buf, *size) != *size) { + perror("File read failed"); + close(fd); + return NULL; + } + close(fd); + return buf; +} + +static void print_sym(Elf_Ehdr *hdr, struct sym *s) +{ + info("sym: %s\n", s->name); + info("addr: 0x%lx\n", s->address); + info("size: %d\n", s->size); + info("offset: 0x%lx\n", (unsigned long)s->offset); +} + +static void print_usage(char *e) +{ + printf("Usage %s [-s <System.map>] -b <vmlinux> -c <certfile>\n", e); +} + +int main(int argc, char **argv) +{ + char *system_map_file = NULL; + char *vmlinux_file = NULL; + char *cert_file = NULL; + int vmlinux_size; + int cert_size; + Elf_Ehdr *hdr; + char *cert; + FILE *system_map; + unsigned long *lsize; + int *used; + int opt; + Elf_Shdr *symtab = NULL; + struct sym cert_sym, lsize_sym, used_sym; + + while ((opt = getopt(argc, argv, "b:c:s:")) != -1) { + switch (opt) { + case 's': + system_map_file = optarg; + break; + case 'b': + vmlinux_file = optarg; + break; + case 'c': + cert_file = optarg; + break; + default: + break; + } + } + + if (!vmlinux_file || !cert_file) { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + cert = read_file(cert_file, &cert_size); + if (!cert) + exit(EXIT_FAILURE); + + hdr = map_file(vmlinux_file, &vmlinux_size); + if (!hdr) + exit(EXIT_FAILURE); + + if (vmlinux_size < sizeof(*hdr)) { + err("Invalid ELF file.\n"); + exit(EXIT_FAILURE); + } + + if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || + (hdr->e_ident[EI_MAG1] != ELFMAG1) || + (hdr->e_ident[EI_MAG2] != ELFMAG2) || + (hdr->e_ident[EI_MAG3] != ELFMAG3)) { + err("Invalid ELF magic.\n"); + exit(EXIT_FAILURE); + } + + if (hdr->e_ident[EI_CLASS] != CURRENT_ELFCLASS) { + err("ELF class mismatch.\n"); + exit(EXIT_FAILURE); + } + + if (hdr->e_ident[EI_DATA] != endianness()) { + err("ELF endian mismatch.\n"); + exit(EXIT_FAILURE); + } + + if (hdr->e_shoff > vmlinux_size) { + err("Could not find section header.\n"); + exit(EXIT_FAILURE); + } + + symtab = get_symbol_table(hdr); + if (!symtab) { + warn("Could not find the symbol table.\n"); + if (!system_map_file) { + err("Please provide a System.map file.\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + system_map = fopen(system_map_file, "r"); + if (!system_map) { + perror(system_map_file); + exit(EXIT_FAILURE); + } + get_symbol_from_map(hdr, system_map, CERT_SYM, &cert_sym); + get_symbol_from_map(hdr, system_map, USED_SYM, &used_sym); + get_symbol_from_map(hdr, system_map, LSIZE_SYM, &lsize_sym); + cert_sym.size = used_sym.address - cert_sym.address; + } else { + info("Symbol table found.\n"); + if (system_map_file) + warn("System.map is ignored.\n"); + get_symbol_from_table(hdr, symtab, CERT_SYM, &cert_sym); + get_symbol_from_table(hdr, symtab, USED_SYM, &used_sym); + get_symbol_from_table(hdr, symtab, LSIZE_SYM, &lsize_sym); + } + + if (!cert_sym.offset || !lsize_sym.offset || !used_sym.offset) + exit(EXIT_FAILURE); + + print_sym(hdr, &cert_sym); + print_sym(hdr, &used_sym); + print_sym(hdr, &lsize_sym); + + lsize = (unsigned long *)lsize_sym.content; + used = (int *)used_sym.content; + + if (cert_sym.size < cert_size) { + err("Certificate is larger than the reserved area!\n"); + exit(EXIT_FAILURE); + } + + /* If the existing cert is the same, don't overwrite */ + if (cert_size == *used && + strncmp(cert_sym.content, cert, cert_size) == 0) { + warn("Certificate was already inserted.\n"); + exit(EXIT_SUCCESS); + } + + if (*used > 0) + warn("Replacing previously inserted certificate.\n"); + + memcpy(cert_sym.content, cert, cert_size); + if (cert_size < cert_sym.size) + memset(cert_sym.content + cert_size, + 0, cert_sym.size - cert_size); + + *lsize = *lsize + cert_size - *used; + *used = cert_size; + info("Inserted the contents of %s into %lx.\n", cert_file, + cert_sym.address); + info("Used %d bytes out of %d bytes reserved.\n", *used, + cert_sym.size); + exit(EXIT_SUCCESS); +} diff --git a/scripts/sign-file.c b/scripts/sign-file.c index 250a7a6..d912d5a 100755 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -2,9 +2,11 @@ * * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved. * Copyright © 2015 Intel Corporation. + * Copyright © 2016 Hewlett Packard Enterprise Development LP * * Authors: David Howells <dhowells@redhat.com> * David Woodhouse <dwmw2@infradead.org> + * Juerg Haefliger <juerg.haefliger@hpe.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -39,7 +41,7 @@ * signing with anything other than SHA1 - so we're stuck with that if such is * the case. */ -#if OPENSSL_VERSION_NUMBER < 0x10000000L +#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS) #define USE_PKCS7 #endif #ifndef USE_PKCS7 @@ -67,6 +69,8 @@ void format(void) { fprintf(stderr, "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n"); + fprintf(stderr, + " scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n"); exit(2); } @@ -126,26 +130,84 @@ static int pem_pw_cb(char *buf, int len, int w, void *v) return pwlen; } +static EVP_PKEY *read_private_key(const char *private_key_name) +{ + EVP_PKEY *private_key; + + if (!strncmp(private_key_name, "pkcs11:", 7)) { + ENGINE *e; + + ENGINE_load_builtin_engines(); + drain_openssl_errors(); + e = ENGINE_by_id("pkcs11"); + ERR(!e, "Load PKCS#11 ENGINE"); + if (ENGINE_init(e)) + drain_openssl_errors(); + else + ERR(1, "ENGINE_init"); + if (key_pass) + ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), + "Set PKCS#11 PIN"); + private_key = ENGINE_load_private_key(e, private_key_name, + NULL, NULL); + ERR(!private_key, "%s", private_key_name); + } else { + BIO *b; + + b = BIO_new_file(private_key_name, "rb"); + ERR(!b, "%s", private_key_name); + private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, + NULL); + ERR(!private_key, "%s", private_key_name); + BIO_free(b); + } + + return private_key; +} + +static X509 *read_x509(const char *x509_name) +{ + X509 *x509; + BIO *b; + + b = BIO_new_file(x509_name, "rb"); + ERR(!b, "%s", x509_name); + x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ + if (!x509) { + ERR(BIO_reset(b) != 1, "%s", x509_name); + x509 = PEM_read_bio_X509(b, NULL, NULL, + NULL); /* PEM encoded X.509 */ + if (x509) + drain_openssl_errors(); + } + BIO_free(b); + ERR(!x509, "%s", x509_name); + + return x509; +} + int main(int argc, char **argv) { struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; char *hash_algo = NULL; - char *private_key_name, *x509_name, *module_name, *dest_name; + char *private_key_name = NULL, *raw_sig_name = NULL; + char *x509_name, *module_name, *dest_name; bool save_sig = false, replace_orig; bool sign_only = false; + bool raw_sig = false; unsigned char buf[4096]; unsigned long module_size, sig_size; unsigned int use_signed_attrs; const EVP_MD *digest_algo; EVP_PKEY *private_key; #ifndef USE_PKCS7 - CMS_ContentInfo *cms; + CMS_ContentInfo *cms = NULL; unsigned int use_keyid = 0; #else - PKCS7 *pkcs7; + PKCS7 *pkcs7 = NULL; #endif X509 *x509; - BIO *b, *bd = NULL, *bm; + BIO *bd, *bm; int opt, n; OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); @@ -160,8 +222,9 @@ int main(int argc, char **argv) #endif do { - opt = getopt(argc, argv, "dpk"); + opt = getopt(argc, argv, "sdpk"); switch (opt) { + case 's': raw_sig = true; break; case 'p': save_sig = true; break; case 'd': sign_only = true; save_sig = true; break; #ifndef USE_PKCS7 @@ -177,8 +240,13 @@ int main(int argc, char **argv) if (argc < 4 || argc > 5) format(); - hash_algo = argv[0]; - private_key_name = argv[1]; + if (raw_sig) { + raw_sig_name = argv[0]; + hash_algo = argv[1]; + } else { + hash_algo = argv[0]; + private_key_name = argv[1]; + } x509_name = argv[2]; module_name = argv[3]; if (argc == 5) { @@ -198,101 +266,74 @@ int main(int argc, char **argv) } #endif - /* Read the private key and the X.509 cert the PKCS#7 message - * will point to. - */ - if (!strncmp(private_key_name, "pkcs11:", 7)) { - ENGINE *e; - - ENGINE_load_builtin_engines(); - drain_openssl_errors(); - e = ENGINE_by_id("pkcs11"); - ERR(!e, "Load PKCS#11 ENGINE"); - if (ENGINE_init(e)) - drain_openssl_errors(); - else - ERR(1, "ENGINE_init"); - if (key_pass) - ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); - private_key = ENGINE_load_private_key(e, private_key_name, NULL, - NULL); - ERR(!private_key, "%s", private_key_name); - } else { - b = BIO_new_file(private_key_name, "rb"); - ERR(!b, "%s", private_key_name); - private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL); - ERR(!private_key, "%s", private_key_name); - BIO_free(b); - } - - b = BIO_new_file(x509_name, "rb"); - ERR(!b, "%s", x509_name); - x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ - if (!x509) { - ERR(BIO_reset(b) != 1, "%s", x509_name); - x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */ - if (x509) - drain_openssl_errors(); - } - BIO_free(b); - ERR(!x509, "%s", x509_name); - - /* Open the destination file now so that we can shovel the module data - * across as we read it. - */ - if (!sign_only) { - bd = BIO_new_file(dest_name, "wb"); - ERR(!bd, "%s", dest_name); - } - - /* Digest the module data. */ - OpenSSL_add_all_digests(); - display_openssl_errors(__LINE__); - digest_algo = EVP_get_digestbyname(hash_algo); - ERR(!digest_algo, "EVP_get_digestbyname"); - + /* Open the module file */ bm = BIO_new_file(module_name, "rb"); ERR(!bm, "%s", module_name); + if (!raw_sig) { + /* Read the private key and the X.509 cert the PKCS#7 message + * will point to. + */ + private_key = read_private_key(private_key_name); + x509 = read_x509(x509_name); + + /* Digest the module data. */ + OpenSSL_add_all_digests(); + display_openssl_errors(__LINE__); + digest_algo = EVP_get_digestbyname(hash_algo); + ERR(!digest_algo, "EVP_get_digestbyname"); + #ifndef USE_PKCS7 - /* Load the signature message from the digest buffer. */ - cms = CMS_sign(NULL, NULL, NULL, NULL, - CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM); - ERR(!cms, "CMS_sign"); - - ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, - CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | - use_keyid | use_signed_attrs), - "CMS_add1_signer"); - ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, - "CMS_final"); + /* Load the signature message from the digest buffer. */ + cms = CMS_sign(NULL, NULL, NULL, NULL, + CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | + CMS_DETACHED | CMS_STREAM); + ERR(!cms, "CMS_sign"); + + ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, + CMS_NOCERTS | CMS_BINARY | + CMS_NOSMIMECAP | use_keyid | + use_signed_attrs), + "CMS_add1_signer"); + ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, + "CMS_final"); #else - pkcs7 = PKCS7_sign(x509, private_key, NULL, bm, - PKCS7_NOCERTS | PKCS7_BINARY | - PKCS7_DETACHED | use_signed_attrs); - ERR(!pkcs7, "PKCS7_sign"); + pkcs7 = PKCS7_sign(x509, private_key, NULL, bm, + PKCS7_NOCERTS | PKCS7_BINARY | + PKCS7_DETACHED | use_signed_attrs); + ERR(!pkcs7, "PKCS7_sign"); #endif - if (save_sig) { - char *sig_file_name; + if (save_sig) { + char *sig_file_name; + BIO *b; - ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0, - "asprintf"); - b = BIO_new_file(sig_file_name, "wb"); - ERR(!b, "%s", sig_file_name); + ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0, + "asprintf"); + b = BIO_new_file(sig_file_name, "wb"); + ERR(!b, "%s", sig_file_name); #ifndef USE_PKCS7 - ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, - "%s", sig_file_name); + ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, + "%s", sig_file_name); #else - ERR(i2d_PKCS7_bio(b, pkcs7) < 0, - "%s", sig_file_name); + ERR(i2d_PKCS7_bio(b, pkcs7) < 0, + "%s", sig_file_name); #endif - BIO_free(b); + BIO_free(b); + } + + if (sign_only) { + BIO_free(bm); + return 0; + } } - if (sign_only) - return 0; + /* Open the destination file now so that we can shovel the module data + * across as we read it. + */ + bd = BIO_new_file(dest_name, "wb"); + ERR(!bd, "%s", dest_name); /* Append the marker and the PKCS#7 message to the destination file */ ERR(BIO_reset(bm) < 0, "%s", module_name); @@ -300,14 +341,29 @@ int main(int argc, char **argv) n > 0) { ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); } + BIO_free(bm); ERR(n < 0, "%s", module_name); module_size = BIO_number_written(bd); + if (!raw_sig) { #ifndef USE_PKCS7 - ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); + ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); #else - ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); + ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name); #endif + } else { + BIO *b; + + /* Read the raw signature file and write the data to the + * destination file + */ + b = BIO_new_file(raw_sig_name, "rb"); + ERR(!b, "%s", raw_sig_name); + while ((n = BIO_read(b, buf, sizeof(buf))), n > 0) + ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); + BIO_free(b); + } + sig_size = BIO_number_written(bd) - module_size; sig_info.sig_len = htonl(sig_size); ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 21d7568..979be65 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -36,6 +36,7 @@ config INTEGRITY_ASYMMETRIC_KEYS select ASYMMETRIC_KEY_TYPE select ASYMMETRIC_PUBLIC_KEY_SUBTYPE select PUBLIC_KEY_ALGO_RSA + select CRYPTO_RSA select X509_CERTIFICATE_PARSER help This option enables digital signature verification using @@ -45,7 +46,6 @@ config INTEGRITY_TRUSTED_KEYRING bool "Require all keys on the integrity keyrings be signed" depends on SYSTEM_TRUSTED_KEYRING depends on INTEGRITY_ASYMMETRIC_KEYS - select KEYS_DEBUG_PROC_KEYS default y help This option requires that all keys added to the .ima and diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 5ade2a7..80052ed 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -16,6 +16,7 @@ #include <linux/ratelimit.h> #include <linux/key-type.h> #include <crypto/public_key.h> +#include <crypto/hash_info.h> #include <keys/asymmetric-type.h> #include <keys/system_keyring.h> @@ -94,7 +95,7 @@ int asymmetric_verify(struct key *keyring, const char *sig, if (siglen != __be16_to_cpu(hdr->sig_size)) return -EBADMSG; - if (hdr->hash_algo >= PKEY_HASH__LAST) + if (hdr->hash_algo >= HASH_ALGO__LAST) return -ENOPKG; key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid)); @@ -103,16 +104,13 @@ int asymmetric_verify(struct key *keyring, const char *sig, memset(&pks, 0, sizeof(pks)); - pks.pkey_hash_algo = hdr->hash_algo; + pks.pkey_algo = "rsa"; + pks.hash_algo = hash_algo_name[hdr->hash_algo]; pks.digest = (u8 *)data; pks.digest_size = datalen; - pks.nr_mpi = 1; - pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen); - - if (pks.rsa.s) - ret = verify_signature(key, &pks); - - mpi_free(pks.rsa.s); + pks.s = hdr->sig; + pks.s_size = siglen; + ret = verify_signature(key, &pks); key_put(key); pr_debug("%s() = %d\n", __func__, ret); return ret; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index c7a111c..e08935c 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -90,7 +90,7 @@ struct ima_digest_data { struct signature_v2_hdr { uint8_t type; /* xattr type */ uint8_t version; /* signature format version */ - uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ + uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */ uint32_t keyid; /* IMA key identifier - not X509/PGP specific */ uint16_t sig_size; /* signature size */ uint8_t sig[0]; /* signature payload */ diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 907c152..c721e39 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -9,7 +9,6 @@ * 2 of the Licence, or (at your option) any later version. */ -#include <linux/module.h> #include <linux/init.h> #include <linux/seq_file.h> #include <linux/file.h> @@ -18,8 +17,6 @@ #include <keys/user-type.h> #include <keys/big_key-type.h> -MODULE_LICENSE("GPL"); - /* * Layout of key payload words. */ @@ -212,18 +209,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) return ret; } -/* - * Module stuff - */ static int __init big_key_init(void) { return register_key_type(&key_type_big_key); } - -static void __exit big_key_cleanup(void) -{ - unregister_key_type(&key_type_big_key); -} - -module_init(big_key_init); -module_exit(big_key_cleanup); +device_initcall(big_key_init); diff --git a/security/keys/key.c b/security/keys/key.c index 09ef276..b287551 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -296,6 +296,8 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->flags |= 1 << KEY_FLAG_IN_QUOTA; if (flags & KEY_ALLOC_TRUSTED) key->flags |= 1 << KEY_FLAG_TRUSTED; + if (flags & KEY_ALLOC_BUILT_IN) + key->flags |= 1 << KEY_FLAG_BUILTIN; #ifdef KEY_DEBUGGING key->magic = KEY_DEBUG_MAGIC; |