blob: bf8ee17b5b885d44981998c9c0fa5c1388e2bf4a [file] [log] [blame]
Raymond Mao7b3dfd02024-10-03 14:50:32 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * PKCS#7 parser using MbedTLS PKCS#7 library
4 *
5 * Copyright (c) 2024 Linaro Limited
6 * Author: Raymond Mao <raymond.mao@linaro.org>
7 */
8
9#include <log.h>
10#include <linux/kernel.h>
11#include <linux/err.h>
12#include <crypto/public_key.h>
13#include <crypto/pkcs7_parser.h>
14
15static void pkcs7_free_mbedtls_ctx(struct pkcs7_mbedtls_ctx *ctx)
16{
17 if (ctx) {
18 kfree(ctx->content_data);
19 kfree(ctx);
20 }
21}
22
23static void pkcs7_free_sinfo_mbedtls_ctx(struct pkcs7_sinfo_mbedtls_ctx *ctx)
24{
25 if (ctx) {
26 kfree(ctx->authattrs_data);
27 kfree(ctx->content_data_digest);
28 kfree(ctx);
29 }
30}
31
32/*
33 * Parse Authenticate Attributes
34 * TODO: Shall we consider to integrate decoding of authenticate attribute into
35 * MbedTLS library?
36 *
37 * There are two kinds of structure for the Authenticate Attributes being used
38 * in U-Boot.
39 *
40 * Type 1 - contains in a PE/COFF EFI image:
41 *
42 * [C.P.0] {
43 * U.P.SEQUENCE {
44 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.3 (OID_contentType)
45 * U.P.SET {
46 * U.P.OBJECTIDENTIFIER 1.3.6.1.4.1.311.2.1.4 (OID_msIndirectData)
47 * }
48 * }
49 * U.P.SEQUENCE {
50 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.5 (OID_signingTime)
51 * U.P.SET {
52 * U.P.UTCTime '<siging_time>'
53 * }
54 * }
55 * U.P.SEQUENCE {
56 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.4 (OID_messageDigest)
57 * U.P.SET {
58 * U.P.OCTETSTRING <digest>
59 * }
60 * }
61 * U.P.SEQUENCE {
62 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.15 (OID_smimeCapabilites)
63 * U.P.SET {
64 * U.P.SEQUENCE {
65 * <...>
66 * }
67 * }
68 * }
69 * }
70 *
71 * Type 2 - contains in an EFI Capsule:
72 *
73 * [C.P.0] {
74 * U.P.SEQUENCE {
75 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.3 (OID_contentType)
76 * U.P.SET {
77 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.7.1 (OID_data)
78 * }
79 * }
80 * U.P.SEQUENCE {
81 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.5 (OID_signingTime)
82 * U.P.SET {
83 * U.P.UTCTime '<siging_time>'
84 * }
85 * }
86 * U.P.SEQUENCE {
87 * U.P.OBJECTIDENTIFIER 1.2.840.113549.1.9.4 (OID_messageDigest)
88 * U.P.SET {
89 * U.P.OCTETSTRING <digest>
90 * }
91 * }
92 *}
93 *
94 * Note:
95 * They have different Content Type (OID_msIndirectData or OID_data).
96 * OID_smimeCapabilites only exists in a PE/COFF EFI image.
97 */
98static int authattrs_parse(struct pkcs7_message *msg, void *aa, size_t aa_len,
99 struct pkcs7_signed_info *sinfo)
100{
101 unsigned char *p = aa;
102 unsigned char *end = (unsigned char *)aa + aa_len;
103 size_t len = 0;
104 int ret;
105 unsigned char *inner_p;
106 size_t seq_len = 0;
107
108 ret = mbedtls_asn1_get_tag(&p, end, &seq_len,
109 MBEDTLS_ASN1_CONTEXT_SPECIFIC |
110 MBEDTLS_ASN1_CONSTRUCTED);
111 if (ret)
112 return ret;
113
114 while (!mbedtls_asn1_get_tag(&p, end, &seq_len,
115 MBEDTLS_ASN1_CONSTRUCTED |
116 MBEDTLS_ASN1_SEQUENCE)) {
117 inner_p = p;
118 ret = mbedtls_asn1_get_tag(&inner_p, p + seq_len, &len,
119 MBEDTLS_ASN1_OID);
120 if (ret)
121 return ret;
122
123 if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS9_CONTENTTYPE, inner_p, len)) {
124 inner_p += len;
125 ret = mbedtls_asn1_get_tag(&inner_p, p + seq_len, &len,
126 MBEDTLS_ASN1_CONSTRUCTED |
127 MBEDTLS_ASN1_SET);
128 if (ret)
129 return ret;
130
131 ret = mbedtls_asn1_get_tag(&inner_p, p + seq_len, &len,
132 MBEDTLS_ASN1_OID);
133 if (ret)
134 return ret;
135
136 /*
137 * We should only support 1.2.840.113549.1.7.1 (OID_data)
138 * for PKCS7 DATA that is used in EFI Capsule and
139 * 1.3.6.1.4.1.311.2.1.4 (OID_msIndirectData) for
140 * MicroSoft Authentication Code that is used in EFI
141 * Secure Boot.
142 */
143 if (MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_MICROSOFT_INDIRECTDATA,
144 inner_p, len) &&
145 MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_DATA,
146 inner_p, len))
147 return -EINVAL;
148
149 if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
150 return -EINVAL;
151 } else if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS9_MESSAGEDIGEST, inner_p,
152 len)) {
153 inner_p += len;
154 ret = mbedtls_asn1_get_tag(&inner_p, p + seq_len, &len,
155 MBEDTLS_ASN1_CONSTRUCTED |
156 MBEDTLS_ASN1_SET);
157 if (ret)
158 return ret;
159
160 ret = mbedtls_asn1_get_tag(&inner_p, p + seq_len, &len,
161 MBEDTLS_ASN1_OCTET_STRING);
162 if (ret)
163 return ret;
164
165 sinfo->msgdigest = inner_p;
166 sinfo->msgdigest_len = len;
167
168 if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
169 return -EINVAL;
170 } else if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS9_SIGNINGTIME, inner_p,
171 len)) {
172 mbedtls_x509_time st;
173
174 inner_p += len;
175 ret = mbedtls_asn1_get_tag(&inner_p, p + seq_len, &len,
176 MBEDTLS_ASN1_CONSTRUCTED |
177 MBEDTLS_ASN1_SET);
178 if (ret)
179 return ret;
180
181 ret = mbedtls_x509_get_time(&inner_p, p + seq_len, &st);
182 if (ret)
183 return ret;
184 sinfo->signing_time = x509_get_timestamp(&st);
185
186 if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
187 return -EINVAL;
188 } else if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS9_SMIMECAP, inner_p,
189 len)) {
190 if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
191 return -EINVAL;
Raymond Mao7b3dfd02024-10-03 14:50:32 -0700192 } else if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_MICROSOFT_SPOPUSINFO, inner_p,
193 len)) {
194 if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
195 return -EINVAL;
196 } else if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_MICROSOFT_STATETYPE, inner_p,
197 len)) {
198 if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
199 return -EINVAL;
200 }
201
202 p += seq_len;
203 }
204
Raymond Mao7b3dfd02024-10-03 14:50:32 -0700205 msg->have_authattrs = true;
206
207 /*
208 * Skip the leading tag byte (MBEDTLS_ASN1_CONTEXT_SPECIFIC |
209 * MBEDTLS_ASN1_CONSTRUCTED) to satisfy pkcs7_digest() when calculating
210 * the digest of authattrs.
211 */
212 sinfo->authattrs = aa + 1;
213 sinfo->authattrs_len = aa_len - 1;
214
215 return 0;
216}
217
218static int x509_populate_content_data(struct pkcs7_message *msg,
219 mbedtls_pkcs7 *pkcs7_ctx)
220{
221 struct pkcs7_mbedtls_ctx *mctx;
222
223 if (!pkcs7_ctx->content_data.data ||
224 !pkcs7_ctx->content_data.data_len)
225 return 0;
226
227 mctx = kzalloc(sizeof(*mctx), GFP_KERNEL);
228 if (!mctx)
229 return -ENOMEM;
230
231 mctx->content_data = kmemdup(pkcs7_ctx->content_data.data,
232 pkcs7_ctx->content_data.data_len,
233 GFP_KERNEL);
234 if (!mctx->content_data) {
235 pkcs7_free_mbedtls_ctx(mctx);
236 return -ENOMEM;
237 }
238
239 msg->data = mctx->content_data;
240 msg->data_len = pkcs7_ctx->content_data.data_len;
241 msg->data_hdrlen = pkcs7_ctx->content_data.data_hdrlen;
242 msg->data_type = pkcs7_ctx->content_data.data_type;
243
244 msg->mbedtls_ctx = mctx;
245 return 0;
246}
247
248static int x509_populate_sinfo(struct pkcs7_message *msg,
249 mbedtls_pkcs7_signer_info *mb_sinfo,
250 struct pkcs7_signed_info **sinfo)
251{
252 struct pkcs7_signed_info *signed_info;
253 struct public_key_signature *s;
254 mbedtls_md_type_t md_alg;
255 struct pkcs7_sinfo_mbedtls_ctx *mctx;
256 int ret;
257
258 signed_info = kzalloc(sizeof(*signed_info), GFP_KERNEL);
259 if (!signed_info)
260 return -ENOMEM;
261
262 s = kzalloc(sizeof(*s), GFP_KERNEL);
263 if (!s) {
264 ret = -ENOMEM;
265 goto out_no_sig;
266 }
267
268 mctx = kzalloc(sizeof(*mctx), GFP_KERNEL);
269 if (!mctx) {
270 ret = -ENOMEM;
271 goto out_no_mctx;
272 }
273
274 /*
275 * Hash algorithm:
276 *
277 * alg_identifier = digestAlgorithm (DigestAlgorithmIdentifier)
278 * MbedTLS internally checks this field to ensure
279 * it is the same as digest_alg_identifiers.
280 * sig_alg_identifier = digestEncryptionAlgorithm
281 * (DigestEncryptionAlgorithmIdentifier)
282 * MbedTLS just saves this field without any actions.
283 * See function pkcs7_get_signer_info() for reference.
284 *
285 * Public key algorithm:
286 * No information related to public key algorithm under MbedTLS signer
287 * info. Assume that we are using RSA.
288 */
289 ret = mbedtls_oid_get_md_alg(&mb_sinfo->alg_identifier, &md_alg);
290 if (ret)
291 goto out_err_sinfo;
292 s->pkey_algo = "rsa";
293
294 /* Translate the hash algorithm */
295 switch (md_alg) {
296 case MBEDTLS_MD_SHA1:
297 s->hash_algo = "sha1";
298 s->digest_size = SHA1_SUM_LEN;
299 break;
300 case MBEDTLS_MD_SHA256:
301 s->hash_algo = "sha256";
302 s->digest_size = SHA256_SUM_LEN;
303 break;
304 case MBEDTLS_MD_SHA384:
305 s->hash_algo = "sha384";
306 s->digest_size = SHA384_SUM_LEN;
307 break;
308 case MBEDTLS_MD_SHA512:
309 s->hash_algo = "sha512";
310 s->digest_size = SHA512_SUM_LEN;
311 break;
312 /* Unsupported algo */
313 case MBEDTLS_MD_MD5:
314 case MBEDTLS_MD_SHA224:
315 default:
316 ret = -EINVAL;
317 goto out_err_sinfo;
318 }
319
320 /*
321 * auth_ids holds AuthorityKeyIdentifier, aka akid
322 * auth_ids[0]:
323 * [PKCS#7 or CMS ver 1] - generated from "Issuer + Serial number"
324 * [CMS ver 3] - generated from skid (subjectKeyId)
325 * auth_ids[1]: generated from skid (subjectKeyId)
326 *
327 * Assume that we are using PKCS#7 (msg->version=1),
328 * not CMS ver 3 (msg->version=3).
329 */
330 s->auth_ids[0] = asymmetric_key_generate_id(mb_sinfo->serial.p,
331 mb_sinfo->serial.len,
332 mb_sinfo->issuer_raw.p,
333 mb_sinfo->issuer_raw.len);
334 if (!s->auth_ids[0]) {
335 ret = -ENOMEM;
336 goto out_err_sinfo;
337 }
338
339 /* skip s->auth_ids[1], no subjectKeyId in MbedTLS signer info ctx */
340
341 /*
342 * Encoding can be pkcs1 or raw, but only pkcs1 is supported.
343 * Set the encoding explicitly to pkcs1.
344 */
345 s->encoding = "pkcs1";
346
347 /* Copy the signature data */
348 s->s = kmemdup(mb_sinfo->sig.p, mb_sinfo->sig.len, GFP_KERNEL);
349 if (!s->s) {
350 ret = -ENOMEM;
351 goto out_err_sinfo;
352 }
353 s->s_size = mb_sinfo->sig.len;
354 signed_info->sig = s;
355
356 /* Save the Authenticate Attributes data if exists */
Raymond Mao24cd1012024-10-16 16:48:26 -0700357 if (!mb_sinfo->authattrs.data || !mb_sinfo->authattrs.data_len) {
358 kfree(mctx);
Raymond Mao7b3dfd02024-10-03 14:50:32 -0700359 goto no_authattrs;
Raymond Mao24cd1012024-10-16 16:48:26 -0700360 }
Raymond Mao7b3dfd02024-10-03 14:50:32 -0700361
362 mctx->authattrs_data = kmemdup(mb_sinfo->authattrs.data,
363 mb_sinfo->authattrs.data_len,
364 GFP_KERNEL);
365 if (!mctx->authattrs_data) {
366 ret = -ENOMEM;
367 goto out_err_sinfo;
368 }
369 signed_info->mbedtls_ctx = mctx;
370
371 /* If authattrs exists, decode it and parse msgdigest from it */
372 ret = authattrs_parse(msg, mctx->authattrs_data,
373 mb_sinfo->authattrs.data_len,
374 signed_info);
375 if (ret)
376 goto out_err_sinfo;
377
378no_authattrs:
379 *sinfo = signed_info;
380 return 0;
381
382out_err_sinfo:
383 pkcs7_free_sinfo_mbedtls_ctx(mctx);
384out_no_mctx:
385 public_key_signature_free(s);
386out_no_sig:
387 kfree(signed_info);
388 return ret;
389}
390
391/*
392 * Free a signed information block.
393 */
394static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
395{
396 if (sinfo) {
397 public_key_signature_free(sinfo->sig);
398 pkcs7_free_sinfo_mbedtls_ctx(sinfo->mbedtls_ctx);
399 kfree(sinfo);
400 }
401}
402
403/**
404 * pkcs7_free_message - Free a PKCS#7 message
405 * @pkcs7: The PKCS#7 message to free
406 */
407void pkcs7_free_message(struct pkcs7_message *pkcs7)
408{
409 struct x509_certificate *cert;
410 struct pkcs7_signed_info *sinfo;
411
412 if (pkcs7) {
413 while (pkcs7->certs) {
414 cert = pkcs7->certs;
415 pkcs7->certs = cert->next;
416 x509_free_certificate(cert);
417 }
418 while (pkcs7->crl) {
419 cert = pkcs7->crl;
420 pkcs7->crl = cert->next;
421 x509_free_certificate(cert);
422 }
423 while (pkcs7->signed_infos) {
424 sinfo = pkcs7->signed_infos;
425 pkcs7->signed_infos = sinfo->next;
426 pkcs7_free_signed_info(sinfo);
427 }
428 pkcs7_free_mbedtls_ctx(pkcs7->mbedtls_ctx);
429 kfree(pkcs7);
430 }
431}
432
433struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
434{
435 int i;
436 int ret;
437 mbedtls_pkcs7 pkcs7_ctx;
438 mbedtls_pkcs7_signer_info *mb_sinfos;
439 mbedtls_x509_crt *mb_certs;
440 struct pkcs7_message *msg;
441 struct x509_certificate **cert;
442 struct pkcs7_signed_info **sinfos;
443
444 msg = kzalloc(sizeof(*msg), GFP_KERNEL);
445 if (!msg) {
446 ret = -ENOMEM;
447 goto out_no_msg;
448 }
449
450 /* Parse the DER encoded PKCS#7 message using MbedTLS */
451 mbedtls_pkcs7_init(&pkcs7_ctx);
452 ret = mbedtls_pkcs7_parse_der(&pkcs7_ctx, data, datalen);
453 /* Check if it is a PKCS#7 message with signed data */
454 if (ret != MBEDTLS_PKCS7_SIGNED_DATA)
455 goto parse_fail;
456
457 /* Assume that we are using PKCS#7, not CMS ver 3 */
458 msg->version = 1; /* 1 for [PKCS#7 or CMS ver 1] */
459
460 /* Populate the certs to msg->certs */
461 for (i = 0, cert = &msg->certs, mb_certs = &pkcs7_ctx.signed_data.certs;
462 i < pkcs7_ctx.signed_data.no_of_certs && mb_certs;
463 i++, cert = &(*cert)->next, mb_certs = mb_certs->next) {
464 ret = x509_populate_cert(mb_certs, cert);
465 if (ret)
466 goto parse_fail;
467
468 (*cert)->index = i + 1;
469 }
470
471 /*
472 * Skip populating crl, that is not currently in-use.
473 */
474
475 /* Populate content data */
476 ret = x509_populate_content_data(msg, &pkcs7_ctx);
477 if (ret)
478 goto parse_fail;
479
480 /* Populate signed info to msg->signed_infos */
481 for (i = 0, sinfos = &msg->signed_infos,
482 mb_sinfos = &pkcs7_ctx.signed_data.signers;
483 i < pkcs7_ctx.signed_data.no_of_signers && mb_sinfos;
484 i++, sinfos = &(*sinfos)->next, mb_sinfos = mb_sinfos->next) {
485 ret = x509_populate_sinfo(msg, mb_sinfos, sinfos);
486 if (ret)
487 goto parse_fail;
488
489 (*sinfos)->index = i + 1;
490 }
491
492 mbedtls_pkcs7_free(&pkcs7_ctx);
493 return msg;
494
495parse_fail:
496 mbedtls_pkcs7_free(&pkcs7_ctx);
497 pkcs7_free_message(msg);
498out_no_msg:
499 msg = ERR_PTR(ret);
500 return msg;
501}