From 747762564258e8812e72b6d06f4c1ebcee0d35c1 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 15 Jan 2013 15:33:41 +0000 Subject: [PATCH 24/28] pefile: Parse the "Microsoft individual code signing" data blob The PKCS#7 certificate should contain a "Microsoft individual code signing" data blob as its signed content. This blob contains a digest of the signed content of the PE binary and the OID of the digest algorithm used (typically SHA256). Signed-off-by: David Howells Reviewed-by: Kees Cook --- arch/x86/kernel/Makefile | 8 ++ arch/x86/kernel/mscode.asn1 | 28 +++++++++ arch/x86/kernel/mscode_parser.c | 123 ++++++++++++++++++++++++++++++++++++++++ arch/x86/kernel/pefile_parser.c | 6 + arch/x86/kernel/pefile_parser.h | 5 + include/linux/oid_registry.h | 7 +- 6 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 crypto/asymmetric_keys/mscode.asn1 create mode 100644 crypto/asymmetric_keys/mscode_parser.c Index: linux-2.6/include/linux/oid_registry.h =================================================================== --- linux-2.6.orig/include/linux/oid_registry.h 2014-06-17 09:12:39.031967183 -0400 +++ linux-2.6/include/linux/oid_registry.h 2014-06-17 09:15:00.572975520 -0400 @@ -52,8 +52,13 @@ enum OID { OID_md4, /* 1.2.840.113549.2.4 */ OID_md5, /* 1.2.840.113549.2.5 */ - OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ + /* Microsoft Authenticode & Software Publishing */ + OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ + OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ + OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ + + OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ OID_sha1, /* 1.3.14.3.2.26 */ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ Index: linux-2.6/arch/x86/kernel/Makefile =================================================================== --- linux-2.6.orig/arch/x86/kernel/Makefile 2014-06-17 09:14:17.502972983 -0400 +++ linux-2.6/arch/x86/kernel/Makefile 2014-06-17 09:15:00.572975520 -0400 @@ -107,7 +107,13 @@ obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o -obj-$(CONFIG_SIGNED_PE_FILE_PARSER) += pefile_parser.o + +obj-$(CONFIG_SIGNED_PE_FILE_PARSER) += pefile_parser.o mscode_parser.o mscode-asn1.o + +$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h +$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h + +clean-files += mscode-asn1.c mscode-asn1.h ### # 64 bit specific files Index: linux-2.6/arch/x86/kernel/mscode.asn1 =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6/arch/x86/kernel/mscode.asn1 2014-06-17 09:15:00.573975521 -0400 @@ -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 +} Index: linux-2.6/arch/x86/kernel/mscode_parser.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6/arch/x86/kernel/mscode_parser.c 2014-06-17 09:15:00.573975521 -0400 @@ -0,0 +1,123 @@ +/* Parse a Microsoft Individual Code Signing blob + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#define pr_fmt(fmt) "MSCODE: "fmt +#include +#include +#include +#include +#include +#include "pefile_parser.h" +#include "mscode-asn1.h" + +/* + * Parse a Microsoft Individual Code Signing blob + */ +int mscode_parse(struct pefile_context *ctx) +{ + const void *content_data; + size_t data_len; + + pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len); + + if (!content_data || !data_len) { + pr_devel("PKCS#7 message does not contain data\n"); + return -EBADMSG; + } + + 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)); + printk("MSCODE: 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) { + printk("MSCODE: 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 = HASH_ALGO_MD4; + break; + case OID_md5: + ctx->digest_algo = HASH_ALGO_MD5; + break; + case OID_sha1: + ctx->digest_algo = HASH_ALGO_SHA1; + break; + case OID_sha256: + ctx->digest_algo = HASH_ALGO_SHA256; + break; + + case OID__NR: + sprint_oid(value, vlen, buffer, sizeof(buffer)); + printk("MSCODE: Unknown OID: %s\n", buffer); + return -EBADMSG; + + default: + printk("MSCODE: 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 = value; + ctx->digest_len = vlen; + return 0; +} Index: linux-2.6/arch/x86/kernel/pefile_parser.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/pefile_parser.c 2014-06-17 09:14:46.773974708 -0400 +++ linux-2.6/arch/x86/kernel/pefile_parser.c 2014-06-17 09:15:00.573975521 -0400 @@ -205,6 +205,12 @@ int pefile_parse_verify_sig(const void * return PTR_ERR(pkcs7); ctx.pkcs7 = pkcs7; + ret = mscode_parse(&ctx); + if (ret < 0) + goto error; + pr_devel("Digest: %u [%*ph]\n", ctx.digest_len, ctx.digest_len, + ctx.digest); + ret = -ENOANO; // Not yet complete error: Index: linux-2.6/arch/x86/kernel/pefile_parser.h =================================================================== --- linux-2.6.orig/arch/x86/kernel/pefile_parser.h 2014-06-17 09:14:17.503972983 -0400 +++ linux-2.6/arch/x86/kernel/pefile_parser.h 2014-06-17 09:15:00.574975521 -0400 @@ -29,3 +29,8 @@ struct pefile_context { }; extern int pefile_parse_verify_sig(const void *pebuf, unsigned int pelen); + +/* + * mscode_parser.c + */ +extern int mscode_parse(struct pefile_context *ctx);