main
cpp 138 lines 4.75 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5 #define SHA1_HASH_LEN 20
6
7 static HRESULT GetPublicKeyIdentifierAndThumbprint(
8 __in_z LPCWSTR wzPath,
9 __inout_z LPWSTR* psczPublicKeyIdentifier,
10 __inout_z LPWSTR* psczThumbprint);
11
12 static HRESULT GetChainContext(
13 __in_z LPCWSTR wzPath,
14 __out PCCERT_CHAIN_CONTEXT* ppChainContext);
15
16
17 HRESULT CertificateHashesCommand(
18 __in int argc,
19 __in_ecount(argc) LPWSTR argv[])
20 {
21 Unused(argc);
22 Unused(argv);
23
24 HRESULT hr = S_OK;
25
26 LPWSTR sczFilePath = NULL;
27 LPWSTR sczPublicKeyIdentifier = NULL;
28 LPWSTR sczThumbprint = NULL;
29
30 hr = WixNativeReadStdinPreamble();
31 ExitOnFailure(hr, "Failed to read stdin preamble before reading paths to get certificate hashes");
32
33 // Get the hash for each provided file.
34 for (;;)
35 {
36 hr = ConsoleReadW(&sczFilePath);
37 ConsoleExitOnFailure(hr, CONSOLE_COLOR_RED, "Failed to read file path to signed file from stdin");
38
39 if (!*sczFilePath)
40 {
41 break;
42 }
43
44 hr = GetPublicKeyIdentifierAndThumbprint(sczFilePath, &sczPublicKeyIdentifier, &sczThumbprint);
45 if (FAILED(hr))
46 {
47 // Treat no signature as success without finding certificate hashes.
48 ConsoleWriteLine(CONSOLE_COLOR_NORMAL, "%ls\t\t\t0x%x", sczFilePath, TRUST_E_NOSIGNATURE == hr ? 0 : hr);
49 }
50 else
51 {
52 ConsoleWriteLine(CONSOLE_COLOR_NORMAL, "%ls\t%ls\t%ls\t0x%x", sczFilePath, sczPublicKeyIdentifier, sczThumbprint, hr);
53 }
54 }
55
56 LExit:
57 ReleaseStr(sczThumbprint);
58 ReleaseStr(sczPublicKeyIdentifier);
59 ReleaseStr(sczFilePath);
60
61 return hr;
62 }
63
64 static HRESULT GetPublicKeyIdentifierAndThumbprint(
65 __in_z LPCWSTR wzPath,
66 __inout_z LPWSTR* psczPublicKeyIdentifier,
67 __inout_z LPWSTR* psczThumbprint)
68 {
69 HRESULT hr = S_OK;
70 PCCERT_CHAIN_CONTEXT pChainContext = NULL;
71 PCCERT_CONTEXT pCertContext = NULL;
72 BYTE rgbPublicKeyIdentifier[SHA1_HASH_LEN] = { };
73 DWORD cbPublicKeyIdentifier = sizeof(rgbPublicKeyIdentifier);
74 BYTE* pbThumbprint = NULL;
75 DWORD cbThumbprint = 0;
76
77 hr = GetChainContext(wzPath, &pChainContext);
78 ExitOnFailure(hr, "Failed to get chain context for file: %ls", wzPath);
79
80 pCertContext = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
81
82 // Get the certificate's public key identifier and thumbprint.
83 if (!::CryptHashPublicKeyInfo(NULL, CALG_SHA1, 0, X509_ASN_ENCODING, &pCertContext->pCertInfo->SubjectPublicKeyInfo, rgbPublicKeyIdentifier, &cbPublicKeyIdentifier))
84 {
85 ExitWithLastError(hr, "Failed to get certificate public key identifier from file: %ls", wzPath);
86 }
87
88 hr = CertReadProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, &pbThumbprint, &cbThumbprint);
89 ExitOnFailure(hr, "Failed to read certificate thumbprint from file: %ls", wzPath);
90
91 // Get the public key indentifier and thumbprint in hex.
92 hr = StrAllocHexEncode(rgbPublicKeyIdentifier, cbPublicKeyIdentifier, psczPublicKeyIdentifier);
93 ExitOnFailure(hr, "Failed to convert certificate public key to hex for file: %ls", wzPath);
94
95 hr = StrAllocHexEncode(pbThumbprint, cbThumbprint, psczThumbprint);
96 ExitOnFailure(hr, "Failed to convert certificate thumbprint to hex for file: %ls", wzPath);
97
98 LExit:
99 ReleaseMem(pbThumbprint);
100 return hr;
101 }
102
103 static HRESULT GetChainContext(
104 __in_z LPCWSTR wzPath,
105 __out PCCERT_CHAIN_CONTEXT* ppChainContext)
106 {
107 HRESULT hr = S_OK;
108
109 GUID guidAuthenticode = WINTRUST_ACTION_GENERIC_VERIFY_V2;
110 WINTRUST_FILE_INFO wfi = { };
111 WINTRUST_DATA wtd = { };
112 CRYPT_PROVIDER_DATA* pProviderData = NULL;
113 CRYPT_PROVIDER_SGNR* pSigner = NULL;
114
115 wfi.cbStruct = sizeof(wfi);
116 wfi.pcwszFilePath = wzPath;
117
118 wtd.cbStruct = sizeof(wtd);
119 wtd.dwUnionChoice = WTD_CHOICE_FILE;
120 wtd.pFile = &wfi;
121 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
122 wtd.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_HASH_ONLY_FLAG | WTD_CACHE_ONLY_URL_RETRIEVAL;
123 wtd.dwUIChoice = WTD_UI_NONE;
124
125 hr = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &guidAuthenticode, &wtd);
126 ExitOnFailure(hr, "Failed to verify certificate on file: %ls", wzPath);
127
128 pProviderData = ::WTHelperProvDataFromStateData(wtd.hWVTStateData);
129 ExitOnNullWithLastError(pProviderData, hr, "Failed to get provider state from authenticode certificate on file: %ls", wzPath);
130
131 pSigner = ::WTHelperGetProvSignerFromChain(pProviderData, 0, FALSE, 0);
132 ExitOnNullWithLastError(pSigner, hr, "Failed to get signer chain from authenticode certificate on file: %ls", wzPath);
133
134 *ppChainContext = pSigner->pChainContext;
135
136 LExit:
137 return hr;
138 }