VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/tools/VBoxCertUtil.cpp@ 96478

最後變更 在這個檔案從96478是 96407,由 vboxsync 提交於 3 年 前

scm copyright and license note update

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.4 KB
 
1/* $Id: VBoxCertUtil.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxCertUtil - VBox Certificate Utility - Windows Only.
4 */
5
6/*
7 * Copyright (C) 2012-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/win/windows.h>
33#include <Wincrypt.h>
34
35#include <iprt/buildconfig.h>
36#include <iprt/errcore.h>
37#include <iprt/file.h>
38#include <iprt/getopt.h>
39#include <iprt/initterm.h>
40#include <iprt/message.h>
41#include <iprt/path.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/time.h>
45#include <iprt/utf16.h>
46
47
48/*********************************************************************************************************************************
49* Global Variables *
50*********************************************************************************************************************************/
51/** The verbosity level. */
52static unsigned g_cVerbosityLevel = 1;
53
54
55static const char *errorToString(DWORD dwErr)
56{
57 switch (dwErr)
58 {
59#define MY_CASE(a_uConst) case a_uConst: return #a_uConst;
60 MY_CASE(CRYPT_E_MSG_ERROR);
61 MY_CASE(CRYPT_E_UNKNOWN_ALGO);
62 MY_CASE(CRYPT_E_OID_FORMAT);
63 MY_CASE(CRYPT_E_INVALID_MSG_TYPE);
64 MY_CASE(CRYPT_E_UNEXPECTED_ENCODING);
65 MY_CASE(CRYPT_E_AUTH_ATTR_MISSING);
66 MY_CASE(CRYPT_E_HASH_VALUE);
67 MY_CASE(CRYPT_E_INVALID_INDEX);
68 MY_CASE(CRYPT_E_ALREADY_DECRYPTED);
69 MY_CASE(CRYPT_E_NOT_DECRYPTED);
70 MY_CASE(CRYPT_E_RECIPIENT_NOT_FOUND);
71 MY_CASE(CRYPT_E_CONTROL_TYPE);
72 MY_CASE(CRYPT_E_ISSUER_SERIALNUMBER);
73 MY_CASE(CRYPT_E_SIGNER_NOT_FOUND);
74 MY_CASE(CRYPT_E_ATTRIBUTES_MISSING);
75 MY_CASE(CRYPT_E_STREAM_MSG_NOT_READY);
76 MY_CASE(CRYPT_E_STREAM_INSUFFICIENT_DATA);
77 MY_CASE(CRYPT_I_NEW_PROTECTION_REQUIRED);
78 MY_CASE(CRYPT_E_BAD_LEN);
79 MY_CASE(CRYPT_E_BAD_ENCODE);
80 MY_CASE(CRYPT_E_FILE_ERROR);
81 MY_CASE(CRYPT_E_NOT_FOUND);
82 MY_CASE(CRYPT_E_EXISTS);
83 MY_CASE(CRYPT_E_NO_PROVIDER);
84 MY_CASE(CRYPT_E_SELF_SIGNED);
85 MY_CASE(CRYPT_E_DELETED_PREV);
86 MY_CASE(CRYPT_E_NO_MATCH);
87 MY_CASE(CRYPT_E_UNEXPECTED_MSG_TYPE);
88 MY_CASE(CRYPT_E_NO_KEY_PROPERTY);
89 MY_CASE(CRYPT_E_NO_DECRYPT_CERT);
90 MY_CASE(CRYPT_E_BAD_MSG);
91 MY_CASE(CRYPT_E_NO_SIGNER);
92 MY_CASE(CRYPT_E_PENDING_CLOSE);
93 MY_CASE(CRYPT_E_REVOKED);
94 MY_CASE(CRYPT_E_NO_REVOCATION_DLL);
95 MY_CASE(CRYPT_E_NO_REVOCATION_CHECK);
96 MY_CASE(CRYPT_E_REVOCATION_OFFLINE);
97 MY_CASE(CRYPT_E_NOT_IN_REVOCATION_DATABASE);
98 MY_CASE(CRYPT_E_INVALID_NUMERIC_STRING);
99 MY_CASE(CRYPT_E_INVALID_PRINTABLE_STRING);
100 MY_CASE(CRYPT_E_INVALID_IA5_STRING);
101 MY_CASE(CRYPT_E_INVALID_X500_STRING);
102 MY_CASE(CRYPT_E_NOT_CHAR_STRING);
103 MY_CASE(CRYPT_E_FILERESIZED);
104 MY_CASE(CRYPT_E_SECURITY_SETTINGS);
105 MY_CASE(CRYPT_E_NO_VERIFY_USAGE_DLL);
106 MY_CASE(CRYPT_E_NO_VERIFY_USAGE_CHECK);
107 MY_CASE(CRYPT_E_VERIFY_USAGE_OFFLINE);
108 MY_CASE(CRYPT_E_NOT_IN_CTL);
109 MY_CASE(CRYPT_E_NO_TRUSTED_SIGNER);
110 MY_CASE(CRYPT_E_MISSING_PUBKEY_PARA);
111 MY_CASE(CRYPT_E_OSS_ERROR);
112 default:
113 {
114 static char s_szErr[80];
115 if (RTErrWinQueryDefine(dwErr, s_szErr, sizeof(s_szErr), true /*fFailIfUnknown*/) == VERR_NOT_FOUND)
116 RTStrPrintf(s_szErr, sizeof(s_szErr), "%#x (%d)", dwErr, dwErr);
117 return s_szErr;
118 }
119 }
120}
121
122#if 0 /* hacking */
123static RTEXITCODE addToStore(const char *pszFilename, PCRTUTF16 pwszStore)
124{
125 /*
126 * Open the source.
127 */
128 void *pvFile;
129 size_t cbFile;
130 int rc = RTFileReadAll(pszFilename, &pvFile, &cbFile);
131 if (RT_FAILURE(rc))
132 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTFileReadAll failed on '%s': %Rrc", pszFilename, rc);
133
134 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
135
136 PCCERT_CONTEXT pCertCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
137 (PBYTE)pvFile,
138 (DWORD)cbFile);
139 if (pCertCtx)
140 {
141 /*
142 * Open the destination.
143 */
144 HCERTSTORE hDstStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
145 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
146 NULL /* hCryptProv = default */,
147 /*CERT_SYSTEM_STORE_LOCAL_MACHINE*/ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG,
148 pwszStore);
149 if (hDstStore != NULL)
150 {
151#if 0
152 DWORD dwContextType;
153 if (CertAddSerializedElementToStore(hDstStore,
154 pCertCtx->pbCertEncoded,
155 pCertCtx->cbCertEncoded,
156 CERT_STORE_ADD_NEW,
157 0 /* dwFlags (reserved) */,
158 CERT_STORE_ALL_CONTEXT_FLAG,
159 &dwContextType,
160 NULL))
161 {
162 RTMsgInfo("Successfully added '%s' to the '%ls' store (ctx type %u)", pszFilename, pwszStore, dwContextType);
163 rcExit = RTEXITCODE_SUCCESS;
164 }
165 else
166 RTMsgError("CertAddSerializedElementToStore returned %s", errorToString(GetLastError()));
167#else
168 if (CertAddCertificateContextToStore(hDstStore, pCertCtx, CERT_STORE_ADD_NEW, NULL))
169 {
170 RTMsgInfo("Successfully added '%s' to the '%ls' store", pszFilename, pwszStore);
171 rcExit = RTEXITCODE_SUCCESS;
172 }
173 else
174 RTMsgError("CertAddCertificateContextToStore returned %s", errorToString(GetLastError()));
175#endif
176
177 CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG);
178 }
179 else
180 RTMsgError("CertOpenStore returned %s", errorToString(GetLastError()));
181 CertFreeCertificateContext(pCertCtx);
182 }
183 else
184 RTMsgError("CertCreateCertificateContext returned %s", errorToString(GetLastError()));
185 RTFileReadAllFree(pvFile, cbFile);
186 return rcExit;
187
188#if 0
189
190 CRYPT_DATA_BLOB Blob;
191 Blob.cbData = (DWORD)cbData;
192 Blob.pbData = (PBYTE)pvData;
193 HCERTSTORE hSrcStore = PFXImportCertStore(&Blob, L"", )
194
195#endif
196}
197#endif /* hacking */
198
199
200/**
201 * Reads a certificate from a file, returning a context or a the handle to a
202 * temporary memory store.
203 *
204 * @returns true on success, false on failure (error message written).
205 * @param pszCertFile The name of the file containing the
206 * certificates.
207 * @param ppOutCtx Where to return the certificate context.
208 * @param phSrcStore Where to return the handle to the temporary
209 * memory store.
210 */
211static bool readCertFile(const char *pszCertFile, PCCERT_CONTEXT *ppOutCtx, HCERTSTORE *phSrcStore)
212{
213 *ppOutCtx = NULL;
214 *phSrcStore = NULL;
215
216 bool fRc = false;
217 void *pvFile;
218 size_t cbFile;
219 int rc = RTFileReadAll(pszCertFile, &pvFile, &cbFile);
220 if (RT_SUCCESS(rc))
221 {
222 *ppOutCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
223 (PBYTE)pvFile, (DWORD)cbFile);
224 if (*ppOutCtx)
225 fRc = true;
226 else
227 {
228 /** @todo figure out if it's some other format... */
229 RTMsgError("CertCreateCertificateContext returned %s parsing the content of '%s'",
230 errorToString(GetLastError()), pszCertFile);
231 }
232 RTFileReadAllFree(pvFile, cbFile);
233 }
234 else
235 RTMsgError("RTFileReadAll failed on '%s': %Rrc", pszCertFile, rc);
236 return fRc;
237}
238
239
240/**
241 * Opens a certificate store.
242 *
243 * @returns true on success, false on failure (error message written).
244 * @param dwDst The destination, like
245 * CERT_SYSTEM_STORE_LOCAL_MACHINE or
246 * CERT_SYSTEM_STORE_CURRENT_USER.
247 * @param pszStoreNm The store name.
248 */
249static HCERTSTORE openCertStore(DWORD dwDst, const char *pszStoreNm)
250{
251 HCERTSTORE hStore = NULL;
252 PRTUTF16 pwszStoreNm;
253 int rc = RTStrToUtf16(pszStoreNm, &pwszStoreNm);
254 if (RT_SUCCESS(rc))
255 {
256 if (g_cVerbosityLevel > 1)
257 RTMsgInfo("Opening store %#x:'%s'", dwDst, pszStoreNm);
258
259 /*
260 * Make sure CERT_STORE_OPEN_EXISTING_FLAG is not set. This causes Windows XP
261 * to return ACCESS_DENIED when installing TrustedPublisher certificates via
262 * CertAddCertificateContextToStore() if the TrustedPublisher store never has
263 * been used (through certmgr.exe and friends) yet.
264 *
265 * According to MSDN, if neither CERT_STORE_OPEN_EXISTING_FLAG nor
266 * CERT_STORE_CREATE_NEW_FLAG is set, the store will be either opened or
267 * created accordingly.
268 */
269 dwDst &= ~CERT_STORE_OPEN_EXISTING_FLAG;
270
271 hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
272 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
273 NULL /* hCryptProv = default */,
274 dwDst,
275 pwszStoreNm);
276 if (hStore == NULL)
277 RTMsgError("CertOpenStore failed opening %#x:'%s': %s",
278 dwDst, pszStoreNm, errorToString(GetLastError()));
279
280 RTUtf16Free(pwszStoreNm);
281 }
282 return hStore;
283}
284
285/**
286 * Removes a certificate, given by file, from a store
287 *
288 * @returns true on success, false on failure (error message written).
289 * @param dwDst The destination, like
290 * CERT_SYSTEM_STORE_LOCAL_MACHINE or
291 * CERT_SYSTEM_STORE_CURRENT_USER.
292 * @param pszStoreNm The store name.
293 * @param pszCertFile The file containing the certificate to add.
294 */
295static bool removeCertFromStoreByFile(DWORD dwDst, const char *pszStoreNm, const char *pszCertFile)
296{
297 /*
298 * Read the certificate file first.
299 */
300 PCCERT_CONTEXT pSrcCtx = NULL;
301 HCERTSTORE hSrcStore = NULL;
302 if (!readCertFile(pszCertFile, &pSrcCtx, &hSrcStore))
303 return false;
304
305 WCHAR wszName[1024];
306 if (!CertGetNameStringW(pSrcCtx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0 /*dwFlags*/, NULL /*pvTypePara*/,
307 wszName, sizeof(wszName)))
308 {
309 RTMsgError("CertGetNameStringW(Subject) failed: %s\n", errorToString(GetLastError()));
310 wszName[0] = '\0';
311 }
312
313 /*
314 * Open the destination store.
315 */
316 bool fRc = false;
317 HCERTSTORE hDstStore = openCertStore(dwDst, pszStoreNm);
318 if (hDstStore)
319 {
320 if (pSrcCtx)
321 {
322 fRc = true;
323 unsigned cDeleted = 0;
324 PCCERT_CONTEXT pCurCtx = NULL;
325 while ((pCurCtx = CertEnumCertificatesInStore(hDstStore, pCurCtx)) != NULL)
326 {
327 if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pCurCtx->pCertInfo, pSrcCtx->pCertInfo))
328 {
329 if (g_cVerbosityLevel > 1)
330 RTMsgInfo("Removing '%ls'...", wszName);
331 PCCERT_CONTEXT pDeleteCtx = CertDuplicateCertificateContext(pCurCtx);
332 if (pDeleteCtx)
333 {
334 if (CertDeleteCertificateFromStore(pDeleteCtx))
335 cDeleted++;
336 else
337 RTMsgError("CertDeleteFromStore('%ls') failed: %s\n", wszName, errorToString(GetLastError()));
338 }
339 else
340 RTMsgError("CertDuplicateCertificateContext('%ls') failed: %s\n", wszName, errorToString(GetLastError()));
341 }
342 }
343
344 if (!cDeleted)
345 RTMsgInfo("Found no matching certificates to remove.");
346 }
347 else
348 {
349 RTMsgError("Path not implemented at line %d\n", __LINE__);
350 }
351
352 CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG);
353 }
354 if (pSrcCtx)
355 CertFreeCertificateContext(pSrcCtx);
356 if (hSrcStore)
357 CertCloseStore(hSrcStore, CERT_CLOSE_STORE_CHECK_FLAG);
358 return fRc;
359}
360
361/**
362 * Adds a certificate to a store.
363 *
364 * @returns true on success, false on failure (error message written).
365 * @param dwDst The destination, like
366 * CERT_SYSTEM_STORE_LOCAL_MACHINE or
367 * CERT_SYSTEM_STORE_CURRENT_USER.
368 * @param pszStoreNm The store name.
369 * @param pszCertFile The file containing the certificate to add.
370 * @param dwDisposition The disposition towards existing certificates when
371 * adding it. CERT_STORE_ADD_NEW is a safe one.
372 */
373static bool addCertToStore(DWORD dwDst, const char *pszStoreNm, const char *pszCertFile, DWORD dwDisposition)
374{
375 /*
376 * Read the certificate file first.
377 */
378 PCCERT_CONTEXT pSrcCtx = NULL;
379 HCERTSTORE hSrcStore = NULL;
380 if (!readCertFile(pszCertFile, &pSrcCtx, &hSrcStore))
381 return false;
382
383 /*
384 * Open the destination store.
385 */
386 bool fRc = false;
387 HCERTSTORE hDstStore = openCertStore(dwDst, pszStoreNm);
388 if (hDstStore)
389 {
390 if (pSrcCtx)
391 {
392 if (g_cVerbosityLevel > 1)
393 RTMsgInfo("Adding '%s' to %#x:'%s'... (disp %d)", pszCertFile, dwDst, pszStoreNm, dwDisposition);
394
395 if (CertAddCertificateContextToStore(hDstStore, pSrcCtx, dwDisposition, NULL))
396 fRc = true;
397 else
398 RTMsgError("CertAddCertificateContextToStore returned %s", errorToString(GetLastError()));
399 }
400 else
401 RTMsgError("Path not implemented at line %d\n", __LINE__);
402
403 CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG);
404 }
405 if (pSrcCtx)
406 CertFreeCertificateContext(pSrcCtx);
407 if (hSrcStore)
408 CertCloseStore(hSrcStore, CERT_CLOSE_STORE_CHECK_FLAG);
409 return fRc;
410}
411
412/**
413 * Worker for cmdDisplayAll.
414 */
415static BOOL WINAPI displaySystemStoreCallback(const void *pvSystemStore, DWORD dwFlags, PCERT_SYSTEM_STORE_INFO pStoreInfo,
416 void *pvReserved, void *pvArg) RT_NOTHROW_DEF
417{
418 RT_NOREF(pvArg);
419 if (g_cVerbosityLevel > 1)
420 RTPrintf(" pvSystemStore=%p dwFlags=%#x pStoreInfo=%p pvReserved=%p\n", pvSystemStore, dwFlags, pStoreInfo, pvReserved);
421 LPCWSTR pwszStoreNm = NULL;
422 if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
423 {
424 const CERT_SYSTEM_STORE_RELOCATE_PARA *pRelPara = (const CERT_SYSTEM_STORE_RELOCATE_PARA *)pvSystemStore;
425 pwszStoreNm = pRelPara->pwszSystemStore;
426 RTPrintf(" %#010x '%ls' hKeyBase=%p\n", dwFlags, pwszStoreNm, pRelPara->hKeyBase);
427 }
428 else
429 {
430 pwszStoreNm = (LPCWSTR)pvSystemStore;
431 RTPrintf(" %#010x '%ls'\n", dwFlags, pwszStoreNm);
432 }
433
434 /*
435 * Open the store and list the certificates within.
436 */
437 DWORD dwDst = (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK);
438 HCERTSTORE hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
439 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
440 NULL /* hCryptProv = default */,
441 dwDst | CERT_STORE_OPEN_EXISTING_FLAG,
442 pwszStoreNm);
443 if (hStore)
444 {
445 PCCERT_CONTEXT pCertCtx = NULL;
446 while ((pCertCtx = CertEnumCertificatesInStore(hStore, pCertCtx)) != NULL)
447 {
448 if (g_cVerbosityLevel > 1)
449 RTPrintf(" pCertCtx=%p dwCertEncodingType=%#x cbCertEncoded=%#x pCertInfo=%p\n",
450 pCertCtx, pCertCtx->dwCertEncodingType, pCertCtx->cbCertEncoded, pCertCtx->pCertInfo);
451 WCHAR wszName[1024];
452 if (CertGetNameStringW(pCertCtx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0 /*dwFlags*/, NULL /*pvTypePara*/,
453 wszName, sizeof(wszName)))
454 {
455 RTPrintf(" '%ls'\n", wszName);
456 if (pCertCtx->pCertInfo)
457 {
458 RTTIMESPEC TmpTS;
459 char szNotBefore[80];
460 RTTimeSpecToString(RTTimeSpecSetNtFileTime(&TmpTS, &pCertCtx->pCertInfo->NotBefore),
461 szNotBefore, sizeof(szNotBefore));
462 char szNotAfter[80];
463 RTTimeSpecToString(RTTimeSpecSetNtFileTime(&TmpTS, &pCertCtx->pCertInfo->NotAfter),
464 szNotAfter, sizeof(szNotAfter));
465
466 RTPrintf(" NotBefore='%s'\n", szNotBefore);
467 RTPrintf(" NotAfter ='%s'\n", szNotAfter);
468 if (pCertCtx->pCertInfo->Issuer.cbData)
469 {
470 if (CertGetNameStringW(pCertCtx, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL /*pvTypePara*/,
471 wszName, sizeof(wszName)))
472 RTPrintf(" Issuer='%ls'\n", wszName);
473 else
474 RTMsgError("CertGetNameStringW(Issuer) failed: %s\n", errorToString(GetLastError()));
475 }
476 }
477 }
478 else
479 RTMsgError("CertGetNameStringW(Subject) failed: %s\n", errorToString(GetLastError()));
480
481 }
482
483 CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
484 }
485 else
486 RTMsgError("CertOpenStore failed opening %#x:'%ls': %s\n", dwDst, pwszStoreNm, errorToString(GetLastError()));
487
488 return TRUE;
489}
490
491/**
492 * Worker for cmdDisplayAll.
493 */
494static BOOL WINAPI
495displaySystemStoreLocation(LPCWSTR pwszStoreLocation, DWORD dwFlags, void *pvReserved, void *pvArg) RT_NOTHROW_DEF
496{
497 NOREF(pvReserved); NOREF(pvArg);
498 RTPrintf("System store location: %#010x '%ls'\n", dwFlags, pwszStoreLocation);
499 if (!CertEnumSystemStore(dwFlags, NULL, NULL /*pvArg*/, displaySystemStoreCallback))
500 RTMsgError("CertEnumSystemStore failed on %#x:'%ls': %s\n",
501 dwFlags, pwszStoreLocation, errorToString(GetLastError()));
502
503 return TRUE;
504}
505
506/**
507 * Handler for the 'display-all' command.
508 */
509static RTEXITCODE cmdDisplayAll(int argc, char **argv)
510{
511 RT_NOREF(argv);
512 if (argc != 1)
513 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "the display-all command takes no arguments\n");
514
515 if (!CertEnumSystemStoreLocation(0, NULL /*pvArg*/, displaySystemStoreLocation))
516 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "CertEnumSystemStoreLocation failed: %s\n", errorToString(GetLastError()));
517
518 return RTEXITCODE_SUCCESS;
519}
520
521/**
522 * Handler for the 'remove-trusted-publisher' command.
523 */
524static RTEXITCODE cmdRemoveTrustedPublisher(int argc, char **argv)
525{
526 /*
527 * Parse arguments.
528 */
529 static const RTGETOPTDEF s_aOptions[] =
530 {
531 { "--root", 'r', RTGETOPT_REQ_STRING },
532 };
533
534 const char *pszRootCert = NULL;
535 const char *pszTrustedCert = NULL;
536
537 int rc;
538 RTGETOPTUNION ValueUnion;
539 RTGETOPTSTATE GetState;
540 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
541 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
542 {
543 switch (rc)
544 {
545 case 'h':
546 RTPrintf("Usage: VBoxCertUtil remove-trusted-publisher [--root <root-cert>] <trusted-cert>\n");
547 break;
548
549 case 'V':
550 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
551 return RTEXITCODE_SUCCESS;
552
553 case 'r':
554 if (pszRootCert)
555 return RTMsgErrorExit(RTEXITCODE_SUCCESS,
556 "You've already specified '%s' as root certificate.",
557 pszRootCert);
558 pszRootCert = ValueUnion.psz;
559 break;
560
561 case VINF_GETOPT_NOT_OPTION:
562 if (pszTrustedCert)
563 return RTMsgErrorExit(RTEXITCODE_SUCCESS,
564 "You've already specified '%s' as trusted certificate.",
565 pszRootCert);
566 pszTrustedCert = ValueUnion.psz;
567 break;
568
569 default:
570 return RTGetOptPrintError(rc, &ValueUnion);
571 }
572 }
573 if (!pszTrustedCert)
574 return RTMsgErrorExit(RTEXITCODE_SUCCESS, "No trusted certificate specified.");
575
576 /*
577 * Do the job.
578 */
579 if ( pszRootCert
580 && !removeCertFromStoreByFile(CERT_SYSTEM_STORE_LOCAL_MACHINE, "Root", pszRootCert))
581 return RTEXITCODE_FAILURE;
582 if (!removeCertFromStoreByFile(CERT_SYSTEM_STORE_LOCAL_MACHINE, "TrustedPublisher", pszTrustedCert))
583 return RTEXITCODE_FAILURE;
584
585 if (g_cVerbosityLevel > 0)
586 {
587 if (pszRootCert)
588 RTMsgInfo("Successfully removed '%s' as root and '%s' as trusted publisher", pszRootCert, pszTrustedCert);
589 else
590 RTMsgInfo("Successfully removed '%s' as trusted publisher", pszTrustedCert);
591 }
592 return RTEXITCODE_SUCCESS;
593}
594
595
596/**
597 * Handler for the 'add-trusted-publisher' command.
598 */
599static RTEXITCODE cmdAddTrustedPublisher(int argc, char **argv)
600{
601 /*
602 * Parse arguments and execute imports as we move along.
603 */
604 static const RTGETOPTDEF s_aOptions[] =
605 {
606 { "--root", 'r', RTGETOPT_REQ_STRING },
607 };
608
609 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
610 unsigned cImports = 0;
611 RTGETOPTUNION ValueUnion;
612 RTGETOPTSTATE GetState;
613 int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
614 AssertRC(rc);
615 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
616 {
617 switch (rc)
618 {
619 case 'h':
620 RTPrintf("Usage: VBoxCertUtil add-trusted-publisher [--root <root-cert>] <trusted-cert>\n");
621 break;
622
623 case 'V':
624 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
625 return RTEXITCODE_SUCCESS;
626
627 case 'r':
628 case VINF_GETOPT_NOT_OPTION:
629 {
630 const char * const pszStoreNm = rc == 'r' ? "Root" : "TrustedPublisher";
631 const char * const pszStoreDesc = rc == 'r' ? "root" : "trusted publisher";
632 PCRTPATHGLOBENTRY pResultHead;
633 rc = RTPathGlob(ValueUnion.psz, RTPATHGLOB_F_NO_DIRS, &pResultHead, NULL);
634 if (RT_SUCCESS(rc))
635 {
636 for (PCRTPATHGLOBENTRY pCur = pResultHead; pCur; pCur = pCur->pNext)
637 {
638 if (addCertToStore(CERT_SYSTEM_STORE_LOCAL_MACHINE, pszStoreNm, pCur->szPath, CERT_STORE_ADD_NEW))
639 RTMsgInfo("Successfully added '%s' as %s", pCur->szPath, pszStoreDesc);
640 else
641 rcExit = RTEXITCODE_FAILURE;
642 cImports++;
643 }
644 RTPathGlobFree(pResultHead);
645 }
646 else
647 {
648 rcExit = RTMsgErrorExit(RTEXITCODE_SUCCESS, "glob failed on '%s': %Rrc", ValueUnion.psz, rc);
649 cImports++;
650 }
651 break;
652 }
653
654 default:
655 return RTGetOptPrintError(rc, &ValueUnion);
656 }
657 }
658 if (cImports == 0)
659 return RTMsgErrorExit(RTEXITCODE_SUCCESS, "No trusted or root certificates specified.");
660 return rcExit;
661}
662
663
664/**
665 * Displays the usage info.
666 * @param argv0 Program name.
667 */
668static void showUsage(const char *argv0)
669{
670 RTPrintf("Usage: %Rbn [-v[v]] <command>\n"
671 " or %Rbn <-V|--version>\n"
672 " or %Rbn <-h|--help>\n"
673 "\n"
674 "Available commands:\n"
675 " add-trusted-publisher, remove-trusted-publisher,\n"
676 " display-all\n"
677 , argv0, argv0, argv0);
678}
679
680
681int main(int argc, char **argv)
682{
683 int rc = RTR3InitExe(argc, &argv, 0);
684 if (RT_FAILURE(rc))
685 return RTMsgInitFailure(rc);
686
687 /*
688 * Parse arguments up to the command and pass it on to the command handlers.
689 */
690 typedef enum
691 {
692 VCUACTION_ADD_TRUSTED_PUBLISHER = 1000,
693 VCUACTION_REMOVE_TRUSTED_PUBLISHER,
694 VCUACTION_DISPLAY_ALL,
695 VCUACTION_END
696 } VCUACTION;
697
698 static const RTGETOPTDEF s_aOptions[] =
699 {
700 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
701 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
702 { "add-trusted-publisher", VCUACTION_ADD_TRUSTED_PUBLISHER, RTGETOPT_REQ_NOTHING },
703 { "remove-trusted-publisher", VCUACTION_REMOVE_TRUSTED_PUBLISHER, RTGETOPT_REQ_NOTHING },
704 { "display-all", VCUACTION_DISPLAY_ALL, RTGETOPT_REQ_NOTHING },
705 };
706
707 RTGETOPTUNION ValueUnion;
708 RTGETOPTSTATE GetState;
709 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
710 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
711 {
712 switch (rc)
713 {
714 case 'v':
715 g_cVerbosityLevel++;
716 break;
717
718 case 'q':
719 if (g_cVerbosityLevel > 0)
720 g_cVerbosityLevel--;
721 break;
722
723 case 'h':
724 showUsage(argv[0]);
725 return RTEXITCODE_SUCCESS;
726
727 case 'V':
728 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
729 return RTEXITCODE_SUCCESS;
730
731 case VCUACTION_ADD_TRUSTED_PUBLISHER:
732 return cmdAddTrustedPublisher(argc - GetState.iNext + 1, argv + GetState.iNext - 1);
733
734 case VCUACTION_REMOVE_TRUSTED_PUBLISHER:
735 return cmdRemoveTrustedPublisher(argc - GetState.iNext + 1, argv + GetState.iNext - 1);
736
737 case VCUACTION_DISPLAY_ALL:
738 return cmdDisplayAll(argc - GetState.iNext + 1, argv + GetState.iNext - 1);
739
740 default:
741 return RTGetOptPrintError(rc, &ValueUnion);
742 }
743 }
744
745 RTMsgError("Missing command...");
746 showUsage(argv[0]);
747 return RTEXITCODE_SYNTAX;
748}
749
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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