|
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 |
|
9 #include "registrycertificates.h" |
|
10 #include "pathhash.h" |
|
11 #include "nsWindowsHelpers.h" |
|
12 #include "servicebase.h" |
|
13 #include "updatehelper.h" |
|
14 #define MAX_KEY_LENGTH 255 |
|
15 |
|
16 /** |
|
17 * Verifies if the file path matches any certificate stored in the registry. |
|
18 * |
|
19 * @param filePath The file path of the application to check if allowed. |
|
20 * @return TRUE if the binary matches any of the allowed certificates. |
|
21 */ |
|
22 BOOL |
|
23 DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) |
|
24 { |
|
25 WCHAR maintenanceServiceKey[MAX_PATH + 1]; |
|
26 if (!CalculateRegistryPathFromFilePath(basePathForUpdate, |
|
27 maintenanceServiceKey)) { |
|
28 return FALSE; |
|
29 } |
|
30 |
|
31 // We use KEY_WOW64_64KEY to always force 64-bit view. |
|
32 // The user may have both x86 and x64 applications installed |
|
33 // which each register information. We need a consistent place |
|
34 // to put those certificate attributes in and hence why we always |
|
35 // force the non redirected registry under Wow6432Node. |
|
36 // This flag is ignored on 32bit systems. |
|
37 HKEY baseKeyRaw; |
|
38 LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
|
39 maintenanceServiceKey, 0, |
|
40 KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); |
|
41 if (retCode != ERROR_SUCCESS) { |
|
42 LOG_WARN(("Could not open key. (%d)", retCode)); |
|
43 // Our tests run with a different apply directory for each test. |
|
44 // We use this registry key on our test slaves to store the |
|
45 // allowed name/issuers. |
|
46 retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, |
|
47 TEST_ONLY_FALLBACK_KEY_PATH, 0, |
|
48 KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); |
|
49 if (retCode != ERROR_SUCCESS) { |
|
50 LOG_WARN(("Could not open fallback key. (%d)", retCode)); |
|
51 return FALSE; |
|
52 } |
|
53 } |
|
54 nsAutoRegKey baseKey(baseKeyRaw); |
|
55 |
|
56 // Get the number of subkeys. |
|
57 DWORD subkeyCount = 0; |
|
58 retCode = RegQueryInfoKeyW(baseKey, nullptr, nullptr, nullptr, &subkeyCount, |
|
59 nullptr, nullptr, nullptr, nullptr, nullptr, |
|
60 nullptr, nullptr); |
|
61 if (retCode != ERROR_SUCCESS) { |
|
62 LOG_WARN(("Could not query info key. (%d)", retCode)); |
|
63 return FALSE; |
|
64 } |
|
65 |
|
66 // Enumerate the subkeys, each subkey represents an allowed certificate. |
|
67 for (DWORD i = 0; i < subkeyCount; i++) { |
|
68 WCHAR subkeyBuffer[MAX_KEY_LENGTH]; |
|
69 DWORD subkeyBufferCount = MAX_KEY_LENGTH; |
|
70 retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer, |
|
71 &subkeyBufferCount, nullptr, |
|
72 nullptr, nullptr, nullptr); |
|
73 if (retCode != ERROR_SUCCESS) { |
|
74 LOG_WARN(("Could not enum certs. (%d)", retCode)); |
|
75 return FALSE; |
|
76 } |
|
77 |
|
78 // Open the subkey for the current certificate |
|
79 HKEY subKeyRaw; |
|
80 retCode = RegOpenKeyExW(baseKey, |
|
81 subkeyBuffer, |
|
82 0, |
|
83 KEY_READ | KEY_WOW64_64KEY, |
|
84 &subKeyRaw); |
|
85 nsAutoRegKey subKey(subKeyRaw); |
|
86 if (retCode != ERROR_SUCCESS) { |
|
87 LOG_WARN(("Could not open subkey. (%d)", retCode)); |
|
88 continue; // Try the next subkey |
|
89 } |
|
90 |
|
91 const int MAX_CHAR_COUNT = 256; |
|
92 DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); |
|
93 WCHAR name[MAX_CHAR_COUNT] = { L'\0' }; |
|
94 WCHAR issuer[MAX_CHAR_COUNT] = { L'\0' }; |
|
95 |
|
96 // Get the name from the registry |
|
97 retCode = RegQueryValueExW(subKey, L"name", 0, nullptr, |
|
98 (LPBYTE)name, &valueBufSize); |
|
99 if (retCode != ERROR_SUCCESS) { |
|
100 LOG_WARN(("Could not obtain name from registry. (%d)", retCode)); |
|
101 continue; // Try the next subkey |
|
102 } |
|
103 |
|
104 // Get the issuer from the registry |
|
105 valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); |
|
106 retCode = RegQueryValueExW(subKey, L"issuer", 0, nullptr, |
|
107 (LPBYTE)issuer, &valueBufSize); |
|
108 if (retCode != ERROR_SUCCESS) { |
|
109 LOG_WARN(("Could not obtain issuer from registry. (%d)", retCode)); |
|
110 continue; // Try the next subkey |
|
111 } |
|
112 |
|
113 CertificateCheckInfo allowedCertificate = { |
|
114 name, |
|
115 issuer, |
|
116 }; |
|
117 |
|
118 retCode = CheckCertificateForPEFile(filePath, allowedCertificate); |
|
119 if (retCode != ERROR_SUCCESS) { |
|
120 LOG_WARN(("Error on certificate check. (%d)", retCode)); |
|
121 continue; // Try the next subkey |
|
122 } |
|
123 |
|
124 retCode = VerifyCertificateTrustForFile(filePath); |
|
125 if (retCode != ERROR_SUCCESS) { |
|
126 LOG_WARN(("Error on certificate trust check. (%d)", retCode)); |
|
127 continue; // Try the next subkey |
|
128 } |
|
129 |
|
130 // Raise the roof, we found a match! |
|
131 return TRUE; |
|
132 } |
|
133 |
|
134 // No certificates match, :'( |
|
135 return FALSE; |
|
136 } |