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 (dhowells@redhat.com) |
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(sig: sinfo->sig); |
49 | kfree(objp: 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(objp: 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(error: -ENOMEM); |
119 | int ret; |
120 | |
121 | ctx = kzalloc(size: sizeof(struct pkcs7_parse_context), GFP_KERNEL); |
122 | if (!ctx) |
123 | goto out_no_ctx; |
124 | ctx->msg = kzalloc(size: sizeof(struct pkcs7_message), GFP_KERNEL); |
125 | if (!ctx->msg) |
126 | goto out_no_msg; |
127 | ctx->sinfo = kzalloc(size: sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
128 | if (!ctx->sinfo) |
129 | goto out_no_sinfo; |
130 | ctx->sinfo->sig = kzalloc(size: 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(error: ret); |
143 | goto out; |
144 | } |
145 | |
146 | ret = pkcs7_check_authattrs(msg: ctx->msg); |
147 | if (ret < 0) { |
148 | msg = ERR_PTR(error: 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(sinfo: ctx->sinfo); |
163 | out_no_sinfo: |
164 | pkcs7_free_message(ctx->msg); |
165 | out_no_msg: |
166 | kfree(objp: 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 *) |
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(data: value, datasize: 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_SM2_with_SM3: |
296 | ctx->sinfo->sig->pkey_algo = "sm2" ; |
297 | ctx->sinfo->sig->encoding = "raw" ; |
298 | break; |
299 | case OID_gost2012PKey256: |
300 | case OID_gost2012PKey512: |
301 | ctx->sinfo->sig->pkey_algo = "ecrdsa" ; |
302 | ctx->sinfo->sig->encoding = "raw" ; |
303 | break; |
304 | default: |
305 | printk("Unsupported pkey algo: %u\n" , ctx->last_oid); |
306 | return -ENOPKG; |
307 | } |
308 | return 0; |
309 | } |
310 | |
311 | /* |
312 | * We only support signed data [RFC2315 sec 9]. |
313 | */ |
314 | int pkcs7_check_content_type(void *context, size_t hdrlen, |
315 | unsigned char tag, |
316 | const void *value, size_t vlen) |
317 | { |
318 | struct pkcs7_parse_context *ctx = context; |
319 | |
320 | if (ctx->last_oid != OID_signed_data) { |
321 | pr_warn("Only support pkcs7_signedData type\n" ); |
322 | return -EINVAL; |
323 | } |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | /* |
329 | * Note the SignedData version |
330 | */ |
331 | int pkcs7_note_signeddata_version(void *context, size_t hdrlen, |
332 | unsigned char tag, |
333 | const void *value, size_t vlen) |
334 | { |
335 | struct pkcs7_parse_context *ctx = context; |
336 | unsigned version; |
337 | |
338 | if (vlen != 1) |
339 | goto unsupported; |
340 | |
341 | ctx->msg->version = version = *(const u8 *)value; |
342 | switch (version) { |
343 | case 1: |
344 | /* PKCS#7 SignedData [RFC2315 sec 9.1] |
345 | * CMS ver 1 SignedData [RFC5652 sec 5.1] |
346 | */ |
347 | break; |
348 | case 3: |
349 | /* CMS ver 3 SignedData [RFC2315 sec 5.1] */ |
350 | break; |
351 | default: |
352 | goto unsupported; |
353 | } |
354 | |
355 | return 0; |
356 | |
357 | unsupported: |
358 | pr_warn("Unsupported SignedData version\n" ); |
359 | return -EINVAL; |
360 | } |
361 | |
362 | /* |
363 | * Note the SignerInfo version |
364 | */ |
365 | int pkcs7_note_signerinfo_version(void *context, size_t hdrlen, |
366 | unsigned char tag, |
367 | const void *value, size_t vlen) |
368 | { |
369 | struct pkcs7_parse_context *ctx = context; |
370 | unsigned version; |
371 | |
372 | if (vlen != 1) |
373 | goto unsupported; |
374 | |
375 | version = *(const u8 *)value; |
376 | switch (version) { |
377 | case 1: |
378 | /* PKCS#7 SignerInfo [RFC2315 sec 9.2] |
379 | * CMS ver 1 SignerInfo [RFC5652 sec 5.3] |
380 | */ |
381 | if (ctx->msg->version != 1) |
382 | goto version_mismatch; |
383 | ctx->expect_skid = false; |
384 | break; |
385 | case 3: |
386 | /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */ |
387 | if (ctx->msg->version == 1) |
388 | goto version_mismatch; |
389 | ctx->expect_skid = true; |
390 | break; |
391 | default: |
392 | goto unsupported; |
393 | } |
394 | |
395 | return 0; |
396 | |
397 | unsupported: |
398 | pr_warn("Unsupported SignerInfo version\n" ); |
399 | return -EINVAL; |
400 | version_mismatch: |
401 | pr_warn("SignedData-SignerInfo version mismatch\n" ); |
402 | return -EBADMSG; |
403 | } |
404 | |
405 | /* |
406 | * Extract a certificate and store it in the context. |
407 | */ |
408 | int (void *context, size_t hdrlen, |
409 | unsigned char tag, |
410 | const void *value, size_t vlen) |
411 | { |
412 | struct pkcs7_parse_context *ctx = context; |
413 | struct x509_certificate *x509; |
414 | |
415 | if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) { |
416 | pr_debug("Cert began with tag %02x at %lu\n" , |
417 | tag, (unsigned long)ctx - ctx->data); |
418 | return -EBADMSG; |
419 | } |
420 | |
421 | /* We have to correct for the header so that the X.509 parser can start |
422 | * from the beginning. Note that since X.509 stipulates DER, there |
423 | * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which |
424 | * stipulates BER). |
425 | */ |
426 | value -= hdrlen; |
427 | vlen += hdrlen; |
428 | |
429 | if (((u8*)value)[1] == 0x80) |
430 | vlen += 2; /* Indefinite length - there should be an EOC */ |
431 | |
432 | x509 = x509_cert_parse(data: value, datalen: vlen); |
433 | if (IS_ERR(ptr: x509)) |
434 | return PTR_ERR(ptr: x509); |
435 | |
436 | x509->index = ++ctx->x509_index; |
437 | pr_debug("Got cert %u for %s\n" , x509->index, x509->subject); |
438 | pr_debug("- fingerprint %*phN\n" , x509->id->len, x509->id->data); |
439 | |
440 | *ctx->ppcerts = x509; |
441 | ctx->ppcerts = &x509->next; |
442 | return 0; |
443 | } |
444 | |
445 | /* |
446 | * Save the certificate list |
447 | */ |
448 | int pkcs7_note_certificate_list(void *context, size_t hdrlen, |
449 | unsigned char tag, |
450 | const void *value, size_t vlen) |
451 | { |
452 | struct pkcs7_parse_context *ctx = context; |
453 | |
454 | pr_devel("Got cert list (%02x)\n" , tag); |
455 | |
456 | *ctx->ppcerts = ctx->msg->certs; |
457 | ctx->msg->certs = ctx->certs; |
458 | ctx->certs = NULL; |
459 | ctx->ppcerts = &ctx->certs; |
460 | return 0; |
461 | } |
462 | |
463 | /* |
464 | * Note the content type. |
465 | */ |
466 | int pkcs7_note_content(void *context, size_t hdrlen, |
467 | unsigned char tag, |
468 | const void *value, size_t vlen) |
469 | { |
470 | struct pkcs7_parse_context *ctx = context; |
471 | |
472 | if (ctx->last_oid != OID_data && |
473 | ctx->last_oid != OID_msIndirectData) { |
474 | pr_warn("Unsupported data type %d\n" , ctx->last_oid); |
475 | return -EINVAL; |
476 | } |
477 | |
478 | ctx->msg->data_type = ctx->last_oid; |
479 | return 0; |
480 | } |
481 | |
482 | /* |
483 | * Extract the data from the message and store that and its content type OID in |
484 | * the context. |
485 | */ |
486 | int pkcs7_note_data(void *context, size_t hdrlen, |
487 | unsigned char tag, |
488 | const void *value, size_t vlen) |
489 | { |
490 | struct pkcs7_parse_context *ctx = context; |
491 | |
492 | pr_debug("Got data\n" ); |
493 | |
494 | ctx->msg->data = value; |
495 | ctx->msg->data_len = vlen; |
496 | ctx->msg->data_hdrlen = hdrlen; |
497 | return 0; |
498 | } |
499 | |
500 | /* |
501 | * Parse authenticated attributes. |
502 | */ |
503 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, |
504 | unsigned char tag, |
505 | const void *value, size_t vlen) |
506 | { |
507 | struct pkcs7_parse_context *ctx = context; |
508 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
509 | enum OID content_type; |
510 | |
511 | pr_devel("AuthAttr: %02x %zu [%*ph]\n" , tag, vlen, (unsigned)vlen, value); |
512 | |
513 | switch (ctx->last_oid) { |
514 | case OID_contentType: |
515 | if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set)) |
516 | goto repeated; |
517 | content_type = look_up_OID(data: value, datasize: vlen); |
518 | if (content_type != ctx->msg->data_type) { |
519 | pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n" , |
520 | ctx->msg->data_type, sinfo->index, |
521 | content_type); |
522 | return -EBADMSG; |
523 | } |
524 | return 0; |
525 | |
526 | case OID_signingTime: |
527 | if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set)) |
528 | goto repeated; |
529 | /* Should we check that the signing time is consistent |
530 | * with the signer's X.509 cert? |
531 | */ |
532 | return x509_decode_time(t: &sinfo->signing_time, |
533 | hdrlen, tag, value, vlen); |
534 | |
535 | case OID_messageDigest: |
536 | if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set)) |
537 | goto repeated; |
538 | if (tag != ASN1_OTS) |
539 | return -EBADMSG; |
540 | sinfo->msgdigest = value; |
541 | sinfo->msgdigest_len = vlen; |
542 | return 0; |
543 | |
544 | case OID_smimeCapabilites: |
545 | if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) |
546 | goto repeated; |
547 | if (ctx->msg->data_type != OID_msIndirectData) { |
548 | pr_warn("S/MIME Caps only allowed with Authenticode\n" ); |
549 | return -EKEYREJECTED; |
550 | } |
551 | return 0; |
552 | |
553 | /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE |
554 | * char URLs and cont[1] 8-bit char URLs. |
555 | * |
556 | * Microsoft StatementType seems to contain a list of OIDs that |
557 | * are also used as extendedKeyUsage types in X.509 certs. |
558 | */ |
559 | case OID_msSpOpusInfo: |
560 | if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) |
561 | goto repeated; |
562 | goto authenticode_check; |
563 | case OID_msStatementType: |
564 | if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set)) |
565 | goto repeated; |
566 | authenticode_check: |
567 | if (ctx->msg->data_type != OID_msIndirectData) { |
568 | pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n" ); |
569 | return -EKEYREJECTED; |
570 | } |
571 | /* I'm not sure how to validate these */ |
572 | return 0; |
573 | default: |
574 | return 0; |
575 | } |
576 | |
577 | repeated: |
578 | /* We permit max one item per AuthenticatedAttribute and no repeats */ |
579 | pr_warn("Repeated/multivalue AuthAttrs not permitted\n" ); |
580 | return -EKEYREJECTED; |
581 | } |
582 | |
583 | /* |
584 | * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3] |
585 | */ |
586 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, |
587 | unsigned char tag, |
588 | const void *value, size_t vlen) |
589 | { |
590 | struct pkcs7_parse_context *ctx = context; |
591 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
592 | |
593 | if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || |
594 | !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) { |
595 | pr_warn("Missing required AuthAttr\n" ); |
596 | return -EBADMSG; |
597 | } |
598 | |
599 | if (ctx->msg->data_type != OID_msIndirectData && |
600 | test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) { |
601 | pr_warn("Unexpected Authenticode AuthAttr\n" ); |
602 | return -EBADMSG; |
603 | } |
604 | |
605 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ |
606 | sinfo->authattrs = value - (hdrlen - 1); |
607 | sinfo->authattrs_len = vlen + (hdrlen - 1); |
608 | return 0; |
609 | } |
610 | |
611 | /* |
612 | * Note the issuing certificate serial number |
613 | */ |
614 | int pkcs7_sig_note_serial(void *context, size_t hdrlen, |
615 | unsigned char tag, |
616 | const void *value, size_t vlen) |
617 | { |
618 | struct pkcs7_parse_context *ctx = context; |
619 | ctx->raw_serial = value; |
620 | ctx->raw_serial_size = vlen; |
621 | return 0; |
622 | } |
623 | |
624 | /* |
625 | * Note the issuer's name |
626 | */ |
627 | int pkcs7_sig_note_issuer(void *context, size_t hdrlen, |
628 | unsigned char tag, |
629 | const void *value, size_t vlen) |
630 | { |
631 | struct pkcs7_parse_context *ctx = context; |
632 | ctx->raw_issuer = value; |
633 | ctx->raw_issuer_size = vlen; |
634 | return 0; |
635 | } |
636 | |
637 | /* |
638 | * Note the issuing cert's subjectKeyIdentifier |
639 | */ |
640 | int pkcs7_sig_note_skid(void *context, size_t hdrlen, |
641 | unsigned char tag, |
642 | const void *value, size_t vlen) |
643 | { |
644 | struct pkcs7_parse_context *ctx = context; |
645 | |
646 | pr_devel("SKID: %02x %zu [%*ph]\n" , tag, vlen, (unsigned)vlen, value); |
647 | |
648 | ctx->raw_skid = value; |
649 | ctx->raw_skid_size = vlen; |
650 | return 0; |
651 | } |
652 | |
653 | /* |
654 | * Note the signature data |
655 | */ |
656 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, |
657 | unsigned char tag, |
658 | const void *value, size_t vlen) |
659 | { |
660 | struct pkcs7_parse_context *ctx = context; |
661 | |
662 | ctx->sinfo->sig->s = kmemdup(p: value, size: vlen, GFP_KERNEL); |
663 | if (!ctx->sinfo->sig->s) |
664 | return -ENOMEM; |
665 | |
666 | ctx->sinfo->sig->s_size = vlen; |
667 | return 0; |
668 | } |
669 | |
670 | /* |
671 | * Note a signature information block |
672 | */ |
673 | int pkcs7_note_signed_info(void *context, size_t hdrlen, |
674 | unsigned char tag, |
675 | const void *value, size_t vlen) |
676 | { |
677 | struct pkcs7_parse_context *ctx = context; |
678 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
679 | struct asymmetric_key_id *kid; |
680 | |
681 | if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) { |
682 | pr_warn("Authenticode requires AuthAttrs\n" ); |
683 | return -EBADMSG; |
684 | } |
685 | |
686 | /* Generate cert issuer + serial number key ID */ |
687 | if (!ctx->expect_skid) { |
688 | kid = asymmetric_key_generate_id(val_1: ctx->raw_serial, |
689 | len_1: ctx->raw_serial_size, |
690 | val_2: ctx->raw_issuer, |
691 | len_2: ctx->raw_issuer_size); |
692 | } else { |
693 | kid = asymmetric_key_generate_id(val_1: ctx->raw_skid, |
694 | len_1: ctx->raw_skid_size, |
695 | val_2: "" , len_2: 0); |
696 | } |
697 | if (IS_ERR(ptr: kid)) |
698 | return PTR_ERR(ptr: kid); |
699 | |
700 | pr_devel("SINFO KID: %u [%*phN]\n" , kid->len, kid->len, kid->data); |
701 | |
702 | sinfo->sig->auth_ids[0] = kid; |
703 | sinfo->index = ++ctx->sinfo_index; |
704 | *ctx->ppsinfo = sinfo; |
705 | ctx->ppsinfo = &sinfo->next; |
706 | ctx->sinfo = kzalloc(size: sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
707 | if (!ctx->sinfo) |
708 | return -ENOMEM; |
709 | ctx->sinfo->sig = kzalloc(size: sizeof(struct public_key_signature), |
710 | GFP_KERNEL); |
711 | if (!ctx->sinfo->sig) |
712 | return -ENOMEM; |
713 | return 0; |
714 | } |
715 | |