summaryrefslogtreecommitdiff
path: root/src/ext/Http/ca/snisslcert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Http/ca/snisslcert.cpp')
-rw-r--r--src/ext/Http/ca/snisslcert.cpp704
1 files changed, 704 insertions, 0 deletions
diff --git a/src/ext/Http/ca/snisslcert.cpp b/src/ext/Http/ca/snisslcert.cpp
new file mode 100644
index 00000000..3a7336af
--- /dev/null
+++ b/src/ext/Http/ca/snisslcert.cpp
@@ -0,0 +1,704 @@
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 SchedHttpSniSslCerts(
31 __in WCA_TODO todoSched
32);
33static HRESULT WriteExistingSniSslCert(
34 __in WCA_TODO action,
35 __in_z LPCWSTR wzId,
36 __in_z LPCWSTR wzHost,
37 __in int iPort,
38 __in int iHandleExisting,
39 __in HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSniSslSet,
40 __inout_z LPWSTR* psczCustomActionData
41);
42static HRESULT WriteSniSslCert(
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_z LPCWSTR wzCertificateThumbprint,
49 __in_z LPCWSTR wzAppId,
50 __in_z_opt LPCWSTR wzCertificateStore,
51 __inout_z LPWSTR* psczCustomActionData
52);
53static HRESULT EnsureAppId(
54 __inout_z LPWSTR* psczAppId,
55 __in_opt HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet
56);
57static HRESULT StringFromGuid(
58 __in REFGUID rguid,
59 __inout_z LPWSTR* psczGuid
60);
61static HRESULT AddSniSslCert(
62 __in_z LPCWSTR wzId,
63 __in_z LPWSTR wzHost,
64 __in int iPort,
65 __in BYTE rgbCertificateThumbprint[],
66 __in DWORD cbCertificateThumbprint,
67 __in GUID* pAppId,
68 __in_z LPWSTR wzSslCertStore
69);
70static HRESULT GetSniSslCert(
71 __in_z LPWSTR wzHost,
72 __in int nPort,
73 __out HTTP_SERVICE_CONFIG_SSL_SNI_SET** ppSet
74);
75static HRESULT RemoveSniSslCert(
76 __in_z LPCWSTR wzId,
77 __in_z LPWSTR wzHost,
78 __in int iPort
79);
80static void SetSniSslCertSetKey(
81 __in HTTP_SERVICE_CONFIG_SSL_SNI_KEY* pKey,
82 __in_z LPWSTR wzHost,
83 __in int iPort
84);
85
86
87LPCWSTR vcsWixHttpSniSslCertQuery =
88L"SELECT `Wix4HttpSniSslCert`.`Wix4HttpSniSslCert`, `Wix4HttpSniSslCert`.`Host`, `Wix4HttpSniSslCert`.`Port`, `Wix4HttpSniSslCert`.`Thumbprint`, `Wix4HttpSniSslCert`.`AppId`, `Wix4HttpSniSslCert`.`Store`, `Wix4HttpSniSslCert`.`HandleExisting`, `Wix4HttpSniSslCert`.`Component_` "
89L"FROM `Wix4HttpSniSslCert`";
90enum eWixHttpSniSslCertQuery { hurqId = 1, hurqHost, hurqPort, hurqCertificateThumbprint, hurqAppId, hurqCertificateStore, hurqHandleExisting, hurqComponent };
91
92/******************************************************************
93 SchedWixHttpSniSslCertsInstall - immediate custom action entry
94 point to prepare adding URL reservations.
95
96********************************************************************/
97extern "C" UINT __stdcall SchedHttpSniSslCertsInstall(
98 __in MSIHANDLE hInstall
99)
100{
101 HRESULT hr = S_OK;
102
103 hr = WcaInitialize(hInstall, "SchedHttpSniSslCertsInstall");
104 ExitOnFailure(hr, "Failed to initialize");
105
106 hr = SchedHttpSniSslCerts(WCA_TODO_INSTALL);
107
108LExit:
109 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
110}
111
112/******************************************************************
113 SchedWixHttpSniSslCertsUninstall - immediate custom action entry
114 point to prepare removing URL reservations.
115
116********************************************************************/
117extern "C" UINT __stdcall SchedHttpSniSslCertsUninstall(
118 __in MSIHANDLE hInstall
119)
120{
121 HRESULT hr = S_OK;
122
123 hr = WcaInitialize(hInstall, "SchedHttpSniSslCertsUninstall");
124 ExitOnFailure(hr, "Failed to initialize");
125
126 hr = SchedHttpSniSslCerts(WCA_TODO_UNINSTALL);
127
128LExit:
129 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
130}
131
132/******************************************************************
133 ExecHttpSniSslCerts - deferred custom action entry point to
134 register and remove URL reservations.
135
136********************************************************************/
137extern "C" UINT __stdcall ExecHttpSniSslCerts(
138 __in MSIHANDLE hInstall
139)
140{
141 HRESULT hr = S_OK;
142 BOOL fHttpInitialized = FALSE;
143 LPWSTR sczCustomActionData = NULL;
144 LPWSTR wz = NULL;
145 int iTodo = WCA_TODO_UNKNOWN;
146 LPWSTR sczId = NULL;
147 LPWSTR sczHost = NULL;
148 int iPort = 0;
149 eHandleExisting handleExisting = heIgnore;
150 LPWSTR sczCertificateThumbprint = NULL;
151 LPWSTR sczAppId = NULL;
152 LPWSTR sczCertificateStore = NULL;
153
154 BOOL fRollback = ::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK);
155 BOOL fRemove = FALSE;
156 BOOL fAdd = FALSE;
157 BOOL fFailOnExisting = FALSE;
158
159 GUID guidAppId = { };
160 BYTE* pbCertificateThumbprint = NULL;
161 DWORD cbCertificateThumbprint = 0;
162
163 // Initialize.
164 hr = WcaInitialize(hInstall, "ExecHttpSniSslCerts");
165 ExitOnFailure(hr, "Failed to initialize");
166
167 hr = HRESULT_FROM_WIN32(::HttpInitialize(HTTPAPI_VERSION_1, HTTP_INITIALIZE_CONFIG, NULL));
168 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration");
169
170 fHttpInitialized = TRUE;
171
172 hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData);
173 ExitOnFailure(hr, "Failed to get CustomActionData");
174 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", sczCustomActionData);
175
176 wz = sczCustomActionData;
177 while (wz && *wz)
178 {
179 // Extract the custom action data and if rolling back, swap INSTALL and UNINSTALL.
180 hr = WcaReadIntegerFromCaData(&wz, &iTodo);
181 ExitOnFailure(hr, "Failed to read todo from custom action data");
182
183 hr = WcaReadStringFromCaData(&wz, &sczId);
184 ExitOnFailure(hr, "Failed to read Id from custom action data");
185
186 hr = WcaReadStringFromCaData(&wz, &sczHost);
187 ExitOnFailure(hr, "Failed to read Host from custom action data");
188
189 hr = WcaReadIntegerFromCaData(&wz, &iPort);
190 ExitOnFailure(hr, "Failed to read Port from custom action data");
191
192 hr = WcaReadIntegerFromCaData(&wz, reinterpret_cast<int*>(&handleExisting));
193 ExitOnFailure(hr, "Failed to read HandleExisting from custom action data");
194
195 hr = WcaReadStringFromCaData(&wz, &sczCertificateThumbprint);
196 ExitOnFailure(hr, "Failed to read CertificateThumbprint from custom action data");
197
198 hr = WcaReadStringFromCaData(&wz, &sczAppId);
199 ExitOnFailure(hr, "Failed to read AppId from custom action data");
200
201 hr = WcaReadStringFromCaData(&wz, &sczCertificateStore);
202 ExitOnFailure(hr, "Failed to read CertificateStore from custom action data");
203
204 switch (iTodo)
205 {
206 case WCA_TODO_INSTALL:
207 case WCA_TODO_REINSTALL:
208 fRemove = heReplace == handleExisting || fRollback;
209 fAdd = !fRollback || *sczCertificateThumbprint;
210 fFailOnExisting = heFail == handleExisting && !fRollback;
211 break;
212
213 case WCA_TODO_UNINSTALL:
214 fRemove = !fRollback;
215 fAdd = fRollback && *sczCertificateThumbprint;
216 fFailOnExisting = FALSE;
217 break;
218 }
219
220 if (fRemove)
221 {
222 hr = RemoveSniSslCert(sczId, sczHost, iPort);
223 if (S_OK == hr)
224 {
225 WcaLog(LOGMSG_STANDARD, "Removed SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
226 }
227 else if (FAILED(hr))
228 {
229 if (fRollback)
230 {
231 WcaLogError(hr, "Failed to remove SNI SSL certificate to rollback '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
232 }
233 else
234 {
235 ExitOnFailure(hr, "Failed to remove SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
236 }
237 }
238 }
239
240 if (fAdd)
241 {
242 WcaLog(LOGMSG_STANDARD, "Adding SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
243
244 hr = StrAllocHexDecode(sczCertificateThumbprint, &pbCertificateThumbprint, &cbCertificateThumbprint);
245 ExitOnFailure(hr, "Failed to convert thumbprint to bytes for SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
246
247 hr = ::IIDFromString(sczAppId, &guidAppId);
248 ExitOnFailure(hr, "Failed to convert AppId '%ls' back to GUID for SNI SSL certificate '%ls' for hostname: %ls:%d", sczAppId, sczId, sczHost, iPort);
249
250 hr = AddSniSslCert(sczId, sczHost, iPort, pbCertificateThumbprint, cbCertificateThumbprint, &guidAppId, sczCertificateStore && *sczCertificateStore ? sczCertificateStore : L"MY");
251 if (S_FALSE == hr && fFailOnExisting)
252 {
253 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
254 }
255
256 if (S_OK == hr)
257 {
258 WcaLog(LOGMSG_STANDARD, "Added SNI SSL certificate '%ls' for hostname: %ls:%d with thumbprint: %ls", sczId, sczHost, iPort, sczCertificateThumbprint);
259 }
260 else if (FAILED(hr))
261 {
262 if (fRollback)
263 {
264 WcaLogError(hr, "Failed to add SNI SSL certificate to rollback '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
265 }
266 else
267 {
268 ExitOnFailure(hr, "Failed to add SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
269 }
270 }
271
272 ReleaseNullMem(pbCertificateThumbprint);
273 }
274 }
275
276LExit:
277 ReleaseMem(pbCertificateThumbprint);
278 ReleaseStr(sczCertificateStore);
279 ReleaseStr(sczAppId);
280 ReleaseStr(sczCertificateThumbprint);
281 ReleaseStr(sczHost);
282 ReleaseStr(sczId);
283 ReleaseStr(sczCustomActionData);
284
285 if (fHttpInitialized)
286 {
287 ::HttpTerminate(HTTP_INITIALIZE_CONFIG, NULL);
288 }
289
290 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
291}
292
293static UINT SchedHttpSniSslCerts(
294 __in WCA_TODO todoSched
295)
296{
297 HRESULT hr = S_OK;
298 UINT er = ERROR_SUCCESS;
299 BOOL fHttpInitialized = FALSE;
300 DWORD cCertificates = 0;
301
302 PMSIHANDLE hView = NULL;
303 PMSIHANDLE hRec = NULL;
304 PMSIHANDLE hQueryReq = NULL;
305 PMSIHANDLE hAceView = NULL;
306
307 LPWSTR sczCustomActionData = NULL;
308 LPWSTR sczRollbackCustomActionData = NULL;
309
310 LPWSTR sczId = NULL;
311 LPWSTR sczComponent = NULL;
312 WCA_TODO todoComponent = WCA_TODO_UNKNOWN;
313 LPWSTR sczHost = NULL;
314 int iPort = 0;
315 LPWSTR sczCertificateThumbprint = NULL;
316 LPWSTR sczAppId = NULL;
317 LPWSTR sczCertificateStore = NULL;
318 int iHandleExisting = 0;
319
320 HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet = NULL;
321
322 // Anything to do?
323 hr = WcaTableExists(L"Wix4HttpSniSslCert");
324 ExitOnFailure(hr, "Failed to check if the Wix4HttpSniSslCert table exists");
325 if (S_FALSE == hr)
326 {
327 WcaLog(LOGMSG_STANDARD, "Wix4HttpSniSslCert table doesn't exist, so there are no URL reservations to configure");
328 ExitFunction();
329 }
330
331 // Query and loop through all the SNI SSL certificates.
332 hr = WcaOpenExecuteView(vcsWixHttpSniSslCertQuery, &hView);
333 ExitOnFailure(hr, "Failed to open view on the Wix4HttpSniSslCert table");
334
335 hr = HRESULT_FROM_WIN32(::HttpInitialize(HTTPAPI_VERSION_1, HTTP_INITIALIZE_CONFIG, NULL));
336 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration");
337
338 fHttpInitialized = TRUE;
339
340 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
341 {
342 hr = WcaGetRecordString(hRec, hurqId, &sczId);
343 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Wix4HttpSniSslCert");
344
345 hr = WcaGetRecordString(hRec, hurqComponent, &sczComponent);
346 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Component_");
347
348 // Figure out what we're doing for this reservation, treating reinstall the same as install.
349 todoComponent = WcaGetComponentToDo(sczComponent);
350 if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
351 {
352 WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d) for Wix4HttpSniSslCert '%ls'", sczComponent, todoComponent, todoSched, sczId);
353 continue;
354 }
355
356 hr = WcaGetRecordFormattedString(hRec, hurqHost, &sczHost);
357 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Host");
358
359 hr = WcaGetRecordFormattedInteger(hRec, hurqPort, &iPort);
360 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Port");
361
362 hr = WcaGetRecordFormattedString(hRec, hurqCertificateThumbprint, &sczCertificateThumbprint);
363 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.CertificateThumbprint");
364
365 if (!sczHost || !*sczHost)
366 {
367 hr = E_INVALIDARG;
368 ExitOnFailure(hr, "Require a Host value for Wix4HttpSniSslCert '%ls'", sczId);
369 }
370
371 if (!iPort)
372 {
373 hr = E_INVALIDARG;
374 ExitOnFailure(hr, "Require a Port value for Wix4HttpSniSslCert '%ls'", sczId);
375 }
376
377 if (!sczCertificateThumbprint || !*sczCertificateThumbprint)
378 {
379 hr = E_INVALIDARG;
380 ExitOnFailure(hr, "Require a CertificateThumbprint value for Wix4HttpSniSslCert '%ls'", sczId);
381 }
382
383 hr = WcaGetRecordFormattedString(hRec, hurqAppId, &sczAppId);
384 ExitOnFailure(hr, "Failed to get AppId for Wix4HttpSniSslCert '%ls'", sczId);
385
386 hr = WcaGetRecordFormattedString(hRec, hurqCertificateStore, &sczCertificateStore);
387 ExitOnFailure(hr, "Failed to get CertificateStore for Wix4HttpSniSslCert '%ls'", sczId);
388
389 hr = WcaGetRecordInteger(hRec, hurqHandleExisting, &iHandleExisting);
390 ExitOnFailure(hr, "Failed to get HandleExisting for Wix4HttpSniSslCert '%ls'", sczId);
391
392 hr = GetSniSslCert(sczHost, iPort, &pExistingSniSslSet);
393 ExitOnFailure(hr, "Failed to get the existing SNI SSL certificate for Wix4HttpSniSslCert '%ls'", sczId);
394
395 hr = EnsureAppId(&sczAppId, pExistingSniSslSet);
396 ExitOnFailure(hr, "Failed to ensure AppId for Wix4HttpSniSslCert '%ls'", sczId);
397
398 hr = WriteExistingSniSslCert(todoComponent, sczId, sczHost, iPort, iHandleExisting, pExistingSniSslSet, &sczRollbackCustomActionData);
399 ExitOnFailure(hr, "Failed to write rollback custom action data for Wix4HttpSniSslCert '%ls'", sczId);
400
401 hr = WriteSniSslCert(todoComponent, sczId, sczHost, iPort, iHandleExisting, sczCertificateThumbprint, sczAppId, sczCertificateStore, &sczCustomActionData);
402 ExitOnFailure(hr, "Failed to write custom action data for Wix4HttpSniSslCert '%ls'", sczId);
403 ++cCertificates;
404
405 ReleaseNullMem(pExistingSniSslSet);
406 }
407
408 // Reaching the end of the list is not an error.
409 if (E_NOMOREITEMS == hr)
410 {
411 hr = S_OK;
412 }
413 ExitOnFailure(hr, "Failure occurred while processing Wix4HttpSniSslCert table");
414
415 // Schedule ExecHttpSniSslCerts if there's anything to do.
416 if (cCertificates)
417 {
418 WcaLog(LOGMSG_STANDARD, "Scheduling SNI SSL certificate (%ls)", sczCustomActionData);
419 WcaLog(LOGMSG_STANDARD, "Scheduling rollback SNI SSL certificate (%ls)", sczRollbackCustomActionData);
420
421 if (WCA_TODO_INSTALL == todoSched)
422 {
423 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixRollbackHttpSniSslCertsInstall"), sczRollbackCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
424 ExitOnFailure(hr, "Failed to schedule install SNI SSL certificate rollback");
425 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixExecHttpSniSslCertsInstall"), sczCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
426 ExitOnFailure(hr, "Failed to schedule install SNI SSL certificate execution");
427 }
428 else
429 {
430 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixRollbackHttpSniSslCertsUninstall"), sczRollbackCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
431 ExitOnFailure(hr, "Failed to schedule uninstall SNI SSL certificate rollback");
432 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixExecHttpSniSslCertsUninstall"), sczCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
433 ExitOnFailure(hr, "Failed to schedule uninstall SNI SSL certificate execution");
434 }
435 }
436 else
437 {
438 WcaLog(LOGMSG_STANDARD, "No SNI SSL certificates scheduled");
439 }
440
441LExit:
442 ReleaseMem(pExistingSniSslSet);
443 ReleaseStr(sczCertificateStore);
444 ReleaseStr(sczAppId);
445 ReleaseStr(sczCertificateThumbprint);
446 ReleaseStr(sczHost);
447 ReleaseStr(sczComponent);
448 ReleaseStr(sczId);
449 ReleaseStr(sczRollbackCustomActionData);
450 ReleaseStr(sczCustomActionData);
451
452 if (fHttpInitialized)
453 {
454 ::HttpTerminate(HTTP_INITIALIZE_CONFIG, NULL);
455 }
456
457 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
458}
459
460static HRESULT WriteExistingSniSslCert(
461 __in WCA_TODO action,
462 __in_z LPCWSTR wzId,
463 __in_z LPCWSTR wzHost,
464 __in int iPort,
465 __in int iHandleExisting,
466 __in HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSniSslSet,
467 __inout_z LPWSTR* psczCustomActionData
468)
469{
470 HRESULT hr = S_OK;
471 LPWSTR sczCertificateThumbprint = NULL;
472 LPWSTR sczAppId = NULL;
473 LPCWSTR wzCertificateStore = NULL;
474
475 if (pSniSslSet)
476 {
477 hr = StrAllocHexEncode(reinterpret_cast<BYTE*>(pSniSslSet->ParamDesc.pSslHash), pSniSslSet->ParamDesc.SslHashLength, &sczCertificateThumbprint);
478 ExitOnFailure(hr, "Failed to convert existing certificate thumbprint to hex for Wix4HttpSniSslCert '%ls'", wzId);
479
480 hr = StringFromGuid(pSniSslSet->ParamDesc.AppId, &sczAppId);
481 ExitOnFailure(hr, "Failed to copy existing AppId for Wix4HttpSniSslCert '%ls'", wzId);
482
483 wzCertificateStore = pSniSslSet->ParamDesc.pSslCertStoreName;
484 }
485
486 hr = WriteSniSslCert(action, wzId, wzHost, iPort, iHandleExisting, sczCertificateThumbprint ? sczCertificateThumbprint : L"", sczAppId ? sczAppId : L"", wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
487 ExitOnFailure(hr, "Failed to write custom action data for Wix4HttpSniSslCert '%ls'", wzId);
488
489LExit:
490 ReleaseStr(sczAppId);
491 ReleaseStr(sczCertificateThumbprint);
492
493 return hr;
494}
495
496static HRESULT WriteSniSslCert(
497 __in WCA_TODO action,
498 __in_z LPCWSTR wzId,
499 __in_z LPCWSTR wzHost,
500 __in int iPort,
501 __in int iHandleExisting,
502 __in_z LPCWSTR wzCertificateThumbprint,
503 __in_z LPCWSTR wzAppId,
504 __in_z_opt LPCWSTR wzCertificateStore,
505 __inout_z LPWSTR* psczCustomActionData
506)
507{
508 HRESULT hr = S_OK;
509
510 hr = WcaWriteIntegerToCaData(action, psczCustomActionData);
511 ExitOnFailure(hr, "Failed to write action to custom action data");
512
513 hr = WcaWriteStringToCaData(wzId, psczCustomActionData);
514 ExitOnFailure(hr, "Failed to write id to custom action data");
515
516 hr = WcaWriteStringToCaData(wzHost, psczCustomActionData);
517 ExitOnFailure(hr, "Failed to write Host to custom action data");
518
519 hr = WcaWriteIntegerToCaData(iPort, psczCustomActionData);
520 ExitOnFailure(hr, "Failed to write Port to custom action data");
521
522 hr = WcaWriteIntegerToCaData(iHandleExisting, psczCustomActionData);
523 ExitOnFailure(hr, "Failed to write HandleExisting to custom action data");
524
525 hr = WcaWriteStringToCaData(wzCertificateThumbprint, psczCustomActionData);
526 ExitOnFailure(hr, "Failed to write CertificateThumbprint to custom action data");
527
528 hr = WcaWriteStringToCaData(wzAppId, psczCustomActionData);
529 ExitOnFailure(hr, "Failed to write AppId to custom action data");
530
531 hr = WcaWriteStringToCaData(wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
532 ExitOnFailure(hr, "Failed to write CertificateStore to custom action data");
533
534LExit:
535 return hr;
536}
537
538static HRESULT EnsureAppId(
539 __inout_z LPWSTR* psczAppId,
540 __in_opt HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet
541)
542{
543 HRESULT hr = S_OK;
544 RPC_STATUS rs = RPC_S_OK;
545 GUID guid = { };
546
547 if (!psczAppId || !*psczAppId || !**psczAppId)
548 {
549 if (pExistingSniSslSet)
550 {
551 hr = StringFromGuid(pExistingSniSslSet->ParamDesc.AppId, psczAppId);
552 ExitOnFailure(hr, "Failed to ensure AppId guid");
553 }
554 else
555 {
556 rs = ::UuidCreate(&guid);
557 hr = HRESULT_FROM_RPC(rs);
558 ExitOnRootFailure(hr, "Failed to create guid for AppId");
559
560 hr = StringFromGuid(guid, psczAppId);
561 ExitOnFailure(hr, "Failed to ensure AppId guid");
562 }
563 }
564
565LExit:
566 return hr;
567}
568
569static HRESULT StringFromGuid(
570 __in REFGUID rguid,
571 __inout_z LPWSTR* psczGuid
572)
573{
574 HRESULT hr = S_OK;
575 WCHAR wzGuid[39];
576
577 if (!::StringFromGUID2(rguid, wzGuid, countof(wzGuid)))
578 {
579 hr = E_OUTOFMEMORY;
580 ExitOnRootFailure(hr, "Failed to convert guid into string");
581 }
582
583 hr = StrAllocString(psczGuid, wzGuid, 0);
584 ExitOnFailure(hr, "Failed to copy guid");
585
586LExit:
587 return hr;
588}
589
590static HRESULT AddSniSslCert(
591 __in_z LPCWSTR /*wzId*/,
592 __in_z LPWSTR wzHost,
593 __in int iPort,
594 __in BYTE rgbCertificateThumbprint[],
595 __in DWORD cbCertificateThumbprint,
596 __in GUID* pAppId,
597 __in_z LPWSTR wzSslCertStore
598)
599{
600 HRESULT hr = S_OK;
601 DWORD er = ERROR_SUCCESS;
602 HTTP_SERVICE_CONFIG_SSL_SNI_SET set = { };
603
604 SetSniSslCertSetKey(&set.KeyDesc, wzHost, iPort);
605 set.ParamDesc.SslHashLength = cbCertificateThumbprint;
606 set.ParamDesc.pSslHash = rgbCertificateThumbprint;
607 set.ParamDesc.AppId = *pAppId;
608 set.ParamDesc.pSslCertStoreName = wzSslCertStore;
609
610 er = ::HttpSetServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &set, sizeof(set), NULL);
611 if (ERROR_ALREADY_EXISTS == er)
612 {
613 hr = S_FALSE;
614 }
615 else
616 {
617 hr = HRESULT_FROM_WIN32(er);
618 }
619
620 return hr;
621}
622
623static HRESULT GetSniSslCert(
624 __in_z LPWSTR wzHost,
625 __in int nPort,
626 __out HTTP_SERVICE_CONFIG_SSL_SNI_SET** ppSet
627)
628{
629 HRESULT hr = S_OK;
630 DWORD er = ERROR_SUCCESS;
631 HTTP_SERVICE_CONFIG_SSL_SNI_QUERY query = { };
632 HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSet = NULL;
633 ULONG cbSet = 0;
634
635 *ppSet = NULL;
636
637 query.QueryDesc = HttpServiceConfigQueryExact;
638 SetSniSslCertSetKey(&query.KeyDesc, wzHost, nPort);
639
640 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
641 if (ERROR_INSUFFICIENT_BUFFER == er)
642 {
643 pSet = reinterpret_cast<HTTP_SERVICE_CONFIG_SSL_SNI_SET*>(MemAlloc(cbSet, TRUE));
644 ExitOnNull(pSet, hr, E_OUTOFMEMORY, "Failed to allocate query SN SSL certificate buffer");
645
646 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
647 }
648
649 if (ERROR_SUCCESS == er)
650 {
651 *ppSet = pSet;
652 pSet = NULL;
653 }
654 else if (ERROR_FILE_NOT_FOUND == er)
655 {
656 hr = S_FALSE;
657 }
658 else
659 {
660 hr = HRESULT_FROM_WIN32(er);
661 }
662
663LExit:
664 ReleaseMem(pSet);
665
666 return hr;
667}
668
669static HRESULT RemoveSniSslCert(
670 __in_z LPCWSTR /*wzId*/,
671 __in_z LPWSTR wzHost,
672 __in int iPort
673)
674{
675 HRESULT hr = S_OK;
676 DWORD er = ERROR_SUCCESS;
677 HTTP_SERVICE_CONFIG_SSL_SNI_SET set = { };
678
679 SetSniSslCertSetKey(&set.KeyDesc, wzHost, iPort);
680
681 er = ::HttpDeleteServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &set, sizeof(set), NULL);
682 if (ERROR_FILE_NOT_FOUND == er)
683 {
684 hr = S_FALSE;
685 }
686 else
687 {
688 hr = HRESULT_FROM_WIN32(er);
689 }
690
691 return hr;
692}
693
694static void SetSniSslCertSetKey(
695 __in HTTP_SERVICE_CONFIG_SSL_SNI_KEY* pKey,
696 __in_z LPWSTR wzHost,
697 __in int iPort
698)
699{
700 pKey->Host = wzHost;
701 SOCKADDR_IN* pss = reinterpret_cast<SOCKADDR_IN*>(&pKey->IpPort);
702 pss->sin_family = AF_INET;
703 pss->sin_port = htons(static_cast<USHORT>(iPort));
704}