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_sha256: |
231 | ctx->sinfo->sig->hash_algo = "sha256" ; |
232 | break; |
233 | case OID_sha384: |
234 | ctx->sinfo->sig->hash_algo = "sha384" ; |
235 | break; |
236 | case OID_sha512: |
237 | ctx->sinfo->sig->hash_algo = "sha512" ; |
238 | break; |
239 | case OID_sha224: |
240 | ctx->sinfo->sig->hash_algo = "sha224" ; |
241 | break; |
242 | case OID_sm3: |
243 | ctx->sinfo->sig->hash_algo = "sm3" ; |
244 | break; |
245 | case OID_gost2012Digest256: |
246 | ctx->sinfo->sig->hash_algo = "streebog256" ; |
247 | break; |
248 | case OID_gost2012Digest512: |
249 | ctx->sinfo->sig->hash_algo = "streebog512" ; |
250 | break; |
251 | case OID_sha3_256: |
252 | ctx->sinfo->sig->hash_algo = "sha3-256" ; |
253 | break; |
254 | case OID_sha3_384: |
255 | ctx->sinfo->sig->hash_algo = "sha3-384" ; |
256 | break; |
257 | case OID_sha3_512: |
258 | ctx->sinfo->sig->hash_algo = "sha3-512" ; |
259 | break; |
260 | default: |
261 | printk("Unsupported digest algo: %u\n" , ctx->last_oid); |
262 | return -ENOPKG; |
263 | } |
264 | return 0; |
265 | } |
266 | |
267 | /* |
268 | * Note the public key algorithm for the signature. |
269 | */ |
270 | int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, |
271 | unsigned char tag, |
272 | const void *value, size_t vlen) |
273 | { |
274 | struct pkcs7_parse_context *ctx = context; |
275 | |
276 | switch (ctx->last_oid) { |
277 | case OID_rsaEncryption: |
278 | ctx->sinfo->sig->pkey_algo = "rsa" ; |
279 | ctx->sinfo->sig->encoding = "pkcs1" ; |
280 | break; |
281 | case OID_id_ecdsa_with_sha224: |
282 | case OID_id_ecdsa_with_sha256: |
283 | case OID_id_ecdsa_with_sha384: |
284 | case OID_id_ecdsa_with_sha512: |
285 | case OID_id_ecdsa_with_sha3_256: |
286 | case OID_id_ecdsa_with_sha3_384: |
287 | case OID_id_ecdsa_with_sha3_512: |
288 | ctx->sinfo->sig->pkey_algo = "ecdsa" ; |
289 | ctx->sinfo->sig->encoding = "x962" ; |
290 | break; |
291 | case OID_SM2_with_SM3: |
292 | ctx->sinfo->sig->pkey_algo = "sm2" ; |
293 | ctx->sinfo->sig->encoding = "raw" ; |
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 (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(data: value, datalen: vlen); |
429 | if (IS_ERR(ptr: x509)) |
430 | return PTR_ERR(ptr: 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(data: value, datasize: 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(t: &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(p: value, size: 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(val_1: ctx->raw_serial, |
685 | len_1: ctx->raw_serial_size, |
686 | val_2: ctx->raw_issuer, |
687 | len_2: ctx->raw_issuer_size); |
688 | } else { |
689 | kid = asymmetric_key_generate_id(val_1: ctx->raw_skid, |
690 | len_1: ctx->raw_skid_size, |
691 | val_2: "" , len_2: 0); |
692 | } |
693 | if (IS_ERR(ptr: kid)) |
694 | return PTR_ERR(ptr: 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(size: sizeof(struct pkcs7_signed_info), GFP_KERNEL); |
703 | if (!ctx->sinfo) |
704 | return -ENOMEM; |
705 | ctx->sinfo->sig = kzalloc(size: sizeof(struct public_key_signature), |
706 | GFP_KERNEL); |
707 | if (!ctx->sinfo->sig) |
708 | return -ENOMEM; |
709 | return 0; |
710 | } |
711 | |