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