blob: 742d8919402c74ce7279040aa1a12ba12a60b47b [file] [log] [blame]
AKASHI Takahiro1faaca42020-04-14 11:51:39 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
4 * Copyright (c) 2019 Linaro Limited, Author: AKASHI Takahiro
5 */
6
7#include <common.h>
8#include <charset.h>
9#include <efi_loader.h>
Heinrich Schuchardtcaeb73b2021-09-09 08:25:08 +020010#include <efi_variable.h>
AKASHI Takahiro1faaca42020-04-14 11:51:39 +090011#include <image.h>
12#include <hexdump.h>
13#include <malloc.h>
AKASHI Takahiro14afd062020-07-21 19:35:22 +090014#include <crypto/pkcs7.h>
AKASHI Takahiro6ec67672020-04-21 09:38:17 +090015#include <crypto/pkcs7_parser.h>
AKASHI Takahiro14afd062020-07-21 19:35:22 +090016#include <crypto/public_key.h>
AKASHI Takahiro1faaca42020-04-14 11:51:39 +090017#include <linux/compat.h>
18#include <linux/oid_registry.h>
Masahisa Kojima915e4272021-05-14 09:53:36 +090019#include <u-boot/hash-checksum.h>
AKASHI Takahiro1faaca42020-04-14 11:51:39 +090020#include <u-boot/rsa.h>
21#include <u-boot/sha256.h>
AKASHI Takahiro1faaca42020-04-14 11:51:39 +090022
AKASHI Takahiro1faaca42020-04-14 11:51:39 +090023const efi_guid_t efi_guid_sha256 = EFI_CERT_SHA256_GUID;
24const efi_guid_t efi_guid_cert_rsa2048 = EFI_CERT_RSA2048_GUID;
25const efi_guid_t efi_guid_cert_x509 = EFI_CERT_X509_GUID;
26const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +030027const efi_guid_t efi_guid_cert_x509_sha384 = EFI_CERT_X509_SHA384_GUID;
28const efi_guid_t efi_guid_cert_x509_sha512 = EFI_CERT_X509_SHA512_GUID;
AKASHI Takahiro5ed9ada2020-05-29 15:41:18 +090029const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +090030
Sughosh Ganuea350082020-12-30 19:27:07 +053031static u8 pkcs7_hdr[] = {
32 /* SEQUENCE */
33 0x30, 0x82, 0x05, 0xc7,
34 /* OID: pkcs7-signedData */
35 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
36 /* Context Structured? */
37 0xa0, 0x82, 0x05, 0xb8,
38};
39
40/**
41 * efi_parse_pkcs7_header - parse a signature in payload
42 * @buf: Pointer to payload's value
43 * @buflen: Length of @buf
44 * @tmpbuf: Pointer to temporary buffer
45 *
46 * Parse a signature embedded in payload's value and instantiate
47 * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
48 * pkcs7's signedData, some header needed be prepended for correctly
49 * parsing authentication data
50 * A temporary buffer will be allocated if needed, and it should be
51 * kept valid during the authentication because some data in the buffer
52 * will be referenced by efi_signature_verify().
53 *
54 * Return: Pointer to pkcs7_message structure on success, NULL on error
55 */
56struct pkcs7_message *efi_parse_pkcs7_header(const void *buf,
57 size_t buflen,
58 u8 **tmpbuf)
59{
60 u8 *ebuf;
61 size_t ebuflen, len;
62 struct pkcs7_message *msg;
63
64 /*
65 * This is the best assumption to check if the binary is
66 * already in a form of pkcs7's signedData.
67 */
68 if (buflen > sizeof(pkcs7_hdr) &&
69 !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
70 msg = pkcs7_parse_message(buf, buflen);
71 if (IS_ERR(msg))
72 return NULL;
73 return msg;
74 }
75
76 /*
77 * Otherwise, we should add a dummy prefix sequence for pkcs7
78 * message parser to be able to process.
79 * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
80 * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
81 * TODO:
82 * The header should be composed in a more refined manner.
83 */
84 EFI_PRINT("Makeshift prefix added to authentication data\n");
85 ebuflen = sizeof(pkcs7_hdr) + buflen;
86 if (ebuflen <= 0x7f) {
87 EFI_PRINT("Data is too short\n");
88 return NULL;
89 }
90
91 ebuf = malloc(ebuflen);
92 if (!ebuf) {
93 EFI_PRINT("Out of memory\n");
94 return NULL;
95 }
96
97 memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
98 memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
99 len = ebuflen - 4;
100 ebuf[2] = (len >> 8) & 0xff;
101 ebuf[3] = len & 0xff;
102 len = ebuflen - 0x13;
103 ebuf[0x11] = (len >> 8) & 0xff;
104 ebuf[0x12] = len & 0xff;
105
106 msg = pkcs7_parse_message(ebuf, ebuflen);
107
108 if (IS_ERR(msg)) {
109 free(ebuf);
110 return NULL;
111 }
112
113 *tmpbuf = ebuf;
114 return msg;
115}
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900116
117/**
118 * efi_hash_regions - calculate a hash value
AKASHI Takahiroddbfa612020-07-08 14:01:55 +0900119 * @regs: Array of regions
120 * @count: Number of regions
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900121 * @hash: Pointer to a pointer to buffer holding a hash value
122 * @size: Size of buffer to be returned
123 *
124 * Calculate a sha256 value of @regs and return a value in @hash.
125 *
126 * Return: true on success, false on error
127 */
AKASHI Takahirof47b9b32022-07-05 14:48:12 +0900128bool efi_hash_regions(struct image_region *regs, int count,
129 void **hash, const char *hash_algo, int *len)
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900130{
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300131 int ret, hash_len;
132
133 if (!hash_algo)
134 return false;
135
136 hash_len = algo_to_len(hash_algo);
137 if (!hash_len)
138 return false;
139
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900140 if (!*hash) {
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300141 *hash = calloc(1, hash_len);
AKASHI Takahiroddbfa612020-07-08 14:01:55 +0900142 if (!*hash) {
143 EFI_PRINT("Out of memory\n");
144 return false;
145 }
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900146 }
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900147
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300148 ret = hash_calculate(hash_algo, regs, count, *hash);
149 if (ret)
150 return false;
151
152 if (len)
153 *len = hash_len;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900154#ifdef DEBUG
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900155 EFI_PRINT("hash calculated:\n");
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900156 print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300157 *hash, hash_len, false);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900158#endif
159
160 return true;
161}
162
163/**
Ilias Apalodimas71eae982022-01-29 00:20:31 +0200164 * hash_algo_supported - check if the requested hash algorithm is supported
165 * @guid: guid of the algorithm
166 *
167 * Return: true if supported false otherwise
168 */
169static bool hash_algo_supported(const efi_guid_t guid)
170{
171 int i;
172 const efi_guid_t unsupported_hashes[] = {
173 EFI_CERT_SHA1_GUID,
174 EFI_CERT_SHA224_GUID,
175 EFI_CERT_SHA384_GUID,
176 EFI_CERT_SHA512_GUID,
177 };
178
179 for (i = 0; i < ARRAY_SIZE(unsupported_hashes); i++) {
180 if (!guidcmp(&unsupported_hashes[i], &guid))
181 return false;
182 }
183
184 return true;
185}
186
187/**
AKASHI Takahirode924072020-07-08 14:01:57 +0900188 * efi_signature_lookup_digest - search for an image's digest in sigdb
189 * @regs: List of regions to be authenticated
190 * @db: Signature database for trusted certificates
Ilias Apalodimas71eae982022-01-29 00:20:31 +0200191 * @dbx Caller needs to set this to true if he is searching dbx
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900192 *
AKASHI Takahirode924072020-07-08 14:01:57 +0900193 * A message digest of image pointed to by @regs is calculated and
194 * its hash value is compared to entries in signature database pointed
195 * to by @db.
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900196 *
AKASHI Takahirode924072020-07-08 14:01:57 +0900197 * Return: true if found, false if not
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900198 */
AKASHI Takahirode924072020-07-08 14:01:57 +0900199bool efi_signature_lookup_digest(struct efi_image_regions *regs,
Ilias Apalodimas71eae982022-01-29 00:20:31 +0200200 struct efi_signature_store *db,
201 bool dbx)
202
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900203{
AKASHI Takahirode924072020-07-08 14:01:57 +0900204 struct efi_signature_store *siglist;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900205 struct efi_sig_data *sig_data;
AKASHI Takahirode924072020-07-08 14:01:57 +0900206 void *hash = NULL;
AKASHI Takahirode924072020-07-08 14:01:57 +0900207 bool found = false;
Ilias Apalodimas81adfff2022-01-29 00:20:32 +0200208 bool hash_done = false;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900209
AKASHI Takahirode924072020-07-08 14:01:57 +0900210 EFI_PRINT("%s: Enter, %p, %p\n", __func__, regs, db);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900211
AKASHI Takahirode924072020-07-08 14:01:57 +0900212 if (!regs || !db || !db->sig_data_list)
213 goto out;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900214
AKASHI Takahirode924072020-07-08 14:01:57 +0900215 for (siglist = db; siglist; siglist = siglist->next) {
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300216 int len = 0;
217 const char *hash_algo = NULL;
Ilias Apalodimas71eae982022-01-29 00:20:31 +0200218 /*
219 * if the hash algorithm is unsupported and we get an entry in
220 * dbx reject the image
221 */
222 if (dbx && !hash_algo_supported(siglist->sig_type)) {
223 found = true;
224 continue;
225 };
226 /*
227 * Only support sha256 for now, that's what
228 * hash-to-efi-sig-list produces
229 */
230 if (guidcmp(&siglist->sig_type, &efi_guid_sha256))
231 continue;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900232
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300233 hash_algo = guid_to_sha_str(&efi_guid_sha256);
234 /*
235 * We could check size and hash_algo but efi_hash_regions()
236 * will do that for us
237 */
Ilias Apalodimas81adfff2022-01-29 00:20:32 +0200238 if (!hash_done &&
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300239 !efi_hash_regions(regs->reg, regs->num, &hash, hash_algo,
240 &len)) {
AKASHI Takahirode924072020-07-08 14:01:57 +0900241 EFI_PRINT("Digesting an image failed\n");
242 break;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900243 }
Ilias Apalodimas81adfff2022-01-29 00:20:32 +0200244 hash_done = true;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900245
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900246 for (sig_data = siglist->sig_data_list; sig_data;
247 sig_data = sig_data->next) {
248#ifdef DEBUG
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900249 EFI_PRINT("Msg digest in database:\n");
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900250 print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
251 sig_data->data, sig_data->size, false);
252#endif
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300253 if (sig_data->size == len &&
254 !memcmp(sig_data->data, hash, len)) {
AKASHI Takahirode924072020-07-08 14:01:57 +0900255 found = true;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900256 free(hash);
257 goto out;
258 }
259 }
AKASHI Takahirode924072020-07-08 14:01:57 +0900260
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900261 free(hash);
AKASHI Takahirode924072020-07-08 14:01:57 +0900262 hash = NULL;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900263 }
264
AKASHI Takahirode924072020-07-08 14:01:57 +0900265out:
266 EFI_PRINT("%s: Exit, found: %d\n", __func__, found);
267 return found;
268}
269
270/**
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900271 * efi_lookup_certificate - find a certificate within db
272 * @msg: Signature
273 * @db: Signature database
AKASHI Takahirode924072020-07-08 14:01:57 +0900274 *
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900275 * Search signature database pointed to by @db and find a certificate
276 * pointed to by @cert.
AKASHI Takahirode924072020-07-08 14:01:57 +0900277 *
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900278 * Return: true if found, false otherwise.
AKASHI Takahirode924072020-07-08 14:01:57 +0900279 */
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900280static bool efi_lookup_certificate(struct x509_certificate *cert,
281 struct efi_signature_store *db)
AKASHI Takahirode924072020-07-08 14:01:57 +0900282{
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900283 struct efi_signature_store *siglist;
AKASHI Takahirode924072020-07-08 14:01:57 +0900284 struct efi_sig_data *sig_data;
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900285 struct image_region reg[1];
286 void *hash = NULL, *hash_tmp = NULL;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300287 int len = 0;
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900288 bool found = false;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300289 const char *hash_algo = NULL;
AKASHI Takahirode924072020-07-08 14:01:57 +0900290
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900291 EFI_PRINT("%s: Enter, %p, %p\n", __func__, cert, db);
AKASHI Takahirode924072020-07-08 14:01:57 +0900292
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900293 if (!cert || !db || !db->sig_data_list)
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900294 goto out;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900295
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900296 /*
297 * TODO: identify a certificate using sha256 digest
298 * Is there any better way?
299 */
300 /* calculate hash of TBSCertificate */
301 reg[0].data = cert->tbs;
302 reg[0].size = cert->tbs_size;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300303
304 /* We just need any sha256 algo to start the matching */
305 hash_algo = guid_to_sha_str(&efi_guid_sha256);
306 if (!efi_hash_regions(reg, 1, &hash, hash_algo, &len))
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900307 goto out;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900308
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900309 EFI_PRINT("%s: searching for %s\n", __func__, cert->subject);
310 for (siglist = db; siglist; siglist = siglist->next) {
311 /* only with x509 certificate */
312 if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509))
313 continue;
314
315 for (sig_data = siglist->sig_data_list; sig_data;
316 sig_data = sig_data->next) {
317 struct x509_certificate *cert_tmp;
318
319 cert_tmp = x509_cert_parse(sig_data->data,
320 sig_data->size);
321 if (IS_ERR_OR_NULL(cert_tmp))
322 continue;
323
AKASHI Takahiro16411802020-08-14 14:39:23 +0900324 EFI_PRINT("%s: against %s\n", __func__,
325 cert_tmp->subject);
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900326 reg[0].data = cert_tmp->tbs;
327 reg[0].size = cert_tmp->tbs_size;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300328 if (!efi_hash_regions(reg, 1, &hash_tmp, hash_algo,
329 NULL))
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900330 goto out;
331
332 x509_free_certificate(cert_tmp);
333
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300334 if (!memcmp(hash, hash_tmp, len)) {
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900335 found = true;
336 goto out;
337 }
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900338 }
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900339 }
340out:
341 free(hash);
342 free(hash_tmp);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900343
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900344 EFI_PRINT("%s: Exit, found: %d\n", __func__, found);
345 return found;
346}
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900347
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900348/**
349 * efi_verify_certificate - verify certificate's signature with database
350 * @signer: Certificate
351 * @db: Signature database
352 * @root: Certificate to verify @signer
353 *
354 * Determine if certificate pointed to by @signer may be verified
355 * by one of certificates in signature database pointed to by @db.
356 *
357 * Return: true if certificate is verified, false otherwise.
358 */
359static bool efi_verify_certificate(struct x509_certificate *signer,
360 struct efi_signature_store *db,
361 struct x509_certificate **root)
362{
363 struct efi_signature_store *siglist;
364 struct efi_sig_data *sig_data;
365 struct x509_certificate *cert;
366 bool verified = false;
367 int ret;
368
369 EFI_PRINT("%s: Enter, %p, %p\n", __func__, signer, db);
370
371 if (!signer || !db || !db->sig_data_list)
372 goto out;
373
374 for (siglist = db; siglist; siglist = siglist->next) {
375 /* only with x509 certificate */
376 if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509))
377 continue;
378
379 for (sig_data = siglist->sig_data_list; sig_data;
380 sig_data = sig_data->next) {
381 cert = x509_cert_parse(sig_data->data, sig_data->size);
382 if (IS_ERR_OR_NULL(cert)) {
383 EFI_PRINT("Cannot parse x509 certificate\n");
384 continue;
385 }
386
387 ret = public_key_verify_signature(cert->pub,
388 signer->sig);
389 if (!ret) {
390 verified = true;
391 if (root)
392 *root = cert;
393 else
394 x509_free_certificate(cert);
395 goto out;
396 }
397 x509_free_certificate(cert);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900398 }
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900399 }
400
401out:
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900402 EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900403 return verified;
404}
405
406/**
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900407 * efi_signature_check_revocation - check revocation with dbx
408 * @sinfo: Signer's info
409 * @cert: x509 certificate
410 * @dbx: Revocation signature database
411 *
412 * Search revocation signature database pointed to by @dbx and find
413 * an entry matching to certificate pointed to by @cert.
414 *
415 * While this entry contains revocation time, we don't support timestamp
416 * protocol at this time and any image will be unconditionally revoked
417 * when this match occurs.
418 *
AKASHI Takahiro16411802020-08-14 14:39:23 +0900419 * Return: true if check passed (not found), false otherwise.
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900420 */
421static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
422 struct x509_certificate *cert,
423 struct efi_signature_store *dbx)
424{
425 struct efi_signature_store *siglist;
426 struct efi_sig_data *sig_data;
427 struct image_region reg[1];
428 void *hash = NULL;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300429 int len = 0;
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900430 time64_t revoc_time;
431 bool revoked = false;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300432 const char *hash_algo = NULL;
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900433
434 EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, sinfo, cert, dbx);
435
436 if (!sinfo || !cert || !dbx || !dbx->sig_data_list)
437 goto out;
438
439 EFI_PRINT("Checking revocation against %s\n", cert->subject);
440 for (siglist = dbx; siglist; siglist = siglist->next) {
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300441 hash_algo = guid_to_sha_str(&siglist->sig_type);
442 if (!hash_algo)
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900443 continue;
444
445 /* calculate hash of TBSCertificate */
446 reg[0].data = cert->tbs;
447 reg[0].size = cert->tbs_size;
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300448 if (!efi_hash_regions(reg, 1, &hash, hash_algo, &len))
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900449 goto out;
450
451 for (sig_data = siglist->sig_data_list; sig_data;
452 sig_data = sig_data->next) {
453 /*
454 * struct efi_cert_x509_sha256 {
455 * u8 tbs_hash[256/8];
456 * time64_t revocation_time;
457 * };
458 */
459#ifdef DEBUG
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300460 if (sig_data->size >= len) {
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900461 EFI_PRINT("hash in db:\n");
462 print_hex_dump(" ", DUMP_PREFIX_OFFSET,
463 16, 1,
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300464 sig_data->data, len, false);
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900465 }
466#endif
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300467 if ((sig_data->size < len + sizeof(time64_t)) ||
468 memcmp(sig_data->data, hash, len))
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900469 continue;
470
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300471 memcpy(&revoc_time, sig_data->data + len,
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900472 sizeof(revoc_time));
473 EFI_PRINT("revocation time: 0x%llx\n", revoc_time);
474 /*
475 * TODO: compare signing timestamp in sinfo
476 * with revocation time
477 */
478
479 revoked = true;
480 free(hash);
481 goto out;
482 }
483 free(hash);
484 hash = NULL;
485 }
486out:
487 EFI_PRINT("%s: Exit, revoked: %d\n", __func__, revoked);
488 return !revoked;
489}
490
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900491/*
492 * efi_signature_verify - verify signatures with db and dbx
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900493 * @regs: List of regions to be authenticated
494 * @msg: Signature
495 * @db: Signature database for trusted certificates
496 * @dbx: Revocation signature database
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900497 *
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900498 * All the signature pointed to by @msg against image pointed to by @regs
499 * will be verified by signature database pointed to by @db and @dbx.
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900500 *
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900501 * Return: true if verification for all signatures passed, false otherwise
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900502 */
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900503bool efi_signature_verify(struct efi_image_regions *regs,
504 struct pkcs7_message *msg,
505 struct efi_signature_store *db,
506 struct efi_signature_store *dbx)
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900507{
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900508 struct pkcs7_signed_info *sinfo;
509 struct x509_certificate *signer, *root;
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900510 bool verified = false;
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900511 int ret;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900512
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900513 EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, dbx);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900514
AKASHI Takahirode924072020-07-08 14:01:57 +0900515 if (!regs || !msg || !db || !db->sig_data_list)
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900516 goto out;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900517
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900518 for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900519 EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900520 sinfo->sig->hash_algo, sinfo->sig->pkey_algo);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900521
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900522 /*
523 * only for authenticated variable.
524 *
525 * If this function is called for image,
526 * hash calculation will be done in
527 * pkcs7_verify_one().
528 */
529 if (!msg->data &&
530 !efi_hash_regions(regs->reg, regs->num,
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300531 (void **)&sinfo->sig->digest,
532 guid_to_sha_str(&efi_guid_sha256),
533 NULL)) {
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900534 EFI_PRINT("Digesting an image failed\n");
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900535 goto out;
536 }
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900537
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900538 EFI_PRINT("Verifying certificate chain\n");
539 signer = NULL;
540 ret = pkcs7_verify_one(msg, sinfo, &signer);
541 if (ret == -ENOPKG)
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900542 continue;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900543
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900544 if (ret < 0 || !signer)
545 goto out;
546
547 if (sinfo->blacklisted)
548 goto out;
549
550 EFI_PRINT("Verifying last certificate in chain\n");
Ilias Apalodimas1ee9c482022-02-14 11:14:22 +0200551 if (efi_lookup_certificate(signer, db))
552 if (efi_signature_check_revocation(sinfo, signer, dbx))
553 break;
554 if (!signer->self_signed &&
555 efi_verify_certificate(signer, db, &root)) {
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900556 bool check;
557
558 check = efi_signature_check_revocation(sinfo, root,
559 dbx);
560 x509_free_certificate(root);
561 if (check)
AKASHI Takahiro16411802020-08-14 14:39:23 +0900562 break;
AKASHI Takahiro14afd062020-07-21 19:35:22 +0900563 }
564
565 EFI_PRINT("Certificate chain didn't reach trusted CA\n");
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900566 }
AKASHI Takahiro16411802020-08-14 14:39:23 +0900567 if (sinfo)
568 verified = true;
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900569out:
570 EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified);
571 return verified;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900572}
573
574/**
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900575 * efi_signature_check_signers - check revocation against all signers with dbx
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900576 * @msg: Signature
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900577 * @dbx: Revocation signature database
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900578 *
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900579 * Determine if none of signers' certificates in @msg are revoked
580 * by signature database pointed to by @dbx.
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900581 *
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900582 * Return: true if all signers passed, false otherwise.
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900583 */
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900584bool efi_signature_check_signers(struct pkcs7_message *msg,
585 struct efi_signature_store *dbx)
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900586{
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900587 struct pkcs7_signed_info *sinfo;
588 bool revoked = false;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900589
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900590 EFI_PRINT("%s: Enter, %p, %p\n", __func__, msg, dbx);
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900591
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900592 if (!msg || !dbx)
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900593 goto out;
594
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900595 for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
596 if (sinfo->signer &&
597 !efi_signature_check_revocation(sinfo, sinfo->signer,
598 dbx)) {
599 revoked = true;
600 break;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900601 }
602 }
603out:
AKASHI Takahiro4154b642020-07-08 14:01:56 +0900604 EFI_PRINT("%s: Exit, revoked: %d\n", __func__, revoked);
605 return !revoked;
AKASHI Takahiro1faaca42020-04-14 11:51:39 +0900606}
607
608/**
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900609 * efi_sigstore_free - free signature store
610 * @sigstore: Pointer to signature store structure
611 *
612 * Feee all the memories held in signature store and itself,
613 * which were allocated by efi_sigstore_parse_sigdb().
614 */
615void efi_sigstore_free(struct efi_signature_store *sigstore)
616{
617 struct efi_signature_store *sigstore_next;
618 struct efi_sig_data *sig_data, *sig_data_next;
619
620 while (sigstore) {
621 sigstore_next = sigstore->next;
622
623 sig_data = sigstore->sig_data_list;
624 while (sig_data) {
625 sig_data_next = sig_data->next;
626 free(sig_data->data);
627 free(sig_data);
628 sig_data = sig_data_next;
629 }
630
631 free(sigstore);
632 sigstore = sigstore_next;
633 }
634}
635
636/**
637 * efi_sigstore_parse_siglist - parse a signature list
638 * @name: Pointer to signature list
639 *
640 * Parse signature list and instantiate a signature store structure.
641 * Signature database is a simple concatenation of one or more
642 * signature list(s).
643 *
644 * Return: Pointer to signature store on success, NULL on error
645 */
646static struct efi_signature_store *
647efi_sigstore_parse_siglist(struct efi_signature_list *esl)
648{
649 struct efi_signature_store *siglist = NULL;
650 struct efi_sig_data *sig_data, *sig_data_next;
651 struct efi_signature_data *esd;
652 size_t left;
653
654 /*
655 * UEFI specification defines certificate types:
656 * for non-signed images,
657 * EFI_CERT_SHA256_GUID
658 * EFI_CERT_RSA2048_GUID
659 * EFI_CERT_RSA2048_SHA256_GUID
660 * EFI_CERT_SHA1_GUID
661 * EFI_CERT_RSA2048_SHA_GUID
662 * EFI_CERT_SHA224_GUID
663 * EFI_CERT_SHA384_GUID
664 * EFI_CERT_SHA512_GUID
665 *
666 * for signed images,
667 * EFI_CERT_X509_GUID
668 * NOTE: Each certificate will normally be in a separate
669 * EFI_SIGNATURE_LIST as the size may vary depending on
670 * its algo's.
671 *
672 * for timestamp revocation of certificate,
673 * EFI_CERT_X509_SHA512_GUID
674 * EFI_CERT_X509_SHA256_GUID
675 * EFI_CERT_X509_SHA384_GUID
676 */
677
678 if (esl->signature_list_size
679 <= (sizeof(*esl) + esl->signature_header_size)) {
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900680 EFI_PRINT("Siglist in wrong format\n");
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900681 return NULL;
682 }
683
684 /* Create a head */
685 siglist = calloc(sizeof(*siglist), 1);
686 if (!siglist) {
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900687 EFI_PRINT("Out of memory\n");
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900688 goto err;
689 }
690 memcpy(&siglist->sig_type, &esl->signature_type, sizeof(efi_guid_t));
691
692 /* Go through the list */
693 sig_data_next = NULL;
694 left = esl->signature_list_size
695 - (sizeof(*esl) + esl->signature_header_size);
696 esd = (struct efi_signature_data *)
697 ((u8 *)esl + sizeof(*esl) + esl->signature_header_size);
698
AKASHI Takahiroa075aa32020-04-21 09:38:57 +0900699 while (left > 0) {
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900700 /* Signature must exist if there is remaining data. */
701 if (left < esl->signature_size) {
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900702 EFI_PRINT("Certificate is too small\n");
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900703 goto err;
704 }
705
706 sig_data = calloc(esl->signature_size
707 - sizeof(esd->signature_owner), 1);
708 if (!sig_data) {
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900709 EFI_PRINT("Out of memory\n");
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900710 goto err;
711 }
712
713 /* Append signature data */
714 memcpy(&sig_data->owner, &esd->signature_owner,
715 sizeof(efi_guid_t));
716 sig_data->size = esl->signature_size
717 - sizeof(esd->signature_owner);
718 sig_data->data = malloc(sig_data->size);
719 if (!sig_data->data) {
AKASHI Takahiro10a9fa82020-06-09 14:09:33 +0900720 EFI_PRINT("Out of memory\n");
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900721 goto err;
722 }
723 memcpy(sig_data->data, esd->signature_data, sig_data->size);
724
725 sig_data->next = sig_data_next;
726 sig_data_next = sig_data;
727
728 /* Next */
729 esd = (struct efi_signature_data *)
730 ((u8 *)esd + esl->signature_size);
731 left -= esl->signature_size;
732 }
733 siglist->sig_data_list = sig_data_next;
734
735 return siglist;
736
737err:
738 efi_sigstore_free(siglist);
739
740 return NULL;
741}
742
743/**
Sughosh Ganufa0faa62020-12-30 19:27:08 +0530744 * efi_sigstore_parse_sigdb - parse the signature list and populate
745 * the signature store
746 *
747 * @sig_list: Pointer to the signature list
748 * @size: Size of the signature list
749 *
750 * Parse the efi signature list and instantiate a signature store
751 * structure.
752 *
753 * Return: Pointer to signature store on success, NULL on error
754 */
755struct efi_signature_store *efi_build_signature_store(void *sig_list,
756 efi_uintn_t size)
757{
758 struct efi_signature_list *esl;
759 struct efi_signature_store *sigstore = NULL, *siglist;
760
761 esl = sig_list;
762 while (size > 0) {
763 /* List must exist if there is remaining data. */
764 if (size < sizeof(*esl)) {
765 EFI_PRINT("Signature list in wrong format\n");
766 goto err;
767 }
768
769 if (size < esl->signature_list_size) {
770 EFI_PRINT("Signature list in wrong format\n");
771 goto err;
772 }
773
774 /* Parse a single siglist. */
775 siglist = efi_sigstore_parse_siglist(esl);
776 if (!siglist) {
777 EFI_PRINT("Parsing of signature list of failed\n");
778 goto err;
779 }
780
781 /* Append siglist */
782 siglist->next = sigstore;
783 sigstore = siglist;
784
785 /* Next */
786 size -= esl->signature_list_size;
787 esl = (void *)esl + esl->signature_list_size;
788 }
789 free(sig_list);
790
791 return sigstore;
792
793err:
794 efi_sigstore_free(sigstore);
795 free(sig_list);
796
797 return NULL;
798}
799
800/**
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900801 * efi_sigstore_parse_sigdb - parse a signature database variable
802 * @name: Variable's name
803 *
804 * Read in a value of signature database variable pointed to by
805 * @name, parse it and instantiate a signature store structure.
806 *
807 * Return: Pointer to signature store on success, NULL on error
808 */
809struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
810{
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900811 const efi_guid_t *vendor;
812 void *db;
813 efi_uintn_t db_size;
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900814
Heinrich Schuchardtcaeb73b2021-09-09 08:25:08 +0200815 vendor = efi_auth_var_get_guid(name);
816 db = efi_get_var(name, vendor, &db_size);
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900817 if (!db) {
Heinrich Schuchardtcaeb73b2021-09-09 08:25:08 +0200818 EFI_PRINT("variable, %ls, not found\n", name);
819 return calloc(sizeof(struct efi_signature_store), 1);
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900820 }
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900821
Sughosh Ganufa0faa62020-12-30 19:27:08 +0530822 return efi_build_signature_store(db, db_size);
AKASHI Takahirod2cefc82020-04-14 11:51:40 +0900823}