aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Http/ca/httpcerts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Http/ca/httpcerts.cpp')
-rw-r--r--src/ext/Http/ca/httpcerts.cpp938
1 files changed, 938 insertions, 0 deletions
diff --git a/src/ext/Http/ca/httpcerts.cpp b/src/ext/Http/ca/httpcerts.cpp
new file mode 100644
index 00000000..c91dbbe1
--- /dev/null
+++ b/src/ext/Http/ca/httpcerts.cpp
@@ -0,0 +1,938 @@
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#if _WIN32_WINNT < 0x0602
6
7typedef struct _HTTP_SERVICE_CONFIG_SSL_SNI_KEY
8{
9 SOCKADDR_STORAGE IpPort;
10 PWSTR Host;
11} HTTP_SERVICE_CONFIG_SSL_SNI_KEY, * PHTTP_SERVICE_CONFIG_SSL_SNI_KEY;
12
13typedef struct _HTTP_SERVICE_CONFIG_SSL_SNI_SET
14{
15 HTTP_SERVICE_CONFIG_SSL_SNI_KEY KeyDesc;
16 HTTP_SERVICE_CONFIG_SSL_PARAM ParamDesc;
17} HTTP_SERVICE_CONFIG_SSL_SNI_SET, * PHTTP_SERVICE_CONFIG_SSL_SNI_SET;
18
19typedef struct _HTTP_SERVICE_CONFIG_SSL_SNI_QUERY
20{
21 HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc;
22 HTTP_SERVICE_CONFIG_SSL_SNI_KEY KeyDesc;
23 DWORD dwToken;
24} HTTP_SERVICE_CONFIG_SSL_SNI_QUERY, * PHTTP_SERVICE_CONFIG_SSL_SNI_QUERY;
25
26#define HttpServiceConfigSslSniCertInfo static_cast<HTTP_SERVICE_CONFIG_ID>(HttpServiceConfigCache + 1)
27
28#endif
29
30static UINT SchedHttpCertificates(
31 __in WCA_TODO todoSched
32);
33static HRESULT FindExistingSniSslCertificate(
34 __in_z LPWSTR wzHost,
35 __in int nPort,
36 __out HTTP_SERVICE_CONFIG_SSL_SNI_SET** ppSet
37);
38static HRESULT FindExistingIpSslCertificate(
39 __in int nPort,
40 __out HTTP_SERVICE_CONFIG_SSL_SET** ppSet
41);
42static HRESULT WriteSniSslCertCustomActionData(
43 __in WCA_TODO action,
44 __in_z LPCWSTR wzId,
45 __in_z LPCWSTR wzHost,
46 __in int iPort,
47 __in int iHandleExisting,
48 __in HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSniSslSet,
49 __inout_z LPWSTR* psczCustomActionData
50);
51static HRESULT WriteIpSslCertCustomActionData(
52 __in WCA_TODO action,
53 __in_z LPCWSTR wzId,
54 __in int iPort,
55 __in int iHandleExisting,
56 __in HTTP_SERVICE_CONFIG_SSL_SET* pSniSslSet,
57 __inout_z LPWSTR* psczCustomActionData
58);
59static HRESULT AddSniSslCert(
60 __in_z LPCWSTR wzId,
61 __in_z LPWSTR wzHost,
62 __in int iPort,
63 __in BYTE rgbCertificateThumbprint[],
64 __in DWORD cbCertificateThumbprint,
65 __in GUID* pAppId,
66 __in_z LPWSTR wzSslCertStore
67);
68static HRESULT AddIpSslCert(
69 __in_z LPCWSTR wzId,
70 __in int iPort,
71 __in BYTE rgbCertificateThumbprint[],
72 __in DWORD cbCertificateThumbprint,
73 __in GUID* pAppId,
74 __in_z LPWSTR wzSslCertStore
75);
76static HRESULT RemoveSniSslCert(
77 __in_z_opt LPCWSTR wzId,
78 __in_z LPWSTR wzHost,
79 __in int iPort
80);
81static HRESULT RemoveIpSslCert(
82 __in_z_opt LPCWSTR wzId,
83 __in int iPort
84);
85static void SetSniSslCertificateKeyPort(
86 __in HTTP_SERVICE_CONFIG_SSL_SNI_KEY* pKey,
87 __in_z LPWSTR wzHost,
88 __in int iPort
89);
90static void SetIpSslCertificateKeyPort(
91 __in HTTP_SERVICE_CONFIG_SSL_KEY* pKey,
92 __in SOCKADDR_IN* pSin,
93 __in int iPort
94);
95static HRESULT EnsureAppId(
96 __inout_z LPWSTR* psczAppId,
97 __in_opt GUID* pGuid
98);
99static HRESULT StringFromGuid(
100 __in REFGUID rguid,
101 __inout_z LPWSTR* psczGuid
102);
103static HRESULT WriteCertificateCaData(
104 __in eCertificateType certType,
105 __in WCA_TODO action,
106 __in_z LPCWSTR wzId,
107 __in_z_opt LPCWSTR wzHost,
108 __in int iPort,
109 __in int iHandleExisting,
110 __in_z LPCWSTR wzCertificateThumbprint,
111 __in_z_opt LPCWSTR wzAppId,
112 __in_z_opt LPCWSTR wzCertificateStore,
113 __inout_z LPWSTR* psczCustomActionData
114);
115
116
117LPCWSTR vcsHttpCertificatesQuery =
118L"SELECT `HttpCertificate`, `Host`, `Port`, `Thumbprint`, `AppId`, `Store`, `HandleExisting`, `Type`, `Component_` "
119L"FROM `Wix6HttpCertificate`";
120enum eHttpCertificatesQuery { hcqId = 1, hcqHost, hcqPort, hcqCertificateThumbprint, hcqAppId, hcqCertificateStore, hcqHandleExisting, hcqType, hcqComponent };
121
122/******************************************************************
123 SchedHttpCertificatesInstall - immediate custom action entry
124 point to prepare adding certificates.
125
126********************************************************************/
127extern "C" UINT __stdcall SchedHttpCertificatesInstall(
128 __in MSIHANDLE hInstall
129)
130{
131 HRESULT hr = S_OK;
132
133 hr = WcaInitialize(hInstall, "SchedHttpCertificatesInstall");
134 ExitOnFailure(hr, "Failed to initialize");
135
136 hr = SchedHttpCertificates(WCA_TODO_INSTALL);
137
138LExit:
139 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
140}
141
142/******************************************************************
143 SchedWixHttpSniSslCertsUninstall - immediate custom action entry
144 point to prepare removing certificates.
145
146********************************************************************/
147extern "C" UINT __stdcall SchedHttpCertificatesUninstall(
148 __in MSIHANDLE hInstall
149)
150{
151 HRESULT hr = S_OK;
152
153 hr = WcaInitialize(hInstall, "SchedHttpCertificatesUninstall");
154 ExitOnFailure(hr, "Failed to initialize");
155
156 hr = SchedHttpCertificates(WCA_TODO_UNINSTALL);
157
158LExit:
159 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
160}
161
162/******************************************************************
163 ExecHttpCertificates - deferred custom action entry point to
164 bind/unbind certificates.
165
166********************************************************************/
167extern "C" UINT __stdcall ExecHttpCertificates(
168 __in MSIHANDLE hInstall
169)
170{
171 HRESULT hr = S_OK;
172 BOOL fHttpInitialized = FALSE;
173 LPWSTR sczCustomActionData = NULL;
174 LPWSTR wz = NULL;
175 int iTodo = WCA_TODO_UNKNOWN;
176 LPWSTR sczId = NULL;
177 LPWSTR sczHost = NULL;
178 int iPort = 0;
179 eHandleExisting handleExisting = heIgnore;
180 eCertificateType certificateType = ctSniSsl;
181 LPWSTR sczCertificateThumbprint = NULL;
182 LPWSTR sczAppId = NULL;
183 LPWSTR sczCertificateStore = NULL;
184
185 BOOL fRollback = ::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK);
186 BOOL fRemove = FALSE;
187 BOOL fAdd = FALSE;
188 BOOL fFailOnExisting = FALSE;
189
190 GUID guidAppId = { };
191 BYTE* pbCertificateThumbprint = NULL;
192 DWORD cbCertificateThumbprint = 0;
193
194 // Initialize.
195 hr = WcaInitialize(hInstall, "ExecHttpCertificates");
196 ExitOnFailure(hr, "Failed to initialize");
197
198 hr = HRESULT_FROM_WIN32(::HttpInitialize(HTTPAPI_VERSION_1, HTTP_INITIALIZE_CONFIG, NULL));
199 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration");
200
201 fHttpInitialized = TRUE;
202
203 hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData);
204 ExitOnFailure(hr, "Failed to get CustomActionData");
205 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", sczCustomActionData);
206
207 wz = sczCustomActionData;
208 while (wz && *wz)
209 {
210 // Extract the custom action data and if rolling back, swap INSTALL and UNINSTALL.
211 hr = WcaReadIntegerFromCaData(&wz, reinterpret_cast<int*>(&certificateType));
212 ExitOnFailure(hr, "Failed to read Type from custom action data");
213
214 hr = WcaReadIntegerFromCaData(&wz, &iTodo);
215 ExitOnFailure(hr, "Failed to read todo from custom action data");
216
217 hr = WcaReadStringFromCaData(&wz, &sczId);
218 ExitOnFailure(hr, "Failed to read Id from custom action data");
219
220 hr = WcaReadStringFromCaData(&wz, &sczHost);
221 ExitOnFailure(hr, "Failed to read Host from custom action data");
222
223 hr = WcaReadIntegerFromCaData(&wz, &iPort);
224 ExitOnFailure(hr, "Failed to read Port from custom action data");
225
226 hr = WcaReadIntegerFromCaData(&wz, reinterpret_cast<int*>(&handleExisting));
227 ExitOnFailure(hr, "Failed to read HandleExisting from custom action data");
228
229 hr = WcaReadStringFromCaData(&wz, &sczCertificateThumbprint);
230 ExitOnFailure(hr, "Failed to read CertificateThumbprint from custom action data");
231
232 hr = WcaReadStringFromCaData(&wz, &sczAppId);
233 ExitOnFailure(hr, "Failed to read AppId from custom action data");
234
235 hr = WcaReadStringFromCaData(&wz, &sczCertificateStore);
236 ExitOnFailure(hr, "Failed to read CertificateStore from custom action data");
237
238 switch (iTodo)
239 {
240 case WCA_TODO_INSTALL:
241 case WCA_TODO_REINSTALL:
242 fRemove = heReplace == handleExisting || fRollback;
243 fAdd = !fRollback || *sczCertificateThumbprint;
244 fFailOnExisting = heFail == handleExisting && !fRollback;
245 break;
246
247 case WCA_TODO_UNINSTALL:
248 fRemove = !fRollback;
249 fAdd = fRollback && *sczCertificateThumbprint;
250 fFailOnExisting = FALSE;
251 break;
252 }
253
254 if (fRemove)
255 {
256 if (ctSniSsl == certificateType)
257 {
258 hr = RemoveSniSslCert(sczId, sczHost, iPort);
259 }
260 else
261 {
262 hr = RemoveIpSslCert(sczId, iPort);
263 }
264
265 if (S_OK == hr)
266 {
267 WcaLog(LOGMSG_STANDARD, "Removed SSL certificate '%ls' for hostname: %ls:%d.", sczId, sczHost, iPort);
268 }
269 else if (FAILED(hr))
270 {
271 if (fRollback)
272 {
273 WcaLogError(hr, "Failed to remove SSL certificate to rollback '%ls' for hostname: %ls:%d.", sczId, sczHost, iPort);
274 }
275 else
276 {
277 ExitOnFailure(hr, "Failed to remove SSL certificate '%ls' for hostname: %ls:%d.", sczId, sczHost, iPort);
278 }
279 }
280 }
281
282 if (fAdd)
283 {
284 WcaLog(LOGMSG_STANDARD, "Adding SSL certificate '%ls' for hostname: %ls:%d.", sczId, sczHost, iPort);
285
286 hr = StrAllocHexDecode(sczCertificateThumbprint, &pbCertificateThumbprint, &cbCertificateThumbprint);
287 ExitOnFailure(hr, "Failed to convert thumbprint to bytes for SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
288
289 hr = ::IIDFromString(sczAppId, &guidAppId);
290 ExitOnFailure(hr, "Failed to convert AppId '%ls' back to GUID for SSL certificate '%ls' for hostname: %ls:%d", sczAppId, sczId, sczHost, iPort);
291 if (ctSniSsl == certificateType)
292 {
293 hr = AddSniSslCert(sczId, sczHost, iPort, pbCertificateThumbprint, cbCertificateThumbprint, &guidAppId, sczCertificateStore && *sczCertificateStore ? sczCertificateStore : L"MY");
294 }
295 else
296 {
297 hr = AddIpSslCert(sczId, iPort, pbCertificateThumbprint, cbCertificateThumbprint, &guidAppId, sczCertificateStore && *sczCertificateStore ? sczCertificateStore : L"MY");
298 }
299
300 if (S_FALSE == hr && fFailOnExisting)
301 {
302 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
303 }
304
305 if (S_OK == hr)
306 {
307 WcaLog(LOGMSG_STANDARD, "Added SSL certificate '%ls' for hostname: %ls:%d with thumbprint: %ls.", sczId, sczHost, iPort, sczCertificateThumbprint);
308 }
309 else if (FAILED(hr))
310 {
311 if (fRollback)
312 {
313 WcaLogError(hr, "Failed to add SSL certificate to rollback '%ls' for hostname: %ls:%d.", sczId, sczHost, iPort);
314 }
315 else
316 {
317 ExitOnFailure(hr, "Failed to add SSL certificate '%ls' for hostname: %ls:%d.", sczId, sczHost, iPort);
318 }
319 }
320
321 ReleaseNullMem(pbCertificateThumbprint);
322 }
323 }
324
325LExit:
326 ReleaseMem(pbCertificateThumbprint);
327 ReleaseStr(sczCertificateStore);
328 ReleaseStr(sczAppId);
329 ReleaseStr(sczCertificateThumbprint);
330 ReleaseStr(sczHost);
331 ReleaseStr(sczId);
332 ReleaseStr(sczCustomActionData);
333
334 if (fHttpInitialized)
335 {
336 ::HttpTerminate(HTTP_INITIALIZE_CONFIG, NULL);
337 }
338
339 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
340}
341
342static UINT SchedHttpCertificates(
343 __in WCA_TODO todoSched
344)
345{
346 HRESULT hr = S_OK;
347 UINT er = ERROR_SUCCESS;
348 BOOL fHttpInitialized = FALSE;
349 DWORD cCertificates = 0;
350
351 PMSIHANDLE hView = NULL;
352 PMSIHANDLE hRec = NULL;
353 PMSIHANDLE hQueryReq = NULL;
354 PMSIHANDLE hAceView = NULL;
355
356 LPWSTR sczCustomActionData = NULL;
357 LPWSTR sczRollbackCustomActionData = NULL;
358
359 LPWSTR sczId = NULL;
360 LPWSTR sczComponent = NULL;
361 eCertificateType certificateType = ctSniSsl;
362 WCA_TODO todoComponent = WCA_TODO_UNKNOWN;
363 LPWSTR sczHost = NULL;
364 int iPort = 0;
365 LPWSTR sczCertificateThumbprint = NULL;
366 LPWSTR sczAppId = NULL;
367 LPWSTR sczCertificateStore = NULL;
368 int iHandleExisting = 0;
369
370 HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet = NULL;
371 HTTP_SERVICE_CONFIG_SSL_SET* pExistingIpSslSet = NULL;
372
373 // Anything to do?
374 hr = WcaTableExists(L"Wix6HttpCertificate");
375 ExitOnFailure(hr, "Failed to check if the Wix6HttpCertificate table exists");
376 if (S_FALSE == hr)
377 {
378 WcaLog(LOGMSG_STANDARD, "Wix6HttpCertificate table doesn't exist, so there are no certificates to configure.");
379 ExitFunction();
380 }
381
382 // Query and loop through all the SNI SSL certificates.
383 hr = WcaOpenExecuteView(vcsHttpCertificatesQuery, &hView);
384 ExitOnFailure(hr, "Failed to open view on the Wix6HttpCertificate table");
385
386 hr = HRESULT_FROM_WIN32(::HttpInitialize(HTTPAPI_VERSION_1, HTTP_INITIALIZE_CONFIG, NULL));
387 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration");
388
389 fHttpInitialized = TRUE;
390
391 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
392 {
393 hr = WcaGetRecordString(hRec, hcqId, &sczId);
394 ExitOnFailure(hr, "Failed to get Wix6HttpCertificate.Wix6HttpCertificate");
395
396 hr = WcaGetRecordString(hRec, hcqComponent, &sczComponent);
397 ExitOnFailure(hr, "Failed to get Wix6HttpCertificate.Component_");
398
399 // Figure out what we're doing for this certificate, treating reinstall the same as install.
400 todoComponent = WcaGetComponentToDo(sczComponent);
401 if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
402 {
403 WcaLog(LOGMSG_VERBOSE, "Component '%ls' action state (%d) doesn't match request (%d) for Wix6HttpCertificate '%ls'.", sczComponent, todoComponent, todoSched, sczId);
404 continue;
405 }
406
407 hr = WcaGetRecordInteger(hRec, hcqType, reinterpret_cast<int*>(&certificateType));
408 ExitOnFailure(hr, "Failed to get Type for Wix6HttpCertificate '%ls'", sczId);
409
410 hr = WcaGetRecordFormattedString(hRec, hcqHost, &sczHost);
411 ExitOnFailure(hr, "Failed to get Wix6HttpCertificate.Host");
412
413 hr = WcaGetRecordFormattedInteger(hRec, hcqPort, &iPort);
414 ExitOnFailure(hr, "Failed to get Wix6HttpCertificate.Port");
415
416 hr = WcaGetRecordFormattedString(hRec, hcqCertificateThumbprint, &sczCertificateThumbprint);
417 ExitOnFailure(hr, "Failed to get Wix6HttpCertificate.CertificateThumbprint");
418
419 if (!iPort)
420 {
421 hr = E_INVALIDARG;
422 ExitOnFailure(hr, "Missing Port value for Wix6HttpCertificate '%ls'", sczId);
423 }
424
425 if (!sczCertificateThumbprint || !*sczCertificateThumbprint)
426 {
427 hr = E_INVALIDARG;
428 ExitOnFailure(hr, "Missing CertificateThumbprint value for Wix6HttpCertificate '%ls'", sczId);
429 }
430
431 hr = WcaGetRecordFormattedString(hRec, hcqAppId, &sczAppId);
432 ExitOnFailure(hr, "Failed to get AppId for Wix6HttpCertificate '%ls'", sczId);
433
434 hr = WcaGetRecordFormattedString(hRec, hcqCertificateStore, &sczCertificateStore);
435 ExitOnFailure(hr, "Failed to get CertificateStore for Wix6HttpCertificate '%ls'", sczId);
436
437 hr = WcaGetRecordInteger(hRec, hcqHandleExisting, &iHandleExisting);
438 ExitOnFailure(hr, "Failed to get HandleExisting for Wix6HttpCertificate '%ls'", sczId);
439
440 if (ctIpSsl == certificateType)
441 {
442 WcaLog(LOGMSG_STANDARD, "Processing IP SSL certificate: %ls on port %d.", sczId, iPort);
443
444 hr = FindExistingIpSslCertificate(iPort, &pExistingIpSslSet);
445 ExitOnFailure(hr, "Failed to search for an existing IP SSL certificate for '%ls' on port %d", sczId, iPort);
446
447 if (S_FALSE != hr)
448 {
449 hr = WriteIpSslCertCustomActionData(todoComponent, sczId, iPort, iHandleExisting, pExistingIpSslSet, &sczRollbackCustomActionData);
450 ExitOnFailure(hr, "Failed to write rollback custom action data for IP SSL '%ls' on port %d", sczId, iPort);
451 }
452
453 hr = EnsureAppId(&sczAppId, pExistingIpSslSet ? &(pExistingIpSslSet->ParamDesc.AppId) : NULL);
454 ExitOnFailure(hr, "Failed to ensure AppId for IP SSL '%ls'", sczId);
455 }
456 else if (ctSniSsl == certificateType)
457 {
458 WcaLog(LOGMSG_STANDARD, "Processing SNI SSL certificate: %ls on host %ls:%d.", sczId, sczHost, iPort);
459
460 hr = FindExistingSniSslCertificate(sczHost, iPort, &pExistingSniSslSet);
461 ExitOnFailure(hr, "Failed to search for an existing SNI SSL certificate for '%ls' on host '%ls', port %d", sczId, sczHost, iPort);
462
463 if (S_FALSE != hr)
464 {
465 hr = WriteSniSslCertCustomActionData(todoComponent, sczId, sczHost, iPort, iHandleExisting, pExistingSniSslSet, &sczRollbackCustomActionData);
466 ExitOnFailure(hr, "Failed to write rollback custom action data for SNI SSL Wix6HttpCertificate '%ls' on host '%ls', port %d", sczId, sczHost, iPort);
467 }
468
469 hr = EnsureAppId(&sczAppId, pExistingSniSslSet ? &(pExistingSniSslSet->ParamDesc.AppId) : NULL);
470 ExitOnFailure(hr, "Failed to ensure AppId for SNI SSL '%ls'", sczId);
471 }
472
473 hr = WriteCertificateCaData(certificateType, todoComponent, sczId, sczHost, iPort, iHandleExisting, sczCertificateThumbprint, sczAppId, sczCertificateStore, &sczCustomActionData);
474 ExitOnFailure(hr, "Failed to write custom action data for SSL '%ls'", sczId);
475 ++cCertificates;
476
477 ReleaseNullMem(pExistingSniSslSet);
478 ReleaseNullMem(pExistingIpSslSet);
479 }
480
481 // Reaching the end of the list is not an error.
482 if (E_NOMOREITEMS == hr)
483 {
484 hr = S_OK;
485 }
486 ExitOnFailure(hr, "Failure occurred while processing Wix6HttpCertificate table");
487
488 WcaLog(LOGMSG_VERBOSE, "Scheduling %d certificates", cCertificates);
489
490 // Schedule ExecHttpSniSslCerts if there's anything to do.
491 if (cCertificates)
492 {
493 WcaLog(LOGMSG_TRACEONLY, "Scheduling SSL certificate: `%ls`", sczCustomActionData);
494 WcaLog(LOGMSG_TRACEONLY, "Scheduling rollback SSL certificate: `%ls`", sczRollbackCustomActionData);
495
496 if (WCA_TODO_INSTALL == todoSched)
497 {
498 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RollbackHttpCertificatesInstall"), sczRollbackCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
499 ExitOnFailure(hr, "Failed to schedule install SSL certificate rollback");
500 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"ExecHttpCertificatesInstall"), sczCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
501 ExitOnFailure(hr, "Failed to schedule install SSL certificate execution");
502 }
503 else
504 {
505 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RollbackHttpCertificatesUninstall"), sczRollbackCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
506 ExitOnFailure(hr, "Failed to schedule uninstall SSL certificate rollback");
507 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"ExecHttpCertificatesUninstall"), sczCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
508 ExitOnFailure(hr, "Failed to schedule uninstall SSL certificate execution");
509 }
510 }
511 else
512 {
513 WcaLog(LOGMSG_STANDARD, "No SNI SSL certificates scheduled.");
514 }
515
516LExit:
517 ReleaseMem(pExistingSniSslSet);
518 ReleaseMem(pExistingIpSslSet);
519 ReleaseStr(sczCertificateStore);
520 ReleaseStr(sczAppId);
521 ReleaseStr(sczCertificateThumbprint);
522 ReleaseStr(sczHost);
523 ReleaseStr(sczComponent);
524 ReleaseStr(sczId);
525 ReleaseStr(sczRollbackCustomActionData);
526 ReleaseStr(sczCustomActionData);
527
528 if (fHttpInitialized)
529 {
530 ::HttpTerminate(HTTP_INITIALIZE_CONFIG, NULL);
531 }
532
533 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
534}
535
536static HRESULT FindExistingSniSslCertificate(
537 __in_z LPWSTR wzHost,
538 __in int nPort,
539 __out HTTP_SERVICE_CONFIG_SSL_SNI_SET** ppSet
540)
541{
542 HRESULT hr = S_OK;
543 DWORD er = ERROR_SUCCESS;
544 HTTP_SERVICE_CONFIG_SSL_SNI_QUERY query = { };
545 HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSet = NULL;
546 ULONG cbSet = 0;
547
548 *ppSet = NULL;
549
550 query.QueryDesc = HttpServiceConfigQueryExact;
551 SetSniSslCertificateKeyPort(&query.KeyDesc, wzHost, nPort);
552
553 WcaLog(LOGMSG_TRACEONLY, "Querying for SNI SSL certificate on port %d...", nPort);
554
555 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
556 if (ERROR_INSUFFICIENT_BUFFER == er)
557 {
558 pSet = reinterpret_cast<HTTP_SERVICE_CONFIG_SSL_SNI_SET*>(MemAlloc(cbSet, TRUE));
559 ExitOnNull(pSet, hr, E_OUTOFMEMORY, "Failed to allocate query SN SSL certificate buffer");
560
561 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
562 }
563
564 if (ERROR_SUCCESS == er)
565 {
566 *ppSet = pSet;
567 pSet = NULL;
568 }
569 else if (ERROR_FILE_NOT_FOUND == er || ERROR_NO_MORE_ITEMS == er)
570 {
571 hr = S_FALSE;
572 }
573 else
574 {
575 hr = HRESULT_FROM_WIN32(er);
576 }
577
578LExit:
579 ReleaseMem(pSet);
580
581 return hr;
582}
583
584static HRESULT FindExistingIpSslCertificate(
585 __in int nPort,
586 __out HTTP_SERVICE_CONFIG_SSL_SET** ppSet
587)
588{
589 HRESULT hr = S_OK;
590 DWORD er = ERROR_SUCCESS;
591 HTTP_SERVICE_CONFIG_SSL_QUERY query = { };
592 SOCKADDR_IN sin = { };
593 HTTP_SERVICE_CONFIG_SSL_SET* pSet = NULL;
594 ULONG cbSet = 0;
595
596 *ppSet = NULL;
597
598 query.QueryDesc = HttpServiceConfigQueryNext;
599
600 SetIpSslCertificateKeyPort(&query.KeyDesc, &sin, nPort);
601
602 WcaLog(LOGMSG_TRACEONLY, "Querying for IP SSL certificate on port %d...", nPort);
603
604 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSSLCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
605 if (ERROR_INSUFFICIENT_BUFFER == er)
606 {
607 pSet = reinterpret_cast<HTTP_SERVICE_CONFIG_SSL_SET*>(MemAlloc(cbSet, TRUE));
608 ExitOnNull(pSet, hr, E_OUTOFMEMORY, "Failed to allocate query IP SSL certificate buffer");
609
610 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSSLCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
611 }
612
613 if (ERROR_SUCCESS == er)
614 {
615 *ppSet = pSet;
616 pSet = NULL;
617 }
618 else if (ERROR_FILE_NOT_FOUND == er || ERROR_NO_MORE_ITEMS == er)
619 {
620 hr = S_FALSE;
621 }
622 else
623 {
624 hr = HRESULT_FROM_WIN32(er);
625 }
626
627LExit:
628 ReleaseMem(pSet);
629
630 return hr;
631}
632
633static HRESULT WriteSniSslCertCustomActionData(
634 __in WCA_TODO action,
635 __in_z LPCWSTR wzId,
636 __in_z LPCWSTR wzHost,
637 __in int iPort,
638 __in int iHandleExisting,
639 __in HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSniSslSet,
640 __inout_z LPWSTR* psczCustomActionData
641)
642{
643 HRESULT hr = S_OK;
644 LPWSTR sczCertificateThumbprint = NULL;
645 LPWSTR sczAppId = NULL;
646 LPCWSTR wzCertificateStore = NULL;
647
648 if (pSniSslSet)
649 {
650 hr = StrAllocHexEncode(reinterpret_cast<BYTE*>(pSniSslSet->ParamDesc.pSslHash), pSniSslSet->ParamDesc.SslHashLength, &sczCertificateThumbprint);
651 ExitOnFailure(hr, "Failed to convert existing certificate thumbprint to hex for Wix6HttpCertificate '%ls'", wzId);
652
653 hr = StringFromGuid(pSniSslSet->ParamDesc.AppId, &sczAppId);
654 ExitOnFailure(hr, "Failed to copy existing AppId for Wix6HttpCertificate '%ls'", wzId);
655
656 wzCertificateStore = pSniSslSet->ParamDesc.pSslCertStoreName;
657 }
658
659 hr = WriteCertificateCaData(ctSniSsl, action, wzId, wzHost, iPort, iHandleExisting, sczCertificateThumbprint ? sczCertificateThumbprint : L"", sczAppId ? sczAppId : L"", wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
660 ExitOnFailure(hr, "Failed to write custom action data for Wix6HttpCertificate '%ls'", wzId);
661
662LExit:
663 ReleaseStr(sczAppId);
664 ReleaseStr(sczCertificateThumbprint);
665
666 return hr;
667}
668
669static HRESULT WriteIpSslCertCustomActionData(
670 __in WCA_TODO action,
671 __in_z LPCWSTR wzId,
672 __in int iPort,
673 __in int iHandleExisting,
674 __in HTTP_SERVICE_CONFIG_SSL_SET* pSslSet,
675 __inout_z LPWSTR* psczCustomActionData
676)
677{
678 HRESULT hr = S_OK;
679 LPWSTR sczCertificateThumbprint = NULL;
680 LPWSTR sczAppId = NULL;
681 LPCWSTR wzCertificateStore = NULL;
682
683 if (pSslSet)
684 {
685 hr = StrAllocHexEncode(reinterpret_cast<BYTE*>(pSslSet->ParamDesc.pSslHash), pSslSet->ParamDesc.SslHashLength, &sczCertificateThumbprint);
686 ExitOnFailure(hr, "Failed to convert existing IP SSL certificate thumbprint to hex for Wix6HttpCertificate '%ls'", wzId);
687
688 hr = StringFromGuid(pSslSet->ParamDesc.AppId, &sczAppId);
689 ExitOnFailure(hr, "Failed to copy existing IP SSL AppId for Wix6HttpCertificate '%ls'", wzId);
690
691 wzCertificateStore = pSslSet->ParamDesc.pSslCertStoreName;
692 }
693
694 hr = WriteCertificateCaData(ctIpSsl, action, wzId, /*wzHost*/NULL, iPort, iHandleExisting, sczCertificateThumbprint ? sczCertificateThumbprint : L"", sczAppId ? sczAppId : L"", wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
695 ExitOnFailure(hr, "Failed to write custom action data for IP SSL Wix6HttpCertificate '%ls'", wzId);
696
697LExit:
698 ReleaseStr(sczAppId);
699 ReleaseStr(sczCertificateThumbprint);
700
701 return hr;
702}
703
704static HRESULT AddSniSslCert(
705 __in_z LPCWSTR /*wzId*/,
706 __in_z LPWSTR wzHost,
707 __in int iPort,
708 __in BYTE rgbCertificateThumbprint[],
709 __in DWORD cbCertificateThumbprint,
710 __in GUID* pAppId,
711 __in_z LPWSTR wzSslCertStore
712)
713{
714 HRESULT hr = S_OK;
715 DWORD er = ERROR_SUCCESS;
716 HTTP_SERVICE_CONFIG_SSL_SNI_SET set = { };
717
718 SetSniSslCertificateKeyPort(&set.KeyDesc, wzHost, iPort);
719 set.ParamDesc.SslHashLength = cbCertificateThumbprint;
720 set.ParamDesc.pSslHash = rgbCertificateThumbprint;
721 set.ParamDesc.AppId = *pAppId;
722 set.ParamDesc.pSslCertStoreName = wzSslCertStore;
723
724 er = ::HttpSetServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &set, sizeof(set), NULL);
725 if (ERROR_ALREADY_EXISTS == er)
726 {
727 hr = S_FALSE;
728 }
729 else
730 {
731 hr = HRESULT_FROM_WIN32(er);
732 }
733
734 return hr;
735}
736
737static HRESULT AddIpSslCert(
738 __in_z LPCWSTR /*wzId*/,
739 __in int iPort,
740 __in BYTE rgbCertificateThumbprint[],
741 __in DWORD cbCertificateThumbprint,
742 __in GUID* pAppId,
743 __in_z LPWSTR wzSslCertStore
744)
745{
746 HRESULT hr = S_OK;
747 DWORD er = ERROR_SUCCESS;
748 HTTP_SERVICE_CONFIG_SSL_SET set = { };
749 SOCKADDR_IN sin = { };
750
751 SetIpSslCertificateKeyPort(&set.KeyDesc, &sin, iPort);
752 set.ParamDesc.SslHashLength = cbCertificateThumbprint;
753 set.ParamDesc.pSslHash = rgbCertificateThumbprint;
754 set.ParamDesc.AppId = *pAppId;
755 set.ParamDesc.pSslCertStoreName = wzSslCertStore;
756
757 er = ::HttpSetServiceConfiguration(NULL, HttpServiceConfigSSLCertInfo, &set, sizeof(set), NULL);
758 if (ERROR_ALREADY_EXISTS == er)
759 {
760 hr = S_FALSE;
761 }
762 else
763 {
764 hr = HRESULT_FROM_WIN32(er);
765 }
766
767 return hr;
768}
769
770static HRESULT RemoveSniSslCert(
771 __in_z_opt LPCWSTR /*wzId*/,
772 __in_z LPWSTR wzHost,
773 __in int iPort
774)
775{
776 HRESULT hr = S_OK;
777 DWORD er = ERROR_SUCCESS;
778 HTTP_SERVICE_CONFIG_SSL_SNI_SET set = { };
779
780 SetSniSslCertificateKeyPort(&set.KeyDesc, wzHost, iPort);
781
782 er = ::HttpDeleteServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &set, sizeof(set), NULL);
783 if (ERROR_FILE_NOT_FOUND == er || ERROR_NO_MORE_ITEMS == er)
784 {
785 hr = S_FALSE;
786 }
787 else
788 {
789 hr = HRESULT_FROM_WIN32(er);
790 }
791
792 return hr;
793}
794
795static HRESULT RemoveIpSslCert(
796 __in_z_opt LPCWSTR /*wzId*/,
797 __in int iPort
798)
799{
800 HRESULT hr = S_OK;
801 DWORD er = ERROR_SUCCESS;
802 HTTP_SERVICE_CONFIG_SSL_SET set = { };
803 SOCKADDR_IN sin = { };
804
805 SetIpSslCertificateKeyPort(&set.KeyDesc, &sin, iPort);
806
807 er = ::HttpDeleteServiceConfiguration(NULL, HttpServiceConfigSSLCertInfo, &set, sizeof(set), NULL);
808 if (ERROR_FILE_NOT_FOUND == er || ERROR_NO_MORE_ITEMS == er)
809 {
810 hr = S_FALSE;
811 }
812 else
813 {
814 hr = HRESULT_FROM_WIN32(er);
815 }
816
817 return hr;
818}
819
820static void SetSniSslCertificateKeyPort(
821 __in HTTP_SERVICE_CONFIG_SSL_SNI_KEY* pKey,
822 __in_z LPWSTR wzHost,
823 __in int iPort
824)
825{
826 pKey->Host = wzHost;
827 SOCKADDR_IN* pss = reinterpret_cast<SOCKADDR_IN*>(&pKey->IpPort);
828 pss->sin_family = AF_INET;
829 pss->sin_port = htons(static_cast<USHORT>(iPort));
830}
831
832static void SetIpSslCertificateKeyPort(
833 __in HTTP_SERVICE_CONFIG_SSL_KEY* pKey,
834 __in SOCKADDR_IN* pSin,
835 __in int iPort
836)
837{
838 pSin->sin_family = AF_INET;
839 pSin->sin_port = htons(static_cast<USHORT>(iPort));
840 pKey->pIpPort = reinterpret_cast<PSOCKADDR>(pSin);
841}
842
843static HRESULT EnsureAppId(
844 __inout_z LPWSTR* psczAppId,
845 __in_opt GUID* pGuid
846)
847{
848 HRESULT hr = S_OK;
849 GUID guid = { };
850
851 if (!psczAppId || !*psczAppId || !**psczAppId)
852 {
853 if (pGuid)
854 {
855 hr = StringFromGuid(*pGuid, psczAppId);
856 ExitOnFailure(hr, "Failed to ensure AppId guid");
857 }
858 else
859 {
860 hr = HRESULT_FROM_RPC(::UuidCreate(&guid));
861 ExitOnRootFailure(hr, "Failed to create guid for AppId");
862
863 hr = StringFromGuid(guid, psczAppId);
864 ExitOnFailure(hr, "Failed to ensure AppId guid");
865 }
866 }
867
868LExit:
869 return hr;
870}
871
872static HRESULT StringFromGuid(
873 __in REFGUID rguid,
874 __inout_z LPWSTR* psczGuid
875)
876{
877 HRESULT hr = S_OK;
878 WCHAR wzGuid[39];
879
880 if (!::StringFromGUID2(rguid, wzGuid, countof(wzGuid)))
881 {
882 hr = E_OUTOFMEMORY;
883 ExitOnRootFailure(hr, "Failed to convert guid into string");
884 }
885
886 hr = StrAllocString(psczGuid, wzGuid, 0);
887 ExitOnFailure(hr, "Failed to copy guid");
888
889LExit:
890 return hr;
891}
892
893static HRESULT WriteCertificateCaData(
894 __in eCertificateType certType,
895 __in WCA_TODO action,
896 __in_z LPCWSTR wzId,
897 __in_z_opt LPCWSTR wzHost,
898 __in int iPort,
899 __in int iHandleExisting,
900 __in_z LPCWSTR wzCertificateThumbprint,
901 __in_z_opt LPCWSTR wzAppId,
902 __in_z_opt LPCWSTR wzCertificateStore,
903 __inout_z LPWSTR* psczCustomActionData
904)
905{
906 HRESULT hr = S_OK;
907
908 hr = WcaWriteIntegerToCaData(certType, psczCustomActionData);
909 ExitOnFailure(hr, "Failed to write IP SSL certificate type to custom action data");
910
911 hr = WcaWriteIntegerToCaData(action, psczCustomActionData);
912 ExitOnFailure(hr, "Failed to write action to custom action data");
913
914 hr = WcaWriteStringToCaData(wzId, psczCustomActionData);
915 ExitOnFailure(hr, "Failed to write id to custom action data");
916
917 hr = WcaWriteStringToCaData(wzHost ? wzHost : L"", psczCustomActionData);
918 ExitOnFailure(hr, "Failed to write Host to custom action data");
919
920 hr = WcaWriteIntegerToCaData(iPort, psczCustomActionData);
921 ExitOnFailure(hr, "Failed to write Port to custom action data");
922
923 hr = WcaWriteIntegerToCaData(iHandleExisting, psczCustomActionData);
924 ExitOnFailure(hr, "Failed to write HandleExisting to custom action data");
925
926 hr = WcaWriteStringToCaData(wzCertificateThumbprint, psczCustomActionData);
927 ExitOnFailure(hr, "Failed to write CertificateThumbprint to custom action data");
928
929 hr = WcaWriteStringToCaData(wzAppId ? wzAppId : L"", psczCustomActionData);
930 ExitOnFailure(hr, "Failed to write AppId to custom action data");
931
932 hr = WcaWriteStringToCaData(wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
933 ExitOnFailure(hr, "Failed to write CertificateStore to custom action data");
934
935LExit:
936 return hr;
937}
938