VirtualBox

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

Last change on this file since 90322 was 90322, checked in by vboxsync, 4 years ago

Runtime/tools/RTEfiSigDb: Add some sub-command to initialize a NVRAM file for secure boot, work in progress, bugref:9580

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

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