From 411a6f585c0f7695942497ae1a0f3f313cefc6e0 Mon Sep 17 00:00:00 2001 From: Codarren Velvindron Date: Tue, 9 Feb 2016 16:40:45 +0000 Subject: v2 linux-next scripts/sign-file.c Fix LibreSSL support In file included from scripts/sign-file.c:47:0: /usr/include/openssl/cms.h:62:2: error: #error CMS is disabled. #error CMS is disabled. ^ scripts/Makefile.host:91: recipe for target 'scripts/sign-file' failed make[1]: *** [scripts/sign-file] Error 1 Makefile:567: recipe for target 'scripts' failed make: *** [scripts] Error 2 Fix SSL headers so that the kernel can build with LibreSSL Signed-off-by: Codarren Velvindron Acked-by: David Woodhouse Signed-off-by: David Howells diff --git a/scripts/sign-file.c b/scripts/sign-file.c index 250a7a6..a0b806d 100755 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -39,7 +39,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 || LIBRESSL_VERSION_NUMBER) #define USE_PKCS7 #endif #ifndef USE_PKCS7 -- cgit v0.10.2 From 5d2787cf0b210d2925e8d44e2e79241385249d6b Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Feb 2016 16:40:46 +0000 Subject: KEYS: Add an alloc flag to convey the builtinness of a key Add KEY_ALLOC_BUILT_IN to convey that a key should have KEY_FLAG_BUILTIN set rather than setting it after the fact. Signed-off-by: David Howells Acked-by: Mimi Zohar 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/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/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; -- cgit v0.10.2 From 50d35015ff0c00a464e35b109231145d2beec1bd Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 3 Feb 2016 15:04:40 +0000 Subject: KEYS: CONFIG_KEYS_DEBUG_PROC_KEYS is no longer an option CONFIG_KEYS_DEBUG_PROC_KEYS is no longer an option as /proc/keys is now mandatory if the keyrings facility is enabled (it's used by libkeyutils in userspace). The defconfig references were removed with: perl -p -i -e 's/CONFIG_KEYS_DEBUG_PROC_KEYS=y\n//' \ `git grep -l CONFIG_KEYS_DEBUG_PROC_KEYS=y` and the integrity Kconfig fixed by hand. Signed-off-by: David Howells cc: Andreas Ziegler cc: Dmitry Kasatkin 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/security/integrity/Kconfig b/security/integrity/Kconfig index 21d7568..7543398 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -45,7 +45,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 -- cgit v0.10.2 From db6c43bd2132dc2dd63d73a6d1ed601cffd0ae06 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 2 Feb 2016 10:08:53 -0800 Subject: crypto: KEYS: convert public key and digsig asym to the akcipher api This patch converts the module verification code to the new akcipher API. Signed-off-by: Tadeusz Struk Acked-by: Herbert Xu Signed-off-by: David Howells diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 4870f28..905d745 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -22,7 +22,7 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE config PUBLIC_KEY_ALGO_RSA tristate "RSA public-key algorithm" - select MPILIB + select CRYPTO_RSA help This option enables support for the RSA algorithm (PKCS#1, RFC3447). diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index cd1406f..b78a194 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -16,21 +16,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/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 8f3056c..3ef62da 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -15,7 +15,7 @@ #include #include #include -#include "public_key.h" +#include #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); @@ -614,16 +614,14 @@ 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 #include #include -#include "public_key.h" +#include #include "pkcs7_parser.h" /** diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 325575c..f5db137 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -16,7 +16,7 @@ #include #include #include -#include "public_key.h" +#include #include "pkcs7_parser.h" /* diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 6db4c01..b383629 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -18,24 +18,16 @@ #include #include #include -#include "public_key.h" +#include MODULE_LICENSE("GPL"); const char *const pkey_algo_name[PKEY_ALGO__LAST] = { - [PKEY_ALGO_DSA] = "DSA", - [PKEY_ALGO_RSA] = "RSA", + [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", @@ -43,6 +35,12 @@ const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { }; EXPORT_SYMBOL_GPL(pkey_id_type_name); +static int (*alg_verify[PKEY_ALGO__LAST])(const struct public_key *pkey, + const struct public_key_signature *sig) = { + NULL, + rsa_verify_signature +}; + /* * Provide a part of a description of the key for /proc/keys. */ @@ -53,7 +51,8 @@ static void public_key_describe(const struct key *asymmetric_key, if (key) seq_printf(m, "%s.%s", - pkey_id_type_name[key->id_type], key->algo->name); + pkey_id_type_name[key->id_type], + pkey_algo_name[key->pkey_algo]); } /* @@ -62,50 +61,31 @@ 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); /* * 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]); + 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); - if (!algo->verify_signature) - return -ENOTSUPP; + if (pkey->pkey_algo >= PKEY_ALGO__LAST) + return -ENOPKG; - 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; - } + if (!alg_verify[pkey->pkey_algo]) + return -ENOPKG; - return algo->verify_signature(pk, sig); + return alg_verify[pkey->pkey_algo](pkey, sig); } 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 - -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 index 508b57b..51502bc 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -11,10 +11,10 @@ #define pr_fmt(fmt) "RSA: "fmt #include -#include #include +#include +#include #include -#include "public_key.h" MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RSA Public Key Algorithm"); @@ -84,72 +84,10 @@ static const struct { #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; -} +struct rsa_completion { + struct completion completion; + int err; +}; /* * Perform the RSA signature verification. @@ -160,7 +98,7 @@ static int RSA_I2OSP(MPI x, size_t xLen, u8 **pX) * @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, +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; @@ -170,9 +108,11 @@ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_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]); + /* Decode the EMSA-PKCS1-v1_5 + * note: leading zeros are stripped by the RSA implementation + */ + if (EM[0] != 0x01) { + kleave(" = -EBADMSG [EM[0] == %02u]", EM[0]); return -EBADMSG; } @@ -183,7 +123,7 @@ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, return -EBADMSG; } - for (i = 2; i < PS_end; i++) { + for (i = 1; i < PS_end; i++) { if (EM[i] != 0xff) { kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); return -EBADMSG; @@ -204,75 +144,81 @@ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, 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) +static void public_key_verify_done(struct crypto_async_request *req, int err) { - size_t tsize; - int ret; + struct rsa_completion *compl = req->data; - /* Variables as per RFC3447 sec 8.2.2 */ - const u8 *H = sig->digest; - u8 *EM = NULL; - MPI m = NULL; - size_t k; + if (err == -EINPROGRESS) + return; - 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); + compl->err = err; + complete(&compl->completion); +} - /* 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; +int rsa_verify_signature(const struct public_key *pkey, + const struct public_key_signature *sig) +{ + struct crypto_akcipher *tfm; + struct akcipher_request *req; + struct rsa_completion compl; + struct scatterlist sig_sg, sg_out; + void *outbuf = NULL; + unsigned int outlen = 0; + int ret = -ENOMEM; + + tfm = crypto_alloc_akcipher("rsa", 0, 0); + if (IS_ERR(tfm)) + goto error_out; + + 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; + + ret = -EINVAL; + outlen = crypto_akcipher_maxsize(tfm); + if (!outlen) + goto error_free_req; + + /* Initialize the output buffer */ + ret = -ENOMEM; + outbuf = kmalloc(outlen, GFP_KERNEL); + if (!outbuf) + goto error_free_req; + + sg_init_one(&sig_sg, sig->s, sig->s_size); + sg_init_one(&sg_out, outbuf, outlen); + akcipher_request_set_crypt(req, &sig_sg, &sg_out, 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); + + ret = crypto_akcipher_verify(req); + if (ret == -EINPROGRESS) { + wait_for_completion(&compl.completion); + ret = compl.err; } - /* Round up and convert to octets */ - k = (k + 7) / 8; + if (ret) + goto error_free_req; - /* (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()! + /* Output from the operation is an encoded message (EM) of + * length k octets. */ - ret = RSA_I2OSP(m, k, &EM); - if (ret < 0) - goto error; - - ret = RSA_verify(H, EM - 1, k, sig->digest_size, + outlen = req->dst_len; + ret = rsa_verify(sig->digest, outbuf, outlen, 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); +error_free_req: + akcipher_request_free(req); +error_free_tfm: + crypto_free_akcipher(tfm); +error_out: + kfree(outbuf); 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); +EXPORT_SYMBOL_GPL(rsa_verify_signature); diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 021d39c..7502029 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -15,11 +15,10 @@ #include #include #include -#include "public_key.h" +#include #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); @@ -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) diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 9e9e5a6..7092d5c 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -13,15 +13,11 @@ #include #include #include -#include -#include -#include #include #include #include #include #include "asymmetric_keys.h" -#include "public_key.h" #include "x509_parser.h" static bool use_builtin_keys; @@ -167,13 +163,15 @@ 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. @@ -296,8 +294,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) 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]) { ret = -ENOPKG; goto error_free_cert; @@ -309,7 +305,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) pkey_algo_name[cert->sig.pkey_algo], hash_algo_name[cert->sig.pkey_hash_algo]); - cert->pub->algo = pkey_algo[cert->pub->pkey_algo]; cert->pub->id_type = PKEY_ID_X509; /* Check the signature on the key if it appears to be self-signed */ 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/include/crypto/public_key.h b/include/crypto/public_key.h index cc2516d..50ac875 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -24,7 +24,6 @@ enum pkey_algo { }; 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) @@ -59,31 +58,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 + void *key; + u32 keylen; 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; - }; }; extern void public_key_destroy(void *payload); @@ -92,6 +70,8 @@ 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[] */ @@ -109,6 +89,7 @@ struct public_key_signature { }; }; +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 +100,9 @@ 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); + +int rsa_verify_signature(const struct public_key *pkey, + const struct public_key_signature *sig); #endif /* _LINUX_PUBLIC_KEY_H */ -- cgit v0.10.2 From eb5798f2e28f3b43091cecc71c84c3f6fb35c7de Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 2 Feb 2016 10:08:58 -0800 Subject: integrity: convert digsig to akcipher api Convert asymmetric_verify to akcipher api. Signed-off-by: Tadeusz Struk Acked-by: Herbert Xu Signed-off-by: David Howells diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 7543398..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 diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 5ade2a7..2fa3bc6 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -106,13 +106,9 @@ int asymmetric_verify(struct key *keyring, const char *sig, pks.pkey_hash_algo = 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; -- cgit v0.10.2 From d846e78e491ff4dd0747026c02414844d504fcb6 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 2 Feb 2016 10:09:03 -0800 Subject: crypto: public_key: remove MPIs from public_key_signature struct After digsig_asymmetric.c is converted the MPIs can be now safely removed from the public_key_signature structure. Signed-off-by: Tadeusz Struk Acked-by: Herbert Xu Signed-off-by: David Howells diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 50ac875..a1693ed 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -14,7 +14,6 @@ #ifndef _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H -#include #include enum pkey_algo { @@ -73,20 +72,9 @@ 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[] */ + u8 digest_size; /* Number of bytes in digest */ 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; - }; }; extern struct asymmetric_key_subtype public_key_subtype; -- cgit v0.10.2 From a1f2bdf338f15dbad10ee6362891ebf79244858b Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 9 Dec 2015 17:37:15 -0500 Subject: security/keys: make big_key.c explicitly non-modular The Kconfig currently controlling compilation of this code is: config BIG_KEYS bool "Large payload keys" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag since all that information is already contained at the top of the file in the comments. Cc: James Morris Cc: "Serge E. Hallyn" Cc: keyrings@vger.kernel.org Cc: linux-security-module@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: David Howells 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 #include #include #include @@ -18,8 +17,6 @@ #include #include -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); -- cgit v0.10.2 From e5a2e3c8478215aea5b4c58e6154f1b6b170b0ca Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Thu, 4 Feb 2016 12:09:25 +0100 Subject: scripts/sign-file.c: Add support for signing with a raw signature This patch adds support for signing a kernel module with a raw detached PKCS#7 signature/message. The signature is not converted and is simply appended to the module so it needs to be in the right format. Using openssl, a valid signature can be generated like this: $ openssl smime -sign -nocerts -noattr -binary -in -inkey \ -signer -outform der -out The resulting raw signature from the above command is (more or less) identical to the raw signature that sign-file itself can produce like this: $ scripts/sign-file -d Signed-off-by: Juerg Haefliger Signed-off-by: David Howells diff --git a/scripts/sign-file.c b/scripts/sign-file.c index a0b806d..80b7f7f 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 * David Woodhouse + * Juerg Haefliger * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -67,6 +69,8 @@ void format(void) { fprintf(stderr, "Usage: scripts/sign-file [-dp] []\n"); + fprintf(stderr, + " scripts/sign-file -s []\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); -- cgit v0.10.2 From 5d06ee20b662a78417245714fc576cba90e6374f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 25 Feb 2016 17:31:32 +0100 Subject: modsign: hide openssl output in silent builds When a user calls 'make -s', we can assume they don't want to see any output except for warnings and errors, but instead they see this for a warning free build: ### ### Now generating an X.509 key pair to be used for signing modules. ### ### If this takes a long time, you might wish to run rngd in the ### background to keep the supply of entropy topped up. It ### needs to be run as root, and uses a hardware random ### number generator if one is available. ### Generating a 4096 bit RSA private key .................................................................................................................................................................................................................................++ ..............................................................................................................................++ writing new private key to 'certs/signing_key.pem' ----- ### ### Key pair generated. ### The output can confuse simple build testing scripts that just check for an empty build log. This patch silences all the output: - "echo" is changed to "@$(kecho)", which is dropped when "-s" gets passed - the openssl command itself is only printed with V=1, using the $(Q) macro - The output of openssl gets redirected to /dev/null on "-s" builds. Signed-off-by: Arnd Bergmann Signed-off-by: David Howells 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" -- cgit v0.10.2 From c4c36105958576fee87d2c75f4b69b6e5bbde772 Mon Sep 17 00:00:00 2001 From: Mehmet Kayaalp Date: Tue, 24 Nov 2015 16:18:05 -0500 Subject: KEYS: Reserve an extra certificate symbol for inserting without recompiling Place a system_extra_cert buffer of configurable size, right after the system_certificate_list, so that inserted keys can be readily processed by the existing mechanism. Added script takes a key file and a kernel image and inserts its contents to the reserved area. The system_certificate_list_size is also adjusted accordingly. Call the script as: scripts/insert-sys-cert -b -c If vmlinux has no symbol table, supply System.map file with -s flag. Subsequent runs replace the previously inserted key, instead of appending the new one. Signed-off-by: Mehmet Kayaalp Signed-off-by: David Howells Acked-by: Mimi Zohar 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/system_certificates.S b/certs/system_certificates.S index 9216e8c..f82e1b2 100644 --- a/certs/system_certificates.S +++ b/certs/system_certificates.S @@ -13,6 +13,18 @@ __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 + + .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/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/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 into kernel symbol system_extra_cert + * + * Copyright (C) IBM Corporation, 2015 + * + * Author: Mehmet Kayaalp + * + * 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 -b -c + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ] -b -c \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); +} -- cgit v0.10.2 From 8e1678988897ebcc29b318ed78af4808202772df Mon Sep 17 00:00:00 2001 From: Mehmet Kayaalp Date: Tue, 24 Nov 2015 16:19:03 -0500 Subject: KEYS: Use the symbol value for list size, updated by scripts/insert-sys-cert When a certificate is inserted to the image using scripts/writekey, the value of __cert_list_end does not change. The updated size can be found out by reading the value pointed by the system_certificate_list_size symbol. Signed-off-by: Mehmet Kayaalp Signed-off-by: David Howells 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); -- cgit v0.10.2 From 06aae592425701851e02bb850cb9f4997f0ae163 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 27 Feb 2016 12:45:26 +0000 Subject: PKCS#7: fix unitialized boolean 'want' The boolean want is not initialized and hence garbage. The default should be false (later it is only set to true on tne sinfo->authattrs check). Found with static analysis using CoverityScan Signed-off-by: Colin Ian King Signed-off-by: David Howells diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 3ef62da..cbbd03f 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -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) { -- cgit v0.10.2 From ac4cbedfdf55455b4c447f17f0fa027dbf02b2a6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Feb 2016 14:37:15 +0000 Subject: X.509: Fix leap year handling again There are still a couple of minor issues in the X.509 leap year handling: (1) To avoid doing a modulus-by-400 in addition to a modulus-by-100 when determining whether the year is a leap year or not, I divided the year by 100 after doing the modulus-by-100, thereby letting the compiler do one instruction for both, and then did a modulus-by-4. Unfortunately, I then passed the now-modified year value to mktime64() to construct a time value. Since this isn't a fast path and since mktime64() does a bunch of divisions, just condense down to "% 400". It's also easier to read. (2) The default month length for any February where the year doesn't divide by four exactly is obtained from the month_length[] array where the value is 29, not 28. This is fixed by altering the table. Reported-by: Rudolf Polzer Signed-off-by: David Howells Acked-by: David Woodhouse Acked-by: Arnd Bergmann cc: stable@vger.kernel.org diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 7502029..794cf0e 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -471,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; @@ -517,9 +517,9 @@ 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; } } } -- cgit v0.10.2 From ede5147d515694e012cd958ec874b9daf8a65fec Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Feb 2016 14:37:53 +0000 Subject: Handle ISO 8601 leap seconds and encodings of midnight in mktime64() Handle the following ISO 8601 features in mktime64(): (1) Leap seconds. Leap seconds are indicated by the seconds parameter being the value 60. Handle this by treating it the same as 00 of the following minute. It has been pointed out that a minute may contain two leap seconds. However, pending discussion of what that looks like and how to handle it, I'm not going to concern myself with it. (2) Alternate encodings of midnight. Two different encodings of midnight are permitted - 00:00:00 and 24:00:00 - the first is midnight today and the second is midnight tomorrow and is exactly equivalent to the first with tomorrow's date. As it happens, we don't actually need to change mktime64() to handle either of these - just comment them as valid parameters. These facility will be used by the X.509 parser. Doing it in mktime64() makes the policy common to the whole kernel and easier to find. Signed-off-by: David Howells Acked-by: Arnd Bergmann cc: John Stultz cc: Rudolf Polzer cc: One Thousand Gnomes 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 */ } -- cgit v0.10.2 From da02559c9f864c8d62f524c1e0b64173711a16ab Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Feb 2016 14:37:53 +0000 Subject: X.509: Support leap seconds The format of ASN.1 GeneralizedTime seems to be specified by ISO 8601 [X.680 46.3] and this apparently supports leap seconds (ie. the seconds field is 60). It's not entirely clear that ASN.1 expects it, but we can relax the seconds check slightly for GeneralizedTime. This results in us passing a time with sec as 60 to mktime64(), which handles it as being a duplicate of the 0th second of the next minute. We can't really do otherwise without giving the kernel much greater knowledge of where all the leap seconds are. Unfortunately, this would require change the mapping of the kernel's current-time-in-seconds. UTCTime, however, only supports a seconds value in the range 00-59, but for the sake of simplicity allow this with UTCTime also. Without this patch, certain X.509 certificates will be rejected, potentially making a kernel unbootable. Reported-by: Rudolf Polzer Signed-off-by: David Howells Acked-by: Arnd Bergmann cc: David Woodhouse cc: John Stultz diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 794cf0e..99ff538 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -527,7 +527,7 @@ int x509_decode_time(time64_t *_t, size_t hdrlen, if (day < 1 || day > mon_len || hour > 23 || 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); -- cgit v0.10.2 From 7650cb80e4e90b0fae7854b6008a46d24360515f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 24 Feb 2016 14:37:54 +0000 Subject: X.509: Handle midnight alternative notation in GeneralizedTime The ASN.1 GeneralizedTime object carries an ISO 8601 format date and time. The time is permitted to show midnight as 00:00 or 24:00 (the latter being equivalent of 00:00 of the following day). The permitted value is checked in x509_decode_time() but the actual handling is left to mktime64(). Without this patch, certain X.509 certificates will be rejected and could lead to an unbootable kernel. Note that with this patch we also permit any 24:mm:ss time and extend this to UTCTime, which whilst not strictly correct don't permit much leeway in fiddling date strings. Reported-by: Rudolf Polzer Signed-off-by: David Howells Acked-by: Arnd Bergmann cc: David Woodhouse cc: John Stultz diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 99ff538..c02c200 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -525,7 +525,7 @@ int x509_decode_time(time64_t *_t, size_t hdrlen, } if (day < 1 || day > mon_len || - hour > 23 || + hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */ min > 59 || sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */ goto invalid_time; -- cgit v0.10.2 From 0d1db3e37022770a221b2a7565cfe425792ed22e Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 29 Feb 2016 14:44:30 +0000 Subject: certs: Fix misaligned data in extra certificate list Fix the following warning found by kbuild: certs/system_certificates.S:24: Error: misaligned data because: KEYS: Reserve an extra certificate symbol for inserting without recompiling doesn't correctly align system_extra_cert_used. Signed-off-by: David Howells cc: Mehmet Kayaalp diff --git a/certs/system_certificates.S b/certs/system_certificates.S index f82e1b2..c9ceb71 100644 --- a/certs/system_certificates.S +++ b/certs/system_certificates.S @@ -19,6 +19,7 @@ __cert_list_end: 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 -- cgit v0.10.2 From 89053aa9c711bd455a68844b4ed37c8b72ef1daa Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 1 Mar 2016 10:36:07 +0000 Subject: MODSIGN: linux/string.h should be #included to get memcpy() linux/string.h should be #included in module_signing.c to get memcpy(), lest the following occur: kernel/module_signing.c: In function 'mod_verify_sig': kernel/module_signing.c:57:2: error: implicit declaration of function 'memcpy' [-Werror=implicit-function-declaration] memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); ^ Reported-by: kbuild test robot Signed-off-by: David Howells diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 6528a79..9cfa46d 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include "module-internal.h" -- cgit v0.10.2 From 41693d1c03212de3267bc77b1cb196294a438616 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Tue, 1 Mar 2016 09:53:00 +0100 Subject: sign-file: fix build with CMS support disabled Some versions of openssl might have the CMS feature disabled LibreSSL disables this feature too If the feature is disabled, fallback to PKCS7 In file included from scripts/sign-file.c:46:0: /usr/x86_64-pc-linux-gnu/include/openssl/cms.h:62:2: error: #error CMS is disabled. #error CMS is disabled. Signed-off-by: Marc-Antoine Perennou Signed-off-by: David Howells diff --git a/scripts/sign-file.c b/scripts/sign-file.c index 80b7f7f..d912d5a 100755 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -41,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 || LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS) #define USE_PKCS7 #endif #ifndef USE_PKCS7 -- cgit v0.10.2 From a49de377e051eac5bc50a3b838614a05671da4e7 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Thu, 3 Mar 2016 21:49:26 +0000 Subject: crypto: Add hash param to pkcs1pad This adds hash param to pkcs1pad. The pkcs1pad template can work with or without the hash. When hash param is provided then the verify operation will also verify the output against the known digest. Signed-off-by: Tadeusz Struk Signed-off-by: David Howells Acked-by: Herbert Xu 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 #include +/* + * 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: -- cgit v0.10.2 From d43de6c780a84def056afaf4fb3e66bdaa1efc00 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 3 Mar 2016 21:49:27 +0000 Subject: akcipher: Move the RSA DER encoding check to the crypto layer Move the RSA EMSA-PKCS1-v1_5 encoding from the asymmetric-key public_key subtype to the rsa crypto module's pkcs1pad template. This means that the public_key subtype no longer has any dependencies on public key type. To make this work, the following changes have been made: (1) The rsa pkcs1pad template is now used for RSA keys. This strips off the padding and returns just the message hash. (2) In a previous patch, the pkcs1pad template gained an optional second parameter that, if given, specifies the hash used. We now give this, and pkcs1pad checks the encoded message E(M) for the EMSA-PKCS1-v1_5 encoding and verifies that the correct digest OID is present. (3) The crypto driver in crypto/asymmetric_keys/rsa.c is now reduced to something that doesn't care about what the encryption actually does and and has been merged into public_key.c. (4) CONFIG_PUBLIC_KEY_ALGO_RSA is gone. Module signing must set CONFIG_CRYPTO_RSA=y instead. Thoughts: (*) Should the encoding style (eg. raw, EMSA-PKCS1-v1_5) also be passed to the padding template? Should there be multiple padding templates registered that share most of the code? Signed-off-by: David Howells Signed-off-by: Tadeusz Struk Acked-by: Herbert Xu diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 905d745..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 CRYPTO_RSA - 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 b78a194..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 diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index b383629..27ebc2f 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -17,8 +17,10 @@ #include #include #include +#include #include #include +#include MODULE_LICENSE("GPL"); @@ -35,12 +37,6 @@ const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { }; EXPORT_SYMBOL_GPL(pkey_id_type_name); -static int (*alg_verify[PKEY_ALGO__LAST])(const struct public_key *pkey, - const struct public_key_signature *sig) = { - NULL, - rsa_verify_signature -}; - /* * Provide a part of a description of the key for /proc/keys. */ @@ -68,24 +64,110 @@ void public_key_destroy(void *payload) } 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 *pkey, const struct public_key_signature *sig) { + 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->s); - if (pkey->pkey_algo >= PKEY_ALGO__LAST) - return -ENOPKG; + alg_name = pkey_algo_name[sig->pkey_algo]; + if (sig->pkey_algo == PKEY_ALGO_RSA) { + /* 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)", + hash_algo_name[sig->pkey_hash_algo] + ) >= CRYPTO_MAX_ALG_NAME) + return -EINVAL; + alg_name = alg_name_buf; + } + + 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; + } + if (ret < 0) + goto out_free_output; - if (!alg_verify[pkey->pkey_algo]) - return -ENOPKG; + /* Do the actual verification step. */ + if (req->dst_len != sig->digest_size || + memcmp(sig->digest, output, sig->digest_size) != 0) + ret = -EKEYREJECTED; - return alg_verify[pkey->pkey_algo](pkey, sig); +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/rsa.c b/crypto/asymmetric_keys/rsa.c deleted file mode 100644 index 51502bc..0000000 --- a/crypto/asymmetric_keys/rsa.c +++ /dev/null @@ -1,224 +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 -#include -#include -#include -#include - -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 _ -}; - -struct rsa_completion { - struct completion completion; - int err; -}; - -/* - * 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 - * note: leading zeros are stripped by the RSA implementation - */ - if (EM[0] != 0x01) { - kleave(" = -EBADMSG [EM[0] == %02u]", EM[0]); - 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 = 1; 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; -} - -static void public_key_verify_done(struct crypto_async_request *req, int err) -{ - struct rsa_completion *compl = req->data; - - if (err == -EINPROGRESS) - return; - - compl->err = err; - complete(&compl->completion); -} - -int rsa_verify_signature(const struct public_key *pkey, - const struct public_key_signature *sig) -{ - struct crypto_akcipher *tfm; - struct akcipher_request *req; - struct rsa_completion compl; - struct scatterlist sig_sg, sg_out; - void *outbuf = NULL; - unsigned int outlen = 0; - int ret = -ENOMEM; - - tfm = crypto_alloc_akcipher("rsa", 0, 0); - if (IS_ERR(tfm)) - goto error_out; - - 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; - - ret = -EINVAL; - outlen = crypto_akcipher_maxsize(tfm); - if (!outlen) - goto error_free_req; - - /* Initialize the output buffer */ - ret = -ENOMEM; - outbuf = kmalloc(outlen, GFP_KERNEL); - if (!outbuf) - goto error_free_req; - - sg_init_one(&sig_sg, sig->s, sig->s_size); - sg_init_one(&sg_out, outbuf, outlen); - akcipher_request_set_crypt(req, &sig_sg, &sg_out, 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); - - ret = crypto_akcipher_verify(req); - if (ret == -EINPROGRESS) { - wait_for_completion(&compl.completion); - ret = compl.err; - } - - if (ret) - goto error_free_req; - - /* Output from the operation is an encoded message (EM) of - * length k octets. - */ - outlen = req->dst_len; - ret = rsa_verify(sig->digest, outbuf, outlen, sig->digest_size, - RSA_ASN1_templates[sig->pkey_hash_algo].data, - RSA_ASN1_templates[sig->pkey_hash_algo].size); -error_free_req: - akcipher_request_free(req); -error_free_tfm: - crypto_free_akcipher(tfm); -error_out: - kfree(outbuf); - return ret; -} -EXPORT_SYMBOL_GPL(rsa_verify_signature); diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index a1693ed..80ab099 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -91,6 +91,4 @@ extern struct key *x509_request_asymmetric_key(struct key *keyring, int public_key_verify_signature(const struct public_key *pkey, const struct public_key_signature *sig); -int rsa_verify_signature(const struct public_key *pkey, - const struct public_key_signature *sig); #endif /* _LINUX_PUBLIC_KEY_H */ 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/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 2fa3bc6..69a92e6 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -103,6 +103,7 @@ int asymmetric_verify(struct key *keyring, const char *sig, memset(&pks, 0, sizeof(pks)); + pks.pkey_algo = PKEY_ALGO_RSA; pks.pkey_hash_algo = hdr->hash_algo; pks.digest = (u8 *)data; pks.digest_size = datalen; -- cgit v0.10.2 From 4e8ae72a75aae285ec5b93518b9680da198afd0d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 3 Mar 2016 21:49:27 +0000 Subject: X.509: Make algo identifiers text instead of enum Make the identifier public key and digest algorithm fields text instead of enum. Signed-off-by: David Howells Acked-by: Herbert Xu 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 cbbd03f..40de03f 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -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); @@ -615,8 +615,6 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen, { struct pkcs7_parse_context *ctx = context; - BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA); - ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL); if (!ctx->sinfo->sig.s) return -ENOMEM; diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index f5db137..50be2a1 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -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 27ebc2f..0f8b264 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -24,19 +24,6 @@ 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 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. */ @@ -46,9 +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], - pkey_algo_name[key->pkey_algo]); + seq_printf(m, "%s.%s", key->id_type, key->pkey_algo); } /* @@ -103,15 +88,14 @@ int public_key_verify_signature(const struct public_key *pkey, BUG_ON(!sig->digest); BUG_ON(!sig->s); - alg_name = pkey_algo_name[sig->pkey_algo]; - if (sig->pkey_algo == PKEY_ALGO_RSA) { + 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)", - hash_algo_name[sig->pkey_hash_algo] + "pkcs1pad(rsa,%s)", sig->hash_algo ) >= CRYPTO_MAX_ALG_NAME) return -EINVAL; alg_name = alg_name_buf; 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 c02c200..4a29bac 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -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; diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 7092d5c..733c046 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -176,7 +176,7 @@ int x509_get_sig_params(struct x509_certificate *cert) /* 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; @@ -291,21 +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 || - !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->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/include/crypto/public_key.h b/include/crypto/public_key.h index 80ab099..aa730ea 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -14,28 +14,6 @@ #ifndef _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H -#include - -enum pkey_algo { - PKEY_ALGO_DSA, - PKEY_ALGO_RSA, - PKEY_ALGO__LAST -}; - -extern const char *const pkey_algo_name[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,8 +37,8 @@ extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; struct public_key { void *key; u32 keylen; - enum pkey_algo pkey_algo : 8; - enum pkey_id_type id_type : 8; + const char *id_type; + const char *pkey_algo; }; extern void public_key_destroy(void *payload); @@ -73,8 +51,8 @@ struct public_key_signature { u32 s_size; /* Number of bytes in signature */ u8 *digest; u8 digest_size; /* Number of bytes in digest */ - enum pkey_algo pkey_algo : 8; - enum hash_algo pkey_hash_algo : 8; + const char *pkey_algo; + const char *hash_algo; }; extern struct asymmetric_key_subtype public_key_subtype; diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 9cfa46d..64b9dea 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -16,6 +16,12 @@ #include #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/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 69a92e6..80052ed 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -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,8 +104,8 @@ int asymmetric_verify(struct key *keyring, const char *sig, memset(&pks, 0, sizeof(pks)); - pks.pkey_algo = PKEY_ALGO_RSA; - 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.s = hdr->sig; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 5efe2ec..c7708d9 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -94,7 +94,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 */ -- cgit v0.10.2