VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTEfiSigDb.cpp@ 90335

Last change on this file since 90335 was 90335, checked in by vboxsync, 3 years ago

Runtime/tools/RTEfiSigDb: Try to fix lin32 builds, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.2 KB
Line 
1/* $Id: RTEfiSigDb.cpp 90335 2021-07-26 13:24:20Z vboxsync $ */
2/** @file
3 * IPRT - Utility for manipulating EFI signature databases.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/assert.h>
32#include <iprt/buildconfig.h>
33#include <iprt/err.h>
34#include <iprt/efi.h>
35#include <iprt/file.h>
36#include <iprt/getopt.h>
37#include <iprt/initterm.h>
38#include <iprt/mem.h>
39#include <iprt/message.h>
40#include <iprt/path.h>
41#include <iprt/stream.h>
42#include <iprt/string.h>
43#include <iprt/uuid.h>
44#include <iprt/vfs.h>
45
46#include <iprt/formats/efi-signature.h>
47#include <iprt/formats/efi-varstore.h>
48
49
50/*********************************************************************************************************************************
51* Structures and Typedefs *
52*********************************************************************************************************************************/
53
54
55/*********************************************************************************************************************************
56* Global Variables *
57*********************************************************************************************************************************/
58/** Signature type identifier to internal type mapping. */
59struct RTEFISIGDBID2TYPEENTRY
60{
61 const char *pszId;
62 RTEFISIGTYPE enmType;
63} g_aId2SigType[] =
64{
65 { "sha256", RTEFISIGTYPE_SHA256 },
66 { "rsa2048", RTEFISIGTYPE_RSA2048 },
67 { "x509", RTEFISIGTYPE_X509 }
68};
69
70
71/*********************************************************************************************************************************
72* Internal Functions *
73*********************************************************************************************************************************/
74
75/**
76 * Display the version of the cache program.
77 *
78 * @returns exit code.
79 */
80static RTEXITCODE rtEfiSigDbVersion(void)
81{
82 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
83 return RTEXITCODE_SUCCESS;
84}
85
86
87/**
88 * Shows the usage of the program.
89 *
90 * @returns Exit code.
91 * @param pszArg0 Program name.
92 * @param pszCommand Command selector, NULL if all.
93 */
94static RTEXITCODE rtEfiSigDbUsage(const char *pszArg0, const char *pszCommand)
95{
96 if (!pszCommand || !strcmp(pszCommand, "list"))
97 RTPrintf("Usage: %s list <signature database path>\n"
98 , RTPathFilename(pszArg0));
99
100 if (!pszCommand || !strcmp(pszCommand, "add"))
101 RTPrintf("Usage: %s add <signature database path> <x509|sha256|rsa2048> <owner uuid> <signature path> ...\n"
102 , RTPathFilename(pszArg0));
103
104 if (!pszCommand || !strcmp(pszCommand, "initnvram"))
105 RTPrintf("Usage: %s initnvram <nvram path> <init options>\n"
106 "\n"
107 "Init Options:\n"
108 " --pk <path>\n"
109 " Init the PK with the given signature.\n"
110 " --pk-owner <uuid>\n"
111 " Set the given UUID as the owner of the PK.\n"
112 " --kek <path>\n"
113 " Init the KEK with the given signature.\n"
114 " --kek-owner <uuid>\n"
115 " Set the given UUID as the owner of the KEK.\n"
116 " --db <x509|sha256|rsa2048>:<owner uuid>:<path>\n"
117 " Adds the given signature with the owner UUID and type to the db, can be given multiple times.\n"
118 " --secure-boot <on|off>\n"
119 " Enables or disables secure boot\n"
120 , RTPathFilename(pszArg0));
121
122 return RTEXITCODE_SUCCESS;
123}
124
125
126static RTEFISIGTYPE rtEfiSigDbGetTypeById(const char *pszId)
127{
128 for (uint32_t i = 0; i < RT_ELEMENTS(g_aId2SigType); i++)
129 if (!strcmp(pszId, g_aId2SigType[i].pszId))
130 return g_aId2SigType[i].enmType;
131
132 return RTEFISIGTYPE_INVALID;
133}
134
135
136/**
137 * Opens the specified signature database, returning an VFS file handle on success.
138 *
139 * @returns IPRT status code.
140 * @param pszPath Path to the signature database.
141 * @param phVfsFile Where to return the VFS file handle on success.
142 */
143static int rtEfiSigDbOpen(const char *pszPath, PRTVFSFILE phVfsFile)
144{
145 int rc;
146
147 if (RTVfsChainIsSpec(pszPath))
148 {
149 RTVFSOBJ hVfsObj;
150 rc = RTVfsChainOpenObj(pszPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
151 RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_ON_LINK,
152 &hVfsObj, NULL, NULL);
153 if ( RT_SUCCESS(rc)
154 && RTVfsObjGetType(hVfsObj) == RTVFSOBJTYPE_FILE)
155 {
156 *phVfsFile = RTVfsObjToFile(hVfsObj);
157 RTVfsObjRelease(hVfsObj);
158 }
159 else
160 {
161 RTPrintf("'%s' doesn't point to a file\n", pszPath);
162 rc = VERR_INVALID_PARAMETER;
163 }
164 }
165 else
166 rc = RTVfsFileOpenNormal(pszPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
167 phVfsFile);
168
169 return rc;
170}
171
172
173/**
174 * Signature database enumeration callback.
175 */
176static DECLCALLBACK(int) rtEfiSgDbEnum(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner,
177 const void *pvSig, size_t cbSig, void *pvUser)
178{
179 RT_NOREF(hEfiSigDb, pvUser);
180
181 uint32_t *pidxSig = (uint32_t *)pvUser;
182
183 RTPrintf("%02u: %s\n", (*pidxSig)++, RTEfiSigDbTypeStringify(enmSigType));
184 RTPrintf(" Owner: %RTuuid\n", pUuidOwner);
185 RTPrintf(" Signature:\n"
186 "%.*Rhxd\n\n", cbSig, pvSig);
187 return VINF_SUCCESS;
188}
189
190
191/**
192 * Handles the 'list' command.
193 *
194 * @returns Program exit code.
195 * @param pszArg0 The program name.
196 * @param cArgs The number of arguments to the 'add' command.
197 * @param papszArgs The argument vector, starting after 'add'.
198 */
199static RTEXITCODE rtEfiSgDbCmdList(const char *pszArg0, int cArgs, char **papszArgs)
200{
201 RT_NOREF(pszArg0);
202
203 if (!cArgs)
204 {
205 RTPrintf("An input path must be given\n");
206 return RTEXITCODE_FAILURE;
207 }
208
209 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
210 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
211 int rc = rtEfiSigDbOpen(papszArgs[0], &hVfsFile);
212 if (RT_SUCCESS(rc))
213 {
214 RTEFISIGDB hEfiSigDb;
215 rc = RTEfiSigDbCreate(&hEfiSigDb);
216 if (RT_SUCCESS(rc))
217 {
218 uint32_t idxSig = 0;
219
220 rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
221 if (RT_SUCCESS(rc))
222 RTEfiSigDbEnum(hEfiSigDb, rtEfiSgDbEnum, &idxSig);
223 else
224 {
225 RTPrintf("Loading the signature database failed with %Rrc\n", rc);
226 rcExit = RTEXITCODE_FAILURE;
227 }
228
229 RTEfiSigDbDestroy(hEfiSigDb);
230 }
231 else
232 {
233 RTPrintf("Creating the signature database failed with %Rrc\n", rc);
234 rcExit = RTEXITCODE_FAILURE;
235 }
236
237 RTVfsFileRelease(hVfsFile);
238 }
239 else
240 rcExit = RTEXITCODE_FAILURE;
241
242 return rcExit;
243}
244
245
246/**
247 * Handles the 'add' command.
248 *
249 * @returns Program exit code.
250 * @param pszArg0 The program name.
251 * @param cArgs The number of arguments to the 'add' command.
252 * @param papszArgs The argument vector, starting after 'add'.
253 */
254static RTEXITCODE rtEfiSgDbCmdAdd(const char *pszArg0, int cArgs, char **papszArgs)
255{
256 RT_NOREF(pszArg0);
257
258 if (!cArgs)
259 {
260 RTPrintf("The signature database path is missing\n");
261 return RTEXITCODE_FAILURE;
262 }
263
264 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
265 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
266 int rc = rtEfiSigDbOpen(papszArgs[0], &hVfsFile);
267 if (RT_SUCCESS(rc))
268 {
269 RTEFISIGDB hEfiSigDb;
270 rc = RTEfiSigDbCreate(&hEfiSigDb);
271 if (RT_SUCCESS(rc))
272 {
273 uint64_t cbSigDb = 0;
274 rc = RTVfsFileQuerySize(hVfsFile, &cbSigDb);
275 if ( RT_SUCCESS(rc)
276 && cbSigDb)
277 rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
278 if (RT_SUCCESS(rc))
279 {
280 cArgs--;
281 papszArgs++;
282
283 while (cArgs >= 3)
284 {
285 RTEFISIGTYPE enmSigType = rtEfiSigDbGetTypeById(papszArgs[0]);
286 const char *pszUuidOwner = papszArgs[1];
287 const char *pszSigDataPath = papszArgs[2];
288
289 if (enmSigType == RTEFISIGTYPE_INVALID)
290 {
291 RTPrintf("Signature type '%s' is not known\n", papszArgs[0]);
292 break;
293 }
294
295 RTUUID UuidOwner;
296 rc = RTUuidFromStr(&UuidOwner, pszUuidOwner);
297 if (RT_FAILURE(rc))
298 {
299 RTPrintf("UUID '%s' is malformed\n", pszUuidOwner);
300 break;
301 }
302
303 RTVFSFILE hVfsFileSigData = NIL_RTVFSFILE;
304 rc = rtEfiSigDbOpen(pszSigDataPath, &hVfsFileSigData);
305 if (RT_FAILURE(rc))
306 {
307 RTPrintf("Opening '%s' failed with %Rrc\n", pszSigDataPath, rc);
308 break;
309 }
310
311 rc = RTEfiSigDbAddSignatureFromFile(hEfiSigDb, enmSigType, &UuidOwner, hVfsFileSigData);
312 RTVfsFileRelease(hVfsFileSigData);
313 if (RT_FAILURE(rc))
314 {
315 RTPrintf("Adding signature data from '%s' failed with %Rrc\n", pszSigDataPath, rc);
316 break;
317 }
318 papszArgs += 3;
319 cArgs -= 3;
320 }
321
322 if (RT_SUCCESS(rc))
323 {
324 if (!cArgs)
325 {
326 rc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
327 AssertRC(rc);
328
329 rc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFile);
330 if (RT_FAILURE(rc))
331 {
332 RTPrintf("Writing the updated signature database failed with %Rrc\n", rc);
333 rcExit = RTEXITCODE_FAILURE;
334 }
335 }
336 else
337 {
338 RTPrintf("Incomplete list of entries to add given\n");
339 rcExit = RTEXITCODE_FAILURE;
340 }
341 }
342 }
343 else
344 {
345 RTPrintf("Loading the signature database failed with %Rrc\n", rc);
346 rcExit = RTEXITCODE_FAILURE;
347 }
348
349 RTEfiSigDbDestroy(hEfiSigDb);
350 }
351 else
352 {
353 RTPrintf("Creating the signature database failed with %Rrc\n", rc);
354 rcExit = RTEXITCODE_FAILURE;
355 }
356
357 RTVfsFileRelease(hVfsFile);
358 }
359 else
360 rcExit = RTEXITCODE_FAILURE;
361
362 return rcExit;
363}
364
365
366/**
367 * Adds the given signature to the given database.
368 *
369 * @returns IPRT status code.
370 * @param hEfiSigDb The EFI signature database handle.
371 * @param pszSigPath The signature data path.
372 * @param pszSigType The signature type.
373 * @param pszUuidOwner The owner UUID.
374 */
375static int rtEfiSigDbAddSig(RTEFISIGDB hEfiSigDb, const char *pszSigPath, const char *pszSigType, const char *pszUuidOwner)
376{
377 RTEFISIGTYPE enmSigType = rtEfiSigDbGetTypeById(pszSigType);
378 if (enmSigType == RTEFISIGTYPE_INVALID)
379 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Signature type '%s' is unknown!", pszSigType);
380
381 RTUUID UuidOwner;
382 int rc = RTUuidFromStr(&UuidOwner, pszUuidOwner);
383 if (RT_FAILURE(rc))
384 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Owner UUID '%s' is malformed!", pszUuidOwner);
385
386 RTVFSFILE hVfsFileSigData = NIL_RTVFSFILE;
387 rc = rtEfiSigDbOpen(pszSigPath, &hVfsFileSigData);
388 if (RT_FAILURE(rc))
389 return RTMsgErrorRc(rc, "Opening '%s' failed: %Rrc", pszSigPath, rc);
390
391 rc = RTEfiSigDbAddSignatureFromFile(hEfiSigDb, enmSigType, &UuidOwner, hVfsFileSigData);
392 RTVfsFileRelease(hVfsFileSigData);
393 if (RT_FAILURE(rc))
394 return RTMsgErrorRc(rc, "Adding signature '%s' failed: %Rrc", pszSigPath, rc);
395
396 return VINF_SUCCESS;
397}
398
399
400/**
401 * Sets the given attributes for the given EFI variable store variable.
402 *
403 * @returns IPRT status code.
404 * @param hVfsVarStore Handle of the EFI variable store VFS.
405 * @param pszVar The variable to set the attributes for.
406 * @param fAttr The attributes to set, see EFI_VAR_HEADER_ATTR_XXX.
407 */
408static int rtEfiSigDbSetVarAttr(RTVFS hVfsVarStore, const char *pszVar, uint32_t fAttr)
409{
410 char szVarPath[_1K];
411 ssize_t cch = RTStrPrintf2(szVarPath, sizeof(szVarPath), "/raw/%s/attr", pszVar);
412 Assert(cch > 0);
413
414 RTVFSFILE hVfsFileAttr = NIL_RTVFSFILE;
415 int rc = RTVfsFileOpen(hVfsVarStore, szVarPath,
416 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
417 &hVfsFileAttr);
418 if (RT_SUCCESS(rc))
419 {
420 uint32_t fAttrLe = RT_H2LE_U32(fAttr);
421 rc = RTVfsFileWrite(hVfsFileAttr, &fAttrLe, sizeof(fAttrLe), NULL /*pcbWritten*/);
422 RTVfsFileRelease(hVfsFileAttr);
423 }
424
425 return rc;
426}
427
428
429/**
430 * Adds the given signature to the given signature database of the given EFI variable store.
431 *
432 * @returns IPRT status code.
433 * @param hVfsVarStore Handle of the EFI variable store VFS.
434 * @param pszDb The signature database to update.
435 * @param fWipeDbBefore Flag whether to wipe the database before adding the signature.
436 * @param cSigs Number of signatures following.
437 * @param ... A triple of signature path, signature type and owner uuid string pointers for each
438 * signature.
439 */
440static int rtEfiSigDbVarStoreAddToDb(RTVFS hVfsVarStore, const char *pszDb, bool fWipeDbBefore, uint32_t cSigs,
441 ... /*const char *pszSigPath, const char *pszSigType, const char *pszUuidOwner*/)
442{
443 EFI_GUID GuidSecurityDb = EFI_IMAGE_SECURITY_DATABASE_GUID;
444 RTUUID UuidSecurityDb;
445 RTEfiGuidToUuid(&UuidSecurityDb, &GuidSecurityDb);
446
447 char szDbPath[_1K];
448 ssize_t cch = RTStrPrintf2(szDbPath, sizeof(szDbPath), "/by-uuid/%RTuuid/%s", &UuidSecurityDb, pszDb);
449 Assert(cch > 0);
450
451 RTVFSFILE hVfsFileSigDb = NIL_RTVFSFILE;
452 int rc = RTVfsFileOpen(hVfsVarStore, szDbPath,
453 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
454 &hVfsFileSigDb);
455 if ( rc == VERR_PATH_NOT_FOUND
456 || rc == VERR_FILE_NOT_FOUND)
457 {
458 /*
459 * Try to create the owner GUID of the variable by creating the appropriate directory,
460 * ignore error if it exists already.
461 */
462 RTVFSDIR hVfsDirRoot = NIL_RTVFSDIR;
463 rc = RTVfsOpenRoot(hVfsVarStore, &hVfsDirRoot);
464 if (RT_SUCCESS(rc))
465 {
466 char szGuidPath[_1K];
467 cch = RTStrPrintf2(szGuidPath, sizeof(szGuidPath), "by-uuid/%RTuuid", &UuidSecurityDb);
468 Assert(cch > 0);
469
470 RTVFSDIR hVfsDirGuid = NIL_RTVFSDIR;
471 rc = RTVfsDirCreateDir(hVfsDirRoot, szGuidPath, 0755, 0 /*fFlags*/, &hVfsDirGuid);
472 if (RT_SUCCESS(rc))
473 RTVfsDirRelease(hVfsDirGuid);
474 else if (rc == VERR_ALREADY_EXISTS)
475 rc = VINF_SUCCESS;
476
477 RTVfsDirRelease(hVfsDirRoot);
478 }
479 else
480 rc = RTMsgErrorRc(rc, "Opening variable storage root directory failed: %Rrc", rc);
481
482 if (RT_SUCCESS(rc))
483 {
484 rc = RTVfsFileOpen(hVfsVarStore, szDbPath,
485 RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE,
486 &hVfsFileSigDb);
487 if (RT_SUCCESS(rc))
488 rc = rtEfiSigDbSetVarAttr(hVfsVarStore, pszDb,
489 EFI_VAR_HEADER_ATTR_NON_VOLATILE
490 | EFI_VAR_HEADER_ATTR_BOOTSERVICE_ACCESS
491 | EFI_VAR_HEADER_ATTR_RUNTIME_ACCESS
492 | EFI_AUTH_VAR_HEADER_ATTR_TIME_BASED_AUTH_WRITE_ACCESS);
493 }
494
495 if (RT_FAILURE(rc))
496 rc = RTMsgErrorRc(rc, "Creating the signature database '%s' failed: %Rrc", pszDb, rc);
497 }
498
499 if (RT_SUCCESS(rc))
500 {
501 RTEFISIGDB hEfiSigDb;
502 rc = RTEfiSigDbCreate(&hEfiSigDb);
503 if (RT_SUCCESS(rc))
504 {
505 if (!fWipeDbBefore)
506 rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFileSigDb);
507 if (RT_SUCCESS(rc))
508 {
509 va_list VarArgs;
510 va_start(VarArgs, cSigs);
511
512 while ( cSigs--
513 && RT_SUCCESS(rc))
514 {
515 const char *pszSigPath = va_arg(VarArgs, const char *);
516 const char *pszSigType = va_arg(VarArgs, const char *);
517 const char *pszUuidOwner = va_arg(VarArgs, const char *);
518
519 rc = rtEfiSigDbAddSig(hEfiSigDb, pszSigPath, pszSigType, pszUuidOwner);
520 }
521
522 va_end(VarArgs);
523 if (RT_SUCCESS(rc))
524 {
525 rc = RTVfsFileSeek(hVfsFileSigDb, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
526 AssertRC(rc);
527
528 rc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFileSigDb);
529 if (RT_FAILURE(rc))
530 rc = RTMsgErrorRc(rc, "Writing updated signature database failed: %Rrc", rc);
531 }
532 }
533 else
534 rc = RTMsgErrorRc(rc, "Loading signature database failed: %Rrc", rc);
535
536 RTEfiSigDbDestroy(hEfiSigDb);
537 }
538 else
539 rc = RTMsgErrorRc(rc, "Creating signature database failed: %Rrc", rc);
540
541 RTVfsFileRelease(hVfsFileSigDb);
542 }
543 else
544 rc = RTMsgErrorRc(rc, "Opening signature database '%s' failed: %Rrc", szDbPath, rc);
545
546 return rc;
547}
548
549
550/**
551 * Handles the 'initnvram' command.
552 *
553 * @returns Program exit code.
554 * @param pszArg0 The program name.
555 * @param cArgs The number of arguments to the 'add' command.
556 * @param papszArgs The argument vector, starting after 'add'.
557 */
558static RTEXITCODE rtEfiSgDbCmdInitNvram(const char *pszArg0, int cArgs, char **papszArgs)
559{
560 RT_NOREF(pszArg0);
561 RTERRINFOSTATIC ErrInfo;
562
563 /*
564 * Parse the command line.
565 */
566 static RTGETOPTDEF const s_aOptions[] =
567 {
568 { "--pk", 'p', RTGETOPT_REQ_STRING },
569 { "--pk-owner", 'o', RTGETOPT_REQ_STRING },
570 { "--kek", 'k', RTGETOPT_REQ_STRING },
571 { "--kek-owner", 'w', RTGETOPT_REQ_STRING },
572 { "--db", 'd', RTGETOPT_REQ_STRING },
573 { "--secure-boot", 's', RTGETOPT_REQ_BOOL_ONOFF }
574 };
575
576 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
577 RTGETOPTSTATE State;
578 int rc = RTGetOptInit(&State, cArgs, papszArgs, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
579 if (RT_FAILURE(rc))
580 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOptInit failed: %Rrc", rc);
581
582 const char *pszNvram = NULL;
583 const char *pszPkPath = NULL;
584 const char *pszUuidPkOwner = NULL;
585 const char *pszKekPath = NULL;
586 const char *pszUuidKekOwner = NULL;
587 const char **papszDb = NULL;
588 bool fSecureBoot = true;
589 bool fSetSecureBoot = false;
590 uint32_t cDbEntries = 0;
591 uint32_t cDbEntriesMax = 0;
592
593 RTGETOPTUNION ValueUnion;
594 int chOpt;
595 while ((chOpt = RTGetOpt(&State, &ValueUnion)) != 0)
596 {
597 switch (chOpt)
598 {
599 case 'p':
600 pszPkPath = ValueUnion.psz;
601 break;
602 case 'o':
603 pszUuidPkOwner = ValueUnion.psz;
604 break;
605
606 case 'k':
607 pszKekPath = ValueUnion.psz;
608 break;
609 case 'w':
610 pszUuidKekOwner = ValueUnion.psz;
611 break;
612
613 case 'd':
614 {
615 if (cDbEntries == cDbEntriesMax)
616 {
617 uint32_t cDbEntriesMaxNew = cDbEntriesMax + 10;
618 const char **papszDbNew = (const char **)RTMemRealloc(papszDb, cDbEntriesMaxNew * sizeof(const char *));
619 if (!papszDbNew)
620 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory allocating memory for '%s'", ValueUnion.psz);
621
622 papszDb = papszDbNew;
623 cDbEntriesMax = cDbEntriesMaxNew;
624 }
625
626 papszDb[cDbEntries++] = ValueUnion.psz;
627 break;
628 }
629
630 case 's':
631 fSecureBoot = ValueUnion.f;
632 fSetSecureBoot = true;
633 break;
634
635 case VINF_GETOPT_NOT_OPTION:
636 /* The first non-option is the NVRAM file. */
637 if (!pszNvram)
638 pszNvram = ValueUnion.psz;
639 else
640 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid option '%s'", ValueUnion.psz);
641 break;
642
643 default:
644 return RTGetOptPrintError(chOpt, &ValueUnion);
645 }
646 }
647
648 if (!pszNvram)
649 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The NVRAM file path is missing");
650
651 if ( pszPkPath
652 && !pszUuidPkOwner)
653 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The PK is missing the owner UUID");
654
655 if ( pszKekPath
656 && !pszUuidKekOwner)
657 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The KEK is missing the owner UUID");
658
659 RTVFSFILE hVfsFileNvram = NIL_RTVFSFILE;
660 rc = RTVfsFileOpenNormal(pszNvram, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
661 &hVfsFileNvram);
662 if (RT_SUCCESS(rc))
663 {
664 RTVFS hVfsEfiVarStore = NIL_RTVFS;
665 rc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, 0 /*fMntFlags*/, 0 /*fVarStoreFlags*/, &hVfsEfiVarStore, RTErrInfoInitStatic(&ErrInfo));
666 if (RT_SUCCESS(rc))
667 {
668 if (pszPkPath)
669 rc = rtEfiSigDbVarStoreAddToDb(hVfsEfiVarStore, "PK", true /*fWipeDbBefore*/, 1 /*cSigs*/, pszPkPath, "x509", pszUuidPkOwner);
670 if ( RT_SUCCESS(rc)
671 && pszKekPath)
672 rc = rtEfiSigDbVarStoreAddToDb(hVfsEfiVarStore, "KEK", true /*fWipeDbBefore*/, 1 /*cSigs*/, pszKekPath, "x509", pszUuidKekOwner);
673
674 if ( RT_SUCCESS(rc)
675 && cDbEntries)
676 {
677 /** @todo Optimize to avoid re-opening and re-parsing the database for every entry. */
678 for (uint32_t i = 0; i < cDbEntries && RT_SUCCESS(rc); i++)
679 {
680 const char *pszDbEntry = papszDb[i];
681
682 const char *pszSigType = pszDbEntry;
683 const char *pszUuidOwner = strchr(pszSigType, ':');
684 if (pszUuidOwner)
685 pszUuidOwner++;
686 const char *pszSigPath = pszUuidOwner ? strchr(pszUuidOwner, ':') : NULL;
687 if (pszSigPath)
688 pszSigPath++;
689
690 if ( pszUuidOwner
691 && pszSigPath)
692 {
693 char *pszSigTypeFree = RTStrDupN(pszSigType, pszUuidOwner - pszSigType - 1);
694 char *pszUuidOwnerFree = RTStrDupN(pszUuidOwner, pszSigPath - pszUuidOwner - 1);
695
696 if ( pszSigTypeFree
697 && pszUuidOwnerFree)
698 rc = rtEfiSigDbVarStoreAddToDb(hVfsEfiVarStore, "db",
699 i == 0 ? true : false /*fWipeDbBefore*/,
700 1 /*cSigs*/,
701 pszSigPath, pszSigTypeFree, pszUuidOwnerFree);
702 else
703 rc = RTMsgErrorRc(VERR_NO_MEMORY, "Out of memory!");
704
705 if (pszSigTypeFree)
706 RTStrFree(pszSigTypeFree);
707 if (pszUuidOwnerFree)
708 RTStrFree(pszUuidOwnerFree);
709 }
710 else
711 rc = RTMsgErrorRc(VERR_INVALID_PARAMETER, "DB entry '%s' is malformed!", pszDbEntry);
712 }
713
714 if (RT_FAILURE(rc))
715 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Initializing the NVRAM '%s' failed: %Rrc", pszNvram, rc);
716 }
717
718 RTVfsRelease(hVfsEfiVarStore);
719 }
720
721 RTVfsFileRelease(hVfsFileNvram);
722 }
723
724 if (papszDb)
725 RTMemFree(papszDb);
726 return rcExit;
727}
728
729int main(int argc, char **argv)
730{
731 int rc = RTR3InitExe(argc, &argv, 0);
732 if (RT_FAILURE(rc))
733 return RTMsgInitFailure(rc);
734
735 /*
736 * Switch on the command.
737 */
738 RTEXITCODE rcExit = RTEXITCODE_SYNTAX;
739 if (argc < 2)
740 rtEfiSigDbUsage(argv[0], NULL);
741 else if (!strcmp(argv[1], "list"))
742 rcExit = rtEfiSgDbCmdList(argv[0], argc - 2, argv + 2);
743 else if (!strcmp(argv[1], "add"))
744 rcExit = rtEfiSgDbCmdAdd(argv[0], argc - 2, argv + 2);
745 else if (!strcmp(argv[1], "initnvram"))
746 rcExit = rtEfiSgDbCmdInitNvram(argv[0], argc - 2, argv + 2);
747 else if ( !strcmp(argv[1], "-h")
748 || !strcmp(argv[1], "-?")
749 || !strcmp(argv[1], "--help"))
750 rcExit = rtEfiSigDbUsage(argv[0], NULL);
751 else if ( !strcmp(argv[1], "-V")
752 || !strcmp(argv[1], "--version"))
753 rcExit = rtEfiSigDbVersion();
754 else
755 RTMsgError("Unknown command: '%s'", argv[1]);
756
757 return rcExit;
758}
759
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette