LibreOffice Module onlineupdate (master) 1
certificatecheck.cxx
Go to the documentation of this file.
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <windows.h>
8#include <softpub.h>
9#include <wintrust.h>
10
11#include "certificatecheck.hxx"
12#include "servicebase.hxx"
13
14#pragma comment(lib, "wintrust.lib")
15#pragma comment(lib, "crypt32.lib")
16
17static const int ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
18
27DWORD
29 CertificateCheckInfo &infoToMatch)
30{
31 HCERTSTORE certStore = nullptr;
32 HCRYPTMSG cryptMsg = nullptr;
33 PCCERT_CONTEXT certContext = nullptr;
34 PCMSG_SIGNER_INFO signerInfo = nullptr;
35 DWORD lastError = ERROR_SUCCESS;
36
37 // Get the HCERTSTORE and HCRYPTMSG from the signed file.
38 DWORD encoding, contentType, formatType;
39 BOOL result = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
41 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
42 CERT_QUERY_CONTENT_FLAG_ALL,
43 0, &encoding, &contentType,
44 &formatType, &certStore, &cryptMsg, nullptr);
45 if (!result)
46 {
47 lastError = GetLastError();
48 LOG_WARN(("CryptQueryObject failed. (%d)", lastError));
49 goto cleanup;
50 }
51
52 // Pass in nullptr to get the needed signer information size.
53 DWORD signerInfoSize;
54 result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0,
55 nullptr, &signerInfoSize);
56 if (!result)
57 {
58 lastError = GetLastError();
59 LOG_WARN(("CryptMsgGetParam failed. (%d)", lastError));
60 goto cleanup;
61 }
62
63 // Allocate the needed size for the signer information.
64 signerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, signerInfoSize);
65 if (!signerInfo)
66 {
67 lastError = GetLastError();
68 LOG_WARN(("Unable to allocate memory for Signer Info. (%d)", lastError));
69 goto cleanup;
70 }
71
72 // Get the signer information (PCMSG_SIGNER_INFO).
73 // In particular we want the issuer and serial number.
74 result = CryptMsgGetParam(cryptMsg, CMSG_SIGNER_INFO_PARAM, 0,
75 (PVOID)signerInfo, &signerInfoSize);
76 if (!result)
77 {
78 lastError = GetLastError();
79 LOG_WARN(("CryptMsgGetParam failed. (%d)", lastError));
80 goto cleanup;
81 }
82
83 // Search for the signer certificate in the certificate store.
84 CERT_INFO certInfo;
85 certInfo.Issuer = signerInfo->Issuer;
86 certInfo.SerialNumber = signerInfo->SerialNumber;
87 certContext = CertFindCertificateInStore(certStore, ENCODING, 0,
88 CERT_FIND_SUBJECT_CERT,
89 (PVOID)&certInfo, nullptr);
90 if (!certContext)
91 {
92 lastError = GetLastError();
93 LOG_WARN(("CertFindCertificateInStore failed. (%d)", lastError));
94 goto cleanup;
95 }
96
97 if (!DoCertificateAttributesMatch(certContext, infoToMatch))
98 {
99 lastError = ERROR_NOT_FOUND;
100 LOG_WARN(("Certificate did not match issuer or name. (%d)", lastError));
101 goto cleanup;
102 }
103
104cleanup:
105 if (signerInfo)
106 {
107 LocalFree(signerInfo);
108 }
109 if (certContext)
110 {
111 CertFreeCertificateContext(certContext);
112 }
113 if (certStore)
114 {
115 CertCloseStore(certStore, 0);
116 }
117 if (cryptMsg)
118 {
119 CryptMsgClose(cryptMsg);
120 }
121 return lastError;
122}
123
131BOOL
132DoCertificateAttributesMatch(PCCERT_CONTEXT certContext,
133 CertificateCheckInfo &infoToMatch)
134{
135 DWORD dwData;
136 LPTSTR szName = nullptr;
137
138 if (infoToMatch.issuer)
139 {
140 // Pass in nullptr to get the needed size of the issuer buffer.
141 dwData = CertGetNameString(certContext,
142 CERT_NAME_SIMPLE_DISPLAY_TYPE,
143 CERT_NAME_ISSUER_FLAG, nullptr,
144 nullptr, 0);
145
146 if (!dwData)
147 {
148 LOG_WARN(("CertGetNameString failed. (%d)", GetLastError()));
149 return FALSE;
150 }
151
152 // Allocate memory for Issuer name buffer.
153 LPTSTR szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
154 if (!szName)
155 {
156 LOG_WARN(("Unable to allocate memory for issuer name. (%d)",
157 GetLastError()));
158 return FALSE;
159 }
160
161 // Get Issuer name.
162 if (!CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
163 CERT_NAME_ISSUER_FLAG, nullptr, szName, dwData))
164 {
165 LOG_WARN(("CertGetNameString failed. (%d)", GetLastError()));
166 LocalFree(szName);
167 return FALSE;
168 }
169
170 // If the issuer does not match, return a failure.
171 if (!infoToMatch.issuer ||
172 wcscmp(szName, infoToMatch.issuer))
173 {
174 LocalFree(szName);
175 return FALSE;
176 }
177
178 LocalFree(szName);
179 szName = nullptr;
180 }
181
182 if (infoToMatch.name)
183 {
184 // Pass in nullptr to get the needed size of the name buffer.
185 dwData = CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
186 0, nullptr, nullptr, 0);
187 if (!dwData)
188 {
189 LOG_WARN(("CertGetNameString failed. (%d)", GetLastError()));
190 return FALSE;
191 }
192
193 // Allocate memory for the name buffer.
194 szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(WCHAR));
195 if (!szName)
196 {
197 LOG_WARN(("Unable to allocate memory for subject name. (%d)",
198 GetLastError()));
199 return FALSE;
200 }
201
202 // Obtain the name.
203 if (!(CertGetNameString(certContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
204 nullptr, szName, dwData)))
205 {
206 LOG_WARN(("CertGetNameString failed. (%d)", GetLastError()));
207 LocalFree(szName);
208 return FALSE;
209 }
210
211 // If the issuer does not match, return a failure.
212 if (!infoToMatch.name ||
213 wcscmp(szName, infoToMatch.name))
214 {
215 LocalFree(szName);
216 return FALSE;
217 }
218
219 // We have a match!
220 LocalFree(szName);
221 }
222
223 // If there were any errors we would have aborted by now.
224 return TRUE;
225}
226
233LPWSTR
234AllocateAndCopyWideString(LPCWSTR inputString)
235{
236 LPWSTR outputString =
237 (LPWSTR)LocalAlloc(LPTR, (wcslen(inputString) + 1) * sizeof(WCHAR));
238 if (outputString)
239 {
240 lstrcpyW(outputString, inputString);
241 }
242 return outputString;
243}
244
251DWORD
253{
254 // Setup the file to check.
255 WINTRUST_FILE_INFO fileToCheck;
256 ZeroMemory(&fileToCheck, sizeof(fileToCheck));
257 fileToCheck.cbStruct = sizeof(WINTRUST_FILE_INFO);
258 fileToCheck.pcwszFilePath = filePath;
259
260 // Setup what to check, we want to check it is signed and trusted.
261 WINTRUST_DATA trustData;
262 ZeroMemory(&trustData, sizeof(trustData));
263 trustData.cbStruct = sizeof(trustData);
264 trustData.pPolicyCallbackData = nullptr;
265 trustData.pSIPClientData = nullptr;
266 trustData.dwUIChoice = WTD_UI_NONE;
267 trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
268 trustData.dwUnionChoice = WTD_CHOICE_FILE;
269 trustData.dwStateAction = 0;
270 trustData.hWVTStateData = nullptr;
271 trustData.pwszURLReference = nullptr;
272 // no UI
273 trustData.dwUIContext = 0;
274 trustData.pFile = &fileToCheck;
275
276 GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
277 // Check if the file is signed by something that is trusted.
278 LONG ret = WinVerifyTrust(nullptr, &policyGUID, &trustData);
279 if (ERROR_SUCCESS == ret)
280 {
281 // The hash that represents the subject is trusted and there were no
282 // verification errors. No publisher nor time stamp chain errors.
283 LOG(("The file \"%ls\" is signed and the signature was verified.",
284 filePath));
285 return ERROR_SUCCESS;
286 }
287
288 DWORD lastError = GetLastError();
289 LOG_WARN(("There was an error validating trust of the certificate for file"
290 " \"%ls\". Returned: %d. (%d)", filePath, ret, lastError));
291 return ret;
292}
DWORD CheckCertificateForPEFile(LPCWSTR filePath, CertificateCheckInfo &infoToMatch)
Checks to see if a file stored at filePath matches the specified info.
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
Duplicates the specified string.
BOOL DoCertificateAttributesMatch(PCCERT_CONTEXT certContext, CertificateCheckInfo &infoToMatch)
Checks to see if a file stored at filePath matches the specified info.
static const int ENCODING
DWORD VerifyCertificateTrustForFile(LPCWSTR filePath)
Verifies the trust of the specified file path.
#define TRUE
#define FALSE
tDoubleVectorPair cleanup(const css::uno::Sequence< double > &rXValues, const css::uno::Sequence< double > &rYValues, Pred aPred)
filePath
const wchar_t *typedef BOOL
LONG
Any result
#define LOG_WARN(args)
Definition: updatelogging.h:38
#define LOG(args)
Definition: updatelogging.h:39