brintos

brintos / linux-shallow public Read only

0
0
Text · 17.0 KiB · 423d13c Raw
711 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* PKCS#7 parser3 *4 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.5 * Written by David Howells (dhowells@redhat.com)6 */7 8#define pr_fmt(fmt) "PKCS7: "fmt9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/export.h>12#include <linux/slab.h>13#include <linux/err.h>14#include <linux/oid_registry.h>15#include <crypto/public_key.h>16#include "pkcs7_parser.h"17#include "pkcs7.asn1.h"18 19MODULE_DESCRIPTION("PKCS#7 parser");20MODULE_AUTHOR("Red Hat, Inc.");21MODULE_LICENSE("GPL");22 23struct pkcs7_parse_context {24	struct pkcs7_message	*msg;		/* Message being constructed */25	struct pkcs7_signed_info *sinfo;	/* SignedInfo being constructed */26	struct pkcs7_signed_info **ppsinfo;27	struct x509_certificate *certs;		/* Certificate cache */28	struct x509_certificate **ppcerts;29	unsigned long	data;			/* Start of data */30	enum OID	last_oid;		/* Last OID encountered */31	unsigned	x509_index;32	unsigned	sinfo_index;33	const void	*raw_serial;34	unsigned	raw_serial_size;35	unsigned	raw_issuer_size;36	const void	*raw_issuer;37	const void	*raw_skid;38	unsigned	raw_skid_size;39	bool		expect_skid;40};41 42/*43 * Free a signed information block.44 */45static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)46{47	if (sinfo) {48		public_key_signature_free(sinfo->sig);49		kfree(sinfo);50	}51}52 53/**54 * pkcs7_free_message - Free a PKCS#7 message55 * @pkcs7: The PKCS#7 message to free56 */57void pkcs7_free_message(struct pkcs7_message *pkcs7)58{59	struct x509_certificate *cert;60	struct pkcs7_signed_info *sinfo;61 62	if (pkcs7) {63		while (pkcs7->certs) {64			cert = pkcs7->certs;65			pkcs7->certs = cert->next;66			x509_free_certificate(cert);67		}68		while (pkcs7->crl) {69			cert = pkcs7->crl;70			pkcs7->crl = cert->next;71			x509_free_certificate(cert);72		}73		while (pkcs7->signed_infos) {74			sinfo = pkcs7->signed_infos;75			pkcs7->signed_infos = sinfo->next;76			pkcs7_free_signed_info(sinfo);77		}78		kfree(pkcs7);79	}80}81EXPORT_SYMBOL_GPL(pkcs7_free_message);82 83/*84 * Check authenticatedAttributes are provided or not provided consistently.85 */86static int pkcs7_check_authattrs(struct pkcs7_message *msg)87{88	struct pkcs7_signed_info *sinfo;89	bool want = false;90 91	sinfo = msg->signed_infos;92	if (!sinfo)93		goto inconsistent;94 95	if (sinfo->authattrs) {96		want = true;97		msg->have_authattrs = true;98	}99 100	for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)101		if (!!sinfo->authattrs != want)102			goto inconsistent;103	return 0;104 105inconsistent:106	pr_warn("Inconsistently supplied authAttrs\n");107	return -EINVAL;108}109 110/**111 * pkcs7_parse_message - Parse a PKCS#7 message112 * @data: The raw binary ASN.1 encoded message to be parsed113 * @datalen: The size of the encoded message114 */115struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)116{117	struct pkcs7_parse_context *ctx;118	struct pkcs7_message *msg = ERR_PTR(-ENOMEM);119	int ret;120 121	ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);122	if (!ctx)123		goto out_no_ctx;124	ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);125	if (!ctx->msg)126		goto out_no_msg;127	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);128	if (!ctx->sinfo)129		goto out_no_sinfo;130	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),131				  GFP_KERNEL);132	if (!ctx->sinfo->sig)133		goto out_no_sig;134 135	ctx->data = (unsigned long)data;136	ctx->ppcerts = &ctx->certs;137	ctx->ppsinfo = &ctx->msg->signed_infos;138 139	/* Attempt to decode the signature */140	ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);141	if (ret < 0) {142		msg = ERR_PTR(ret);143		goto out;144	}145 146	ret = pkcs7_check_authattrs(ctx->msg);147	if (ret < 0) {148		msg = ERR_PTR(ret);149		goto out;150	}151 152	msg = ctx->msg;153	ctx->msg = NULL;154 155out:156	while (ctx->certs) {157		struct x509_certificate *cert = ctx->certs;158		ctx->certs = cert->next;159		x509_free_certificate(cert);160	}161out_no_sig:162	pkcs7_free_signed_info(ctx->sinfo);163out_no_sinfo:164	pkcs7_free_message(ctx->msg);165out_no_msg:166	kfree(ctx);167out_no_ctx:168	return msg;169}170EXPORT_SYMBOL_GPL(pkcs7_parse_message);171 172/**173 * pkcs7_get_content_data - Get access to the PKCS#7 content174 * @pkcs7: The preparsed PKCS#7 message to access175 * @_data: Place to return a pointer to the data176 * @_data_len: Place to return the data length177 * @_headerlen: Size of ASN.1 header not included in _data178 *179 * Get access to the data content of the PKCS#7 message.  The size of the180 * header of the ASN.1 object that contains it is also provided and can be used181 * to adjust *_data and *_data_len to get the entire object.182 *183 * Returns -ENODATA if the data object was missing from the message.184 */185int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,186			   const void **_data, size_t *_data_len,187			   size_t *_headerlen)188{189	if (!pkcs7->data)190		return -ENODATA;191 192	*_data = pkcs7->data;193	*_data_len = pkcs7->data_len;194	if (_headerlen)195		*_headerlen = pkcs7->data_hdrlen;196	return 0;197}198EXPORT_SYMBOL_GPL(pkcs7_get_content_data);199 200/*201 * Note an OID when we find one for later processing when we know how202 * to interpret it.203 */204int pkcs7_note_OID(void *context, size_t hdrlen,205		   unsigned char tag,206		   const void *value, size_t vlen)207{208	struct pkcs7_parse_context *ctx = context;209 210	ctx->last_oid = look_up_OID(value, vlen);211	if (ctx->last_oid == OID__NR) {212		char buffer[50];213		sprint_oid(value, vlen, buffer, sizeof(buffer));214		printk("PKCS7: Unknown OID: [%lu] %s\n",215		       (unsigned long)value - ctx->data, buffer);216	}217	return 0;218}219 220/*221 * Note the digest algorithm for the signature.222 */223int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,224			       unsigned char tag,225			       const void *value, size_t vlen)226{227	struct pkcs7_parse_context *ctx = context;228 229	switch (ctx->last_oid) {230	case OID_sha1:231		ctx->sinfo->sig->hash_algo = "sha1";232		break;233	case OID_sha256:234		ctx->sinfo->sig->hash_algo = "sha256";235		break;236	case OID_sha384:237		ctx->sinfo->sig->hash_algo = "sha384";238		break;239	case OID_sha512:240		ctx->sinfo->sig->hash_algo = "sha512";241		break;242	case OID_sha224:243		ctx->sinfo->sig->hash_algo = "sha224";244		break;245	case OID_sm3:246		ctx->sinfo->sig->hash_algo = "sm3";247		break;248	case OID_gost2012Digest256:249		ctx->sinfo->sig->hash_algo = "streebog256";250		break;251	case OID_gost2012Digest512:252		ctx->sinfo->sig->hash_algo = "streebog512";253		break;254	case OID_sha3_256:255		ctx->sinfo->sig->hash_algo = "sha3-256";256		break;257	case OID_sha3_384:258		ctx->sinfo->sig->hash_algo = "sha3-384";259		break;260	case OID_sha3_512:261		ctx->sinfo->sig->hash_algo = "sha3-512";262		break;263	default:264		printk("Unsupported digest algo: %u\n", ctx->last_oid);265		return -ENOPKG;266	}267	return 0;268}269 270/*271 * Note the public key algorithm for the signature.272 */273int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,274			     unsigned char tag,275			     const void *value, size_t vlen)276{277	struct pkcs7_parse_context *ctx = context;278 279	switch (ctx->last_oid) {280	case OID_rsaEncryption:281		ctx->sinfo->sig->pkey_algo = "rsa";282		ctx->sinfo->sig->encoding = "pkcs1";283		break;284	case OID_id_ecdsa_with_sha1:285	case OID_id_ecdsa_with_sha224:286	case OID_id_ecdsa_with_sha256:287	case OID_id_ecdsa_with_sha384:288	case OID_id_ecdsa_with_sha512:289	case OID_id_ecdsa_with_sha3_256:290	case OID_id_ecdsa_with_sha3_384:291	case OID_id_ecdsa_with_sha3_512:292		ctx->sinfo->sig->pkey_algo = "ecdsa";293		ctx->sinfo->sig->encoding = "x962";294		break;295	case OID_gost2012PKey256:296	case OID_gost2012PKey512:297		ctx->sinfo->sig->pkey_algo = "ecrdsa";298		ctx->sinfo->sig->encoding = "raw";299		break;300	default:301		printk("Unsupported pkey algo: %u\n", ctx->last_oid);302		return -ENOPKG;303	}304	return 0;305}306 307/*308 * We only support signed data [RFC2315 sec 9].309 */310int pkcs7_check_content_type(void *context, size_t hdrlen,311			     unsigned char tag,312			     const void *value, size_t vlen)313{314	struct pkcs7_parse_context *ctx = context;315 316	if (ctx->last_oid != OID_signed_data) {317		pr_warn("Only support pkcs7_signedData type\n");318		return -EINVAL;319	}320 321	return 0;322}323 324/*325 * Note the SignedData version326 */327int pkcs7_note_signeddata_version(void *context, size_t hdrlen,328				  unsigned char tag,329				  const void *value, size_t vlen)330{331	struct pkcs7_parse_context *ctx = context;332	unsigned version;333 334	if (vlen != 1)335		goto unsupported;336 337	ctx->msg->version = version = *(const u8 *)value;338	switch (version) {339	case 1:340		/* PKCS#7 SignedData [RFC2315 sec 9.1]341		 * CMS ver 1 SignedData [RFC5652 sec 5.1]342		 */343		break;344	case 3:345		/* CMS ver 3 SignedData [RFC2315 sec 5.1] */346		break;347	default:348		goto unsupported;349	}350 351	return 0;352 353unsupported:354	pr_warn("Unsupported SignedData version\n");355	return -EINVAL;356}357 358/*359 * Note the SignerInfo version360 */361int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,362				  unsigned char tag,363				  const void *value, size_t vlen)364{365	struct pkcs7_parse_context *ctx = context;366	unsigned version;367 368	if (vlen != 1)369		goto unsupported;370 371	version = *(const u8 *)value;372	switch (version) {373	case 1:374		/* PKCS#7 SignerInfo [RFC2315 sec 9.2]375		 * CMS ver 1 SignerInfo [RFC5652 sec 5.3]376		 */377		if (ctx->msg->version != 1)378			goto version_mismatch;379		ctx->expect_skid = false;380		break;381	case 3:382		/* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */383		if (ctx->msg->version == 1)384			goto version_mismatch;385		ctx->expect_skid = true;386		break;387	default:388		goto unsupported;389	}390 391	return 0;392 393unsupported:394	pr_warn("Unsupported SignerInfo version\n");395	return -EINVAL;396version_mismatch:397	pr_warn("SignedData-SignerInfo version mismatch\n");398	return -EBADMSG;399}400 401/*402 * Extract a certificate and store it in the context.403 */404int pkcs7_extract_cert(void *context, size_t hdrlen,405		       unsigned char tag,406		       const void *value, size_t vlen)407{408	struct pkcs7_parse_context *ctx = context;409	struct x509_certificate *x509;410 411	if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {412		pr_debug("Cert began with tag %02x at %lu\n",413			 tag, (unsigned long)ctx - ctx->data);414		return -EBADMSG;415	}416 417	/* We have to correct for the header so that the X.509 parser can start418	 * from the beginning.  Note that since X.509 stipulates DER, there419	 * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which420	 * stipulates BER).421	 */422	value -= hdrlen;423	vlen += hdrlen;424 425	if (((u8*)value)[1] == 0x80)426		vlen += 2; /* Indefinite length - there should be an EOC */427 428	x509 = x509_cert_parse(value, vlen);429	if (IS_ERR(x509))430		return PTR_ERR(x509);431 432	x509->index = ++ctx->x509_index;433	pr_debug("Got cert %u for %s\n", x509->index, x509->subject);434	pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);435 436	*ctx->ppcerts = x509;437	ctx->ppcerts = &x509->next;438	return 0;439}440 441/*442 * Save the certificate list443 */444int pkcs7_note_certificate_list(void *context, size_t hdrlen,445				unsigned char tag,446				const void *value, size_t vlen)447{448	struct pkcs7_parse_context *ctx = context;449 450	pr_devel("Got cert list (%02x)\n", tag);451 452	*ctx->ppcerts = ctx->msg->certs;453	ctx->msg->certs = ctx->certs;454	ctx->certs = NULL;455	ctx->ppcerts = &ctx->certs;456	return 0;457}458 459/*460 * Note the content type.461 */462int pkcs7_note_content(void *context, size_t hdrlen,463		       unsigned char tag,464		       const void *value, size_t vlen)465{466	struct pkcs7_parse_context *ctx = context;467 468	if (ctx->last_oid != OID_data &&469	    ctx->last_oid != OID_msIndirectData) {470		pr_warn("Unsupported data type %d\n", ctx->last_oid);471		return -EINVAL;472	}473 474	ctx->msg->data_type = ctx->last_oid;475	return 0;476}477 478/*479 * Extract the data from the message and store that and its content type OID in480 * the context.481 */482int pkcs7_note_data(void *context, size_t hdrlen,483		    unsigned char tag,484		    const void *value, size_t vlen)485{486	struct pkcs7_parse_context *ctx = context;487 488	pr_debug("Got data\n");489 490	ctx->msg->data = value;491	ctx->msg->data_len = vlen;492	ctx->msg->data_hdrlen = hdrlen;493	return 0;494}495 496/*497 * Parse authenticated attributes.498 */499int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,500				      unsigned char tag,501				      const void *value, size_t vlen)502{503	struct pkcs7_parse_context *ctx = context;504	struct pkcs7_signed_info *sinfo = ctx->sinfo;505	enum OID content_type;506 507	pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);508 509	switch (ctx->last_oid) {510	case OID_contentType:511		if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))512			goto repeated;513		content_type = look_up_OID(value, vlen);514		if (content_type != ctx->msg->data_type) {515			pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",516				ctx->msg->data_type, sinfo->index,517				content_type);518			return -EBADMSG;519		}520		return 0;521 522	case OID_signingTime:523		if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))524			goto repeated;525		/* Should we check that the signing time is consistent526		 * with the signer's X.509 cert?527		 */528		return x509_decode_time(&sinfo->signing_time,529					hdrlen, tag, value, vlen);530 531	case OID_messageDigest:532		if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))533			goto repeated;534		if (tag != ASN1_OTS)535			return -EBADMSG;536		sinfo->msgdigest = value;537		sinfo->msgdigest_len = vlen;538		return 0;539 540	case OID_smimeCapabilites:541		if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))542			goto repeated;543		if (ctx->msg->data_type != OID_msIndirectData) {544			pr_warn("S/MIME Caps only allowed with Authenticode\n");545			return -EKEYREJECTED;546		}547		return 0;548 549		/* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE550		 * char URLs and cont[1] 8-bit char URLs.551		 *552		 * Microsoft StatementType seems to contain a list of OIDs that553		 * are also used as extendedKeyUsage types in X.509 certs.554		 */555	case OID_msSpOpusInfo:556		if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))557			goto repeated;558		goto authenticode_check;559	case OID_msStatementType:560		if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))561			goto repeated;562	authenticode_check:563		if (ctx->msg->data_type != OID_msIndirectData) {564			pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");565			return -EKEYREJECTED;566		}567		/* I'm not sure how to validate these */568		return 0;569	default:570		return 0;571	}572 573repeated:574	/* We permit max one item per AuthenticatedAttribute and no repeats */575	pr_warn("Repeated/multivalue AuthAttrs not permitted\n");576	return -EKEYREJECTED;577}578 579/*580 * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]581 */582int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,583				    unsigned char tag,584				    const void *value, size_t vlen)585{586	struct pkcs7_parse_context *ctx = context;587	struct pkcs7_signed_info *sinfo = ctx->sinfo;588 589	if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||590	    !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {591		pr_warn("Missing required AuthAttr\n");592		return -EBADMSG;593	}594 595	if (ctx->msg->data_type != OID_msIndirectData &&596	    test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {597		pr_warn("Unexpected Authenticode AuthAttr\n");598		return -EBADMSG;599	}600 601	/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */602	sinfo->authattrs = value - (hdrlen - 1);603	sinfo->authattrs_len = vlen + (hdrlen - 1);604	return 0;605}606 607/*608 * Note the issuing certificate serial number609 */610int pkcs7_sig_note_serial(void *context, size_t hdrlen,611			  unsigned char tag,612			  const void *value, size_t vlen)613{614	struct pkcs7_parse_context *ctx = context;615	ctx->raw_serial = value;616	ctx->raw_serial_size = vlen;617	return 0;618}619 620/*621 * Note the issuer's name622 */623int pkcs7_sig_note_issuer(void *context, size_t hdrlen,624			  unsigned char tag,625			  const void *value, size_t vlen)626{627	struct pkcs7_parse_context *ctx = context;628	ctx->raw_issuer = value;629	ctx->raw_issuer_size = vlen;630	return 0;631}632 633/*634 * Note the issuing cert's subjectKeyIdentifier635 */636int pkcs7_sig_note_skid(void *context, size_t hdrlen,637			unsigned char tag,638			const void *value, size_t vlen)639{640	struct pkcs7_parse_context *ctx = context;641 642	pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);643 644	ctx->raw_skid = value;645	ctx->raw_skid_size = vlen;646	return 0;647}648 649/*650 * Note the signature data651 */652int pkcs7_sig_note_signature(void *context, size_t hdrlen,653			     unsigned char tag,654			     const void *value, size_t vlen)655{656	struct pkcs7_parse_context *ctx = context;657 658	ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);659	if (!ctx->sinfo->sig->s)660		return -ENOMEM;661 662	ctx->sinfo->sig->s_size = vlen;663	return 0;664}665 666/*667 * Note a signature information block668 */669int pkcs7_note_signed_info(void *context, size_t hdrlen,670			   unsigned char tag,671			   const void *value, size_t vlen)672{673	struct pkcs7_parse_context *ctx = context;674	struct pkcs7_signed_info *sinfo = ctx->sinfo;675	struct asymmetric_key_id *kid;676 677	if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {678		pr_warn("Authenticode requires AuthAttrs\n");679		return -EBADMSG;680	}681 682	/* Generate cert issuer + serial number key ID */683	if (!ctx->expect_skid) {684		kid = asymmetric_key_generate_id(ctx->raw_serial,685						 ctx->raw_serial_size,686						 ctx->raw_issuer,687						 ctx->raw_issuer_size);688	} else {689		kid = asymmetric_key_generate_id(ctx->raw_skid,690						 ctx->raw_skid_size,691						 "", 0);692	}693	if (IS_ERR(kid))694		return PTR_ERR(kid);695 696	pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);697 698	sinfo->sig->auth_ids[0] = kid;699	sinfo->index = ++ctx->sinfo_index;700	*ctx->ppsinfo = sinfo;701	ctx->ppsinfo = &sinfo->next;702	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);703	if (!ctx->sinfo)704		return -ENOMEM;705	ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),706				  GFP_KERNEL);707	if (!ctx->sinfo->sig)708		return -ENOMEM;709	return 0;710}711