diff mbox series

[1/5] lib: crypto: add mscode_parser

Message ID 20220705054815.30318-2-takahiro.akashi@linaro.org
State Accepted
Commit b124efc09fc5f62cc2e17d956ba3c5c9168738e8
Headers show
Series efi_loader: fix a verification process issue in secure boot | expand

Commit Message

AKASHI Takahiro July 5, 2022, 5:48 a.m. UTC
In MS authenticode, pkcs7 should have data in its contentInfo field.
This data is tagged with SpcIndirectData type and, for a signed PE image,
provides a image's message digest as SpcPeImageData.

This parser is used in image authentication to parse the field and
retrieve a message digest.

Imported from linux v5.19-rc, crypto/asymmetric_keys/mscode*.
Checkpatch.pl generates tones of warnings, but those are not fixed
for the sake of maintainability (importing from another source).

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 include/crypto/mscode.h    |  43 ++++++++++++
 lib/crypto/Kconfig         |   9 +++
 lib/crypto/Makefile        |  12 ++++
 lib/crypto/mscode.asn1     |  28 ++++++++
 lib/crypto/mscode_parser.c | 135 +++++++++++++++++++++++++++++++++++++
 5 files changed, 227 insertions(+)
 create mode 100644 include/crypto/mscode.h
 create mode 100644 lib/crypto/mscode.asn1
 create mode 100644 lib/crypto/mscode_parser.c

Comments

Jason A. Donenfeld July 5, 2022, 1:13 p.m. UTC | #1
On Tue, Jul 05, 2022 at 02:48:11PM +0900, AKASHI Takahiro wrote:
> +	  This option provides support for parsing MicroSoft's Authenticode
> +	  in pkcs7 message.

I chuckled when I saw "MicroSoft" in the cover letter, thinking it was a
wink, but here too... haha ummm. We could change it to "MikeRoweSoft"
instead in honor of the Belmont High School student. But... I think
"Microsoft" is what you're after here.

> +	pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
> +		 content_data);

That's a weird cast around (data_len), but are you sure you want to keep
that print line in there?
 
Jason
AKASHI Takahiro July 6, 2022, 1:07 a.m. UTC | #2
Hi,

On Tue, Jul 05, 2022 at 03:13:17PM +0200, Jason A. Donenfeld wrote:
> On Tue, Jul 05, 2022 at 02:48:11PM +0900, AKASHI Takahiro wrote:
> > +	  This option provides support for parsing MicroSoft's Authenticode
> > +	  in pkcs7 message.
> 
> I chuckled when I saw "MicroSoft" in the cover letter, thinking it was a
> wink, but here too... haha ummm. We could change it to "MikeRoweSoft"
> instead in honor of the Belmont High School student. But... I think

I have never heard of his name, but

> "Microsoft" is what you're after here.

If so, yes.

> > +	pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
> > +		 content_data);
> 
> That's a weird cast around (data_len), but are you sure you want to keep
> that print line in there?

My basic policy in importing a file form Linux, as far as lib/crypto/*.c is
concerned, is not to modify the original code unless it's harmful but to add
"#ifndef __UBOOT__" to exclude useless or never-used code so that someone else
other than me can easily synchronize files again in the future.

So even if it looks weird (and checkpatch.pl, which ironically comes from
Linux as well, might raise warnings), I'd like to leave it as it is.

Having said that, if maintainers have a different policy, I don't hesitate
to follow it.

Thanks,
-Takahiro Akashi

> Jason
diff mbox series

Patch

diff --git a/include/crypto/mscode.h b/include/crypto/mscode.h
new file mode 100644
index 000000000000..551058b96e60
--- /dev/null
+++ b/include/crypto/mscode.h
@@ -0,0 +1,43 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* PE Binary parser bits
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <crypto/pkcs7.h>
+#ifndef __UBOOT__
+#include <crypto/hash_info.h>
+#endif
+
+struct pefile_context {
+#ifndef __UBOOT__
+	unsigned	header_size;
+	unsigned	image_checksum_offset;
+	unsigned	cert_dirent_offset;
+	unsigned	n_data_dirents;
+	unsigned	n_sections;
+	unsigned	certs_size;
+	unsigned	sig_offset;
+	unsigned	sig_len;
+	const struct section_header *secs;
+#endif
+
+	/* PKCS#7 MS Individual Code Signing content */
+	const void	*digest;		/* Digest */
+	unsigned	digest_len;		/* Digest length */
+	const char	*digest_algo;		/* Digest algorithm */
+};
+
+#ifndef __UBOOT__
+#define kenter(FMT, ...)					\
+	pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+	pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+#endif
+
+/*
+ * mscode_parser.c
+ */
+extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
+			size_t asn1hdrlen);
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 1c04a7ec5f48..c3f563b2e174 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -82,4 +82,13 @@  config PKCS7_MESSAGE_PARSER
 config PKCS7_VERIFY
 	bool
 
+config MSCODE_PARSER
+	bool "MS authenticode parser"
+	select ASN1_DECODER
+	select ASN1_COMPILER
+	select OID_REGISTRY
+	help
+	  This option provides support for parsing MicroSoft's Authenticode
+	  in pkcs7 message.
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 6792b1d4f007..bec1bc95a658 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -55,3 +55,15 @@  obj-$(CONFIG_$(SPL_)PKCS7_VERIFY) += pkcs7_verify.o
 
 $(obj)/pkcs7_parser.o: $(obj)/pkcs7.asn1.h
 $(obj)/pkcs7.asn1.o: $(obj)/pkcs7.asn1.c $(obj)/pkcs7.asn1.h
+
+#
+# Signed PE binary-wrapped key handling
+#
+obj-$(CONFIG_$(SPL_)MSCODE_PARSER) += mscode.o
+
+mscode-y := \
+	mscode_parser.o \
+	mscode.asn1.o
+
+$(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h
+$(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h
diff --git a/lib/crypto/mscode.asn1 b/lib/crypto/mscode.asn1
new file mode 100644
index 000000000000..6d09ba48c41c
--- /dev/null
+++ b/lib/crypto/mscode.asn1
@@ -0,0 +1,28 @@ 
+--- Microsoft individual code signing data blob parser
+---
+--- Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+--- Written by David Howells (dhowells@redhat.com)
+---
+--- This program is free software; you can redistribute it and/or
+--- modify it under the terms of the GNU General Public Licence
+--- as published by the Free Software Foundation; either version
+--- 2 of the Licence, or (at your option) any later version.
+---
+
+MSCode ::= SEQUENCE {
+	type			SEQUENCE {
+		contentType	ContentType,
+		parameters	ANY
+	},
+	content			SEQUENCE {
+		digestAlgorithm	DigestAlgorithmIdentifier,
+		digest		OCTET STRING ({ mscode_note_digest })
+	}
+}
+
+ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
+
+DigestAlgorithmIdentifier ::= SEQUENCE {
+	algorithm   OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
+	parameters  ANY OPTIONAL
+}
diff --git a/lib/crypto/mscode_parser.c b/lib/crypto/mscode_parser.c
new file mode 100644
index 000000000000..90d5b37a6cf2
--- /dev/null
+++ b/lib/crypto/mscode_parser.c
@@ -0,0 +1,135 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Parse a Microsoft Individual Code Signing blob
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "MSCODE: "fmt
+#include <linux/kernel.h>
+#ifndef __UBOOT__
+#include <linux/slab.h>
+#endif
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#include <crypto/pkcs7.h>
+#ifdef __UBOOT__
+#include <crypto/mscode.h>
+#else
+#include "verify_pefile.h"
+#endif
+#include "mscode.asn1.h"
+
+/*
+ * Parse a Microsoft Individual Code Signing blob
+ */
+int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
+		 size_t asn1hdrlen)
+{
+	struct pefile_context *ctx = _ctx;
+
+	content_data -= asn1hdrlen;
+	data_len += asn1hdrlen;
+	pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
+		 content_data);
+
+	return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
+}
+
+/*
+ * Check the content type OID
+ */
+int mscode_note_content_type(void *context, size_t hdrlen,
+			     unsigned char tag,
+			     const void *value, size_t vlen)
+{
+	enum OID oid;
+
+	oid = look_up_OID(value, vlen);
+	if (oid == OID__NR) {
+		char buffer[50];
+
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_err("Unknown OID: %s\n", buffer);
+		return -EBADMSG;
+	}
+
+	/*
+	 * pesign utility had a bug where it was putting
+	 * OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
+	 * So allow both OIDs.
+	 */
+	if (oid != OID_msPeImageDataObjId &&
+	    oid != OID_msIndividualSPKeyPurpose) {
+		pr_err("Unexpected content type OID %u\n", oid);
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/*
+ * Note the digest algorithm OID
+ */
+int mscode_note_digest_algo(void *context, size_t hdrlen,
+			    unsigned char tag,
+			    const void *value, size_t vlen)
+{
+	struct pefile_context *ctx = context;
+	char buffer[50];
+	enum OID oid;
+
+	oid = look_up_OID(value, vlen);
+	switch (oid) {
+	case OID_md4:
+		ctx->digest_algo = "md4";
+		break;
+	case OID_md5:
+		ctx->digest_algo = "md5";
+		break;
+	case OID_sha1:
+		ctx->digest_algo = "sha1";
+		break;
+	case OID_sha256:
+		ctx->digest_algo = "sha256";
+		break;
+	case OID_sha384:
+		ctx->digest_algo = "sha384";
+		break;
+	case OID_sha512:
+		ctx->digest_algo = "sha512";
+		break;
+	case OID_sha224:
+		ctx->digest_algo = "sha224";
+		break;
+
+	case OID__NR:
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_err("Unknown OID: %s\n", buffer);
+		return -EBADMSG;
+
+	default:
+		pr_err("Unsupported content type: %u\n", oid);
+		return -ENOPKG;
+	}
+
+	return 0;
+}
+
+/*
+ * Note the digest we're guaranteeing with this certificate
+ */
+int mscode_note_digest(void *context, size_t hdrlen,
+		       unsigned char tag,
+		       const void *value, size_t vlen)
+{
+	struct pefile_context *ctx = context;
+
+	ctx->digest = kmemdup(value, vlen, GFP_KERNEL);
+	if (!ctx->digest)
+		return -ENOMEM;
+
+	ctx->digest_len = vlen;
+
+	return 0;
+}