You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
7.0 KiB
297 lines
7.0 KiB
// 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>
|
|
//#include <linux/slab.h>
|
|
//#include <linux/err.h>
|
|
//#include <linux/oid_registry.h>
|
|
//#include <crypto/pkcs7.h>
|
|
//#include "verify_pefile.h"
|
|
//#include "mscode.asn1.h"
|
|
|
|
#include "verify_pefile.h"
|
|
#include "pkcs7.h"
|
|
#include "asn1.h"
|
|
#include "asn1_ber_bytecode.h"
|
|
#include "asn1_decoder.h"
|
|
#include "errno.h"
|
|
#include "oid_registry.h"
|
|
|
|
#include "../rewrite/Lib.SoulExtraction.rewrite.h"
|
|
|
|
#define pr_debug
|
|
#define pr_devel
|
|
#define pr_warn
|
|
#define pr_err
|
|
#define printk
|
|
|
|
#define GFP_ATOMIC /*(__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)*/ 1
|
|
#define GFP_KERNEL /*(__GFP_RECLAIM | __GFP_IO | __GFP_FS)*/ 2
|
|
#define GFP_KERNEL_ACCOUNT /*(GFP_KERNEL | __GFP_ACCOUNT)*/ 3
|
|
#define GFP_NOWAIT /*(__GFP_KSWAPD_RECLAIM)*/ 4
|
|
#define GFP_NOIO /*(__GFP_RECLAIM)*/ 5
|
|
#define GFP_NOFS /*(__GFP_RECLAIM | __GFP_IO)*/ 6
|
|
#define GFP_USER /*(__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)*/ 7
|
|
#define GFP_DMA /*__GFP_DMA*/ 8
|
|
#define GFP_DMA32 /*__GFP_DMA32*/ 9
|
|
#define GFP_HIGHUSER /*(GFP_USER | __GFP_HIGHMEM)*/ 10
|
|
#define GFP_HIGHUSER_MOVABLE /*(GFP_HIGHUSER | __GFP_MOVABLE)*/ 11
|
|
#define GFP_TRANSHUGE_LIGHT 12
|
|
#define GFP_TRANSHUGE /*(GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)*/ 13
|
|
|
|
#define ERR_PTR(err) ((void *)((long)(err)))
|
|
#define PTR_ERR(ptr) ((long)(ptr))
|
|
#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
|
|
|
|
//
|
|
// fun decla
|
|
//
|
|
|
|
/*
|
|
* Check the content type OID
|
|
*/
|
|
int
|
|
mscode_note_content_type(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
|
|
|
/*
|
|
* 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);
|
|
|
|
/*
|
|
* Note the digest algorithm OID
|
|
*/
|
|
int
|
|
mscode_note_digest_algo(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen);
|
|
|
|
//
|
|
// enum
|
|
//
|
|
|
|
enum mscode_actions
|
|
{
|
|
ACT_mscode_note_content_type = 0,
|
|
ACT_mscode_note_digest = 1,
|
|
ACT_mscode_note_digest_algo = 2,
|
|
NR__mscode_actions = 3
|
|
};
|
|
|
|
//
|
|
// global
|
|
//
|
|
|
|
static const asn1_action_t mscode_action_table[NR__mscode_actions] = {
|
|
mscode_note_content_type,
|
|
mscode_note_digest,
|
|
mscode_note_digest_algo,
|
|
};
|
|
|
|
static const unsigned char mscode_machine[] = {
|
|
// MSCode
|
|
ASN1_OP_MATCH,
|
|
_tag(UNIV, CONS, SEQ),
|
|
ASN1_OP_MATCH, // type
|
|
_tag(UNIV, CONS, SEQ),
|
|
// ContentType
|
|
ASN1_OP_MATCH_ACT,
|
|
_tag(UNIV, PRIM, OID),
|
|
_action(ACT_mscode_note_content_type),
|
|
ASN1_OP_MATCH_ANY, // parameters
|
|
ASN1_OP_END_SEQ,
|
|
ASN1_OP_MATCH, // content
|
|
_tag(UNIV, CONS, SEQ),
|
|
// DigestAlgorithmIdentifier
|
|
ASN1_OP_MATCH,
|
|
_tag(UNIV, CONS, SEQ),
|
|
ASN1_OP_MATCH_ACT, // algorithm
|
|
_tag(UNIV, PRIM, OID),
|
|
_action(ACT_mscode_note_digest_algo),
|
|
ASN1_OP_MATCH_ANY_OR_SKIP, // parameters
|
|
ASN1_OP_END_SEQ,
|
|
ASN1_OP_MATCH_ACT, // digest
|
|
_tag(UNIV, PRIM, OTS),
|
|
_action(ACT_mscode_note_digest),
|
|
ASN1_OP_END_SEQ,
|
|
ASN1_OP_END_SEQ,
|
|
ASN1_OP_COMPLETE,
|
|
};
|
|
|
|
const struct asn1_decoder mscode_decoder = {
|
|
mscode_machine,
|
|
sizeof(mscode_machine),
|
|
mscode_action_table,
|
|
};
|
|
|
|
/*
|
|
* 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 = (void *)((unsigned char *)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)
|
|
{
|
|
char tmp1[] = {// md4
|
|
'm',
|
|
'd',
|
|
'4',
|
|
0};
|
|
|
|
char tmp2[] = {// md5
|
|
'm',
|
|
'd',
|
|
'5',
|
|
0};
|
|
|
|
char tmp3[] = {// sha1
|
|
's',
|
|
'h',
|
|
'a',
|
|
'1',
|
|
0};
|
|
|
|
char tmp4[] = {// sha256
|
|
's',
|
|
'h',
|
|
'a',
|
|
'2',
|
|
'5',
|
|
'6',
|
|
0};
|
|
|
|
char tmp5[] = {// sha384
|
|
's',
|
|
'h',
|
|
'a',
|
|
'3',
|
|
'8',
|
|
'4',
|
|
0};
|
|
|
|
char tmp6[] = {// sha512
|
|
's',
|
|
'h',
|
|
'a',
|
|
'5',
|
|
'1',
|
|
'2',
|
|
0};
|
|
|
|
char tmp7[] = {// sha224
|
|
's',
|
|
'h',
|
|
'a',
|
|
'2',
|
|
'2',
|
|
'4',
|
|
0};
|
|
|
|
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 = tmp1;
|
|
break;
|
|
case OID_md5:
|
|
ctx->digest_algo = tmp2;
|
|
break;
|
|
case OID_sha1:
|
|
ctx->digest_algo = tmp3;
|
|
break;
|
|
case OID_sha256:
|
|
ctx->digest_algo = tmp4;
|
|
break;
|
|
case OID_sha384:
|
|
ctx->digest_algo = tmp5;
|
|
break;
|
|
case OID_sha512:
|
|
ctx->digest_algo = tmp6;
|
|
break;
|
|
case OID_sha224:
|
|
ctx->digest_algo = tmp7;
|
|
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;
|
|
}
|