162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* PKCS#7 parser
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) "PKCS7: "fmt
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/oid_registry.h>
1562306a36Sopenharmony_ci#include <crypto/public_key.h>
1662306a36Sopenharmony_ci#include "pkcs7_parser.h"
1762306a36Sopenharmony_ci#include "pkcs7.asn1.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciMODULE_DESCRIPTION("PKCS#7 parser");
2062306a36Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc.");
2162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct pkcs7_parse_context {
2462306a36Sopenharmony_ci	struct pkcs7_message	*msg;		/* Message being constructed */
2562306a36Sopenharmony_ci	struct pkcs7_signed_info *sinfo;	/* SignedInfo being constructed */
2662306a36Sopenharmony_ci	struct pkcs7_signed_info **ppsinfo;
2762306a36Sopenharmony_ci	struct x509_certificate *certs;		/* Certificate cache */
2862306a36Sopenharmony_ci	struct x509_certificate **ppcerts;
2962306a36Sopenharmony_ci	unsigned long	data;			/* Start of data */
3062306a36Sopenharmony_ci	enum OID	last_oid;		/* Last OID encountered */
3162306a36Sopenharmony_ci	unsigned	x509_index;
3262306a36Sopenharmony_ci	unsigned	sinfo_index;
3362306a36Sopenharmony_ci	const void	*raw_serial;
3462306a36Sopenharmony_ci	unsigned	raw_serial_size;
3562306a36Sopenharmony_ci	unsigned	raw_issuer_size;
3662306a36Sopenharmony_ci	const void	*raw_issuer;
3762306a36Sopenharmony_ci	const void	*raw_skid;
3862306a36Sopenharmony_ci	unsigned	raw_skid_size;
3962306a36Sopenharmony_ci	bool		expect_skid;
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * Free a signed information block.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistatic void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	if (sinfo) {
4862306a36Sopenharmony_ci		public_key_signature_free(sinfo->sig);
4962306a36Sopenharmony_ci		kfree(sinfo);
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/**
5462306a36Sopenharmony_ci * pkcs7_free_message - Free a PKCS#7 message
5562306a36Sopenharmony_ci * @pkcs7: The PKCS#7 message to free
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_civoid pkcs7_free_message(struct pkcs7_message *pkcs7)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct x509_certificate *cert;
6062306a36Sopenharmony_ci	struct pkcs7_signed_info *sinfo;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (pkcs7) {
6362306a36Sopenharmony_ci		while (pkcs7->certs) {
6462306a36Sopenharmony_ci			cert = pkcs7->certs;
6562306a36Sopenharmony_ci			pkcs7->certs = cert->next;
6662306a36Sopenharmony_ci			x509_free_certificate(cert);
6762306a36Sopenharmony_ci		}
6862306a36Sopenharmony_ci		while (pkcs7->crl) {
6962306a36Sopenharmony_ci			cert = pkcs7->crl;
7062306a36Sopenharmony_ci			pkcs7->crl = cert->next;
7162306a36Sopenharmony_ci			x509_free_certificate(cert);
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci		while (pkcs7->signed_infos) {
7462306a36Sopenharmony_ci			sinfo = pkcs7->signed_infos;
7562306a36Sopenharmony_ci			pkcs7->signed_infos = sinfo->next;
7662306a36Sopenharmony_ci			pkcs7_free_signed_info(sinfo);
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci		kfree(pkcs7);
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pkcs7_free_message);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/*
8462306a36Sopenharmony_ci * Check authenticatedAttributes are provided or not provided consistently.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic int pkcs7_check_authattrs(struct pkcs7_message *msg)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct pkcs7_signed_info *sinfo;
8962306a36Sopenharmony_ci	bool want = false;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	sinfo = msg->signed_infos;
9262306a36Sopenharmony_ci	if (!sinfo)
9362306a36Sopenharmony_ci		goto inconsistent;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (sinfo->authattrs) {
9662306a36Sopenharmony_ci		want = true;
9762306a36Sopenharmony_ci		msg->have_authattrs = true;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
10162306a36Sopenharmony_ci		if (!!sinfo->authattrs != want)
10262306a36Sopenharmony_ci			goto inconsistent;
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciinconsistent:
10662306a36Sopenharmony_ci	pr_warn("Inconsistently supplied authAttrs\n");
10762306a36Sopenharmony_ci	return -EINVAL;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/**
11162306a36Sopenharmony_ci * pkcs7_parse_message - Parse a PKCS#7 message
11262306a36Sopenharmony_ci * @data: The raw binary ASN.1 encoded message to be parsed
11362306a36Sopenharmony_ci * @datalen: The size of the encoded message
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_cistruct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx;
11862306a36Sopenharmony_ci	struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
11962306a36Sopenharmony_ci	int ret;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
12262306a36Sopenharmony_ci	if (!ctx)
12362306a36Sopenharmony_ci		goto out_no_ctx;
12462306a36Sopenharmony_ci	ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
12562306a36Sopenharmony_ci	if (!ctx->msg)
12662306a36Sopenharmony_ci		goto out_no_msg;
12762306a36Sopenharmony_ci	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
12862306a36Sopenharmony_ci	if (!ctx->sinfo)
12962306a36Sopenharmony_ci		goto out_no_sinfo;
13062306a36Sopenharmony_ci	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
13162306a36Sopenharmony_ci				  GFP_KERNEL);
13262306a36Sopenharmony_ci	if (!ctx->sinfo->sig)
13362306a36Sopenharmony_ci		goto out_no_sig;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ctx->data = (unsigned long)data;
13662306a36Sopenharmony_ci	ctx->ppcerts = &ctx->certs;
13762306a36Sopenharmony_ci	ctx->ppsinfo = &ctx->msg->signed_infos;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Attempt to decode the signature */
14062306a36Sopenharmony_ci	ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
14162306a36Sopenharmony_ci	if (ret < 0) {
14262306a36Sopenharmony_ci		msg = ERR_PTR(ret);
14362306a36Sopenharmony_ci		goto out;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	ret = pkcs7_check_authattrs(ctx->msg);
14762306a36Sopenharmony_ci	if (ret < 0) {
14862306a36Sopenharmony_ci		msg = ERR_PTR(ret);
14962306a36Sopenharmony_ci		goto out;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	msg = ctx->msg;
15362306a36Sopenharmony_ci	ctx->msg = NULL;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ciout:
15662306a36Sopenharmony_ci	while (ctx->certs) {
15762306a36Sopenharmony_ci		struct x509_certificate *cert = ctx->certs;
15862306a36Sopenharmony_ci		ctx->certs = cert->next;
15962306a36Sopenharmony_ci		x509_free_certificate(cert);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ciout_no_sig:
16262306a36Sopenharmony_ci	pkcs7_free_signed_info(ctx->sinfo);
16362306a36Sopenharmony_ciout_no_sinfo:
16462306a36Sopenharmony_ci	pkcs7_free_message(ctx->msg);
16562306a36Sopenharmony_ciout_no_msg:
16662306a36Sopenharmony_ci	kfree(ctx);
16762306a36Sopenharmony_ciout_no_ctx:
16862306a36Sopenharmony_ci	return msg;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pkcs7_parse_message);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/**
17362306a36Sopenharmony_ci * pkcs7_get_content_data - Get access to the PKCS#7 content
17462306a36Sopenharmony_ci * @pkcs7: The preparsed PKCS#7 message to access
17562306a36Sopenharmony_ci * @_data: Place to return a pointer to the data
17662306a36Sopenharmony_ci * @_data_len: Place to return the data length
17762306a36Sopenharmony_ci * @_headerlen: Size of ASN.1 header not included in _data
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * Get access to the data content of the PKCS#7 message.  The size of the
18062306a36Sopenharmony_ci * header of the ASN.1 object that contains it is also provided and can be used
18162306a36Sopenharmony_ci * to adjust *_data and *_data_len to get the entire object.
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * Returns -ENODATA if the data object was missing from the message.
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_ciint pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
18662306a36Sopenharmony_ci			   const void **_data, size_t *_data_len,
18762306a36Sopenharmony_ci			   size_t *_headerlen)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	if (!pkcs7->data)
19062306a36Sopenharmony_ci		return -ENODATA;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	*_data = pkcs7->data;
19362306a36Sopenharmony_ci	*_data_len = pkcs7->data_len;
19462306a36Sopenharmony_ci	if (_headerlen)
19562306a36Sopenharmony_ci		*_headerlen = pkcs7->data_hdrlen;
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pkcs7_get_content_data);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci/*
20162306a36Sopenharmony_ci * Note an OID when we find one for later processing when we know how
20262306a36Sopenharmony_ci * to interpret it.
20362306a36Sopenharmony_ci */
20462306a36Sopenharmony_ciint pkcs7_note_OID(void *context, size_t hdrlen,
20562306a36Sopenharmony_ci		   unsigned char tag,
20662306a36Sopenharmony_ci		   const void *value, size_t vlen)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ctx->last_oid = look_up_OID(value, vlen);
21162306a36Sopenharmony_ci	if (ctx->last_oid == OID__NR) {
21262306a36Sopenharmony_ci		char buffer[50];
21362306a36Sopenharmony_ci		sprint_oid(value, vlen, buffer, sizeof(buffer));
21462306a36Sopenharmony_ci		printk("PKCS7: Unknown OID: [%lu] %s\n",
21562306a36Sopenharmony_ci		       (unsigned long)value - ctx->data, buffer);
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci	return 0;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/*
22162306a36Sopenharmony_ci * Note the digest algorithm for the signature.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_ciint pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
22462306a36Sopenharmony_ci			       unsigned char tag,
22562306a36Sopenharmony_ci			       const void *value, size_t vlen)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	switch (ctx->last_oid) {
23062306a36Sopenharmony_ci	case OID_md4:
23162306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "md4";
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	case OID_md5:
23462306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "md5";
23562306a36Sopenharmony_ci		break;
23662306a36Sopenharmony_ci	case OID_sha1:
23762306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "sha1";
23862306a36Sopenharmony_ci		break;
23962306a36Sopenharmony_ci	case OID_sha256:
24062306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "sha256";
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci	case OID_sha384:
24362306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "sha384";
24462306a36Sopenharmony_ci		break;
24562306a36Sopenharmony_ci	case OID_sha512:
24662306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "sha512";
24762306a36Sopenharmony_ci		break;
24862306a36Sopenharmony_ci	case OID_sha224:
24962306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "sha224";
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci	case OID_sm3:
25262306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "sm3";
25362306a36Sopenharmony_ci		break;
25462306a36Sopenharmony_ci	case OID_gost2012Digest256:
25562306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "streebog256";
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci	case OID_gost2012Digest512:
25862306a36Sopenharmony_ci		ctx->sinfo->sig->hash_algo = "streebog512";
25962306a36Sopenharmony_ci		break;
26062306a36Sopenharmony_ci	default:
26162306a36Sopenharmony_ci		printk("Unsupported digest algo: %u\n", ctx->last_oid);
26262306a36Sopenharmony_ci		return -ENOPKG;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * Note the public key algorithm for the signature.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_ciint pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
27162306a36Sopenharmony_ci			     unsigned char tag,
27262306a36Sopenharmony_ci			     const void *value, size_t vlen)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	switch (ctx->last_oid) {
27762306a36Sopenharmony_ci	case OID_rsaEncryption:
27862306a36Sopenharmony_ci		ctx->sinfo->sig->pkey_algo = "rsa";
27962306a36Sopenharmony_ci		ctx->sinfo->sig->encoding = "pkcs1";
28062306a36Sopenharmony_ci		break;
28162306a36Sopenharmony_ci	case OID_id_ecdsa_with_sha1:
28262306a36Sopenharmony_ci	case OID_id_ecdsa_with_sha224:
28362306a36Sopenharmony_ci	case OID_id_ecdsa_with_sha256:
28462306a36Sopenharmony_ci	case OID_id_ecdsa_with_sha384:
28562306a36Sopenharmony_ci	case OID_id_ecdsa_with_sha512:
28662306a36Sopenharmony_ci		ctx->sinfo->sig->pkey_algo = "ecdsa";
28762306a36Sopenharmony_ci		ctx->sinfo->sig->encoding = "x962";
28862306a36Sopenharmony_ci		break;
28962306a36Sopenharmony_ci	case OID_SM2_with_SM3:
29062306a36Sopenharmony_ci		ctx->sinfo->sig->pkey_algo = "sm2";
29162306a36Sopenharmony_ci		ctx->sinfo->sig->encoding = "raw";
29262306a36Sopenharmony_ci		break;
29362306a36Sopenharmony_ci	case OID_gost2012PKey256:
29462306a36Sopenharmony_ci	case OID_gost2012PKey512:
29562306a36Sopenharmony_ci		ctx->sinfo->sig->pkey_algo = "ecrdsa";
29662306a36Sopenharmony_ci		ctx->sinfo->sig->encoding = "raw";
29762306a36Sopenharmony_ci		break;
29862306a36Sopenharmony_ci	default:
29962306a36Sopenharmony_ci		printk("Unsupported pkey algo: %u\n", ctx->last_oid);
30062306a36Sopenharmony_ci		return -ENOPKG;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci	return 0;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/*
30662306a36Sopenharmony_ci * We only support signed data [RFC2315 sec 9].
30762306a36Sopenharmony_ci */
30862306a36Sopenharmony_ciint pkcs7_check_content_type(void *context, size_t hdrlen,
30962306a36Sopenharmony_ci			     unsigned char tag,
31062306a36Sopenharmony_ci			     const void *value, size_t vlen)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (ctx->last_oid != OID_signed_data) {
31562306a36Sopenharmony_ci		pr_warn("Only support pkcs7_signedData type\n");
31662306a36Sopenharmony_ci		return -EINVAL;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/*
32362306a36Sopenharmony_ci * Note the SignedData version
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_ciint pkcs7_note_signeddata_version(void *context, size_t hdrlen,
32662306a36Sopenharmony_ci				  unsigned char tag,
32762306a36Sopenharmony_ci				  const void *value, size_t vlen)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
33062306a36Sopenharmony_ci	unsigned version;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (vlen != 1)
33362306a36Sopenharmony_ci		goto unsupported;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	ctx->msg->version = version = *(const u8 *)value;
33662306a36Sopenharmony_ci	switch (version) {
33762306a36Sopenharmony_ci	case 1:
33862306a36Sopenharmony_ci		/* PKCS#7 SignedData [RFC2315 sec 9.1]
33962306a36Sopenharmony_ci		 * CMS ver 1 SignedData [RFC5652 sec 5.1]
34062306a36Sopenharmony_ci		 */
34162306a36Sopenharmony_ci		break;
34262306a36Sopenharmony_ci	case 3:
34362306a36Sopenharmony_ci		/* CMS ver 3 SignedData [RFC2315 sec 5.1] */
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	default:
34662306a36Sopenharmony_ci		goto unsupported;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return 0;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ciunsupported:
35262306a36Sopenharmony_ci	pr_warn("Unsupported SignedData version\n");
35362306a36Sopenharmony_ci	return -EINVAL;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/*
35762306a36Sopenharmony_ci * Note the SignerInfo version
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_ciint pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
36062306a36Sopenharmony_ci				  unsigned char tag,
36162306a36Sopenharmony_ci				  const void *value, size_t vlen)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
36462306a36Sopenharmony_ci	unsigned version;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (vlen != 1)
36762306a36Sopenharmony_ci		goto unsupported;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	version = *(const u8 *)value;
37062306a36Sopenharmony_ci	switch (version) {
37162306a36Sopenharmony_ci	case 1:
37262306a36Sopenharmony_ci		/* PKCS#7 SignerInfo [RFC2315 sec 9.2]
37362306a36Sopenharmony_ci		 * CMS ver 1 SignerInfo [RFC5652 sec 5.3]
37462306a36Sopenharmony_ci		 */
37562306a36Sopenharmony_ci		if (ctx->msg->version != 1)
37662306a36Sopenharmony_ci			goto version_mismatch;
37762306a36Sopenharmony_ci		ctx->expect_skid = false;
37862306a36Sopenharmony_ci		break;
37962306a36Sopenharmony_ci	case 3:
38062306a36Sopenharmony_ci		/* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
38162306a36Sopenharmony_ci		if (ctx->msg->version == 1)
38262306a36Sopenharmony_ci			goto version_mismatch;
38362306a36Sopenharmony_ci		ctx->expect_skid = true;
38462306a36Sopenharmony_ci		break;
38562306a36Sopenharmony_ci	default:
38662306a36Sopenharmony_ci		goto unsupported;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ciunsupported:
39262306a36Sopenharmony_ci	pr_warn("Unsupported SignerInfo version\n");
39362306a36Sopenharmony_ci	return -EINVAL;
39462306a36Sopenharmony_civersion_mismatch:
39562306a36Sopenharmony_ci	pr_warn("SignedData-SignerInfo version mismatch\n");
39662306a36Sopenharmony_ci	return -EBADMSG;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * Extract a certificate and store it in the context.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_ciint pkcs7_extract_cert(void *context, size_t hdrlen,
40362306a36Sopenharmony_ci		       unsigned char tag,
40462306a36Sopenharmony_ci		       const void *value, size_t vlen)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
40762306a36Sopenharmony_ci	struct x509_certificate *x509;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
41062306a36Sopenharmony_ci		pr_debug("Cert began with tag %02x at %lu\n",
41162306a36Sopenharmony_ci			 tag, (unsigned long)ctx - ctx->data);
41262306a36Sopenharmony_ci		return -EBADMSG;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* We have to correct for the header so that the X.509 parser can start
41662306a36Sopenharmony_ci	 * from the beginning.  Note that since X.509 stipulates DER, there
41762306a36Sopenharmony_ci	 * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
41862306a36Sopenharmony_ci	 * stipulates BER).
41962306a36Sopenharmony_ci	 */
42062306a36Sopenharmony_ci	value -= hdrlen;
42162306a36Sopenharmony_ci	vlen += hdrlen;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (((u8*)value)[1] == 0x80)
42462306a36Sopenharmony_ci		vlen += 2; /* Indefinite length - there should be an EOC */
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	x509 = x509_cert_parse(value, vlen);
42762306a36Sopenharmony_ci	if (IS_ERR(x509))
42862306a36Sopenharmony_ci		return PTR_ERR(x509);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	x509->index = ++ctx->x509_index;
43162306a36Sopenharmony_ci	pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
43262306a36Sopenharmony_ci	pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	*ctx->ppcerts = x509;
43562306a36Sopenharmony_ci	ctx->ppcerts = &x509->next;
43662306a36Sopenharmony_ci	return 0;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/*
44062306a36Sopenharmony_ci * Save the certificate list
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_ciint pkcs7_note_certificate_list(void *context, size_t hdrlen,
44362306a36Sopenharmony_ci				unsigned char tag,
44462306a36Sopenharmony_ci				const void *value, size_t vlen)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	pr_devel("Got cert list (%02x)\n", tag);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	*ctx->ppcerts = ctx->msg->certs;
45162306a36Sopenharmony_ci	ctx->msg->certs = ctx->certs;
45262306a36Sopenharmony_ci	ctx->certs = NULL;
45362306a36Sopenharmony_ci	ctx->ppcerts = &ctx->certs;
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci/*
45862306a36Sopenharmony_ci * Note the content type.
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_ciint pkcs7_note_content(void *context, size_t hdrlen,
46162306a36Sopenharmony_ci		       unsigned char tag,
46262306a36Sopenharmony_ci		       const void *value, size_t vlen)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (ctx->last_oid != OID_data &&
46762306a36Sopenharmony_ci	    ctx->last_oid != OID_msIndirectData) {
46862306a36Sopenharmony_ci		pr_warn("Unsupported data type %d\n", ctx->last_oid);
46962306a36Sopenharmony_ci		return -EINVAL;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	ctx->msg->data_type = ctx->last_oid;
47362306a36Sopenharmony_ci	return 0;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/*
47762306a36Sopenharmony_ci * Extract the data from the message and store that and its content type OID in
47862306a36Sopenharmony_ci * the context.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_ciint pkcs7_note_data(void *context, size_t hdrlen,
48162306a36Sopenharmony_ci		    unsigned char tag,
48262306a36Sopenharmony_ci		    const void *value, size_t vlen)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	pr_debug("Got data\n");
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	ctx->msg->data = value;
48962306a36Sopenharmony_ci	ctx->msg->data_len = vlen;
49062306a36Sopenharmony_ci	ctx->msg->data_hdrlen = hdrlen;
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/*
49562306a36Sopenharmony_ci * Parse authenticated attributes.
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_ciint pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
49862306a36Sopenharmony_ci				      unsigned char tag,
49962306a36Sopenharmony_ci				      const void *value, size_t vlen)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
50262306a36Sopenharmony_ci	struct pkcs7_signed_info *sinfo = ctx->sinfo;
50362306a36Sopenharmony_ci	enum OID content_type;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	switch (ctx->last_oid) {
50862306a36Sopenharmony_ci	case OID_contentType:
50962306a36Sopenharmony_ci		if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
51062306a36Sopenharmony_ci			goto repeated;
51162306a36Sopenharmony_ci		content_type = look_up_OID(value, vlen);
51262306a36Sopenharmony_ci		if (content_type != ctx->msg->data_type) {
51362306a36Sopenharmony_ci			pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
51462306a36Sopenharmony_ci				ctx->msg->data_type, sinfo->index,
51562306a36Sopenharmony_ci				content_type);
51662306a36Sopenharmony_ci			return -EBADMSG;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci		return 0;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	case OID_signingTime:
52162306a36Sopenharmony_ci		if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
52262306a36Sopenharmony_ci			goto repeated;
52362306a36Sopenharmony_ci		/* Should we check that the signing time is consistent
52462306a36Sopenharmony_ci		 * with the signer's X.509 cert?
52562306a36Sopenharmony_ci		 */
52662306a36Sopenharmony_ci		return x509_decode_time(&sinfo->signing_time,
52762306a36Sopenharmony_ci					hdrlen, tag, value, vlen);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	case OID_messageDigest:
53062306a36Sopenharmony_ci		if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
53162306a36Sopenharmony_ci			goto repeated;
53262306a36Sopenharmony_ci		if (tag != ASN1_OTS)
53362306a36Sopenharmony_ci			return -EBADMSG;
53462306a36Sopenharmony_ci		sinfo->msgdigest = value;
53562306a36Sopenharmony_ci		sinfo->msgdigest_len = vlen;
53662306a36Sopenharmony_ci		return 0;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	case OID_smimeCapabilites:
53962306a36Sopenharmony_ci		if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
54062306a36Sopenharmony_ci			goto repeated;
54162306a36Sopenharmony_ci		if (ctx->msg->data_type != OID_msIndirectData) {
54262306a36Sopenharmony_ci			pr_warn("S/MIME Caps only allowed with Authenticode\n");
54362306a36Sopenharmony_ci			return -EKEYREJECTED;
54462306a36Sopenharmony_ci		}
54562306a36Sopenharmony_ci		return 0;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
54862306a36Sopenharmony_ci		 * char URLs and cont[1] 8-bit char URLs.
54962306a36Sopenharmony_ci		 *
55062306a36Sopenharmony_ci		 * Microsoft StatementType seems to contain a list of OIDs that
55162306a36Sopenharmony_ci		 * are also used as extendedKeyUsage types in X.509 certs.
55262306a36Sopenharmony_ci		 */
55362306a36Sopenharmony_ci	case OID_msSpOpusInfo:
55462306a36Sopenharmony_ci		if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
55562306a36Sopenharmony_ci			goto repeated;
55662306a36Sopenharmony_ci		goto authenticode_check;
55762306a36Sopenharmony_ci	case OID_msStatementType:
55862306a36Sopenharmony_ci		if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
55962306a36Sopenharmony_ci			goto repeated;
56062306a36Sopenharmony_ci	authenticode_check:
56162306a36Sopenharmony_ci		if (ctx->msg->data_type != OID_msIndirectData) {
56262306a36Sopenharmony_ci			pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
56362306a36Sopenharmony_ci			return -EKEYREJECTED;
56462306a36Sopenharmony_ci		}
56562306a36Sopenharmony_ci		/* I'm not sure how to validate these */
56662306a36Sopenharmony_ci		return 0;
56762306a36Sopenharmony_ci	default:
56862306a36Sopenharmony_ci		return 0;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cirepeated:
57262306a36Sopenharmony_ci	/* We permit max one item per AuthenticatedAttribute and no repeats */
57362306a36Sopenharmony_ci	pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
57462306a36Sopenharmony_ci	return -EKEYREJECTED;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/*
57862306a36Sopenharmony_ci * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_ciint pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
58162306a36Sopenharmony_ci				    unsigned char tag,
58262306a36Sopenharmony_ci				    const void *value, size_t vlen)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
58562306a36Sopenharmony_ci	struct pkcs7_signed_info *sinfo = ctx->sinfo;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
58862306a36Sopenharmony_ci	    !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
58962306a36Sopenharmony_ci		pr_warn("Missing required AuthAttr\n");
59062306a36Sopenharmony_ci		return -EBADMSG;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (ctx->msg->data_type != OID_msIndirectData &&
59462306a36Sopenharmony_ci	    test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
59562306a36Sopenharmony_ci		pr_warn("Unexpected Authenticode AuthAttr\n");
59662306a36Sopenharmony_ci		return -EBADMSG;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
60062306a36Sopenharmony_ci	sinfo->authattrs = value - (hdrlen - 1);
60162306a36Sopenharmony_ci	sinfo->authattrs_len = vlen + (hdrlen - 1);
60262306a36Sopenharmony_ci	return 0;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/*
60662306a36Sopenharmony_ci * Note the issuing certificate serial number
60762306a36Sopenharmony_ci */
60862306a36Sopenharmony_ciint pkcs7_sig_note_serial(void *context, size_t hdrlen,
60962306a36Sopenharmony_ci			  unsigned char tag,
61062306a36Sopenharmony_ci			  const void *value, size_t vlen)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
61362306a36Sopenharmony_ci	ctx->raw_serial = value;
61462306a36Sopenharmony_ci	ctx->raw_serial_size = vlen;
61562306a36Sopenharmony_ci	return 0;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci/*
61962306a36Sopenharmony_ci * Note the issuer's name
62062306a36Sopenharmony_ci */
62162306a36Sopenharmony_ciint pkcs7_sig_note_issuer(void *context, size_t hdrlen,
62262306a36Sopenharmony_ci			  unsigned char tag,
62362306a36Sopenharmony_ci			  const void *value, size_t vlen)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
62662306a36Sopenharmony_ci	ctx->raw_issuer = value;
62762306a36Sopenharmony_ci	ctx->raw_issuer_size = vlen;
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/*
63262306a36Sopenharmony_ci * Note the issuing cert's subjectKeyIdentifier
63362306a36Sopenharmony_ci */
63462306a36Sopenharmony_ciint pkcs7_sig_note_skid(void *context, size_t hdrlen,
63562306a36Sopenharmony_ci			unsigned char tag,
63662306a36Sopenharmony_ci			const void *value, size_t vlen)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	ctx->raw_skid = value;
64362306a36Sopenharmony_ci	ctx->raw_skid_size = vlen;
64462306a36Sopenharmony_ci	return 0;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci/*
64862306a36Sopenharmony_ci * Note the signature data
64962306a36Sopenharmony_ci */
65062306a36Sopenharmony_ciint pkcs7_sig_note_signature(void *context, size_t hdrlen,
65162306a36Sopenharmony_ci			     unsigned char tag,
65262306a36Sopenharmony_ci			     const void *value, size_t vlen)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
65762306a36Sopenharmony_ci	if (!ctx->sinfo->sig->s)
65862306a36Sopenharmony_ci		return -ENOMEM;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	ctx->sinfo->sig->s_size = vlen;
66162306a36Sopenharmony_ci	return 0;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/*
66562306a36Sopenharmony_ci * Note a signature information block
66662306a36Sopenharmony_ci */
66762306a36Sopenharmony_ciint pkcs7_note_signed_info(void *context, size_t hdrlen,
66862306a36Sopenharmony_ci			   unsigned char tag,
66962306a36Sopenharmony_ci			   const void *value, size_t vlen)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct pkcs7_parse_context *ctx = context;
67262306a36Sopenharmony_ci	struct pkcs7_signed_info *sinfo = ctx->sinfo;
67362306a36Sopenharmony_ci	struct asymmetric_key_id *kid;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
67662306a36Sopenharmony_ci		pr_warn("Authenticode requires AuthAttrs\n");
67762306a36Sopenharmony_ci		return -EBADMSG;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* Generate cert issuer + serial number key ID */
68162306a36Sopenharmony_ci	if (!ctx->expect_skid) {
68262306a36Sopenharmony_ci		kid = asymmetric_key_generate_id(ctx->raw_serial,
68362306a36Sopenharmony_ci						 ctx->raw_serial_size,
68462306a36Sopenharmony_ci						 ctx->raw_issuer,
68562306a36Sopenharmony_ci						 ctx->raw_issuer_size);
68662306a36Sopenharmony_ci	} else {
68762306a36Sopenharmony_ci		kid = asymmetric_key_generate_id(ctx->raw_skid,
68862306a36Sopenharmony_ci						 ctx->raw_skid_size,
68962306a36Sopenharmony_ci						 "", 0);
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci	if (IS_ERR(kid))
69262306a36Sopenharmony_ci		return PTR_ERR(kid);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	sinfo->sig->auth_ids[0] = kid;
69762306a36Sopenharmony_ci	sinfo->index = ++ctx->sinfo_index;
69862306a36Sopenharmony_ci	*ctx->ppsinfo = sinfo;
69962306a36Sopenharmony_ci	ctx->ppsinfo = &sinfo->next;
70062306a36Sopenharmony_ci	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
70162306a36Sopenharmony_ci	if (!ctx->sinfo)
70262306a36Sopenharmony_ci		return -ENOMEM;
70362306a36Sopenharmony_ci	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
70462306a36Sopenharmony_ci				  GFP_KERNEL);
70562306a36Sopenharmony_ci	if (!ctx->sinfo->sig)
70662306a36Sopenharmony_ci		return -ENOMEM;
70762306a36Sopenharmony_ci	return 0;
70862306a36Sopenharmony_ci}
709