From patchwork Wed Dec 16 17:41:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 344581 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8C46C0018C for ; Wed, 16 Dec 2020 17:47:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6D6CB24CEE for ; Wed, 16 Dec 2020 17:47:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727913AbgLPRqv (ORCPT ); Wed, 16 Dec 2020 12:46:51 -0500 Received: from mga11.intel.com ([192.55.52.93]:21277 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727910AbgLPRqv (ORCPT ); Wed, 16 Dec 2020 12:46:51 -0500 IronPort-SDR: FHCNSNE+EbSxvLK81ZjDgvPD40DAJBsx3JcAA/ak3+AGx6Bl37qNo0r2Me1uuPNUdg+3WTolAI XkXZyl1dlKQA== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593386" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593386" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:08 -0800 IronPort-SDR: vc/gIUBXwr+CriwiA/LGCx4DIQieb5+v7dbpC2fRljcRg+wxfdMrtM8XuvCifKgpZLYhKgqEuM MfVCquXvf66A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854176" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:08 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com Subject: [RFC PATCH 1/8] x86/cpufeature: Enumerate Key Locker feature Date: Wed, 16 Dec 2020 09:41:39 -0800 Message-Id: <20201216174146.10446-2-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Intel's Key Locker is a new security feature providing a mechanism to protect a data encryption key when processing the Advanced Encryption Standard algorithm. Here we add it to the kernel/user ABI by enumerating the hardware capability. E.g., /proc/cpuinfo: keylocker. Also, define the feature-specific CPUID leaf and bits for the feature enablement. Key Locker is on the disabled list, which is useful for compile-time configuration later. Signed-off-by: Chang S. Bae Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/disabled-features.h | 8 +++++++- arch/x86/include/asm/keylocker.h | 18 ++++++++++++++++++ arch/x86/include/uapi/asm/processor-flags.h | 2 ++ arch/x86/kernel/cpu/cpuid-deps.c | 1 + 5 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/keylocker.h diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index dad350d42ecf..8f2f050023b7 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -352,6 +352,7 @@ #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ +#define X86_FEATURE_KEYLOCKER (16*32+23) /* Key Locker */ #define X86_FEATURE_CLDEMOTE (16*32+25) /* CLDEMOTE instruction */ #define X86_FEATURE_MOVDIRI (16*32+27) /* MOVDIRI instruction */ #define X86_FEATURE_MOVDIR64B (16*32+28) /* MOVDIR64B instruction */ diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h index 5861d34f9771..0ac9414da242 100644 --- a/arch/x86/include/asm/disabled-features.h +++ b/arch/x86/include/asm/disabled-features.h @@ -44,6 +44,12 @@ # define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE & 31)) #endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ +#ifdef CONFIG_X86_KEYLOCKER +# define DISABLE_KEYLOCKER 0 +#else +# define DISABLE_KEYLOCKER (1<<(X86_FEATURE_KEYLOCKER & 31)) +#endif /* CONFIG_X86_KEYLOCKER */ + #ifdef CONFIG_X86_5LEVEL # define DISABLE_LA57 0 #else @@ -82,7 +88,7 @@ #define DISABLED_MASK14 0 #define DISABLED_MASK15 0 #define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE|DISABLE_LA57|DISABLE_UMIP| \ - DISABLE_ENQCMD) + DISABLE_ENQCMD|DISABLE_KEYLOCKER) #define DISABLED_MASK17 0 #define DISABLED_MASK18 0 #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) diff --git a/arch/x86/include/asm/keylocker.h b/arch/x86/include/asm/keylocker.h new file mode 100644 index 000000000000..2fe13c21c63f --- /dev/null +++ b/arch/x86/include/asm/keylocker.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_KEYLOCKER_H +#define _ASM_KEYLOCKER_H + +#ifndef __ASSEMBLY__ + +#include + +#define KEYLOCKER_CPUID 0x019 +#define KEYLOCKER_CPUID_EAX_SUPERVISOR BIT(0) +#define KEYLOCKER_CPUID_EBX_AESKLE BIT(0) +#define KEYLOCKER_CPUID_EBX_WIDE BIT(2) +#define KEYLOCKER_CPUID_EBX_BACKUP BIT(4) +#define KEYLOCKER_CPUID_ECX_RAND BIT(1) + +#endif /*__ASSEMBLY__ */ +#endif /* _ASM_KEYLOCKER_H */ diff --git a/arch/x86/include/uapi/asm/processor-flags.h b/arch/x86/include/uapi/asm/processor-flags.h index bcba3c643e63..b958a95a0908 100644 --- a/arch/x86/include/uapi/asm/processor-flags.h +++ b/arch/x86/include/uapi/asm/processor-flags.h @@ -124,6 +124,8 @@ #define X86_CR4_PCIDE _BITUL(X86_CR4_PCIDE_BIT) #define X86_CR4_OSXSAVE_BIT 18 /* enable xsave and xrestore */ #define X86_CR4_OSXSAVE _BITUL(X86_CR4_OSXSAVE_BIT) +#define X86_CR4_KEYLOCKER_BIT 19 /* enable Key Locker */ +#define X86_CR4_KEYLOCKER _BITUL(X86_CR4_KEYLOCKER_BIT) #define X86_CR4_SMEP_BIT 20 /* enable SMEP support */ #define X86_CR4_SMEP _BITUL(X86_CR4_SMEP_BIT) #define X86_CR4_SMAP_BIT 21 /* enable SMAP support */ diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c index d502241995a3..b8edcb91fe4f 100644 --- a/arch/x86/kernel/cpu/cpuid-deps.c +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -71,6 +71,7 @@ static const struct cpuid_dep cpuid_deps[] = { { X86_FEATURE_AVX512_BF16, X86_FEATURE_AVX512VL }, { X86_FEATURE_ENQCMD, X86_FEATURE_XSAVES }, { X86_FEATURE_PER_THREAD_MBA, X86_FEATURE_MBA }, + { X86_FEATURE_KEYLOCKER, X86_FEATURE_XMM2 }, {} }; From patchwork Wed Dec 16 17:41:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 344580 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03191C2BBD4 for ; Wed, 16 Dec 2020 17:47:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D0D0824CED for ; Wed, 16 Dec 2020 17:47:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727919AbgLPRqx (ORCPT ); Wed, 16 Dec 2020 12:46:53 -0500 Received: from mga11.intel.com ([192.55.52.93]:21280 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727915AbgLPRqw (ORCPT ); Wed, 16 Dec 2020 12:46:52 -0500 IronPort-SDR: LvBIZcwP+fGV2WTPHVekXzDDYRnHu3QtS4F9v/C5WFwonf3rTGVz8eHJcJSggUGV8YWmv2WotB pNwVr1wB6CMQ== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593400" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593400" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:09 -0800 IronPort-SDR: Z3R3Ty3wnnDIkHCQLlHTencVqCPO5gmKwByNJ/BrboFvD9zXayDzafsfVGBqZD8Qka3XtQqu3m palQHDgtu0OQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854185" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:09 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com Subject: [RFC PATCH 2/8] x86/cpu: Load Key Locker internal key at boot-time Date: Wed, 16 Dec 2020 09:41:40 -0800 Message-Id: <20201216174146.10446-3-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Internal (Wrapping) Key is a new entity of Intel Key Locker feature. This internal key is loaded in a software-inaccessible CPU state and used to encode a data encryption key. The kernel makes random data and loads it as the internal key in each CPU. The data need to be invalidated as soon as the load is done. The BIOS may disable the feature. Check the dynamic CPUID bit (KEYLOCKER_CPUID_EBX_AESKLE) at first. Add byte code for LOADIWKEY -- an instruction to load the internal key, in the 'x86-opcode-map.txt' file to avoid objtool's misinterpretation. Signed-off-by: Chang S. Bae Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/include/asm/keylocker.h | 11 +++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/cpu/common.c | 38 +++++++++++++- arch/x86/kernel/keylocker.c | 71 +++++++++++++++++++++++++++ arch/x86/kernel/smpboot.c | 2 + arch/x86/lib/x86-opcode-map.txt | 2 +- tools/arch/x86/lib/x86-opcode-map.txt | 2 +- 7 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 arch/x86/kernel/keylocker.c diff --git a/arch/x86/include/asm/keylocker.h b/arch/x86/include/asm/keylocker.h index 2fe13c21c63f..daf0734a4095 100644 --- a/arch/x86/include/asm/keylocker.h +++ b/arch/x86/include/asm/keylocker.h @@ -14,5 +14,16 @@ #define KEYLOCKER_CPUID_EBX_BACKUP BIT(4) #define KEYLOCKER_CPUID_ECX_RAND BIT(1) +bool check_keylocker_readiness(void); + +bool load_keylocker(void); + +void make_keylocker_data(void); +#ifdef CONFIG_X86_KEYLOCKER +void invalidate_keylocker_data(void); +#else +#define invalidate_keylocker_data() do { } while (0) +#endif + #endif /*__ASSEMBLY__ */ #endif /* _ASM_KEYLOCKER_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 68608bd892c0..085dbf49b3b9 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -145,6 +145,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_SCHED_MC_PRIO) += itmt.o obj-$(CONFIG_X86_UMIP) += umip.o +obj-$(CONFIG_X86_KEYLOCKER) += keylocker.o obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 35ad8480c464..d675075848bb 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -57,6 +57,8 @@ #include #include #include +#include + #include #include "cpu.h" @@ -459,6 +461,39 @@ static __init int x86_nofsgsbase_setup(char *arg) } __setup("nofsgsbase", x86_nofsgsbase_setup); +static __always_inline void setup_keylocker(struct cpuinfo_x86 *c) +{ + bool keyloaded; + + if (!cpu_feature_enabled(X86_FEATURE_KEYLOCKER)) + goto out; + + cr4_set_bits(X86_CR4_KEYLOCKER); + + if (c == &boot_cpu_data) { + if (!check_keylocker_readiness()) + goto disable_keylocker; + + make_keylocker_data(); + } + + keyloaded = load_keylocker(); + if (!keyloaded) { + pr_err_once("x86/keylocker: Failed to load internal key\n"); + goto disable_keylocker; + } + + pr_info_once("x86/keylocker: Activated\n"); + return; + +disable_keylocker: + clear_cpu_cap(c, X86_FEATURE_KEYLOCKER); + pr_info_once("x86/keylocker: Disabled\n"); +out: + /* Make sure the feature disabled for kexec-reboot. */ + cr4_clear_bits(X86_CR4_KEYLOCKER); +} + /* * Protection Keys are not available in 32-bit mode. */ @@ -1554,10 +1589,11 @@ static void identify_cpu(struct cpuinfo_x86 *c) /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); - /* Set up SMEP/SMAP/UMIP */ + /* Setup various Intel-specific CPU security features */ setup_smep(c); setup_smap(c); setup_umip(c); + setup_keylocker(c); /* Enable FSGSBASE instructions if available. */ if (cpu_has(c, X86_FEATURE_FSGSBASE)) { diff --git a/arch/x86/kernel/keylocker.c b/arch/x86/kernel/keylocker.c new file mode 100644 index 000000000000..e455d806b80c --- /dev/null +++ b/arch/x86/kernel/keylocker.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Key Locker feature check and support the internal key + */ + +#include + +#include +#include +#include + +bool check_keylocker_readiness(void) +{ + u32 eax, ebx, ecx, edx; + + cpuid_count(KEYLOCKER_CPUID, 0, &eax, &ebx, &ecx, &edx); + /* BIOS may not enable it on some systems. */ + if (!(ebx & KEYLOCKER_CPUID_EBX_AESKLE)) { + pr_debug("x86/keylocker: not fully enabled\n"); + return false; + } + + return true; +} + +/* Load Internal (Wrapping) Key */ +#define LOADIWKEY ".byte 0xf3,0x0f,0x38,0xdc,0xd1" +#define LOADIWKEY_NUM_OPERANDS 3 + +static struct key { + struct reg_128_bit value[LOADIWKEY_NUM_OPERANDS]; +} keydata; + +void make_keylocker_data(void) +{ + int i; + + for (i = 0; i < LOADIWKEY_NUM_OPERANDS; i++) + get_random_bytes(&keydata.value[i], sizeof(struct reg_128_bit)); +} + +void invalidate_keylocker_data(void) +{ + memset(&keydata.value, 0, sizeof(struct reg_128_bit) * LOADIWKEY_NUM_OPERANDS); +} + +#define USE_SWKEY 0 + +bool load_keylocker(void) +{ + struct reg_128_bit zeros = { 0 }; + u32 keysrc = USE_SWKEY; + bool err = true; + + kernel_fpu_begin(); + + asm volatile ("movdqu %0, %%xmm0; movdqu %1, %%xmm1; movdqu %2, %%xmm2;" + :: "m"(keydata.value[0]), + "m"(keydata.value[1]), + "m"(keydata.value[2])); + + asm volatile (LOADIWKEY CC_SET(z) : CC_OUT(z) (err) : "a"(keysrc)); + + asm volatile ("movdqu %0, %%xmm0; movdqu %0, %%xmm1; movdqu %0, %%xmm2;" + :: "m"(zeros)); + + kernel_fpu_end(); + + return err ? false : true; +} diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index de776b2e6046..a01edf46d4c7 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -81,6 +81,7 @@ #include #include #include +#include /* representing HT siblings of each logical CPU */ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map); @@ -1423,6 +1424,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus) nmi_selftest(); impress_friends(); mtrr_aps_init(); + invalidate_keylocker_data(); } static int __initdata setup_possible_cpus = -1; diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index ec31f5b60323..3e241cddfc86 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -795,7 +795,7 @@ cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) cf: vgf2p8mulb Vx,Wx (66) db: VAESIMC Vdq,Wdq (66),(v1) -dc: vaesenc Vx,Hx,Wx (66) +dc: vaesenc Vx,Hx,Wx (66) | loadiwkey Vx,Hx (F3) dd: vaesenclast Vx,Hx,Wx (66) de: vaesdec Vx,Hx,Wx (66) df: vaesdeclast Vx,Hx,Wx (66) diff --git a/tools/arch/x86/lib/x86-opcode-map.txt b/tools/arch/x86/lib/x86-opcode-map.txt index ec31f5b60323..3e241cddfc86 100644 --- a/tools/arch/x86/lib/x86-opcode-map.txt +++ b/tools/arch/x86/lib/x86-opcode-map.txt @@ -795,7 +795,7 @@ cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) cf: vgf2p8mulb Vx,Wx (66) db: VAESIMC Vdq,Wdq (66),(v1) -dc: vaesenc Vx,Hx,Wx (66) +dc: vaesenc Vx,Hx,Wx (66) | loadiwkey Vx,Hx (F3) dd: vaesenclast Vx,Hx,Wx (66) de: vaesdec Vx,Hx,Wx (66) df: vaesdeclast Vx,Hx,Wx (66) From patchwork Wed Dec 16 17:41:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 344579 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5EE05C4361B for ; Wed, 16 Dec 2020 17:47:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2498424D45 for ; Wed, 16 Dec 2020 17:47:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727949AbgLPRrE (ORCPT ); Wed, 16 Dec 2020 12:47:04 -0500 Received: from mga11.intel.com ([192.55.52.93]:21271 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727944AbgLPRrD (ORCPT ); Wed, 16 Dec 2020 12:47:03 -0500 IronPort-SDR: K3nTCLNCBG9scbCgDKFw1y5zWbWGu3QpoqbYpgrkNNthHxAB5GlG0nmyEJnIE6lmDG2YZ5+Llw R/LmIf6ZDhoA== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593410" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593410" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:10 -0800 IronPort-SDR: CswevTuAltLLcorHxfxDrSrxs6CfJ69SKuDxN29ceLCUBc2xoe1i8kC2+C/TLIABczSY2ppds8 GLvpNwey9jVQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854193" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:10 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com Subject: [RFC PATCH 3/8] x86/msr-index: Add MSRs for Key Locker internal key Date: Wed, 16 Dec 2020 09:41:41 -0800 Message-Id: <20201216174146.10446-4-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Key Locker internal key in a CPU state can be backed up in a platform register. The backup can be also copied back to a CPU state. This mechanism is useful to restore the key (after system sleep). Add MSRs for the internal key backup, copy, and status check. Signed-off-by: Chang S. Bae Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/include/asm/msr-index.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 972a34d93505..c0b9157806f7 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -922,4 +922,10 @@ #define MSR_VM_IGNNE 0xc0010115 #define MSR_VM_HSAVE_PA 0xc0010117 +/* MSRs for Key Locker Internal (Wrapping) Key management */ +#define MSR_IA32_COPY_LOCAL_TO_PLATFORM 0x00000d91 +#define MSR_IA32_COPY_PLATFORM_TO_LOCAL 0x00000d92 +#define MSR_IA32_COPY_STATUS 0x00000990 +#define MSR_IA32_IWKEYBACKUP_STATUS 0x00000991 + #endif /* _ASM_X86_MSR_INDEX_H */ From patchwork Wed Dec 16 17:41:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 345030 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C6021C2BBCD for ; Wed, 16 Dec 2020 17:47:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 847CF24D48 for ; Wed, 16 Dec 2020 17:47:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727958AbgLPRrH (ORCPT ); Wed, 16 Dec 2020 12:47:07 -0500 Received: from mga11.intel.com ([192.55.52.93]:21277 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727734AbgLPRrG (ORCPT ); Wed, 16 Dec 2020 12:47:06 -0500 IronPort-SDR: 5+j0WtlbCDnvv+CerGX/D1+/WIvC+4XOMxkHRDgp8ZDf5sW9VsCc+JQPgeRNDRByOCuPwjzvSe Ec7BgR/Yhxqw== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593419" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593419" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:11 -0800 IronPort-SDR: tJMQXqgSTx46jc7Phntu/p82oYkqENqqSLs/wotaRKjVcXvIoShxsBh+u7l2XT5hiWnKfF818+ l+Pvpae+F1+A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854198" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:11 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, linux-pm@vger.kernel.org Subject: [RFC PATCH 4/8] x86/power: Restore Key Locker internal key from the ACPI S3/4 sleep states Date: Wed, 16 Dec 2020 09:41:42 -0800 Message-Id: <20201216174146.10446-5-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org When the system state switches to these sleep states, the internal key gets reset. Since this system transition is transparent to userspace, the internal key needs to be restored properly. Key Locker provides a mechanism to back up the internal key in non-volatile memory. The kernel requests a backup right after the key loaded at boot-time and copies it later when the system wakes up. The backup during the S5 sleep state is not trusted. It is overwritten by a new key at the next boot. On a system with the S3/4 states, enable the feature only when the backup mechanism is supported. Disable the feature when the copy fails (or the backup corrupts). The shutdown is considered too noisy. A new key is considerable only when threads can be synchronously suspended. Signed-off-by: Chang S. Bae Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-pm@vger.kernel.org --- arch/x86/include/asm/keylocker.h | 12 ++++++++ arch/x86/kernel/cpu/common.c | 25 +++++++++++----- arch/x86/kernel/keylocker.c | 51 ++++++++++++++++++++++++++++++++ arch/x86/power/cpu.c | 34 +++++++++++++++++++++ 4 files changed, 115 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/keylocker.h b/arch/x86/include/asm/keylocker.h index daf0734a4095..722574c305c2 100644 --- a/arch/x86/include/asm/keylocker.h +++ b/arch/x86/include/asm/keylocker.h @@ -6,6 +6,7 @@ #ifndef __ASSEMBLY__ #include +#include #define KEYLOCKER_CPUID 0x019 #define KEYLOCKER_CPUID_EAX_SUPERVISOR BIT(0) @@ -25,5 +26,16 @@ void invalidate_keylocker_data(void); #define invalidate_keylocker_data() do { } while (0) #endif +static inline u64 read_keylocker_backup_status(void) +{ + u64 status; + + rdmsrl(MSR_IA32_IWKEYBACKUP_STATUS, status); + return status; +} + +void backup_keylocker(void); +bool copy_keylocker(void); + #endif /*__ASSEMBLY__ */ #endif /* _ASM_KEYLOCKER_H */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index d675075848bb..a446d5aff08f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -463,24 +463,35 @@ __setup("nofsgsbase", x86_nofsgsbase_setup); static __always_inline void setup_keylocker(struct cpuinfo_x86 *c) { - bool keyloaded; - if (!cpu_feature_enabled(X86_FEATURE_KEYLOCKER)) goto out; cr4_set_bits(X86_CR4_KEYLOCKER); if (c == &boot_cpu_data) { + bool keyloaded; + if (!check_keylocker_readiness()) goto disable_keylocker; make_keylocker_data(); - } - keyloaded = load_keylocker(); - if (!keyloaded) { - pr_err_once("x86/keylocker: Failed to load internal key\n"); - goto disable_keylocker; + keyloaded = load_keylocker(); + if (!keyloaded) { + pr_err("x86/keylocker: Fail to load internal key\n"); + goto disable_keylocker; + } + + backup_keylocker(); + } else { + bool keycopied; + + /* NB: When system wakes up, this path recovers the internal key. */ + keycopied = copy_keylocker(); + if (!keycopied) { + pr_err_once("x86/keylocker: Fail to copy internal key\n"); + goto disable_keylocker; + } } pr_info_once("x86/keylocker: Activated\n"); diff --git a/arch/x86/kernel/keylocker.c b/arch/x86/kernel/keylocker.c index e455d806b80c..229875ac80d5 100644 --- a/arch/x86/kernel/keylocker.c +++ b/arch/x86/kernel/keylocker.c @@ -5,11 +5,15 @@ */ #include +#include +#include #include #include #include +static bool keybackup_available; + bool check_keylocker_readiness(void) { u32 eax, ebx, ecx, edx; @@ -21,6 +25,14 @@ bool check_keylocker_readiness(void) return false; } + keybackup_available = (ebx & KEYLOCKER_CPUID_EBX_BACKUP); + /* Internal Key backup is essential with S3/4 states */ + if (!keybackup_available && + (acpi_sleep_state_supported(ACPI_STATE_S3) || + acpi_sleep_state_supported(ACPI_STATE_S4))) { + pr_debug("x86/keylocker: no key backup support with possible S3/4\n"); + return false; + } return true; } @@ -29,6 +41,7 @@ bool check_keylocker_readiness(void) #define LOADIWKEY_NUM_OPERANDS 3 static struct key { + bool valid; struct reg_128_bit value[LOADIWKEY_NUM_OPERANDS]; } keydata; @@ -38,11 +51,15 @@ void make_keylocker_data(void) for (i = 0; i < LOADIWKEY_NUM_OPERANDS; i++) get_random_bytes(&keydata.value[i], sizeof(struct reg_128_bit)); + + keydata.valid = true; } void invalidate_keylocker_data(void) { memset(&keydata.value, 0, sizeof(struct reg_128_bit) * LOADIWKEY_NUM_OPERANDS); + + keydata.valid = false; } #define USE_SWKEY 0 @@ -69,3 +86,37 @@ bool load_keylocker(void) return err ? false : true; } + +void backup_keylocker(void) +{ + if (keybackup_available) + wrmsrl(MSR_IA32_COPY_LOCAL_TO_PLATFORM, 1); +} + +#define KEYRESTORE_RETRY 1 + +bool copy_keylocker(void) +{ + bool copied = false; + int i; + + /* Use valid key data when available */ + if (keydata.valid) + return load_keylocker(); + + if (!keybackup_available) + return copied; + + wrmsrl(MSR_IA32_COPY_PLATFORM_TO_LOCAL, 1); + + for (i = 0; (i <= KEYRESTORE_RETRY) && !copied; i++) { + u64 status; + + if (i) + udelay(1); + rdmsrl(MSR_IA32_COPY_STATUS, status); + copied = status & BIT(0) ? true : false; + } + + return copied; +} diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index db1378c6ff26..5412440e7c5c 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef CONFIG_X86_32 __visible unsigned long saved_context_ebx; @@ -57,6 +58,38 @@ static void msr_restore_context(struct saved_context *ctxt) } } +/* + * The boot CPU executes this function, while other CPUs restore the key + * through the setup path in setup_keylocker(). + */ +static void restore_keylocker(void) +{ + u64 keybackup_status; + bool keycopied; + + if (!cpu_feature_enabled(X86_FEATURE_KEYLOCKER)) + return; + + keybackup_status = read_keylocker_backup_status(); + if (!(keybackup_status & BIT(0))) { + pr_err("x86/keylocker: internal key restoration failed with %s\n", + (keybackup_status & BIT(2)) ? "read error" : "invalid status"); + WARN_ON(1); + goto disable_keylocker; + } + + keycopied = copy_keylocker(); + if (keycopied) + return; + + pr_err("x86/keylocker: internal key copy failure\n"); + +disable_keylocker: + pr_info("x86/keylocker: Disabled with internal key restoration failure\n"); + setup_clear_cpu_cap(X86_FEATURE_KEYLOCKER); + cr4_clear_bits(X86_CR4_KEYLOCKER); +} + /** * __save_processor_state - save CPU registers before creating a * hibernation image and before restoring the memory state from it @@ -265,6 +298,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt) mtrr_bp_restore(); perf_restore_debug_store(); msr_restore_context(ctxt); + restore_keylocker(); c = &cpu_data(smp_processor_id()); if (cpu_has(c, X86_FEATURE_MSR_IA32_FEAT_CTL)) From patchwork Wed Dec 16 17:41:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 344578 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 22A17C2BBD5 for ; Wed, 16 Dec 2020 17:47:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EE04323B3E for ; Wed, 16 Dec 2020 17:47:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727960AbgLPRrI (ORCPT ); Wed, 16 Dec 2020 12:47:08 -0500 Received: from mga11.intel.com ([192.55.52.93]:21280 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727910AbgLPRrI (ORCPT ); Wed, 16 Dec 2020 12:47:08 -0500 IronPort-SDR: Qzhg1+mb5/ypRD+vC9ZxbrFzB2ac0s0N1t4tJHOulXPz5vOmgxYz0x5HJtt86FnasPRevU76t3 j8BuwMXatH8A== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593428" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593428" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:12 -0800 IronPort-SDR: 4FnDo7nVzF8J2anLlDJCKdYCVEECMXpXPaDaB9NPJtszykzPwM+CjUCaAfNOc3Li1y8SnbXB5x FpP1pogRR2rw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854209" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:12 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, linux-doc@vger.kernel.org Subject: [RFC PATCH 5/8] x86/cpu: Add a config option and a chicken bit for Key Locker Date: Wed, 16 Dec 2020 09:41:43 -0800 Message-Id: <20201216174146.10446-6-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Add a kernel config option to enable the feature (disabled by default) at compile-time. Also, add a new command-line parameter -- 'nokeylocker' to disable the feature at boot-time. Signed-off-by: Chang S. Bae Cc: x86@kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- Documentation/admin-guide/kernel-parameters.txt | 2 ++ arch/x86/Kconfig | 14 ++++++++++++++ arch/x86/kernel/cpu/common.c | 16 ++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 44fde25bb221..c389ad8fb9de 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3220,6 +3220,8 @@ nohugeiomap [KNL,X86,PPC,ARM64] Disable kernel huge I/O mappings. + nokeylocker [X86] Disables Key Locker hardware feature. + nosmt [KNL,S390] Disable symmetric multithreading (SMT). Equivalent to smt=1. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fbf26e0f7a6a..7623af32f919 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1886,6 +1886,20 @@ config X86_INTEL_MEMORY_PROTECTION_KEYS If unsure, say y. +config X86_KEYLOCKER + prompt "Key Locker" + def_bool n + depends on CPU_SUP_INTEL + help + Key Locker is a new security feature to protect a data encryption + key for the Advanced Encryption Standard (AES) algorithm. + + When enabled, every CPU has a unique internal key to wrap the AES + key into an encoded format. The internal key is not accessible + to software once loaded. + + If unsure, say y. + choice prompt "TSX enable mode" depends on CPU_SUP_INTEL diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a446d5aff08f..ba5bd79fbac2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -354,6 +354,22 @@ static __always_inline void setup_umip(struct cpuinfo_x86 *c) /* These bits should not change their value after CPU init is finished. */ static const unsigned long cr4_pinned_mask = X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP | X86_CR4_FSGSBASE; + +static __init int x86_nokeylocker_setup(char *arg) +{ + /* Expect an exact match without trailing characters */ + if (strlen(arg)) + return 0; + + if (!cpu_feature_enabled(X86_FEATURE_KEYLOCKER)) + return 1; + + setup_clear_cpu_cap(X86_FEATURE_KEYLOCKER); + pr_info("x86/keylocker: Disabled by kernel command line\n"); + return 1; +} +__setup("nokeylocker", x86_nokeylocker_setup); + static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning); static unsigned long cr4_pinned_bits __ro_after_init; From patchwork Wed Dec 16 17:41:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 345029 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED1C5C3526C for ; Wed, 16 Dec 2020 17:47:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BBEAE24D45 for ; Wed, 16 Dec 2020 17:47:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727986AbgLPRrT (ORCPT ); Wed, 16 Dec 2020 12:47:19 -0500 Received: from mga11.intel.com ([192.55.52.93]:21271 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727982AbgLPRrT (ORCPT ); Wed, 16 Dec 2020 12:47:19 -0500 IronPort-SDR: RHp2/9W3L3m3RkY0saUzRG1yqdiSth/igyabycXvhClOiGR0yPYCF08WNQQvOHIL6v3D7vW4Cq bQVnIUHrBfTw== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593438" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593438" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:13 -0800 IronPort-SDR: 6s/7eqTL8aFJezfJCuYyl1RK/0Mx09HmkBbcdt/0qcc2GpHptnoGcx4pLV5q8Bz/2LvrqtJ6r0 gE2r3ziEcnXg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854221" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:13 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, linux-kselftest@vger.kernel.org Subject: [RFC PATCH 6/8] selftests/x86: Test Key Locker internal key maintenance Date: Wed, 16 Dec 2020 09:41:44 -0800 Message-Id: <20201216174146.10446-7-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org The test validates the internal key to be the same in all CPUs. It performs the validation again with the Suspend-To-RAM (ACPI S3) state. Signed-off-by: Chang S. Bae Cc: linux-kernel@vger.kernel.org Cc: linux-kselftest@vger.kernel.org --- tools/testing/selftests/x86/Makefile | 2 +- tools/testing/selftests/x86/keylocker.c | 177 ++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/keylocker.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 6703c7906b71..c53e496d77b2 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -13,7 +13,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ test_vdso test_vsyscall mov_ss_trap \ - syscall_arg_fault fsgsbase_restore + syscall_arg_fault fsgsbase_restore keylocker TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer diff --git a/tools/testing/selftests/x86/keylocker.c b/tools/testing/selftests/x86/keylocker.c new file mode 100644 index 000000000000..3d69c1615bca --- /dev/null +++ b/tools/testing/selftests/x86/keylocker.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * keylocker.c, validating the internal key management + */ +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HANDLE_SIZE 48 + +static bool keylocker_disabled; + +/* Encode a 128-bit key to a 384-bit handle */ +static inline void __encode_key(char *handle) +{ + static const unsigned char aeskey[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x71, 0x77, 0x74, 0x69, 0x6f, 0x6b, 0x6c, 0x78 }; + + asm volatile ("movdqu %0, %%xmm0" : : "m" (*aeskey) :); + + /* Set no restriction to the handle */ + asm volatile ("mov $0, %%eax" :); + + /* ENCODEKEY128 %EAX */ + asm volatile (".byte 0xf3, 0xf, 0x38, 0xfa, 0xc0"); + + asm volatile ("movdqu %%xmm0, %0; movdqu %%xmm1, %1; movdqu %%xmm2, %2;" + : "=m" (handle[0]), "=m" (handle[0x10]), "=m" (handle[0x20])); +} + +static jmp_buf jmpbuf; + +static void handle_sigill(int sig, siginfo_t *si, void *ctx_void) +{ + keylocker_disabled = true; + siglongjmp(jmpbuf, 1); +} + +static bool encode_key(char *handle) +{ + bool success = true; + struct sigaction sa; + int ret; + + memset(&sa, 0, sizeof(sa)); + + /* Set signal handler */ + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handle_sigill; + sigemptyset(&sa.sa_mask); + ret = sigaction(SIGILL, &sa, 0); + if (ret) + err(1, "sigaction"); + + if (sigsetjmp(jmpbuf, 1)) + success = false; + else + __encode_key(handle); + + /* Clear signal handler */ + sa.sa_flags = 0; + sa.sa_sigaction = NULL; + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + ret = sigaction(SIGILL, &sa, 0); + if (ret) + err(1, "sigaction"); + + return success; +} + +/* + * Test if the internal key is the same in all the CPUs: + * + * Since the value is not readable, compare the encoded output of a AES key + * between CPUs. + */ + +static int nerrs; + +static unsigned char cpu0_handle[HANDLE_SIZE] = { 0 }; + +static void test_internal_key(bool slept, long cpus) +{ + int cpu, errs; + + printf("Test the internal key consistency between CPUs\n"); + + for (cpu = 0, errs = 0; cpu < cpus; cpu++) { + char handle[HANDLE_SIZE] = { 0 }; + cpu_set_t mask; + bool success; + + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + sched_setaffinity(0, sizeof(cpu_set_t), &mask); + + success = encode_key(handle); + if (!success) { + /* The encode should success after the S3 sleep */ + if (slept) + errs++; + printf("[%s]\tKey Locker disabled at CPU%d\n", + slept ? "FAIL" : "NOTE", cpu); + continue; + } + + if (cpu == 0 && !slept) { + /* Record the first handle value as reference */ + memcpy(cpu0_handle, handle, HANDLE_SIZE); + } else if (memcmp(cpu0_handle, handle, HANDLE_SIZE)) { + printf("[FAIL]\tMismatched internal key at CPU%d\n", + cpu); + errs++; + } + } + + if (errs == 0 && !keylocker_disabled) + printf("[OK]\tAll the internal keys are the same\n"); + else + nerrs += errs; +} + +static void switch_to_sleep(bool *slept) +{ + ssize_t bytes; + int fd; + + printf("Transition to Suspend-To-RAM state\n"); + + fd = open("/sys/power/mem_sleep", O_RDWR); + if (fd < 0) + err(1, "Open /sys/power/mem_sleep"); + + bytes = write(fd, "deep", strlen("deep")); + if (bytes != strlen("deep")) + err(1, "Write /sys/power/mem_sleep"); + close(fd); + + fd = open("/sys/power/state", O_RDWR); + if (fd < 0) + err(1, "Open /sys/power/state"); + + bytes = write(fd, "mem", strlen("mem")); + if (bytes != strlen("mem")) + err(1, "Write /sys/power/state"); + close(fd); + + printf("Wake up from Suspend-To-RAM state\n"); + *slept = true; +} + +int main(void) +{ + bool slept = false; + long cpus; + + cpus = sysconf(_SC_NPROCESSORS_ONLN); + printf("%ld CPUs in the system\n", cpus); + + test_internal_key(slept, cpus); + if (keylocker_disabled) + return nerrs ? 1 : 0; + + switch_to_sleep(&slept); + test_internal_key(slept, cpus); + return nerrs ? 1 : 0; +} From patchwork Wed Dec 16 17:41:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 344577 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D1D3C35270 for ; Wed, 16 Dec 2020 17:47:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 01B9024D45 for ; Wed, 16 Dec 2020 17:47:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727994AbgLPRrX (ORCPT ); Wed, 16 Dec 2020 12:47:23 -0500 Received: from mga11.intel.com ([192.55.52.93]:21277 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727990AbgLPRrX (ORCPT ); Wed, 16 Dec 2020 12:47:23 -0500 IronPort-SDR: p+yBueh+aVfr5Ym399EVPdZWE2YVW3ar4yYmYuVV+pRZEfEXjgJjBNSM5RpsOTztgdILBpoILd I5JAkCfLAulg== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="171593450" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="171593450" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:14 -0800 IronPort-SDR: QhxffoV/E1PAAqd0iiMGem9EA7G+6FwS3ngdS/hQgulntfHqeS1LKJgVaqfRANOeOweNNzYQeh LNIS6Ua04X3w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854232" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:13 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com Subject: [RFC PATCH 7/8] crypto: x86/aes-kl - Support AES algorithm using Key Locker instructions Date: Wed, 16 Dec 2020 09:41:45 -0800 Message-Id: <20201216174146.10446-8-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Key Locker (KL) is Intel's new security feature that protects the AES key at the time of data transformation. New AES SIMD instructions -- as a successor of Intel's AES-NI -- are provided to encode an AES key and reference it for the AES algorithm. New instructions support 128/256-bit keys. While it is not desirable to receive any 192-bit key, AES-NI instructions are taken to serve this size. New instructions are operational in both 32-/64-bit modes. Add a set of new macros for the new instructions so that no new binutils version is required. Implemented methods are for a single block as well as ECB, CBC, CTR, and XTS modes. The methods are not compatible with other AES implementations as accessing an encrypted key instead of the normal AES key. setkey() call encodes an AES key. User may displace the AES key once encoded, as encrypt()/decrypt() methods do not need the key. Most C code follows the AES-NI implementation. It has higher priority than the AES-NI as providing key protection. Signed-off-by: Chang S. Bae Cc: Herbert Xu Cc: x86@kernel.org Cc: linux-crypto@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/crypto/Makefile | 3 + arch/x86/crypto/aeskl-intel_asm.S | 881 +++++++++++++++++++++++++++++ arch/x86/crypto/aeskl-intel_glue.c | 697 +++++++++++++++++++++++ arch/x86/include/asm/inst.h | 201 +++++++ crypto/Kconfig | 28 + 5 files changed, 1810 insertions(+) create mode 100644 arch/x86/crypto/aeskl-intel_asm.S create mode 100644 arch/x86/crypto/aeskl-intel_glue.c diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index a31de0c6ccde..8e2e34e73a21 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -54,6 +54,9 @@ obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o aes_ctrby8_avx-x86_64.o +obj-$(CONFIG_CRYPTO_AES_KL) += aeskl-intel.o +aeskl-intel-y := aeskl-intel_asm.o aesni-intel_asm.o aeskl-intel_glue.o + obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o sha1-ssse3-y := sha1_avx2_x86_64_asm.o sha1_ssse3_asm.o sha1_ssse3_glue.o sha1-ssse3-$(CONFIG_AS_SHA1_NI) += sha1_ni_asm.o diff --git a/arch/x86/crypto/aeskl-intel_asm.S b/arch/x86/crypto/aeskl-intel_asm.S new file mode 100644 index 000000000000..80ddeda11bdf --- /dev/null +++ b/arch/x86/crypto/aeskl-intel_asm.S @@ -0,0 +1,881 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Implement AES algorithm using Intel AES Key Locker instructions. + * + * Most codes are based from AES-NI implementation, aesni-intel_asm.S + * + */ + +#include +#include +#include + +#define STATE1 %xmm0 +#define STATE2 %xmm1 +#define STATE3 %xmm2 +#define STATE4 %xmm3 +#define STATE5 %xmm4 +#define STATE6 %xmm5 +#define STATE7 %xmm6 +#define STATE8 %xmm7 +#define STATE STATE1 + +#ifdef __x86_64__ +#define IN1 %xmm8 +#define IN2 %xmm9 +#define IN3 %xmm10 +#define IN4 %xmm11 +#define IN5 %xmm12 +#define IN6 %xmm13 +#define IN7 %xmm14 +#define IN8 %xmm15 +#define IN IN1 +#else +#define IN %xmm1 +#endif + +#ifdef __x86_64__ +#define AREG %rax +#define HANDLEP %rdi +#define OUTP %rsi +#define KLEN %r9d +#define INP %rdx +#define T1 %r10 +#define LEN %rcx +#define IVP %r8 +#else +#define AREG %eax +#define HANDLEP %edi +#define OUTP AREG +#define KLEN %ebx +#define INP %edx +#define T1 %ecx +#define LEN %esi +#define IVP %ebp +#endif + +#define UKEYP OUTP + +/* + * int __aeskl_setkey(struct crypto_aes_ctx *ctx, + * const u8 *in_key, + * unsigned int key_len) + */ +SYM_FUNC_START(__aeskl_setkey) + FRAME_BEGIN +#ifndef __x86_64__ + push HANDLEP + movl (FRAME_OFFSET+8)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+12)(%esp), UKEYP # in_key + movl (FRAME_OFFSET+16)(%esp), %edx # key_len +#endif + movl %edx, 480(HANDLEP) + movdqu (UKEYP), STATE1 + mov $1, %eax + cmp $16, %dl + je .Lsetkey_128 + + movdqu 0x10(UKEYP), STATE2 + ENCODEKEY256 %eax, %eax + movdqu STATE4, 0x30(HANDLEP) + jmp .Lsetkey_end +.Lsetkey_128: + ENCODEKEY128 %eax, %eax + +.Lsetkey_end: + movdqu STATE1, (HANDLEP) + movdqu STATE2, 0x10(HANDLEP) + movdqu STATE3, 0x20(HANDLEP) + + xor AREG, AREG +#ifndef __x86_64__ + popl HANDLEP +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_setkey) + +/* + * int __aeskl_enc1(const void *ctx, + * u8 *dst, + * const u8 *src) + */ +SYM_FUNC_START(__aeskl_enc1) + FRAME_BEGIN +#ifndef __x86_64__ + pushl HANDLEP + pushl KLEN + movl (FRAME_OFFSET+12)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+16)(%esp), OUTP # dst + movl (FRAME_OFFSET+20)(%esp), INP # src +#endif + movdqu (INP), STATE + movl 480(HANDLEP), KLEN + + cmp $16, KLEN + je .Lenc_128 + AESENC256KL HANDLEP, STATE + jz .Lenc_err + jmp .Lenc_noerr +.Lenc_128: + AESENC128KL HANDLEP, STATE + jz .Lenc_err + +.Lenc_noerr: + xor AREG, AREG + jmp .Lenc_end +.Lenc_err: + mov $1, AREG +.Lenc_end: + movdqu STATE, (OUTP) +#ifndef __x86_64__ + popl KLEN + popl HANDLEP +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_enc1) + +/* + * int __aeskl_dec1(const void *ctx, + * u8 *dst, + * const u8 *src) + */ +SYM_FUNC_START(__aeskl_dec1) + FRAME_BEGIN +#ifndef __x86_64__ + pushl HANDLEP + pushl KLEN + movl (FRAME_OFFSET+12)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+16)(%esp), OUTP # dst + movl (FRAME_OFFSET+20)(%esp), INP # src +#endif + movdqu (INP), STATE + mov 480(HANDLEP), KLEN + + cmp $16, KLEN + je .Ldec_128 + AESDEC256KL HANDLEP, STATE + jz .Ldec_err + jmp .Ldec_noerr +.Ldec_128: + AESDEC128KL HANDLEP, STATE + jz .Ldec_err + +.Ldec_noerr: + xor AREG, AREG + jmp .Ldec_end +.Ldec_err: + mov $1, AREG +.Ldec_end: + movdqu STATE, (OUTP) +#ifndef __x86_64__ + popl KLEN + popl HANDLEP +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_dec1) + +/* + * int __aeskl_ecb_enc(struct crypto_aes_ctx *ctx, + * const u8 *dst, + * u8 *src, + * size_t len) + */ +SYM_FUNC_START(__aeskl_ecb_enc) + FRAME_BEGIN +#ifndef __x86_64__ + pushl LEN + pushl HANDLEP + pushl KLEN + movl (FRAME_OFFSET+16)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+20)(%esp), OUTP # dst + movl (FRAME_OFFSET+24)(%esp), INP # src + movl (FRAME_OFFSET+28)(%esp), LEN # len +#endif + test LEN, LEN + jz .Lecb_enc_noerr + mov 480(HANDLEP), KLEN + cmp $16, LEN + jb .Lecb_enc_noerr + cmp $128, LEN + jb .Lecb_enc1 + +.align 4 +.Lecb_enc8: + movdqu (INP), STATE1 + movdqu 0x10(INP), STATE2 + movdqu 0x20(INP), STATE3 + movdqu 0x30(INP), STATE4 + movdqu 0x40(INP), STATE5 + movdqu 0x50(INP), STATE6 + movdqu 0x60(INP), STATE7 + movdqu 0x70(INP), STATE8 + + cmp $16, KLEN + je .Lecb_enc8_128 + AESENCWIDE256KL HANDLEP + jz .Lecb_enc_err + jmp .Lecb_enc8_end +.Lecb_enc8_128: + AESENCWIDE128KL HANDLEP + jz .Lecb_enc_err + +.Lecb_enc8_end: + movdqu STATE1, (OUTP) + movdqu STATE2, 0x10(OUTP) + movdqu STATE3, 0x20(OUTP) + movdqu STATE4, 0x30(OUTP) + movdqu STATE5, 0x40(OUTP) + movdqu STATE6, 0x50(OUTP) + movdqu STATE7, 0x60(OUTP) + movdqu STATE8, 0x70(OUTP) + + sub $128, LEN + add $128, INP + add $128, OUTP + cmp $128, LEN + jge .Lecb_enc8 + cmp $16, LEN + jb .Lecb_enc_noerr + +.align 4 +.Lecb_enc1: + movdqu (INP), STATE1 + cmp $16, KLEN + je .Lecb_enc1_128 + AESENC256KL HANDLEP, STATE + jz .Lecb_enc_err + jmp .Lecb_enc1_end +.Lecb_enc1_128: + AESENC128KL HANDLEP, STATE + jz .Lecb_enc_err + +.Lecb_enc1_end: + movdqu STATE1, (OUTP) + sub $16, LEN + add $16, INP + add $16, OUTP + cmp $16, LEN + jge .Lecb_enc1 + +.Lecb_enc_noerr: + xor AREG, AREG + jmp .Lecb_enc_end +.Lecb_enc_err: + mov $1, AREG +.Lecb_enc_end: +#ifndef __x86_64__ + popl KLEN + popl HANDLEP + popl LEN +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_ecb_enc) + +/* + * int __aeskl_ecb_dec(struct crypto_aes_ctx *ctx, + * const u8 *dst, + * u8 *src, + * size_t len); + */ +SYM_FUNC_START(__aeskl_ecb_dec) + FRAME_BEGIN +#ifndef __x86_64__ + pushl LEN + pushl HANDLEP + pushl KLEN + movl (FRAME_OFFSET+16)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+20)(%esp), OUTP # dst + movl (FRAME_OFFSET+24)(%esp), INP # src + movl (FRAME_OFFSET+28)(%esp), LEN # len +#endif + + test LEN, LEN + jz .Lecb_dec_noerr + mov 480(HANDLEP), KLEN + cmp $16, LEN + jb .Lecb_dec_noerr + cmp $128, LEN + jb .Lecb_dec1 + +.align 4 +.Lecb_dec8: + movdqu (INP), STATE1 + movdqu 0x10(INP), STATE2 + movdqu 0x20(INP), STATE3 + movdqu 0x30(INP), STATE4 + movdqu 0x40(INP), STATE5 + movdqu 0x50(INP), STATE6 + movdqu 0x60(INP), STATE7 + movdqu 0x70(INP), STATE8 + + cmp $16, KLEN + je .Lecb_dec8_128 + AESDECWIDE256KL HANDLEP + jz .Lecb_dec_err + jmp .Lecb_dec8_end +.Lecb_dec8_128: + AESDECWIDE128KL HANDLEP + jz .Lecb_dec_err + +.Lecb_dec8_end: + movdqu STATE1, (OUTP) + movdqu STATE2, 0x10(OUTP) + movdqu STATE3, 0x20(OUTP) + movdqu STATE4, 0x30(OUTP) + movdqu STATE5, 0x40(OUTP) + movdqu STATE6, 0x50(OUTP) + movdqu STATE7, 0x60(OUTP) + movdqu STATE8, 0x70(OUTP) + + sub $128, LEN + add $128, INP + add $128, OUTP + cmp $128, LEN + jge .Lecb_dec8 + cmp $16, LEN + jb .Lecb_dec_noerr + +.align 4 +.Lecb_dec1: + movdqu (INP), STATE1 + cmp $16, KLEN + je .Lecb_dec1_128 + AESDEC256KL HANDLEP, STATE + jz .Lecb_dec_err + jmp .Lecb_dec1_end +.Lecb_dec1_128: + AESDEC128KL HANDLEP, STATE + jz .Lecb_dec_err + +.Lecb_dec1_end: + movdqu STATE1, (OUTP) + sub $16, LEN + add $16, INP + add $16, OUTP + cmp $16, LEN + jge .Lecb_dec1 + +.Lecb_dec_noerr: + xor AREG, AREG + jmp .Lecb_dec_end +.Lecb_dec_err: + mov $1, AREG +.Lecb_dec_end: +#ifndef __x86_64__ + popl KLEN + popl HANDLEP + popl LEN +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_ecb_dec) + +/* + * int __aeskl_cbc_enc(struct crypto_aes_ctx *ctx, + * const u8 *dst, + * u8 *src, + * size_t len, + * u8 *iv) + */ +SYM_FUNC_START(__aeskl_cbc_enc) + FRAME_BEGIN +#ifndef __x86_64__ + pushl IVP + pushl LEN + pushl HANDLEP + pushl KLEN + movl (FRAME_OFFSET+20)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+24)(%esp), OUTP # dst + movl (FRAME_OFFSET+28)(%esp), INP # src + movl (FRAME_OFFSET+32)(%esp), LEN # len + movl (FRAME_OFFSET+36)(%esp), IVP # iv +#endif + + cmp $16, LEN + jb .Lcbc_enc_noerr + mov 480(HANDLEP), KLEN + movdqu (IVP), STATE + +.align 4 +.Lcbc_enc1: + movdqu (INP), IN + pxor IN, STATE + + cmp $16, KLEN + je .Lcbc_enc1_128 + AESENC256KL HANDLEP, STATE + jz .Lcbc_enc_err + jmp .Lcbc_enc1_end +.Lcbc_enc1_128: + AESENC128KL HANDLEP, STATE + jz .Lcbc_enc_err + +.Lcbc_enc1_end: + movdqu STATE, (OUTP) + sub $16, LEN + add $16, INP + add $16, OUTP + cmp $16, LEN + jge .Lcbc_enc1 + movdqu STATE, (IVP) + +.Lcbc_enc_noerr: + xor AREG, AREG + jmp .Lcbc_enc_end +.Lcbc_enc_err: + mov $1, AREG +.Lcbc_enc_end: +#ifndef __x86_64__ + popl KLEN + popl HANDLEP + popl LEN + popl IVP +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_cbc_enc) + +/* + * int __aeskl_cbc_dec(struct crypto_aes_ctx *ctx, + * const u8 *dst, + * u8 *src, + * size_t len, + * u8 *iv) + */ +SYM_FUNC_START(__aeskl_cbc_dec) + FRAME_BEGIN +#ifndef __x86_64__ + pushl IVP + pushl LEN + pushl HANDLEP + pushl KLEN + movl (FRAME_OFFSET+20)(%esp), HANDLEP # ctx + movl (FRAME_OFFSET+24)(%esp), OUTP # dst + movl (FRAME_OFFSET+28)(%esp), INP # src + movl (FRAME_OFFSET+32)(%esp), LEN # len + movl (FRAME_OFFSET+36)(%esp), IVP # iv +#endif + + cmp $16, LEN + jb .Lcbc_dec_noerr + mov 480(HANDLEP), KLEN +#ifdef __x86_64__ + cmp $128, LEN + jb .Lcbc_dec1_pre + +.align 4 +.Lcbc_dec8: + movdqu 0x0(INP), STATE1 + movdqu 0x10(INP), STATE2 + movdqu 0x20(INP), STATE3 + movdqu 0x30(INP), STATE4 + movdqu 0x40(INP), STATE5 + movdqu 0x50(INP), STATE6 + movdqu 0x60(INP), STATE7 + movdqu 0x70(INP), STATE8 + + movdqu (IVP), IN1 + movdqa STATE1, IN2 + movdqa STATE2, IN3 + movdqa STATE3, IN4 + movdqa STATE4, IN5 + movdqa STATE5, IN6 + movdqa STATE6, IN7 + movdqa STATE7, IN8 + movdqu STATE8, (IVP) + + cmp $16, KLEN + je .Lcbc_dec8_128 + AESDECWIDE256KL HANDLEP + jz .Lcbc_dec_err + jmp .Lcbc_dec8_end +.Lcbc_dec8_128: + AESDECWIDE128KL HANDLEP + jz .Lcbc_dec_err + +.Lcbc_dec8_end: + pxor IN1, STATE1 + pxor IN2, STATE2 + pxor IN3, STATE3 + pxor IN4, STATE4 + pxor IN5, STATE5 + pxor IN6, STATE6 + pxor IN7, STATE7 + pxor IN8, STATE8 + + movdqu STATE1, 0x0(OUTP) + movdqu STATE2, 0x10(OUTP) + movdqu STATE3, 0x20(OUTP) + movdqu STATE4, 0x30(OUTP) + movdqu STATE5, 0x40(OUTP) + movdqu STATE6, 0x50(OUTP) + movdqu STATE7, 0x60(OUTP) + movdqu STATE8, 0x70(OUTP) + + sub $128, LEN + add $128, INP + add $128, OUTP + cmp $128, LEN + jge .Lcbc_dec8 + cmp $16, LEN + jb .Lcbc_dec_noerr +#endif + +.align 4 +.Lcbc_dec1_pre: + movdqu (IVP), STATE3 +.Lcbc_dec1: + movdqu (INP), STATE2 + movdqa STATE2, STATE1 + + cmp $16, KLEN + je .Lcbc_dec1_128 + AESDEC256KL HANDLEP, STATE1 + jz .Lcbc_dec_err + jmp .Lcbc_dec1_end +.Lcbc_dec1_128: + AESDEC128KL HANDLEP, STATE1 + jz .Lcbc_dec_err + +.Lcbc_dec1_end: + pxor STATE3, STATE1 + movdqu STATE1, (OUTP) + movdqa STATE2, STATE3 + sub $16, LEN + add $16, INP + add $16, OUTP + cmp $16, LEN + jge .Lcbc_dec1 + movdqu STATE3, (IVP) + +.Lcbc_dec_noerr: + xor AREG, AREG + jmp .Lcbc_dec_end +.Lcbc_dec_err: + mov $1, AREG +.Lcbc_dec_end: +#ifndef __x86_64__ + popl KLEN + popl HANDLEP + popl LEN + popl IVP +#endif + FRAME_END + ret +SYM_FUNC_END(__aeskl_cbc_dec) + + +#ifdef __x86_64__ + +/* + * CTR implementations + */ + +.pushsection .rodata +.align 16 +.Lbswap_mask: + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +.popsection + +.section .rodata.cst16.gf128mul_x_ble_mask, "aM", @progbits, 16 +.align 16 +.Lgf128mul_x_ble_mask: + .octa 0x00000000000000010000000000000087 + +#define BSWAP_MASK %xmm10 +#define CTR %xmm11 +#define INC %xmm12 +#define IV %xmm13 +#define TCTR_LOW %r11 + +.text +.align 4 +__aeskl_ctr_init: + movdqa .Lbswap_mask, BSWAP_MASK + movdqa IV, CTR + pshufb BSWAP_MASK, CTR + mov $1, TCTR_LOW + movq TCTR_LOW, INC + movq CTR, TCTR_LOW + ret +SYM_FUNC_END(__aeskl_ctr_init) + +.align 4 +__aeskl_ctr_inc: + paddq INC, CTR + add $1, TCTR_LOW + jnc .Lctr_inc_low + pslldq $8, INC + paddq INC, CTR + psrldq $8, INC +.Lctr_inc_low: + movdqa CTR, IV + pshufb BSWAP_MASK, IV + ret +SYM_FUNC_END(__aeskl_ctr_inc) + +/* + * int __aeskl_ctr_enc(struct crypto_aes_ctx *ctx, + * const u8 *dst, + * u8 *src, + * size_t len, + * u8 *iv) + */ +SYM_FUNC_START(__aeskl_ctr_enc) + FRAME_BEGIN + cmp $16, LEN + jb .Lctr_enc_noerr + mov 480(HANDLEP), KLEN + movdqu (IVP), IV + call __aeskl_ctr_init + cmp $128, LEN + jb .Lctr_enc1 + +.align 4 +.Lctr_enc8: + movdqa IV, STATE1 + call __aeskl_ctr_inc + movdqa IV, STATE2 + call __aeskl_ctr_inc + movdqa IV, STATE3 + call __aeskl_ctr_inc + movdqa IV, STATE4 + call __aeskl_ctr_inc + movdqa IV, STATE5 + call __aeskl_ctr_inc + movdqa IV, STATE6 + call __aeskl_ctr_inc + movdqa IV, STATE7 + call __aeskl_ctr_inc + movdqa IV, STATE8 + call __aeskl_ctr_inc + + cmp $16, KLEN + je .Lctr_enc8_128 + AESENCWIDE256KL %rdi + jz .Lctr_enc_err + jmp .Lctr_enc8_end +.Lctr_enc8_128: + AESENCWIDE128KL %rdi + jz .Lctr_enc_err +.Lctr_enc8_end: + + movdqu (INP), IN1 + pxor IN1, STATE1 + movdqu STATE1, (OUTP) + + movdqu 0x10(INP), IN1 + pxor IN1, STATE2 + movdqu STATE2, 0x10(OUTP) + + movdqu 0x20(INP), IN1 + pxor IN1, STATE3 + movdqu STATE3, 0x20(OUTP) + + movdqu 0x30(INP), IN1 + pxor IN1, STATE4 + movdqu STATE4, 0x30(OUTP) + + movdqu 0x40(INP), IN1 + pxor IN1, STATE5 + movdqu STATE5, 0x40(OUTP) + + movdqu 0x50(INP), IN1 + pxor IN1, STATE6 + movdqu STATE6, 0x50(OUTP) + + movdqu 0x60(INP), IN1 + pxor IN1, STATE7 + movdqu STATE7, 0x60(OUTP) + + movdqu 0x70(INP), IN1 + pxor IN1, STATE8 + movdqu STATE8, 0x70(OUTP) + + sub $128, LEN + add $128, INP + add $128, OUTP + cmp $128, LEN + jge .Lctr_enc8 + cmp $16, LEN + jb .Lctr_enc_end + +.align 4 +.Lctr_enc1: + movdqa IV, STATE + call __aeskl_ctr_inc + + cmp $16, KLEN + je .Lctr_enc1_128 + AESENC256KL HANDLEP, STATE + jmp .Lctr_enc1_end +.Lctr_enc1_128: + AESENC128KL HANDLEP, STATE + +.Lctr_enc1_end: + movdqu (INP), IN + pxor IN, STATE + movdqu STATE, (OUTP) + sub $16, LEN + add $16, INP + add $16, OUTP + cmp $16, LEN + jge .Lctr_enc1 + +.Lctr_enc_end: + movdqu IV, (IVP) +.Lctr_enc_noerr: + xor AREG, AREG + jmp .Lctr_enc_ret +.Lctr_enc_err: + mov $1, AREG +.Lctr_enc_ret: + FRAME_END + ret +SYM_FUNC_END(__aeskl_ctr_enc) + +/* + * XTS implementation + */ +#define GF128MUL_MASK %xmm10 + +#define __aeskl_gf128mul_x_ble() \ + pshufd $0x13, IV, CTR; \ + paddq IV, IV; \ + psrad $31, CTR; \ + pand GF128MUL_MASK, CTR; \ + pxor CTR, IV; + +/* + * int __aeskl_xts_crypt8(const struct crypto_aes_ctx *ctx, + * const u8 *dst, + * u8 *src, + * bool enc, + * u8 *iv) + */ +SYM_FUNC_START(__aeskl_xts_crypt8) + FRAME_BEGIN + + movdqa .Lgf128mul_x_ble_mask, GF128MUL_MASK + movdqu (IVP), IV + + mov 480(HANDLEP), KLEN + + movdqa IV, STATE1 + movdqu (INP), INC + pxor INC, STATE1 + movdqu IV, (OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE2 + movdqu 0x10(INP), INC + pxor INC, STATE2 + movdqu IV, 0x10(OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE3 + movdqu 0x20(INP), INC + pxor INC, STATE3 + movdqu IV, 0x20(OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE4 + movdqu 0x30(INP), INC + pxor INC, STATE4 + movdqu IV, 0x30(OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE5 + movdqu 0x40(INP), INC + pxor INC, STATE5 + movdqu IV, 0x40(OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE6 + movdqu 0x50(INP), INC + pxor INC, STATE6 + movdqu IV, 0x50(OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE7 + movdqu 0x60(INP), INC + pxor INC, STATE7 + movdqu IV, 0x60(OUTP) + + __aeskl_gf128mul_x_ble() + movdqa IV, STATE8 + movdqu 0x70(INP), INC + pxor INC, STATE8 + movdqu IV, 0x70(OUTP) + + cmpb $0, %cl + je .Lxts_dec8 + cmp $16, KLEN + je .Lxts_enc8_128 + AESENCWIDE256KL %rdi + jz .Lxts_err + jmp .Lxts_crypt8_end +.Lxts_enc8_128: + AESENCWIDE128KL %rdi + jz .Lxts_err + jmp .Lxts_crypt8_end +.Lxts_dec8: + cmp $16, KLEN + je .Lxts_dec8_128 + AESDECWIDE256KL %rdi + jz .Lxts_err + jmp .Lxts_crypt8_end +.Lxts_dec8_128: + AESDECWIDE128KL %rdi + jz .Lxts_err + +.Lxts_crypt8_end: + movdqu 0x00(OUTP), INC + pxor INC, STATE1 + movdqu STATE1, 0x00(OUTP) + + movdqu 0x10(OUTP), INC + pxor INC, STATE2 + movdqu STATE2, 0x10(OUTP) + + movdqu 0x20(OUTP), INC + pxor INC, STATE3 + movdqu STATE3, 0x20(OUTP) + + movdqu 0x30(OUTP), INC + pxor INC, STATE4 + movdqu STATE4, 0x30(OUTP) + + movdqu 0x40(OUTP), INC + pxor INC, STATE5 + movdqu STATE5, 0x40(OUTP) + + movdqu 0x50(OUTP), INC + pxor INC, STATE6 + movdqu STATE6, 0x50(OUTP) + + movdqu 0x60(OUTP), INC + pxor INC, STATE7 + movdqu STATE7, 0x60(OUTP) + + movdqu 0x70(OUTP), INC + pxor INC, STATE8 + movdqu STATE8, 0x70(OUTP) + + __aeskl_gf128mul_x_ble() + movdqu IV, (IVP) + + xor AREG, AREG + jmp .Lxts_end +.Lxts_err: + mov $1, AREG +.Lxts_end: + FRAME_END + ret +SYM_FUNC_END(__aeskl_xts_crypt8) + +#endif diff --git a/arch/x86/crypto/aeskl-intel_glue.c b/arch/x86/crypto/aeskl-intel_glue.c new file mode 100644 index 000000000000..9e3f900ad4af --- /dev/null +++ b/arch/x86/crypto/aeskl-intel_glue.c @@ -0,0 +1,697 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Support for AES Key Locker instructions. This file contains glue + * code, the real AES implementation will be in aeskl-intel_asm.S. + * + * Most code is based on AES-NI glue code, aesni-intel_glue.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_X86_64 +#include +#endif + +#define AESKL_ALIGN 16 +#define AESKL_ALIGN_ATTR __aligned(AESKL_ALIGN) +#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE - 1)) +#define RFC4106_HASH_SUBKEY_SZ 16 +#define AESKL_ALIGN_EXTRA ((AESKL_ALIGN - 1) & ~(CRYPTO_MINALIGN - 1)) +#define CRYPTO_AESKL_CTX_SIZE (sizeof(struct crypto_aes_ctx) + AESKL_ALIGN_EXTRA) + +struct aeskl_xts_ctx { + u8 raw_tweak_ctx[sizeof(struct crypto_aes_ctx)] AESKL_ALIGN_ATTR; + u8 raw_crypt_ctx[sizeof(struct crypto_aes_ctx)] AESKL_ALIGN_ATTR; +}; + +#define XTS_AESKL_CTX_SIZE (sizeof(struct aeskl_xts_ctx) + AESKL_ALIGN_EXTRA) + +asmlinkage int __aeskl_setkey(struct crypto_aes_ctx *ctx, const u8 *in_key, unsigned int key_len); +asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key, unsigned int key_en); + +asmlinkage int __aeskl_enc1(const void *ctx, u8 *out, const u8 *in); +asmlinkage int __aeskl_dec1(const void *ctx, u8 *out, const u8 *in); +asmlinkage void aesni_enc(const void *ctx, u8 *out, const u8 *in); +asmlinkage void aesni_dec(const void *ctx, u8 *out, const u8 *in); + +asmlinkage int __aeskl_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len); +asmlinkage int __aeskl_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len); +asmlinkage void aesni_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len); +asmlinkage void aesni_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len); + +asmlinkage int __aeskl_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, unsigned int len, u8 *iv); +asmlinkage int __aeskl_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, unsigned int len, u8 *iv); +asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, unsigned int len, u8 *iv); +asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, unsigned int len, u8 *iv); + +#ifdef CONFIG_X86_64 +asmlinkage int __aeskl_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, unsigned int len, u8 *iv); +asmlinkage void aesni_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, unsigned int len, u8 *iv); +asmlinkage int __aeskl_xts_crypt8(const struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, bool enc, u8 *iv); +asmlinkage void aesni_xts_crypt8(const struct crypto_aes_ctx *ctx, u8 *out, + const u8 *in, bool enc, u8 *iv); +#endif + +static inline void aeskl_enc1(const void *ctx, u8 *out, const u8 *in) +{ + int err; + + err = __aeskl_enc1(ctx, out, in); + if (err) + pr_err("aes-kl: invalid handle\n"); +} + +static inline void aeskl_dec1(const void *ctx, u8 *out, const u8 *in) +{ + int err; + + err = __aeskl_dec1(ctx, out, in); + if (err) + pr_err("aes-kl: invalid handle\n"); +} + +static inline struct crypto_aes_ctx *aes_ctx(void *raw_ctx) +{ + unsigned long addr = (unsigned long)raw_ctx; + unsigned long align = AESKL_ALIGN; + + if (align <= crypto_tfm_ctx_alignment()) + align = 1; + return (struct crypto_aes_ctx *)ALIGN(addr, align); +} + +static int aeskl_setkey_common(struct crypto_tfm *tfm, void *raw_ctx, const u8 *in_key, + unsigned int key_len) +{ + struct crypto_aes_ctx *ctx = aes_ctx(raw_ctx); + int err; + + if (!crypto_simd_usable()) + return -EBUSY; + + /* + * 192-bit key is not supported by Key Locker. Fall back to + * the AES-NI implementation. + */ + if (unlikely(key_len == AES_KEYSIZE_192)) { + kernel_fpu_begin(); + err = aesni_set_key(ctx, in_key, key_len); + kernel_fpu_end(); + return err; + } + + if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_256) + return -EINVAL; + + kernel_fpu_begin(); + /* Encode the key to a handle, only usable at ring 0 */ + err = __aeskl_setkey(ctx, in_key, key_len); + kernel_fpu_end(); + + return err; +} + +static int aeskl_setkey(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) +{ + return aeskl_setkey_common(tfm, crypto_tfm_ctx(tfm), in_key, key_len); +} + +static void aeskl_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); + int err = 0; + + if (!crypto_simd_usable()) + return; + + kernel_fpu_begin(); + /* 192-bit key not supported, fall back to AES-NI.*/ + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_enc(ctx, dst, src); + else + err = __aeskl_enc1(ctx, dst, src); + kernel_fpu_end(); + + if (err) + pr_err("aes-kl (encrypt): invalid handle\n"); +} + +static void aeskl_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm)); + int err = 0; + + if (!crypto_simd_usable()) + return; + + kernel_fpu_begin(); + /* 192-bit key not supported, fall back to AES-NI */ + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_dec(ctx, dst, src); + else + err = __aeskl_dec1(ctx, dst, src); + kernel_fpu_end(); + + if (err) + pr_err("aes-kl (encrypt): invalid handle\n"); +} + +static int aeskl_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int len) +{ + return aeskl_setkey_common(crypto_skcipher_tfm(tfm), + crypto_skcipher_ctx(tfm), key, len); +} + +static int ecb_encrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm; + struct crypto_aes_ctx *ctx; + struct skcipher_walk walk; + unsigned int nbytes; + int err; + + tfm = crypto_skcipher_reqtfm(req); + ctx = aes_ctx(crypto_skcipher_ctx(tfm)); + + err = skcipher_walk_virt(&walk, req, true); + if (err) + return err; + + while ((nbytes = walk.nbytes)) { + unsigned int len = nbytes & AES_BLOCK_MASK; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + + kernel_fpu_begin(); + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_ecb_enc(ctx, dst, src, len); + else + err = __aeskl_ecb_enc(ctx, dst, src, len); + kernel_fpu_end(); + + if (err) { + skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1)); + return -EINVAL; + } + + nbytes &= AES_BLOCK_SIZE - 1; + + err = skcipher_walk_done(&walk, nbytes); + if (err) + return err; + } + + return err; +} + +static int ecb_decrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm; + struct crypto_aes_ctx *ctx; + struct skcipher_walk walk; + unsigned int nbytes; + int err; + + tfm = crypto_skcipher_reqtfm(req); + ctx = aes_ctx(crypto_skcipher_ctx(tfm)); + + err = skcipher_walk_virt(&walk, req, true); + if (err) + return err; + + while ((nbytes = walk.nbytes)) { + unsigned int len = nbytes & AES_BLOCK_MASK; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + + kernel_fpu_begin(); + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_ecb_dec(ctx, dst, src, len); + else + err = __aeskl_ecb_dec(ctx, dst, src, len); + kernel_fpu_end(); + + if (err) { + skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1)); + return -EINVAL; + } + + nbytes &= AES_BLOCK_SIZE - 1; + + err = skcipher_walk_done(&walk, nbytes); + if (err) + return err; + } + + return err; +} + +static int cbc_encrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm; + struct crypto_aes_ctx *ctx; + struct skcipher_walk walk; + unsigned int nbytes; + int err; + + tfm = crypto_skcipher_reqtfm(req); + ctx = aes_ctx(crypto_skcipher_ctx(tfm)); + err = skcipher_walk_virt(&walk, req, true); + if (err) + return err; + + while ((nbytes = walk.nbytes)) { + unsigned int len = nbytes & AES_BLOCK_MASK; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 *iv = walk.iv; + + kernel_fpu_begin(); + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_cbc_enc(ctx, dst, src, len, iv); + else + err = __aeskl_cbc_enc(ctx, dst, src, len, iv); + kernel_fpu_end(); + + if (err) { + skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1)); + return -EINVAL; + } + + nbytes &= AES_BLOCK_SIZE - 1; + + err = skcipher_walk_done(&walk, nbytes); + if (err) + return err; + } + + return err; +} + +static int cbc_decrypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm; + struct crypto_aes_ctx *ctx; + struct skcipher_walk walk; + unsigned int nbytes; + int err; + + tfm = crypto_skcipher_reqtfm(req); + ctx = aes_ctx(crypto_skcipher_ctx(tfm)); + err = skcipher_walk_virt(&walk, req, true); + if (err) + return err; + + while ((nbytes = walk.nbytes)) { + unsigned int len = nbytes & AES_BLOCK_MASK; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 *iv = walk.iv; + + kernel_fpu_begin(); + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_cbc_dec(ctx, dst, src, len, iv); + else + err = __aeskl_cbc_dec(ctx, dst, src, len, iv); + kernel_fpu_end(); + + if (err) { + skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1)); + return -EINVAL; + } + + nbytes &= AES_BLOCK_SIZE - 1; + + err = skcipher_walk_done(&walk, nbytes); + if (err) + return err; + } + + return err; +} + +#ifdef CONFIG_X86_64 +static int ctr_crypt(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm; + struct crypto_aes_ctx *ctx; + struct skcipher_walk walk; + unsigned int nbytes; + int err; + + tfm = crypto_skcipher_reqtfm(req); + ctx = aes_ctx(crypto_skcipher_ctx(tfm)); + + err = skcipher_walk_virt(&walk, req, true); + if (err) + return err; + + while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { + unsigned int len = nbytes & AES_BLOCK_MASK; + const u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 *iv = walk.iv; + + kernel_fpu_begin(); + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_ctr_enc(ctx, dst, src, len, iv); + else + err = __aeskl_ctr_enc(ctx, dst, src, len, iv); + kernel_fpu_end(); + + if (err) { + skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1)); + return -EINVAL; + } + + nbytes &= AES_BLOCK_SIZE - 1; + + err = skcipher_walk_done(&walk, nbytes); + if (err) + return err; + } + + if (nbytes) { + u8 keystream[AES_BLOCK_SIZE]; + u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 *ctrblk = walk.iv; + + kernel_fpu_begin(); + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_enc(ctx, keystream, ctrblk); + else + err = __aeskl_enc1(ctx, keystream, ctrblk); + kernel_fpu_end(); + + if (err) { + skcipher_walk_done(&walk, 0); + return -EINVAL; + } + + crypto_xor(keystream, src, nbytes); + memcpy(dst, keystream, nbytes); + crypto_inc(ctrblk, AES_BLOCK_SIZE); + + err = skcipher_walk_done(&walk, 0); + } + + return err; +} + +static int aeskl_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct aeskl_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + int err; + + err = xts_verify_key(tfm, key, keylen); + if (err) + return err; + + keylen /= 2; + + /* first half of xts-key is for crypt */ + err = aeskl_setkey_common(crypto_skcipher_tfm(tfm), ctx->raw_crypt_ctx, key, keylen); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return aeskl_setkey_common(crypto_skcipher_tfm(tfm), ctx->raw_tweak_ctx, key + keylen, + keylen); +} + +static void aeskl_xts_tweak(const void *raw_ctx, u8 *out, const u8 *in) +{ + struct crypto_aes_ctx *ctx = aes_ctx((void *)raw_ctx); + + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_enc(raw_ctx, out, in); + else + aeskl_enc1(raw_ctx, out, in); +} + +static void aeskl_xts_enc1(const void *raw_ctx, u8 *dst, const u8 *src, le128 *iv) +{ + struct crypto_aes_ctx *ctx = aes_ctx((void *)raw_ctx); + common_glue_func_t fn = aeskl_enc1; + + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + fn = aesni_enc; + + glue_xts_crypt_128bit_one(raw_ctx, dst, src, iv, fn); +} + +static void aeskl_xts_dec1(const void *raw_ctx, u8 *dst, const u8 *src, le128 *iv) +{ + struct crypto_aes_ctx *ctx = aes_ctx((void *)raw_ctx); + common_glue_func_t fn = aeskl_dec1; + + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + fn = aesni_dec; + + glue_xts_crypt_128bit_one(raw_ctx, dst, src, iv, fn); +} + +static void aeskl_xts_enc8(const void *raw_ctx, u8 *dst, const u8 *src, le128 *iv) +{ + struct crypto_aes_ctx *ctx = aes_ctx((void *)raw_ctx); + int err = 0; + + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_xts_crypt8(raw_ctx, dst, src, true, (u8 *)iv); + else + err = __aeskl_xts_crypt8(raw_ctx, dst, src, true, (u8 *)iv); + + if (err) + pr_err("aes-kl (XTS encrypt): invalid handle\n"); +} + +static void aeskl_xts_dec8(const void *raw_ctx, u8 *dst, const u8 *src, le128 *iv) +{ + struct crypto_aes_ctx *ctx = aes_ctx((void *)raw_ctx); + int err = 0; + + if (unlikely(ctx->key_length == AES_KEYSIZE_192)) + aesni_xts_crypt8(raw_ctx, dst, src, false, (u8 *)iv); + else + __aeskl_xts_crypt8(raw_ctx, dst, src, false, (u8 *)iv); + + if (err) + pr_err("aes-kl (XTS decrypt): invalid handle\n"); +} + +static const struct common_glue_ctx aeskl_xts_enc = { + .num_funcs = 2, + .fpu_blocks_limit = 1, + + .funcs = { { + .num_blocks = 8, + .fn_u = { .xts = aeskl_xts_enc8 } + }, { + .num_blocks = 1, + .fn_u = { .xts = aeskl_xts_enc1 } + } } +}; + +static const struct common_glue_ctx aeskl_xts_dec = { + .num_funcs = 2, + .fpu_blocks_limit = 1, + + .funcs = { { + .num_blocks = 8, + .fn_u = { .xts = aeskl_xts_dec8 } + }, { + .num_blocks = 1, + .fn_u = { .xts = aeskl_xts_dec1 } + } } +}; + +static int xts_crypt(struct skcipher_request *req, bool decrypt) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct aeskl_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + const struct common_glue_ctx *gctx; + + if (decrypt) + gctx = &aeskl_xts_dec; + else + gctx = &aeskl_xts_enc; + + return glue_xts_req_128bit(gctx, req, aeskl_xts_tweak, + aes_ctx(ctx->raw_tweak_ctx), + aes_ctx(ctx->raw_crypt_ctx), + decrypt); +} + +static int xts_encrypt(struct skcipher_request *req) +{ + return xts_crypt(req, false); +} + +static int xts_decrypt(struct skcipher_request *req) +{ + return xts_crypt(req, true); +} +#endif + +static struct crypto_alg aeskl_cipher_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-aeskl", + .cra_priority = 301, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = CRYPTO_AESKL_CTX_SIZE, + .cra_module = THIS_MODULE, + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aeskl_setkey, + .cia_encrypt = aeskl_encrypt, + .cia_decrypt = aeskl_decrypt + } + } +}; + +static struct skcipher_alg aeskl_skciphers[] = { + { + .base = { + .cra_name = "__ecb(aes)", + .cra_driver_name = "__ecb-aes-aeskl", + .cra_priority = 401, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = CRYPTO_AESKL_CTX_SIZE, + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = aeskl_skcipher_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, { + .base = { + .cra_name = "__cbc(aes)", + .cra_driver_name = "__cbc-aes-aeskl", + .cra_priority = 401, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = CRYPTO_AESKL_CTX_SIZE, + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = aeskl_skcipher_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, +#ifdef CONFIG_X86_64 + }, { + .base = { + .cra_name = "__ctr(aes)", + .cra_driver_name = "__ctr-aes-aeskl", + .cra_priority = 401, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = 1, + .cra_ctxsize = CRYPTO_AESKL_CTX_SIZE, + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .chunksize = AES_BLOCK_SIZE, + .setkey = aeskl_skcipher_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, { + .base = { + .cra_name = "__xts(aes)", + .cra_driver_name = "__xts-aes-aeskl", + .cra_priority = 402, + .cra_flags = CRYPTO_ALG_INTERNAL, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = XTS_AESKL_CTX_SIZE, + .cra_module = THIS_MODULE, + }, + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = aeskl_xts_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, +#endif + } +}; + +static struct simd_skcipher_alg *aeskl_simd_skciphers[ARRAY_SIZE(aeskl_skciphers)]; + +static const struct x86_cpu_id aes_keylocker_cpuid[] = { + X86_MATCH_FEATURE(X86_FEATURE_AES, NULL), + X86_MATCH_FEATURE(X86_FEATURE_KEYLOCKER, NULL), + {} +}; + +static int __init aeskl_init(void) +{ + u32 eax, ebx, ecx, edx; + int err; + + if (!x86_match_cpu(aes_keylocker_cpuid)) + return -ENODEV; + + cpuid_count(KEYLOCKER_CPUID, 0, &eax, &ebx, &ecx, &edx); + if (!(ebx & KEYLOCKER_CPUID_EBX_AESKLE) || + !(eax & KEYLOCKER_CPUID_EAX_SUPERVISOR) || + !(ebx & KEYLOCKER_CPUID_EBX_WIDE)) + return -ENODEV; + + err = crypto_register_alg(&aeskl_cipher_alg); + if (err) + return err; + + err = simd_register_skciphers_compat(aeskl_skciphers, ARRAY_SIZE(aeskl_skciphers), + aeskl_simd_skciphers); + if (err) + goto unregister_algs; + + return 0; + +unregister_algs: + crypto_unregister_alg(&aeskl_cipher_alg); + + return err; +} + +static void __exit aeskl_exit(void) +{ + simd_unregister_skciphers(aeskl_skciphers, ARRAY_SIZE(aeskl_skciphers), + aeskl_simd_skciphers); + crypto_unregister_alg(&aeskl_cipher_alg); +} + +late_initcall(aeskl_init); +module_exit(aeskl_exit); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, AES Key Locker implementation"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CRYPTO("aes"); diff --git a/arch/x86/include/asm/inst.h b/arch/x86/include/asm/inst.h index bd7f02480ca1..b719a11a2905 100644 --- a/arch/x86/include/asm/inst.h +++ b/arch/x86/include/asm/inst.h @@ -122,9 +122,62 @@ #endif .endm + .macro XMM_NUM opd xmm + \opd = REG_NUM_INVALID + .ifc \xmm,%xmm0 + \opd = 0 + .endif + .ifc \xmm,%xmm1 + \opd = 1 + .endif + .ifc \xmm,%xmm2 + \opd = 2 + .endif + .ifc \xmm,%xmm3 + \opd = 3 + .endif + .ifc \xmm,%xmm4 + \opd = 4 + .endif + .ifc \xmm,%xmm5 + \opd = 5 + .endif + .ifc \xmm,%xmm6 + \opd = 6 + .endif + .ifc \xmm,%xmm7 + \opd = 7 + .endif + .ifc \xmm,%xmm8 + \opd = 8 + .endif + .ifc \xmm,%xmm9 + \opd = 9 + .endif + .ifc \xmm,%xmm10 + \opd = 10 + .endif + .ifc \xmm,%xmm11 + \opd = 11 + .endif + .ifc \xmm,%xmm12 + \opd = 12 + .endif + .ifc \xmm,%xmm13 + \opd = 13 + .endif + .ifc \xmm,%xmm14 + \opd = 14 + .endif + .ifc \xmm,%xmm15 + \opd = 15 + .endif + .endm + .macro REG_TYPE type reg R32_NUM reg_type_r32 \reg R64_NUM reg_type_r64 \reg + XMM_NUM reg_type_xmm \reg .if reg_type_r64 <> REG_NUM_INVALID \type = REG_TYPE_R64 .elseif reg_type_r32 <> REG_NUM_INVALID @@ -134,6 +187,14 @@ .endif .endm + .macro PFX_OPD_SIZE + .byte 0x66 + .endm + + .macro PFX_RPT + .byte 0xf3 + .endm + .macro PFX_REX opd1 opd2 W=0 .if ((\opd1 | \opd2) & 8) || \W .byte 0x40 | ((\opd1 & 8) >> 3) | ((\opd2 & 8) >> 1) | (\W << 3) @@ -158,6 +219,146 @@ .byte 0x0f, 0xc7 MODRM 0xc0 rdpid_opd 0x7 .endm + + .macro ENCODEKEY128 reg1 reg2 + R32_NUM encodekey128_opd1 \reg1 + R32_NUM encodekey128_opd2 \reg2 + PFX_RPT + .byte 0xf, 0x38, 0xfa + MODRM 0xc0 encodekey128_opd2 encodekey128_opd1 + .endm + + .macro ENCODEKEY256 reg1 reg2 + R32_NUM encodekey256_opd1 \reg1 + R32_NUM encodekey256_opd2 \reg2 + PFX_RPT + .byte 0x0f, 0x38, 0xfb + MODRM 0xc0 encodekey256_opd1 encodekey256_opd2 + .endm + + .macro AESENC128KL reg, xmm + REG_TYPE aesenc128kl_opd1_type \reg + .if aesenc128kl_opd1_type == REG_TYPE_R64 + R64_NUM aesenc128kl_opd1 \reg + .elseif aesenc128kl_opd1_type == REG_TYPE_R32 + R32_NUM aesenc128kl_opd1 \reg + .else + aesenc128kl_opd1 = REG_NUM_INVALID + .endif + XMM_NUM aesenc128kl_opd2 \xmm + PFX_RPT + .byte 0x0f, 0x38, 0xdc + MODRM 0x0 aesenc128kl_opd1 aesenc128kl_opd2 + .endm + + .macro AESDEC128KL reg, xmm + REG_TYPE aesdec128kl_opd1_type \reg + .if aesdec128kl_opd1_type == REG_TYPE_R64 + R64_NUM aesdec128kl_opd1 \reg + .elseif aesdec128kl_opd1_type == REG_TYPE_R32 + R32_NUM aesdec128kl_opd1 \reg + .else + aesdec128kl_opd1 = REG_NUM_INVALID + .endif + XMM_NUM aesdec128kl_opd2 \xmm + PFX_RPT + .byte 0x0f, 0x38, 0xdd + MODRM 0x0 aesdec128kl_opd1 aesdec128kl_opd2 + .endm + + .macro AESENC256KL reg, xmm + REG_TYPE aesenc256kl_opd1_type \reg + .if aesenc256kl_opd1_type == REG_TYPE_R64 + R64_NUM aesenc256kl_opd1 \reg + .elseif aesenc256kl_opd1_type == REG_TYPE_R32 + R32_NUM aesenc256kl_opd1 \reg + .else + aesenc256kl_opd1 = REG_NUM_INVALID + .endif + XMM_NUM aesenc256kl_opd2 \xmm + PFX_RPT + .byte 0x0f, 0x38, 0xde + MODRM 0x0 aesenc256kl_opd1 aesenc256kl_opd2 + .endm + + .macro AESDEC256KL reg, xmm + REG_TYPE aesdec256kl_opd1_type \reg + .if aesdec256kl_opd1_type == REG_TYPE_R64 + R64_NUM aesdec256kl_opd1 \reg + .elseif aesdec256kl_opd1_type == REG_TYPE_R32 + R32_NUM aesdec256kl_opd1 \reg + .else + aesdec256kl_opd1 = REG_NUM_INVALID + .endif + XMM_NUM aesdec256kl_opd2 \xmm + PFX_RPT + .byte 0x0f, 0x38, 0xdf + MODRM 0x0 aesdec256kl_opd1 aesdec256kl_opd2 + .endm + + .macro AESENCWIDE128KL reg + REG_TYPE aesencwide128kl_opd1_type \reg + .if aesencwide128kl_opd1_type == REG_TYPE_R64 + R64_NUM aesencwide128kl_opd1 \reg + .elseif aesencwide128kl_opd1_type == REG_TYPE_R32 + R32_NUM aesencwide128kl_opd1 \reg + .else + aesencwide128kl_opd1 = REG_NUM_INVALID + .endif + PFX_RPT + .byte 0x0f, 0x38, 0xd8 + MODRM 0x0 aesencwide128kl_opd1 0x0 + .endm + + .macro AESDECWIDE128KL reg + REG_TYPE aesdecwide128kl_opd1_type \reg + .if aesdecwide128kl_opd1_type == REG_TYPE_R64 + R64_NUM aesdecwide128kl_opd1 \reg + .elseif aesdecwide128kl_opd1_type == REG_TYPE_R32 + R32_NUM aesdecwide128kl_opd1 \reg + .else + aesdecwide128kl_opd1 = REG_NUM_INVALID + .endif + PFX_RPT + .byte 0x0f, 0x38, 0xd8 + MODRM 0x0 aesdecwide128kl_opd1 0x1 + .endm + + .macro AESENCWIDE256KL reg + REG_TYPE aesencwide256kl_opd1_type \reg + .if aesencwide256kl_opd1_type == REG_TYPE_R64 + R64_NUM aesencwide256kl_opd1 \reg + .elseif aesencwide256kl_opd1_type == REG_TYPE_R32 + R32_NUM aesencwide256kl_opd1 \reg + .else + aesencwide256kl_opd1 = REG_NUM_INVALID + .endif + PFX_RPT + .byte 0x0f, 0x38, 0xd8 + MODRM 0x0 aesencwide256kl_opd1 0x2 + .endm + + .macro AESDECWIDE256KL reg + REG_TYPE aesdecwide256kl_opd1_type \reg + .if aesdecwide256kl_opd1_type == REG_TYPE_R64 + R64_NUM aesdecwide256kl_opd1 \reg + .elseif aesdecwide256kl_opd1_type == REG_TYPE_R32 + R32_NUM aesdecwide256kl_opd1 \reg + .else + aesdecwide256kl_opd1 = REG_NUM_INVALID + .endif + PFX_RPT + .byte 0x0f, 0x38, 0xd8 + MODRM 0x0 aesdecwide256kl_opd1 0x3 + .endm + + .macro LOADIWKEY xmm1, xmm2 + XMM_NUM loadiwkey_opd1 \xmm1 + XMM_NUM loadiwkey_opd2 \xmm2 + PFX_RPT + .byte 0x0f, 0x38, 0xdc + MODRM 0xc0 loadiwkey_opd1 loadiwkey_opd2 + .endm #endif #endif diff --git a/crypto/Kconfig b/crypto/Kconfig index 094ef56ab7b4..75a184179c72 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1159,6 +1159,34 @@ config CRYPTO_AES_NI_INTEL ECB, CBC, LRW, XTS. The 64 bit version has additional acceleration for CTR. +config CRYPTO_AES_KL + tristate "AES cipher algorithms (AES-KL)" + depends on X86_KEYLOCKER + select CRYPTO_AES_NI_INTEL + help + Use AES Key Locker instructions for AES algorithm. + + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in both + hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + The AES specifies three key sizes: 128, 192 and 256 bits + + See for more information. + + For 128- and 256-bit keys, the AES cipher algorithm is + implemented by AES Key Locker instructions. This implementation + does not need an AES key once wrapped to an encoded form. For AES + compliance, 192-bit is processed by AES-NI instructions. + config CRYPTO_AES_SPARC64 tristate "AES cipher algorithms (SPARC64)" depends on SPARC64 From patchwork Wed Dec 16 17:41:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 345031 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D5B2C3526A for ; Wed, 16 Dec 2020 17:47:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0D7A224CEE for ; Wed, 16 Dec 2020 17:47:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727936AbgLPRq4 (ORCPT ); Wed, 16 Dec 2020 12:46:56 -0500 Received: from mga14.intel.com ([192.55.52.115]:47854 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727910AbgLPRqz (ORCPT ); Wed, 16 Dec 2020 12:46:55 -0500 IronPort-SDR: LY3Z26DK1FEwhmp7xe5AgpmZ7IxPalVshEHuLct1huOWi/OA39vsKt7bFxTJ+/hEjmGoqnB7Ao akO6lDjzZuXg== X-IronPort-AV: E=McAfee;i="6000,8403,9837"; a="174334339" X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="174334339" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Dec 2020 09:46:15 -0800 IronPort-SDR: 1Dtyu2ObXKQBTf8yYOrEa7eV6kN2H6QsYiIwMmQ3HxM5mLcAEkcXVp4P+UIVEKVrXVBV0OOifT BJ9ZIa7bAARw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.78,424,1599548400"; d="scan'208";a="391854238" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 16 Dec 2020 09:46:14 -0800 From: "Chang S. Bae" To: tglx@linutronix.de, mingo@kernel.org, bp@suse.de, luto@kernel.org, x86@kernel.org, herbert@gondor.apana.org.au Cc: dan.j.williams@intel.com, dave.hansen@intel.com, ravi.v.shankar@intel.com, ning.sun@intel.com, kumar.n.dwarakanath@intel.com, linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, Mark Brown , linux-doc@vger.kernel.org Subject: [RFC PATCH 8/8] x86/cpu: Support the hardware randomization option for Key Locker internal key Date: Wed, 16 Dec 2020 09:41:46 -0800 Message-Id: <20201216174146.10446-9-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201216174146.10446-1-chang.seok.bae@intel.com> References: <20201216174146.10446-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Hardware can load the internal key with randomization. random.trust_cpu determines the use of the CPU's random number generator. Take the parameter to use the CPU's internal key randomization. The backup mechanism is required to distribute the key. It is the only way to copy the (unknown) key value to other CPUs. This randomization option is disabled when hardware does not support the key backup. Signed-off-by: Chang S. Bae Cc: Mark Brown Cc: x86@kernel.org Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/x86/include/asm/keylocker.h | 2 +- arch/x86/kernel/cpu/common.c | 3 ++- arch/x86/kernel/keylocker.c | 31 ++++++++++++++++++++++++++++--- drivers/char/random.c | 6 ++++++ include/linux/random.h | 2 ++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/keylocker.h b/arch/x86/include/asm/keylocker.h index 722574c305c2..a6774ced916a 100644 --- a/arch/x86/include/asm/keylocker.h +++ b/arch/x86/include/asm/keylocker.h @@ -19,7 +19,7 @@ bool check_keylocker_readiness(void); bool load_keylocker(void); -void make_keylocker_data(void); +void make_keylocker_data(bool use_hwrand); #ifdef CONFIG_X86_KEYLOCKER void invalidate_keylocker_data(void); #else diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index ba5bd79fbac2..48881d8ea559 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -485,12 +485,13 @@ static __always_inline void setup_keylocker(struct cpuinfo_x86 *c) cr4_set_bits(X86_CR4_KEYLOCKER); if (c == &boot_cpu_data) { + bool use_hwrand = check_random_trust_cpu(); bool keyloaded; if (!check_keylocker_readiness()) goto disable_keylocker; - make_keylocker_data(); + make_keylocker_data(use_hwrand); keyloaded = load_keylocker(); if (!keyloaded) { diff --git a/arch/x86/kernel/keylocker.c b/arch/x86/kernel/keylocker.c index 229875ac80d5..e77e4c3d785e 100644 --- a/arch/x86/kernel/keylocker.c +++ b/arch/x86/kernel/keylocker.c @@ -13,6 +13,7 @@ #include static bool keybackup_available; +static bool keyhwrand_available; bool check_keylocker_readiness(void) { @@ -33,25 +34,33 @@ bool check_keylocker_readiness(void) pr_debug("x86/keylocker: no key backup support with possible S3/4\n"); return false; } + + keyhwrand_available = (ecx & KEYLOCKER_CPUID_ECX_RAND); return true; } /* Load Internal (Wrapping) Key */ #define LOADIWKEY ".byte 0xf3,0x0f,0x38,0xdc,0xd1" #define LOADIWKEY_NUM_OPERANDS 3 +#define LOADIWKEY_HWRAND_RETRY 10 static struct key { bool valid; + bool hwrand; struct reg_128_bit value[LOADIWKEY_NUM_OPERANDS]; } keydata; -void make_keylocker_data(void) +void make_keylocker_data(bool use_hwrand) { int i; for (i = 0; i < LOADIWKEY_NUM_OPERANDS; i++) get_random_bytes(&keydata.value[i], sizeof(struct reg_128_bit)); + keydata.hwrand = (use_hwrand && keyhwrand_available && keybackup_available); + if (use_hwrand && !keydata.hwrand) + pr_warn("x86/keylocker: hardware random key not fully supported\n"); + keydata.valid = true; } @@ -63,12 +72,22 @@ void invalidate_keylocker_data(void) } #define USE_SWKEY 0 +#define USE_HWRANDKEY BIT(1) bool load_keylocker(void) { struct reg_128_bit zeros = { 0 }; - u32 keysrc = USE_SWKEY; bool err = true; + u32 keysrc; + int retry; + + if (keydata.hwrand) { + keysrc = USE_HWRANDKEY; + retry = LOADIWKEY_HWRAND_RETRY; + } else { + keysrc = USE_SWKEY; + retry = 0; + } kernel_fpu_begin(); @@ -77,13 +96,19 @@ bool load_keylocker(void) "m"(keydata.value[1]), "m"(keydata.value[2])); - asm volatile (LOADIWKEY CC_SET(z) : CC_OUT(z) (err) : "a"(keysrc)); + do { + asm volatile (LOADIWKEY CC_SET(z) : CC_OUT(z) (err) : "a"(keysrc)); + retry--; + } while (err && retry >= 0); asm volatile ("movdqu %0, %%xmm0; movdqu %0, %%xmm1; movdqu %0, %%xmm2;" :: "m"(zeros)); kernel_fpu_end(); + if (keydata.hwrand) + invalidate_keylocker_data(); + return err ? false : true; } diff --git a/drivers/char/random.c b/drivers/char/random.c index 2a41b21623ae..3ee0d659ab2a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -781,6 +781,12 @@ static int __init parse_trust_cpu(char *arg) } early_param("random.trust_cpu", parse_trust_cpu); +bool check_random_trust_cpu(void) +{ + return trust_cpu; +} +EXPORT_SYMBOL(check_random_trust_cpu); + static bool crng_init_try_arch(struct crng_state *crng) { int i; diff --git a/include/linux/random.h b/include/linux/random.h index f45b8be3e3c4..f08f44988b13 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -158,4 +158,6 @@ static inline bool __init arch_get_random_long_early(unsigned long *v) } #endif +extern bool check_random_trust_cpu(void); + #endif /* _LINUX_RANDOM_H */