Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/asymmetric_keys/pkcs7_parser.c
26278 views
1
// 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 ([email protected])
6
*/
7
8
#define pr_fmt(fmt) "PKCS7: "fmt
9
#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
19
MODULE_DESCRIPTION("PKCS#7 parser");
20
MODULE_AUTHOR("Red Hat, Inc.");
21
MODULE_LICENSE("GPL");
22
23
struct 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
*/
45
static 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 message
55
* @pkcs7: The PKCS#7 message to free
56
*/
57
void 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
}
81
EXPORT_SYMBOL_GPL(pkcs7_free_message);
82
83
/*
84
* Check authenticatedAttributes are provided or not provided consistently.
85
*/
86
static 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
105
inconsistent:
106
pr_warn("Inconsistently supplied authAttrs\n");
107
return -EINVAL;
108
}
109
110
/**
111
* pkcs7_parse_message - Parse a PKCS#7 message
112
* @data: The raw binary ASN.1 encoded message to be parsed
113
* @datalen: The size of the encoded message
114
*/
115
struct 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
155
out:
156
while (ctx->certs) {
157
struct x509_certificate *cert = ctx->certs;
158
ctx->certs = cert->next;
159
x509_free_certificate(cert);
160
}
161
out_no_sig:
162
pkcs7_free_signed_info(ctx->sinfo);
163
out_no_sinfo:
164
pkcs7_free_message(ctx->msg);
165
out_no_msg:
166
kfree(ctx);
167
out_no_ctx:
168
return msg;
169
}
170
EXPORT_SYMBOL_GPL(pkcs7_parse_message);
171
172
/**
173
* pkcs7_get_content_data - Get access to the PKCS#7 content
174
* @pkcs7: The preparsed PKCS#7 message to access
175
* @_data: Place to return a pointer to the data
176
* @_data_len: Place to return the data length
177
* @_headerlen: Size of ASN.1 header not included in _data
178
*
179
* Get access to the data content of the PKCS#7 message. The size of the
180
* header of the ASN.1 object that contains it is also provided and can be used
181
* 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
*/
185
int 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
}
198
EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
199
200
/*
201
* Note an OID when we find one for later processing when we know how
202
* to interpret it.
203
*/
204
int 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
*/
223
int 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
*/
273
int 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
*/
310
int 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 version
326
*/
327
int 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
353
unsupported:
354
pr_warn("Unsupported SignedData version\n");
355
return -EINVAL;
356
}
357
358
/*
359
* Note the SignerInfo version
360
*/
361
int 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
393
unsupported:
394
pr_warn("Unsupported SignerInfo version\n");
395
return -EINVAL;
396
version_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
*/
404
int 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 start
418
* from the beginning. Note that since X.509 stipulates DER, there
419
* probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
420
* 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 list
443
*/
444
int 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
*/
462
int 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 in
480
* the context.
481
*/
482
int 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
*/
499
int 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 consistent
526
* 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 BE
550
* char URLs and cont[1] 8-bit char URLs.
551
*
552
* Microsoft StatementType seems to contain a list of OIDs that
553
* 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
573
repeated:
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
*/
582
int 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 number
609
*/
610
int 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 name
622
*/
623
int 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 subjectKeyIdentifier
635
*/
636
int 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 data
651
*/
652
int 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 block
668
*/
669
int 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
712