1/* Parse a Microsoft Individual Code Signing blob
2 *
3 * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#define pr_fmt(fmt) "MSCODE: "fmt
13#include <linux/kernel.h>
14#include <linux/slab.h>
15#include <linux/err.h>
16#include <linux/oid_registry.h>
17#include <crypto/pkcs7.h>
18#include "verify_pefile.h"
19#include "mscode-asn1.h"
20
21/*
22 * Parse a Microsoft Individual Code Signing blob
23 */
24int mscode_parse(struct pefile_context *ctx)
25{
26	const void *content_data;
27	size_t data_len;
28	int ret;
29
30	ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
31
32	if (ret) {
33		pr_debug("PKCS#7 message does not contain data\n");
34		return ret;
35	}
36
37	pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
38		 content_data);
39
40	return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
41}
42
43/*
44 * Check the content type OID
45 */
46int mscode_note_content_type(void *context, size_t hdrlen,
47			     unsigned char tag,
48			     const void *value, size_t vlen)
49{
50	enum OID oid;
51
52	oid = look_up_OID(value, vlen);
53	if (oid == OID__NR) {
54		char buffer[50];
55
56		sprint_oid(value, vlen, buffer, sizeof(buffer));
57		pr_err("Unknown OID: %s\n", buffer);
58		return -EBADMSG;
59	}
60
61	/*
62	 * pesign utility had a bug where it was putting
63	 * OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
64	 * So allow both OIDs.
65	 */
66	if (oid != OID_msPeImageDataObjId &&
67	    oid != OID_msIndividualSPKeyPurpose) {
68		pr_err("Unexpected content type OID %u\n", oid);
69		return -EBADMSG;
70	}
71
72	return 0;
73}
74
75/*
76 * Note the digest algorithm OID
77 */
78int mscode_note_digest_algo(void *context, size_t hdrlen,
79			    unsigned char tag,
80			    const void *value, size_t vlen)
81{
82	struct pefile_context *ctx = context;
83	char buffer[50];
84	enum OID oid;
85
86	oid = look_up_OID(value, vlen);
87	switch (oid) {
88	case OID_md4:
89		ctx->digest_algo = HASH_ALGO_MD4;
90		break;
91	case OID_md5:
92		ctx->digest_algo = HASH_ALGO_MD5;
93		break;
94	case OID_sha1:
95		ctx->digest_algo = HASH_ALGO_SHA1;
96		break;
97	case OID_sha256:
98		ctx->digest_algo = HASH_ALGO_SHA256;
99		break;
100
101	case OID__NR:
102		sprint_oid(value, vlen, buffer, sizeof(buffer));
103		pr_err("Unknown OID: %s\n", buffer);
104		return -EBADMSG;
105
106	default:
107		pr_err("Unsupported content type: %u\n", oid);
108		return -ENOPKG;
109	}
110
111	return 0;
112}
113
114/*
115 * Note the digest we're guaranteeing with this certificate
116 */
117int mscode_note_digest(void *context, size_t hdrlen,
118		       unsigned char tag,
119		       const void *value, size_t vlen)
120{
121	struct pefile_context *ctx = context;
122
123	ctx->digest = value;
124	ctx->digest_len = vlen;
125	return 0;
126}
127