VirtualBox

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

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

Runtime/tools/RTEfiSigDb: Build fix, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
Line 
1/* $Id: RTEfiSigDb.cpp 90317 2021-07-23 16:02:55Z 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/errcore.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
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50
51
52/*********************************************************************************************************************************
53* Global Variables *
54*********************************************************************************************************************************/
55/** Signature type identifier to internal type mapping. */
56struct
57{
58 const char *pszId;
59 RTEFISIGTYPE enmType;
60} g_aId2SigType[] =
61{
62 { "sha256", RTEFISIGTYPE_SHA256 },
63 { "rsa2048", RTEFISIGTYPE_RSA2048 },
64 { "x509", RTEFISIGTYPE_X509 }
65};
66
67
68/*********************************************************************************************************************************
69* Internal Functions *
70*********************************************************************************************************************************/
71
72/**
73 * Display the version of the cache program.
74 *
75 * @returns exit code.
76 */
77static RTEXITCODE rtEfiSigDbVersion(void)
78{
79 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
80 return RTEXITCODE_SUCCESS;
81}
82
83
84/**
85 * Shows the usage of the program.
86 *
87 * @returns Exit code.
88 * @param pszArg0 Program name.
89 * @param pszCommand Command selector, NULL if all.
90 */
91static RTEXITCODE rtEfiSigDbUsage(const char *pszArg0, const char *pszCommand)
92{
93 if (!pszCommand || !strcmp(pszCommand, "list"))
94 RTPrintf("Usage: %s list <signature database path>\n"
95 , RTPathFilename(pszArg0));
96
97 if (!pszCommand || !strcmp(pszCommand, "add"))
98 RTPrintf("Usage: %s add <signature database path> <x509|sha256|rsa2048> <owner uuid> <signature path> ...\n"
99 , RTPathFilename(pszArg0));
100
101 return RTEXITCODE_SUCCESS;
102}
103
104
105static RTEFISIGTYPE rtEfiSigDbGetTypeById(const char *pszId)
106{
107 for (uint32_t i = 0; i < RT_ELEMENTS(g_aId2SigType); i++)
108 if (!strcmp(pszId, g_aId2SigType[i].pszId))
109 return g_aId2SigType[i].enmType;
110
111 return RTEFISIGTYPE_INVALID;
112}
113
114
115/**
116 * Opens the specified signature database, returning an VFS file handle on success.
117 *
118 * @returns IPRT status code.
119 * @param pszPath Path to the signature database.
120 * @param phVfsFile Where to return the VFS file handle on success.
121 */
122static int rtEfiSigDbOpen(const char *pszPath, PRTVFSFILE phVfsFile)
123{
124 int rc;
125
126 if (RTVfsChainIsSpec(pszPath))
127 {
128 RTVFSOBJ hVfsObj;
129 rc = RTVfsChainOpenObj(pszPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
130 RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING | RTPATH_F_ON_LINK,
131 &hVfsObj, NULL, NULL);
132 if ( RT_SUCCESS(rc)
133 && RTVfsObjGetType(hVfsObj) == RTVFSOBJTYPE_FILE)
134 {
135 *phVfsFile = RTVfsObjToFile(hVfsObj);
136 RTVfsObjRelease(hVfsObj);
137 }
138 else
139 {
140 RTPrintf("'%s' doesn't point to a file\n", pszPath);
141 rc = VERR_INVALID_PARAMETER;
142 }
143 }
144 else
145 rc = RTVfsFileOpenNormal(pszPath, RTFILE_O_READWRITE | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
146 phVfsFile);
147
148 return rc;
149}
150
151
152/**
153 * Signature database enumeration callback.
154 */
155static DECLCALLBACK(int) rtEfiSgDbEnum(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner,
156 const void *pvSig, size_t cbSig, void *pvUser)
157{
158 RT_NOREF(hEfiSigDb, pvUser);
159
160 uint32_t *pidxSig = (uint32_t *)pvUser;
161
162 RTPrintf("%02u: %s\n", (*pidxSig)++, RTEfiSigDbTypeStringify(enmSigType));
163 RTPrintf(" Owner: %RTuuid\n", pUuidOwner);
164 RTPrintf(" Signature:\n"
165 "%.*Rhxd\n\n", cbSig, pvSig);
166 return VINF_SUCCESS;
167}
168
169
170/**
171 * Handles the 'list' command.
172 *
173 * @returns Program exit code.
174 * @param pszArg0 The program name.
175 * @param cArgs The number of arguments to the 'add' command.
176 * @param papszArgs The argument vector, starting after 'add'.
177 */
178static RTEXITCODE rtEfiSgDbCmdList(const char *pszArg0, int cArgs, char **papszArgs)
179{
180 RT_NOREF(pszArg0);
181
182 if (!cArgs)
183 {
184 RTPrintf("An input path must be given\n");
185 return RTEXITCODE_FAILURE;
186 }
187
188 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
189 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
190 int rc = rtEfiSigDbOpen(papszArgs[0], &hVfsFile);
191 if (RT_SUCCESS(rc))
192 {
193 RTEFISIGDB hEfiSigDb;
194 rc = RTEfiSigDbCreate(&hEfiSigDb);
195 if (RT_SUCCESS(rc))
196 {
197 uint32_t idxSig = 0;
198
199 rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
200 if (RT_SUCCESS(rc))
201 RTEfiSigDbEnum(hEfiSigDb, rtEfiSgDbEnum, &idxSig);
202 else
203 {
204 RTPrintf("Loading the signature database failed with %Rrc\n", rc);
205 rcExit = RTEXITCODE_FAILURE;
206 }
207
208 RTEfiSigDbDestroy(hEfiSigDb);
209 }
210 else
211 {
212 RTPrintf("Creating the signature database failed with %Rrc\n", rc);
213 rcExit = RTEXITCODE_FAILURE;
214 }
215
216 RTVfsFileRelease(hVfsFile);
217 }
218 else
219 rcExit = RTEXITCODE_FAILURE;
220
221 return rcExit;
222}
223
224
225/**
226 * Handles the 'add' command.
227 *
228 * @returns Program exit code.
229 * @param pszArg0 The program name.
230 * @param cArgs The number of arguments to the 'add' command.
231 * @param papszArgs The argument vector, starting after 'add'.
232 */
233static RTEXITCODE rtEfiSgDbCmdAdd(const char *pszArg0, int cArgs, char **papszArgs)
234{
235 RT_NOREF(pszArg0);
236
237 if (!cArgs)
238 {
239 RTPrintf("The signature database path is missing\n");
240 return RTEXITCODE_FAILURE;
241 }
242
243 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
244 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
245 int rc = rtEfiSigDbOpen(papszArgs[0], &hVfsFile);
246 if (RT_SUCCESS(rc))
247 {
248 RTEFISIGDB hEfiSigDb;
249 rc = RTEfiSigDbCreate(&hEfiSigDb);
250 if (RT_SUCCESS(rc))
251 {
252 uint64_t cbSigDb = 0;
253 rc = RTVfsFileQuerySize(hVfsFile, &cbSigDb);
254 if ( RT_SUCCESS(rc)
255 && cbSigDb)
256 rc = RTEfiSigDbAddFromExistingDb(hEfiSigDb, hVfsFile);
257 if (RT_SUCCESS(rc))
258 {
259 cArgs--;
260 papszArgs++;
261
262 while (cArgs >= 3)
263 {
264 RTEFISIGTYPE enmSigType = rtEfiSigDbGetTypeById(papszArgs[0]);
265 const char *pszUuidOwner = papszArgs[1];
266 const char *pszSigDataPath = papszArgs[2];
267
268 if (enmSigType == RTEFISIGTYPE_INVALID)
269 {
270 RTPrintf("Signature type '%s' is not known\n", papszArgs[0]);
271 break;
272 }
273
274 RTUUID UuidOwner;
275 rc = RTUuidFromStr(&UuidOwner, pszUuidOwner);
276 if (RT_FAILURE(rc))
277 {
278 RTPrintf("UUID '%s' is malformed\n", pszUuidOwner);
279 break;
280 }
281
282 RTVFSFILE hVfsFileSigData = NIL_RTVFSFILE;
283 rc = rtEfiSigDbOpen(pszSigDataPath, &hVfsFileSigData);
284 if (RT_FAILURE(rc))
285 {
286 RTPrintf("Opening '%s' failed with %Rrc\n", pszSigDataPath, rc);
287 break;
288 }
289
290 rc = RTEfiSigDbAddSignatureFromFile(hEfiSigDb, enmSigType, &UuidOwner, hVfsFileSigData);
291 RTVfsFileRelease(hVfsFileSigData);
292 if (RT_FAILURE(rc))
293 {
294 RTPrintf("Adding signature data from '%s' failed with %Rrc\n", pszSigDataPath, rc);
295 break;
296 }
297 papszArgs += 3;
298 cArgs -= 3;
299 }
300
301 if (RT_SUCCESS(rc))
302 {
303 if (!cArgs)
304 {
305 rc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
306 AssertRC(rc);
307
308 rc = RTEfiSigDbWriteToFile(hEfiSigDb, hVfsFile);
309 if (RT_FAILURE(rc))
310 {
311 RTPrintf("Writing the updated signature database failed with %Rrc\n", rc);
312 rcExit = RTEXITCODE_FAILURE;
313 }
314 }
315 else
316 {
317 RTPrintf("Incomplete list of entries to add given\n");
318 rcExit = RTEXITCODE_FAILURE;
319 }
320 }
321 }
322 else
323 {
324 RTPrintf("Loading the signature database failed with %Rrc\n", rc);
325 rcExit = RTEXITCODE_FAILURE;
326 }
327
328 RTEfiSigDbDestroy(hEfiSigDb);
329 }
330 else
331 {
332 RTPrintf("Creating the signature database failed with %Rrc\n", rc);
333 rcExit = RTEXITCODE_FAILURE;
334 }
335
336 RTVfsFileRelease(hVfsFile);
337 }
338 else
339 rcExit = RTEXITCODE_FAILURE;
340
341 return rcExit;
342}
343
344
345int main(int argc, char **argv)
346{
347 int rc = RTR3InitExe(argc, &argv, 0);
348 if (RT_FAILURE(rc))
349 return RTMsgInitFailure(rc);
350
351 /*
352 * Switch on the command.
353 */
354 RTEXITCODE rcExit = RTEXITCODE_SYNTAX;
355 if (argc < 2)
356 rtEfiSigDbUsage(argv[0], NULL);
357 else if (!strcmp(argv[1], "list"))
358 rcExit = rtEfiSgDbCmdList(argv[0], argc - 2, argv + 2);
359 else if (!strcmp(argv[1], "add"))
360 rcExit = rtEfiSgDbCmdAdd(argv[0], argc - 2, argv + 2);
361 else if ( !strcmp(argv[1], "-h")
362 || !strcmp(argv[1], "-?")
363 || !strcmp(argv[1], "--help"))
364 rcExit = rtEfiSigDbUsage(argv[0], NULL);
365 else if ( !strcmp(argv[1], "-V")
366 || !strcmp(argv[1], "--version"))
367 rcExit = rtEfiSigDbVersion();
368 else
369 RTMsgError("Unknown command: '%s'", argv[1]);
370
371 return rcExit;
372}
373
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