aboutsummaryrefslogtreecommitdiff
path: root/src/ca
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca')
-rw-r--r--src/ca/cost.h1
-rw-r--r--src/ca/httpca.vcxproj21
-rw-r--r--src/ca/httpca.vcxproj.filters3
-rw-r--r--src/ca/precomp.h7
-rw-r--r--src/ca/snisslcert.cpp704
-rw-r--r--src/ca/wixhttpca.cpp12
-rw-r--r--src/ca/wixhttpca.def3
7 files changed, 737 insertions, 14 deletions
diff --git a/src/ca/cost.h b/src/ca/cost.h
index 283758b0..9677e7e8 100644
--- a/src/ca/cost.h
+++ b/src/ca/cost.h
@@ -3,3 +3,4 @@
3 3
4 4
5const UINT COST_HTTP_URL_ACL = 2000; 5const UINT COST_HTTP_URL_ACL = 2000;
6const UINT COST_HTTP_SNI_SSL = 2000;
diff --git a/src/ca/httpca.vcxproj b/src/ca/httpca.vcxproj
index 9abe7598..fde00ff4 100644
--- a/src/ca/httpca.vcxproj
+++ b/src/ca/httpca.vcxproj
@@ -3,7 +3,7 @@
3<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 <Import Project="..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" /> 4 <Import Project="..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" />
5 <Import Project="..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props" Condition="Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" /> 5 <Import Project="..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props" Condition="Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" />
6 6
7 <ItemGroup Label="ProjectConfigurations"> 7 <ItemGroup Label="ProjectConfigurations">
8 <ProjectConfiguration Include="Debug|Win32"> 8 <ProjectConfiguration Include="Debug|Win32">
9 <Configuration>Debug</Configuration> 9 <Configuration>Debug</Configuration>
@@ -13,7 +13,7 @@
13 <Configuration>Release</Configuration> 13 <Configuration>Release</Configuration>
14 <Platform>Win32</Platform> 14 <Platform>Win32</Platform>
15 </ProjectConfiguration> 15 </ProjectConfiguration>
16 <ProjectConfiguration Include="Debug|x64"> 16 <ProjectConfiguration Include="Debug|x64">
17 <Configuration>Debug</Configuration> 17 <Configuration>Debug</Configuration>
18 <Platform>x64</Platform> 18 <Platform>x64</Platform>
19 </ProjectConfiguration> 19 </ProjectConfiguration>
@@ -30,7 +30,7 @@
30 <Platform>ARM64</Platform> 30 <Platform>ARM64</Platform>
31 </ProjectConfiguration> 31 </ProjectConfiguration>
32 </ItemGroup> 32 </ItemGroup>
33 33
34 <PropertyGroup Label="Globals"> 34 <PropertyGroup Label="Globals">
35 <ProjectGuid>{90743805-C043-47C7-B5FF-8F5EE5C8A2DE}</ProjectGuid> 35 <ProjectGuid>{90743805-C043-47C7-B5FF-8F5EE5C8A2DE}</ProjectGuid>
36 <ConfigurationType>DynamicLibrary</ConfigurationType> 36 <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -40,27 +40,28 @@
40 <ProjectModuleDefinitionFile>wixhttpca.def</ProjectModuleDefinitionFile> 40 <ProjectModuleDefinitionFile>wixhttpca.def</ProjectModuleDefinitionFile>
41 <Description>WiX Toolset Http CustomAction</Description> 41 <Description>WiX Toolset Http CustomAction</Description>
42 </PropertyGroup> 42 </PropertyGroup>
43 43
44 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 44 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
45 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 45 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
46 46
47 <PropertyGroup> 47 <PropertyGroup>
48 <ProjectAdditionalLinkLibraries>crypt32.lib;httpapi.lib;msi.lib</ProjectAdditionalLinkLibraries> 48 <ProjectAdditionalLinkLibraries>crypt32.lib;httpapi.lib;msi.lib;rpcrt4.lib;ws2_32.lib</ProjectAdditionalLinkLibraries>
49 </PropertyGroup> 49 </PropertyGroup>
50 50
51 <ItemGroup> 51 <ItemGroup>
52 <ClCompile Include="dllmain.cpp"> 52 <ClCompile Include="dllmain.cpp">
53 <PrecompiledHeader>Create</PrecompiledHeader> 53 <PrecompiledHeader>Create</PrecompiledHeader>
54 </ClCompile> 54 </ClCompile>
55 <ClCompile Include="snisslcert.cpp" />
55 <ClCompile Include="wixhttpca.cpp" /> 56 <ClCompile Include="wixhttpca.cpp" />
56 <ClInclude Include="cost.h" /> 57 <ClInclude Include="cost.h" />
57 <ClInclude Include="precomp.h" /> 58 <ClInclude Include="precomp.h" />
58 <None Include="packages.config" /> 59 <None Include="packages.config" />
59 <None Include="wixhttpca.def" /> 60 <None Include="wixhttpca.def" />
60 </ItemGroup> 61 </ItemGroup>
61 62
62 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 63 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
63 64
64 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> 65 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
65 <PropertyGroup> 66 <PropertyGroup>
66 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> 67 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
@@ -68,4 +69,4 @@
68 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props'))" /> 69 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props'))" />
69 <Error Condition="!Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props'))" /> 70 <Error Condition="!Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props'))" />
70 </Target> 71 </Target>
71</Project> \ No newline at end of file 72</Project>
diff --git a/src/ca/httpca.vcxproj.filters b/src/ca/httpca.vcxproj.filters
index 979b9ef3..2ccd604d 100644
--- a/src/ca/httpca.vcxproj.filters
+++ b/src/ca/httpca.vcxproj.filters
@@ -21,6 +21,9 @@
21 <ClCompile Include="dllmain.cpp"> 21 <ClCompile Include="dllmain.cpp">
22 <Filter>Source Files</Filter> 22 <Filter>Source Files</Filter>
23 </ClCompile> 23 </ClCompile>
24 <ClCompile Include="snisslcert.cpp">
25 <Filter>Source Files</Filter>
26 </ClCompile>
24 </ItemGroup> 27 </ItemGroup>
25 <ItemGroup> 28 <ItemGroup>
26 <ClInclude Include="precomp.h"> 29 <ClInclude Include="precomp.h">
diff --git a/src/ca/precomp.h b/src/ca/precomp.h
index d5143dac..c78d78c1 100644
--- a/src/ca/precomp.h
+++ b/src/ca/precomp.h
@@ -16,3 +16,10 @@
16#include "cost.h" 16#include "cost.h"
17 17
18#include "caDecor.h" 18#include "caDecor.h"
19
20enum eHandleExisting
21{
22 heReplace = 0,
23 heIgnore = 1,
24 heFail = 2
25};
diff --git a/src/ca/snisslcert.cpp b/src/ca/snisslcert.cpp
new file mode 100644
index 00000000..466ef0b9
--- /dev/null
+++ b/src/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 `WixHttpSniSslCert`.`WixHttpSniSslCert`, `WixHttpSniSslCert`.`Host`, `WixHttpSniSslCert`.`Port`, `WixHttpSniSslCert`.`Thumbprint`, `WixHttpSniSslCert`.`AppId`, `WixHttpSniSslCert`.`Store`, `WixHttpSniSslCert`.`HandleExisting`, `WixHttpSniSslCert`.`Component_` "
89L"FROM `WixHttpSniSslCert`";
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"WixHttpSniSslCert");
324 ExitOnFailure(hr, "Failed to check if the WixHttpSniSslCert table exists");
325 if (S_FALSE == hr)
326 {
327 WcaLog(LOGMSG_STANDARD, "WixHttpSniSslCert 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 WixHttpSniSslCert 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 WixHttpSniSslCert.WixHttpSniSslCert");
344
345 hr = WcaGetRecordString(hRec, hurqComponent, &sczComponent);
346 ExitOnFailure(hr, "Failed to get WixHttpSniSslCert.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 WixHttpSniSslCert '%ls'", sczComponent, todoComponent, todoSched, sczId);
353 continue;
354 }
355
356 hr = WcaGetRecordFormattedString(hRec, hurqHost, &sczHost);
357 ExitOnFailure(hr, "Failed to get WixHttpSniSslCert.Host");
358
359 hr = WcaGetRecordFormattedInteger(hRec, hurqPort, &iPort);
360 ExitOnFailure(hr, "Failed to get WixHttpSniSslCert.Port");
361
362 hr = WcaGetRecordFormattedString(hRec, hurqCertificateThumbprint, &sczCertificateThumbprint);
363 ExitOnFailure(hr, "Failed to get WixHttpSniSslCert.CertificateThumbprint");
364
365 if (!sczHost || !*sczHost)
366 {
367 hr = E_INVALIDARG;
368 ExitOnFailure(hr, "Require a Host value for WixHttpSniSslCert '%ls'", sczId);
369 }
370
371 if (!iPort)
372 {
373 hr = E_INVALIDARG;
374 ExitOnFailure(hr, "Require a Port value for WixHttpSniSslCert '%ls'", sczId);
375 }
376
377 if (!sczCertificateThumbprint || !*sczCertificateThumbprint)
378 {
379 hr = E_INVALIDARG;
380 ExitOnFailure(hr, "Require a CertificateThumbprint value for WixHttpSniSslCert '%ls'", sczId);
381 }
382
383 hr = WcaGetRecordFormattedString(hRec, hurqAppId, &sczAppId);
384 ExitOnFailure(hr, "Failed to get AppId for WixHttpSniSslCert '%ls'", sczId);
385
386 hr = WcaGetRecordFormattedString(hRec, hurqCertificateStore, &sczCertificateStore);
387 ExitOnFailure(hr, "Failed to get CertificateStore for WixHttpSniSslCert '%ls'", sczId);
388
389 hr = WcaGetRecordInteger(hRec, hurqHandleExisting, &iHandleExisting);
390 ExitOnFailure(hr, "Failed to get HandleExisting for WixHttpSniSslCert '%ls'", sczId);
391
392 hr = GetSniSslCert(sczHost, iPort, &pExistingSniSslSet);
393 ExitOnFailure(hr, "Failed to get the existing SNI SSL certificate for WixHttpSniSslCert '%ls'", sczId);
394
395 hr = EnsureAppId(&sczAppId, pExistingSniSslSet);
396 ExitOnFailure(hr, "Failed to ensure AppId for WixHttpSniSslCert '%ls'", sczId);
397
398 hr = WriteExistingSniSslCert(todoComponent, sczId, sczHost, iPort, iHandleExisting, pExistingSniSslSet, &sczRollbackCustomActionData);
399 ExitOnFailure(hr, "Failed to write rollback custom action data for WixHttpSniSslCert '%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 WixHttpSniSslCert '%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 WixHttpSniSslCert 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 WixHttpSniSslCert '%ls'", wzId);
479
480 hr = StringFromGuid(pSniSslSet->ParamDesc.AppId, &sczAppId);
481 ExitOnFailure(hr, "Failed to copy existing AppId for WixHttpSniSslCert '%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 WixHttpSniSslCert '%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}
diff --git a/src/ca/wixhttpca.cpp b/src/ca/wixhttpca.cpp
index 3c091192..0355f718 100644
--- a/src/ca/wixhttpca.cpp
+++ b/src/ca/wixhttpca.cpp
@@ -40,8 +40,6 @@ LPCWSTR vcsHttpUrlAceQuery =
40 L"WHERE `WixHttpUrlAce`.`WixHttpUrlReservation_`=?"; 40 L"WHERE `WixHttpUrlAce`.`WixHttpUrlReservation_`=?";
41enum eHttpUrlAceQuery { huaqSecurityPrincipal = 1, huaqRights }; 41enum eHttpUrlAceQuery { huaqSecurityPrincipal = 1, huaqRights };
42 42
43enum eHandleExisting { heReplace = 0, heIgnore = 1, heFail = 2 };
44
45/****************************************************************** 43/******************************************************************
46 SchedHttpUrlReservations - immediate custom action worker to 44 SchedHttpUrlReservations - immediate custom action worker to
47 prepare configuring URL reservations. 45 prepare configuring URL reservations.
@@ -348,6 +346,11 @@ extern "C" UINT __stdcall ExecHttpUrlReservations(
348 ExitOnFailure(hr, "Failed to get CustomActionData."); 346 ExitOnFailure(hr, "Failed to get CustomActionData.");
349 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", sczCustomActionData); 347 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", sczCustomActionData);
350 348
349 if (!sczCustomActionData || !*sczCustomActionData)
350 {
351 WcaLog(LOGMSG_STANDARD, "No URL reservations to be executed.");
352 }
353
351 wz = sczCustomActionData; 354 wz = sczCustomActionData;
352 while (wz && *wz) 355 while (wz && *wz)
353 { 356 {
@@ -388,7 +391,7 @@ extern "C" UINT __stdcall ExecHttpUrlReservations(
388 { 391 {
389 if (fRollback) 392 if (fRollback)
390 { 393 {
391 WcaLogError(hr, "Failed to remove reservation for URL '%ls'", sczUrl); 394 WcaLogError(hr, "Failed to remove reservation for rollback for URL '%ls'", sczUrl);
392 } 395 }
393 else 396 else
394 { 397 {
@@ -396,6 +399,7 @@ extern "C" UINT __stdcall ExecHttpUrlReservations(
396 } 399 }
397 } 400 }
398 } 401 }
402
399 if (fAdd) 403 if (fAdd)
400 { 404 {
401 WcaLog(LOGMSG_STANDARD, "Adding reservation for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL); 405 WcaLog(LOGMSG_STANDARD, "Adding reservation for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL);
@@ -408,7 +412,7 @@ extern "C" UINT __stdcall ExecHttpUrlReservations(
408 { 412 {
409 if (fRollback) 413 if (fRollback)
410 { 414 {
411 WcaLogError(hr, "Failed to add reservation for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL); 415 WcaLogError(hr, "Failed to add reservation for rollback for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL);
412 } 416 }
413 else 417 else
414 { 418 {
diff --git a/src/ca/wixhttpca.def b/src/ca/wixhttpca.def
index f7e3e004..281c5631 100644
--- a/src/ca/wixhttpca.def
+++ b/src/ca/wixhttpca.def
@@ -7,3 +7,6 @@ EXPORTS
7 SchedHttpUrlReservationsInstall 7 SchedHttpUrlReservationsInstall
8 SchedHttpUrlReservationsUninstall 8 SchedHttpUrlReservationsUninstall
9 ExecHttpUrlReservations 9 ExecHttpUrlReservations
10 SchedHttpSniSslCertsInstall
11 SchedHttpSniSslCertsUninstall
12 ExecHttpSniSslCerts