VirtualBox

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

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

scm --update-copyright-year

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