[v7,06/13] x86: Add early SHA support for Secure Launch early measurements
Commit Message
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
The SHA algorithms are necessary to measure configuration information into
the TPM as early as possible before using the values. This implementation
uses the established approach of #including the SHA libraries directly in
the code since the compressed kernel is not uncompressed at this point.
The SHA code here has its origins in the code from the main kernel:
commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
A modified version of this code was introduced to the lib/crypto/sha1.c
to bring it in line with the sha256 code and allow it to be pulled into the
setup kernel in the same manner as sha256 is.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/boot/compressed/Makefile | 2 +
arch/x86/boot/compressed/early_sha1.c | 12 ++++
arch/x86/boot/compressed/early_sha256.c | 6 ++
include/crypto/sha1.h | 1 +
lib/crypto/sha1.c | 81 +++++++++++++++++++++++++
5 files changed, 102 insertions(+)
create mode 100644 arch/x86/boot/compressed/early_sha1.c
create mode 100644 arch/x86/boot/compressed/early_sha256.c
Comments
On Fri, Nov 10, 2023 at 05:27:44PM -0500, Ross Philipson wrote:
> arch/x86/boot/compressed/early_sha1.c | 12 ++++
> lib/crypto/sha1.c | 81 +++++++++++++++++++++++++
It's surprising to still see this new use of SHA-1 after so many people objected
to it in the v6 patchset. It's also frustrating that the SHA-1 support is still
being obfuscated by being combined in one patch with SHA-2 support, perhaps in
an attempt to conflate the two algorithms and avoid having to give a rationale
for the inclusion of SHA-1. Finally, new functions should not be added to
lib/crypto/sha1.c unless those functions have multiple users.
- Eric
On 11/11/2023 5:44 pm, Eric Biggers wrote:
> On Fri, Nov 10, 2023 at 05:27:44PM -0500, Ross Philipson wrote:
>> arch/x86/boot/compressed/early_sha1.c | 12 ++++
>> lib/crypto/sha1.c | 81 +++++++++++++++++++++++++
> It's surprising to still see this new use of SHA-1 after so many people objected
> to it in the v6 patchset. It's also frustrating that the SHA-1 support is still
> being obfuscated by being combined in one patch with SHA-2 support, perhaps in
> an attempt to conflate the two algorithms and avoid having to give a rationale
> for the inclusion of SHA-1. Finally, new functions should not be added to
> lib/crypto/sha1.c unless those functions have multiple users.
The rational was given. Let me reiterate it.
There are real TPMs in the world that can't use SHA-2. The use of SHA-1
is necessary to support DRTM on such systems, and there are real users
of such configurations.
DRTM with SHA-1-only is a damnsight better than no DTRM, even if SHA-1
is getting a little long in the tooth.
So unless you have a credible plan to upgrade every non-SHA-2 TPM in the
world, you are deliberately breaking part of the usecase paying for the
effort of trying to upstream DRTM support into Linux.
~Andrew
On Sat, 2023-11-11 at 18:19 +0000, Andrew Cooper wrote:
> On 11/11/2023 5:44 pm, Eric Biggers wrote:
> > On Fri, Nov 10, 2023 at 05:27:44PM -0500, Ross Philipson wrote:
> > > arch/x86/boot/compressed/early_sha1.c | 12 ++++
> > > lib/crypto/sha1.c | 81
> > > +++++++++++++++++++++++++
> > It's surprising to still see this new use of SHA-1 after so many
> > people objected to it in the v6 patchset. It's also frustrating
> > that the SHA-1 support is still being obfuscated by being combined
> > in one patch with SHA-2 support, perhaps in an attempt to conflate
> > the two algorithms and avoid having to give a rationale for the
> > inclusion of SHA-1. Finally, new functions should not be added to
> > lib/crypto/sha1.c unless those functions have multiple users.
>
> The rational was given. Let me reiterate it.
>
> There are real TPMs in the world that can't use SHA-2. The use of
> SHA-1 is necessary to support DRTM on such systems, and there are
> real users of such configurations.
Given that TPM 2.0 has been shipping in bulk since Windows 10 (2015)
and is required for Windows 11 (2021), are there really such huge
numbers of TPM 1.2 systems involved in security functions?
> DRTM with SHA-1-only is a damnsight better than no DTRM, even if SHA-
> 1 is getting a little long in the tooth.
That's not the problem. The problem is that sha1 is seen as a
compromised algorithm by NIST which began deprecating it in 2011 and is
now requiring it to be removed from all systems supplied to the US
government by 2030
https://www.nist.gov/news-events/news/2022/12/nist-retires-sha-1-cryptographic-algorithm
That means we have to control all uses of sha1 in the kernel and have
an option to build without it. FIPS has an even tighter timetable: it
requires sha1 to be out by 2025.
> So unless you have a credible plan to upgrade every non-SHA-2 TPM in
> the world, you are deliberately breaking part of the usecase paying
> for the effort of trying to upstream DRTM support into Linux.
Given that most CSOs follow NIST and FIPS it seems a little strange
that there would be a huge demand for such an intricate security
protocol as Dynamic Launch on a system that can't be FIPS 140-3
certified.
James
On 11/11/2023 8:36 pm, James Bottomley wrote:
> On Sat, 2023-11-11 at 18:19 +0000, Andrew Cooper wrote:
>> On 11/11/2023 5:44 pm, Eric Biggers wrote:
>>> On Fri, Nov 10, 2023 at 05:27:44PM -0500, Ross Philipson wrote:
>>>> arch/x86/boot/compressed/early_sha1.c | 12 ++++
>>>> lib/crypto/sha1.c | 81
>>>> +++++++++++++++++++++++++
>>> It's surprising to still see this new use of SHA-1 after so many
>>> people objected to it in the v6 patchset. It's also frustrating
>>> that the SHA-1 support is still being obfuscated by being combined
>>> in one patch with SHA-2 support, perhaps in an attempt to conflate
>>> the two algorithms and avoid having to give a rationale for the
>>> inclusion of SHA-1. Finally, new functions should not be added to
>>> lib/crypto/sha1.c unless those functions have multiple users.
>> The rational was given. Let me reiterate it.
>>
>> There are real TPMs in the world that can't use SHA-2. The use of
>> SHA-1 is necessary to support DRTM on such systems, and there are
>> real users of such configurations.
> Given that TPM 2.0 has been shipping in bulk since Windows 10 (2015)
> and is required for Windows 11 (2021), are there really such huge
> numbers of TPM 1.2 systems involved in security functions?
Yes.
As ever, it's not as simple as a straight TPM version issue.
AMD's firmware-TPM2 isn't compatible with their DRTM implementation.
Users are limited to whatever headers are available on the motherboard.
Furthermore, even with a TPM2, it is the firmware (Intel TXT ACM) or
hardware (AMD SKINIT) which chooses the hash algorithms to use, and in a
lot of cases the end user doesn't get a choice.
So yes - there really are modern systems which you can't use SHA-2-only
with.
>> DRTM with SHA-1-only is a damnsight better than no DTRM, even if SHA-
>> 1 is getting a little long in the tooth.
> That's not the problem. The problem is that sha1 is seen as a
> compromised algorithm by NIST which began deprecating it in 2011 and is
> now requiring it to be removed from all systems supplied to the US
> government by 2030
This is a non-issue.
People who care about having no SHA-1 can not compile in DRTM support.
But there are people who will tolerate SHA-1 code to get DTRM support.
~Andrew
@@ -118,6 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
+vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
+
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld)
new file mode 100644
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Apertus Solutions, LLC.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/string.h>
+#include <asm/boot.h>
+#include <asm/unaligned.h>
+
+#include "../../../../lib/crypto/sha1.c"
new file mode 100644
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Apertus Solutions, LLC
+ */
+
+#include "../../../../lib/crypto/sha256.c"
@@ -42,5 +42,6 @@ extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
#define SHA1_WORKSPACE_WORDS 16
void sha1_init(__u32 *buf);
void sha1_transform(__u32 *digest, const char *data, __u32 *W);
+void sha1(const u8 *data, unsigned int len, u8 *out);
#endif /* _CRYPTO_SHA1_H */
@@ -137,4 +137,85 @@ void sha1_init(__u32 *buf)
}
EXPORT_SYMBOL(sha1_init);
+static void __sha1_transform(u32 *digest, const char *data)
+{
+ u32 ws[SHA1_WORKSPACE_WORDS];
+
+ sha1_transform(digest, data, ws);
+
+ memzero_explicit(ws, sizeof(ws));
+}
+
+static void sha1_update(struct sha1_state *sctx, const u8 *data, unsigned int len)
+{
+ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+
+ sctx->count += len;
+
+ if (likely((partial + len) >= SHA1_BLOCK_SIZE)) {
+ int blocks;
+
+ if (partial) {
+ int p = SHA1_BLOCK_SIZE - partial;
+
+ memcpy(sctx->buffer + partial, data, p);
+ data += p;
+ len -= p;
+
+ __sha1_transform(sctx->state, sctx->buffer);
+ }
+
+ blocks = len / SHA1_BLOCK_SIZE;
+ len %= SHA1_BLOCK_SIZE;
+
+ if (blocks) {
+ while (blocks--) {
+ __sha1_transform(sctx->state, data);
+ data += SHA1_BLOCK_SIZE;
+ }
+ }
+ partial = 0;
+ }
+
+ if (len)
+ memcpy(sctx->buffer + partial, data, len);
+}
+
+static void sha1_final(struct sha1_state *sctx, u8 *out)
+{
+ const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
+ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+ __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
+ __be32 *digest = (__be32 *)out;
+ int i;
+
+ sctx->buffer[partial++] = 0x80;
+ if (partial > bit_offset) {
+ memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
+ partial = 0;
+
+ __sha1_transform(sctx->state, sctx->buffer);
+ }
+
+ memset(sctx->buffer + partial, 0x0, bit_offset - partial);
+ *bits = cpu_to_be64(sctx->count << 3);
+ __sha1_transform(sctx->state, sctx->buffer);
+
+ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
+ put_unaligned_be32(sctx->state[i], digest++);
+
+ *sctx = (struct sha1_state){};
+}
+
+void sha1(const u8 *data, unsigned int len, u8 *out)
+{
+ struct sha1_state sctx = {0};
+
+ sha1_init(sctx.state);
+ sctx.count = 0;
+ sha1_update(&sctx, data, len);
+ sha1_final(&sctx, out);
+}
+EXPORT_SYMBOL(sha1);
+
MODULE_LICENSE("GPL");