vb@88
|
1 |
#include "stdafx.h"
|
vb@88
|
2 |
|
vb@88
|
3 |
#include "GateKeeper.h"
|
vb@110
|
4 |
#include "pEpCOMServerAdapter.h"
|
vb@123
|
5 |
#include "utf8_helper.h"
|
vb@88
|
6 |
|
vb@88
|
7 |
using namespace std;
|
vb@88
|
8 |
|
vb@130
|
9 |
// from https://msdn.microsoft.com/en-us/library/windows/desktop/dd388945(v=vs.85).aspx
|
vb@123
|
10 |
|
vb@123
|
11 |
struct PUBLIC_KEY_VALUES {
|
vb@123
|
12 |
BLOBHEADER blobheader;
|
vb@123
|
13 |
RSAPUBKEY rsapubkey;
|
vb@123
|
14 |
BYTE modulus[4096];
|
vb@123
|
15 |
};
|
vb@123
|
16 |
|
vb@123
|
17 |
static void ReverseMemCopy(
|
vb@123
|
18 |
_Out_ BYTE *pbDest,
|
vb@123
|
19 |
_In_ BYTE const *pbSource,
|
vb@123
|
20 |
_In_ DWORD cb
|
vb@123
|
21 |
)
|
vb@123
|
22 |
{
|
vb@123
|
23 |
for (DWORD i = 0; i < cb; i++) {
|
vb@123
|
24 |
pbDest[cb - 1 - i] = pbSource[i];
|
vb@123
|
25 |
}
|
vb@123
|
26 |
}
|
vb@123
|
27 |
|
vb@123
|
28 |
static NTSTATUS ImportRsaPublicKey(
|
vb@123
|
29 |
_In_ BCRYPT_ALG_HANDLE hAlg, // CNG provider
|
vb@123
|
30 |
_In_ PUBLIC_KEY_VALUES *pKey, // Pointer to the RSAPUBKEY blob.
|
vb@123
|
31 |
_In_ BCRYPT_KEY_HANDLE *phKey // Receives a handle the imported public key.
|
vb@123
|
32 |
)
|
vb@123
|
33 |
{
|
vb@123
|
34 |
NTSTATUS hr = 0;
|
vb@123
|
35 |
|
vb@123
|
36 |
BYTE *pbPublicKey = NULL;
|
vb@123
|
37 |
DWORD cbKey = 0;
|
vb@123
|
38 |
|
vb@123
|
39 |
// Layout of the RSA public key blob:
|
vb@123
|
40 |
|
vb@123
|
41 |
// +----------------------------------------------------------------+
|
vb@123
|
42 |
// | BCRYPT_RSAKEY_BLOB | BE( dwExp ) | BE( Modulus ) |
|
vb@123
|
43 |
// +----------------------------------------------------------------+
|
vb@123
|
44 |
//
|
vb@123
|
45 |
// sizeof(BCRYPT_RSAKEY_BLOB) cbExp cbModulus
|
vb@123
|
46 |
// <--------------------------><------------><---------------------->
|
vb@123
|
47 |
//
|
vb@123
|
48 |
// BE = Big Endian Format
|
vb@123
|
49 |
|
vb@123
|
50 |
DWORD cbModulus = (pKey->rsapubkey.bitlen + 7) / 8;
|
vb@123
|
51 |
DWORD dwExp = pKey->rsapubkey.pubexp;
|
vb@123
|
52 |
DWORD cbExp = (dwExp & 0xFF000000) ? 4 :
|
vb@123
|
53 |
(dwExp & 0x00FF0000) ? 3 :
|
vb@123
|
54 |
(dwExp & 0x0000FF00) ? 2 : 1;
|
vb@123
|
55 |
|
vb@123
|
56 |
BCRYPT_RSAKEY_BLOB *pRsaBlob;
|
vb@123
|
57 |
PBYTE pbCurrent;
|
vb@123
|
58 |
|
vb@123
|
59 |
if (!SUCCEEDED(hr = DWordAdd(cbModulus, sizeof(BCRYPT_RSAKEY_BLOB), &cbKey))) {
|
vb@123
|
60 |
goto cleanup;
|
vb@123
|
61 |
}
|
vb@123
|
62 |
|
vb@123
|
63 |
cbKey += cbExp;
|
vb@123
|
64 |
|
vb@123
|
65 |
pbPublicKey = (PBYTE) CoTaskMemAlloc(cbKey);
|
vb@123
|
66 |
if (pbPublicKey == NULL) {
|
vb@123
|
67 |
hr = E_OUTOFMEMORY;
|
vb@123
|
68 |
goto cleanup;
|
vb@123
|
69 |
}
|
vb@123
|
70 |
|
vb@123
|
71 |
ZeroMemory(pbPublicKey, cbKey);
|
vb@123
|
72 |
pRsaBlob = (BCRYPT_RSAKEY_BLOB *) (pbPublicKey);
|
vb@123
|
73 |
|
vb@123
|
74 |
//
|
vb@123
|
75 |
// Make the Public Key Blob Header
|
vb@123
|
76 |
//
|
vb@123
|
77 |
|
vb@123
|
78 |
pRsaBlob->Magic = BCRYPT_RSAPUBLIC_MAGIC;
|
vb@123
|
79 |
pRsaBlob->BitLength = pKey->rsapubkey.bitlen;
|
vb@123
|
80 |
pRsaBlob->cbPublicExp = cbExp;
|
vb@123
|
81 |
pRsaBlob->cbModulus = cbModulus;
|
vb@123
|
82 |
pRsaBlob->cbPrime1 = 0;
|
vb@123
|
83 |
pRsaBlob->cbPrime2 = 0;
|
vb@123
|
84 |
|
vb@123
|
85 |
pbCurrent = (PBYTE) (pRsaBlob + 1);
|
vb@123
|
86 |
|
vb@123
|
87 |
//
|
vb@123
|
88 |
// Copy pubExp Big Endian
|
vb@123
|
89 |
//
|
vb@123
|
90 |
|
vb@123
|
91 |
ReverseMemCopy(pbCurrent, (PBYTE) &dwExp, cbExp);
|
vb@123
|
92 |
pbCurrent += cbExp;
|
vb@123
|
93 |
|
vb@123
|
94 |
//
|
vb@123
|
95 |
// Copy Modulus Big Endian
|
vb@123
|
96 |
//
|
vb@123
|
97 |
|
vb@123
|
98 |
ReverseMemCopy(pbCurrent, pKey->modulus, cbModulus);
|
vb@123
|
99 |
|
vb@123
|
100 |
//
|
vb@123
|
101 |
// Import the public key
|
vb@123
|
102 |
//
|
vb@123
|
103 |
|
vb@123
|
104 |
hr = BCryptImportKeyPair(hAlg, NULL, BCRYPT_RSAPUBLIC_BLOB, phKey, (PUCHAR) pbPublicKey, cbKey, 0);
|
vb@123
|
105 |
|
vb@123
|
106 |
cleanup:
|
vb@123
|
107 |
CoTaskMemFree(pbPublicKey);
|
vb@123
|
108 |
return hr;
|
vb@123
|
109 |
}
|
vb@123
|
110 |
|
vb@96
|
111 |
namespace pEp {
|
vb@96
|
112 |
|
vb@96
|
113 |
const LPCTSTR GateKeeper::plugin_reg_path = _T("Software\\Microsoft\\Office\\Outlook\\Addins\\pEp");
|
vb@96
|
114 |
const LPCTSTR GateKeeper::plugin_reg_value_name = _T("LoadBehavior");
|
vb@135
|
115 |
const LPCTSTR GateKeeper::updater_reg_path = _T("Software\\pEp\\Updater");
|
vb@96
|
116 |
|
vb@96
|
117 |
const time_t GateKeeper::cycle = 7200; // 7200 sec is 2 h
|
vb@137
|
118 |
const time_t GateKeeper::fraction = 10; // first update is at 10% of cycle
|
vb@96
|
119 |
const DWORD GateKeeper::waiting = 10000; // 10000 ms is 10 sec
|
vb@88
|
120 |
|
vb@117
|
121 |
GateKeeper::GateKeeper(CpEpCOMServerAdapterModule * self)
|
vb@141
|
122 |
: _self(self), now(time(NULL)), next(now + time_diff()), hkUpdater(NULL), hkPluginStart(NULL),
|
vb@141
|
123 |
internet(NULL), hAES(NULL), hRSA(NULL)
|
vb@96
|
124 |
{
|
vb@96
|
125 |
LONG lResult = RegOpenCurrentUser(KEY_READ, &cu);
|
vb@96
|
126 |
assert(lResult == ERROR_SUCCESS);
|
vb@96
|
127 |
if (lResult == ERROR_SUCCESS)
|
vb@96
|
128 |
cu_open = true;
|
vb@96
|
129 |
else
|
vb@96
|
130 |
cu_open = false;
|
vb@88
|
131 |
|
vb@96
|
132 |
if (cu_open) {
|
vb@96
|
133 |
LONG lResult = RegOpenKeyEx(cu, updater_reg_path, 0, KEY_READ, &hkUpdater);
|
vb@96
|
134 |
assert(lResult == ERROR_SUCCESS);
|
vb@96
|
135 |
if (lResult != ERROR_SUCCESS)
|
vb@96
|
136 |
return;
|
vb@141
|
137 |
|
vb@141
|
138 |
lResult = RegOpenKeyEx(cu, plugin_reg_path, 0, KEY_WRITE, &hkPluginStart);
|
vb@141
|
139 |
assert(lResult == ERROR_SUCCESS);
|
vb@141
|
140 |
if (lResult != ERROR_SUCCESS)
|
vb@141
|
141 |
return;
|
vb@141
|
142 |
RegCloseKey(hkPluginStart);
|
vb@96
|
143 |
}
|
vb@96
|
144 |
}
|
vb@96
|
145 |
|
vb@96
|
146 |
GateKeeper::~GateKeeper()
|
vb@96
|
147 |
{
|
vb@96
|
148 |
if (cu_open) {
|
vb@96
|
149 |
if (hkUpdater)
|
vb@96
|
150 |
RegCloseKey(hkUpdater);
|
vb@96
|
151 |
RegCloseKey(cu);
|
vb@96
|
152 |
}
|
vb@96
|
153 |
}
|
vb@88
|
154 |
|
vb@96
|
155 |
time_t GateKeeper::time_diff()
|
vb@96
|
156 |
{
|
vb@96
|
157 |
try {
|
vb@96
|
158 |
static random_device rd;
|
vb@96
|
159 |
static mt19937 gen(rd());
|
vb@88
|
160 |
|
vb@137
|
161 |
uniform_int_distribution<time_t> dist(0, cycle/fraction);
|
vb@96
|
162 |
|
vb@96
|
163 |
return dist(gen);
|
vb@96
|
164 |
}
|
vb@96
|
165 |
catch (exception&) {
|
vb@96
|
166 |
assert(0);
|
vb@96
|
167 |
return 0;
|
vb@96
|
168 |
}
|
vb@88
|
169 |
}
|
vb@96
|
170 |
|
vb@96
|
171 |
void GateKeeper::keep()
|
vb@96
|
172 |
{
|
vb@96
|
173 |
if (!cu_open)
|
vb@96
|
174 |
return;
|
vb@96
|
175 |
|
vb@96
|
176 |
while (1) {
|
vb@96
|
177 |
keep_plugin();
|
vb@96
|
178 |
|
vb@96
|
179 |
now = time(NULL);
|
vb@96
|
180 |
assert(now != -1);
|
vb@96
|
181 |
|
vb@134
|
182 |
if (now > next) {
|
vb@96
|
183 |
next = now + GateKeeper::cycle;
|
vb@96
|
184 |
keep_updated();
|
vb@134
|
185 |
}
|
vb@96
|
186 |
|
vb@96
|
187 |
Sleep(waiting);
|
vb@96
|
188 |
}
|
vb@88
|
189 |
}
|
vb@96
|
190 |
|
vb@96
|
191 |
void GateKeeper::keep_plugin()
|
vb@96
|
192 |
{
|
vb@141
|
193 |
if (!hkPluginStart)
|
vb@141
|
194 |
return;
|
vb@141
|
195 |
|
vb@141
|
196 |
LONG lResult = RegOpenKeyEx(cu, plugin_reg_path, 0, KEY_WRITE, &hkPluginStart);
|
vb@141
|
197 |
assert(lResult == ERROR_SUCCESS);
|
vb@96
|
198 |
if (lResult != ERROR_SUCCESS)
|
vb@96
|
199 |
return;
|
vb@96
|
200 |
|
vb@141
|
201 |
DWORD v = 3;
|
vb@141
|
202 |
lResult = RegSetValueEx(hkPluginStart, plugin_reg_value_name, 0, REG_DWORD, (const BYTE *) &v, sizeof(DWORD));
|
vb@141
|
203 |
assert(lResult == ERROR_SUCCESS);
|
vb@141
|
204 |
|
vb@141
|
205 |
RegCloseKey(hkPluginStart);
|
vb@96
|
206 |
}
|
vb@96
|
207 |
|
vb@111
|
208 |
string GateKeeper::update_key()
|
vb@110
|
209 |
{
|
vb@110
|
210 |
static string key;
|
vb@110
|
211 |
|
vb@110
|
212 |
if (key.length() == 0) {
|
vb@110
|
213 |
HRSRC res = FindResource(_self->hModule(), MAKEINTRESOURCE(IRD_UPDATEKEY), RT_RCDATA);
|
vb@110
|
214 |
assert(res);
|
vb@110
|
215 |
if (!res)
|
vb@110
|
216 |
throw runtime_error("FindResource: IRD_UPDATEKEY");
|
vb@110
|
217 |
|
vb@110
|
218 |
HGLOBAL hRes = LoadResource(_self->hModule(), res);
|
vb@110
|
219 |
assert(hRes);
|
vb@110
|
220 |
if (!hRes)
|
vb@110
|
221 |
throw runtime_error("LoadResource: IRD_UPDATEKEY");
|
vb@110
|
222 |
|
vb@110
|
223 |
key = string((char *)LockResource(hRes), SizeofResource(_self->hModule(), res));
|
vb@110
|
224 |
UnlockResource(hRes);
|
vb@110
|
225 |
}
|
vb@110
|
226 |
|
vb@110
|
227 |
return key;
|
vb@110
|
228 |
}
|
vb@110
|
229 |
|
vb@116
|
230 |
BCRYPT_KEY_HANDLE GateKeeper::delivery_key()
|
vb@112
|
231 |
{
|
vb@112
|
232 |
aeskey_t key;
|
vb@112
|
233 |
|
vb@112
|
234 |
static random_device rd;
|
vb@112
|
235 |
static mt19937 gen(rd());
|
vb@112
|
236 |
|
vb@123
|
237 |
uniform_int_distribution<int64_t> dist(0, UINT32_MAX);
|
vb@112
|
238 |
|
vb@123
|
239 |
for (int i = 0; i < 8; i++)
|
vb@123
|
240 |
key.dw_key[i] = (uint32_t) dist(gen);
|
vb@113
|
241 |
|
vb@116
|
242 |
BCRYPT_KEY_HANDLE hKey;
|
vb@142
|
243 |
|
vb@116
|
244 |
NTSTATUS status = BCryptGenerateSymmetricKey(hAES, &hKey, NULL, 0, (PUCHAR) &key, (ULONG) sizeof(aeskey_t), 0);
|
vb@116
|
245 |
assert(status == 0);
|
vb@116
|
246 |
if (status)
|
vb@116
|
247 |
throw runtime_error("BCryptGenerateSymmetricKey");
|
vb@116
|
248 |
|
vb@142
|
249 |
#ifndef NDEBUG
|
vb@131
|
250 |
DWORD keylength = 0;
|
vb@131
|
251 |
ULONG copied = 0;
|
vb@131
|
252 |
status = BCryptGetProperty(hKey, BCRYPT_KEY_LENGTH, (PUCHAR) &keylength, sizeof(DWORD), &copied, 0);
|
vb@131
|
253 |
assert(keylength == 256);
|
vb@142
|
254 |
#endif
|
vb@131
|
255 |
|
vb@116
|
256 |
return hKey;
|
vb@113
|
257 |
}
|
vb@113
|
258 |
|
vb@121
|
259 |
string GateKeeper::wrapped_delivery_key(BCRYPT_KEY_HANDLE hDeliveryKey)
|
vb@113
|
260 |
{
|
vb@113
|
261 |
string result;
|
vb@113
|
262 |
|
vb@116
|
263 |
BCRYPT_KEY_HANDLE hUpdateKey;
|
vb@117
|
264 |
string _update_key = update_key();
|
vb@113
|
265 |
|
vb@123
|
266 |
PCERT_PUBLIC_KEY_INFO uk;
|
vb@123
|
267 |
DWORD uk_size;
|
vb@142
|
268 |
|
vb@123
|
269 |
BOOL bResult = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
|
vb@123
|
270 |
(const BYTE *) _update_key.data(), _update_key.size(), CRYPT_DECODE_ALLOC_FLAG, NULL, &uk, &uk_size);
|
vb@123
|
271 |
if (!bResult)
|
vb@123
|
272 |
throw runtime_error("CryptDecodeObjectEx: X509_PUBLIC_KEY_INFO");
|
vb@123
|
273 |
|
vb@123
|
274 |
PUBLIC_KEY_VALUES *_uk;
|
vb@123
|
275 |
DWORD _uk_size;
|
vb@142
|
276 |
|
vb@123
|
277 |
bResult = CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
|
vb@123
|
278 |
uk->PublicKey.pbData, uk->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &_uk, &_uk_size);
|
vb@123
|
279 |
LocalFree(uk);
|
vb@123
|
280 |
if (!bResult)
|
vb@123
|
281 |
throw runtime_error("CryptDecodeObjectEx: X509_PUBLIC_KEY_INFO");
|
vb@123
|
282 |
|
vb@123
|
283 |
HRESULT hResult = ImportRsaPublicKey(hRSA, _uk, &hUpdateKey);
|
vb@123
|
284 |
LocalFree(_uk);
|
vb@123
|
285 |
if (hResult)
|
vb@123
|
286 |
throw runtime_error("ImportRsaPublicKey");
|
vb@117
|
287 |
|
vb@129
|
288 |
ULONG psize;
|
vb@129
|
289 |
NTSTATUS status = BCryptGetProperty(hUpdateKey, BCRYPT_ALGORITHM_NAME, NULL, 0, &psize, 0);
|
vb@129
|
290 |
char *prop = new char[psize];
|
vb@129
|
291 |
TCHAR *_prop = (TCHAR *) prop;
|
vb@129
|
292 |
BCryptGetProperty(hUpdateKey, BCRYPT_ALGORITHM_NAME, (PUCHAR) prop, psize, &psize, 0);
|
vb@129
|
293 |
|
vb@129
|
294 |
ULONG export_size;
|
vb@129
|
295 |
status = BCryptExportKey(hDeliveryKey, NULL, BCRYPT_KEY_DATA_BLOB, NULL, NULL,
|
vb@129
|
296 |
&export_size, 0);
|
vb@129
|
297 |
if (status)
|
vb@129
|
298 |
throw runtime_error("BCryptExportKey: measuring export size");
|
vb@129
|
299 |
|
vb@129
|
300 |
PUCHAR _delivery_key = new UCHAR[export_size];
|
vb@120
|
301 |
ULONG copied;
|
vb@129
|
302 |
status = BCryptExportKey(hDeliveryKey, NULL, BCRYPT_KEY_DATA_BLOB, _delivery_key, export_size,
|
vb@123
|
303 |
&copied, 0);
|
vb@129
|
304 |
if (status) {
|
vb@129
|
305 |
delete[] _delivery_key;
|
vb@120
|
306 |
throw runtime_error("BCryptExportKey: delivery_key");
|
vb@129
|
307 |
}
|
vb@120
|
308 |
|
vb@117
|
309 |
BCRYPT_OAEP_PADDING_INFO pi;
|
vb@119
|
310 |
memset(&pi, 0, sizeof(BCRYPT_OAEP_PADDING_INFO));
|
vb@117
|
311 |
pi.pszAlgId = BCRYPT_SHA256_ALGORITHM;
|
vb@117
|
312 |
|
vb@117
|
313 |
ULONG result_size;
|
vb@118
|
314 |
PUCHAR _result = NULL;
|
vb@129
|
315 |
ULONG blob_size = export_size - sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
|
vb@129
|
316 |
PUCHAR blob = _delivery_key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
|
vb@129
|
317 |
status = BCryptEncrypt(hUpdateKey, blob, blob_size, &pi, NULL, 0, NULL, 0, &result_size, BCRYPT_PAD_OAEP);
|
vb@119
|
318 |
if (status) {
|
vb@129
|
319 |
delete[] _delivery_key;
|
vb@119
|
320 |
BCryptDestroyKey(hUpdateKey);
|
vb@117
|
321 |
throw runtime_error("BCryptEncrypt: calculating result size");
|
vb@119
|
322 |
}
|
vb@117
|
323 |
|
vb@117
|
324 |
_result = new UCHAR[result_size];
|
vb@129
|
325 |
status = BCryptEncrypt(hUpdateKey, blob, blob_size, &pi, NULL, 0, _result, result_size, &copied, BCRYPT_PAD_OAEP);
|
vb@129
|
326 |
delete[] _delivery_key;
|
vb@119
|
327 |
if (status) {
|
vb@119
|
328 |
BCryptDestroyKey(hUpdateKey);
|
vb@119
|
329 |
delete[] _result;
|
vb@118
|
330 |
throw runtime_error("BCryptEncrypt: encrypting using update_key");
|
vb@119
|
331 |
}
|
vb@117
|
332 |
|
vb@120
|
333 |
BCryptDestroyKey(hUpdateKey);
|
vb@120
|
334 |
|
vb@117
|
335 |
stringstream s;
|
vb@129
|
336 |
for (ULONG i = 0; i < copied; i++) {
|
vb@129
|
337 |
s << hex << setw(2) << setfill('0');
|
vb@118
|
338 |
s << (int) _result[i];
|
vb@129
|
339 |
}
|
vb@117
|
340 |
delete[] _result;
|
vb@117
|
341 |
s >> result;
|
vb@117
|
342 |
|
vb@113
|
343 |
return result;
|
vb@112
|
344 |
}
|
vb@112
|
345 |
|
vb@96
|
346 |
GateKeeper::product_list& GateKeeper::registered_products()
|
vb@96
|
347 |
{
|
vb@96
|
348 |
static product_list products;
|
vb@88
|
349 |
|
vb@96
|
350 |
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872(v=vs.85).aspx
|
vb@138
|
351 |
TCHAR value_name[16384];
|
vb@96
|
352 |
DWORD value_name_size;
|
vb@138
|
353 |
TCHAR value[L_MAX_URL_LENGTH + 1];
|
vb@96
|
354 |
DWORD value_size;
|
vb@88
|
355 |
|
vb@96
|
356 |
products.empty();
|
vb@96
|
357 |
|
vb@96
|
358 |
LONG lResult = ERROR_SUCCESS;
|
vb@96
|
359 |
for (DWORD i = 0; lResult == ERROR_SUCCESS; i++) {
|
vb@138
|
360 |
value_name_size = 16383;
|
vb@96
|
361 |
value_size = L_MAX_URL_LENGTH + 1;
|
vb@139
|
362 |
lResult = RegEnumValue(hkUpdater, i, value_name, &value_name_size, NULL, NULL, (LPBYTE) value, &value_size);
|
vb@139
|
363 |
if (lResult == ERROR_SUCCESS) {
|
vb@96
|
364 |
products.push_back({ value_name, value });
|
vb@139
|
365 |
}
|
vb@88
|
366 |
}
|
vb@88
|
367 |
|
vb@96
|
368 |
return products;
|
vb@88
|
369 |
}
|
vb@88
|
370 |
|
vb@126
|
371 |
void GateKeeper::install_msi(tstring filename)
|
vb@126
|
372 |
{
|
vb@198
|
373 |
HANDLE hMutex = CreateMutex(NULL, TRUE, _T("PEPINSTALLERMUTEX"));
|
vb@198
|
374 |
if (hMutex) {
|
vb@198
|
375 |
CloseHandle(hMutex);
|
vb@198
|
376 |
ShellExecute(NULL, _T("open"), filename.c_str(), NULL, NULL, SW_SHOW);
|
vb@198
|
377 |
}
|
vb@126
|
378 |
}
|
vb@126
|
379 |
|
vb@97
|
380 |
void GateKeeper::update_product(product p, DWORD context)
|
vb@96
|
381 |
{
|
vb@199
|
382 |
{
|
vb@207
|
383 |
const tstring _fileName = _T("\\pEpSetup.lck");
|
vb@207
|
384 |
|
vb@207
|
385 |
unique_ptr < TCHAR[] > _pathName(new TCHAR[MAX_PATH + 1]);
|
vb@207
|
386 |
DWORD size = GetTempPath(MAX_PATH, _pathName.get());
|
vb@207
|
387 |
if (size > MAX_PATH - _fileName.size())
|
vb@207
|
388 |
throw runtime_error("TEMP path too long");
|
vb@207
|
389 |
|
vb@207
|
390 |
tstring fileName(_pathName.get());
|
vb@207
|
391 |
fileName += _fileName;
|
vb@207
|
392 |
|
vb@207
|
393 |
HANDLE file = CreateFile(fileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
vb@207
|
394 |
if (file == INVALID_HANDLE_VALUE) {
|
vb@207
|
395 |
return;
|
vb@206
|
396 |
}
|
vb@206
|
397 |
else {
|
vb@207
|
398 |
CloseHandle(file);
|
vb@207
|
399 |
DeleteFile(fileName.c_str());
|
vb@206
|
400 |
}
|
vb@199
|
401 |
}
|
vb@199
|
402 |
|
vb@127
|
403 |
BCRYPT_KEY_HANDLE dk = delivery_key();
|
vb@126
|
404 |
#ifdef UNICODE
|
vb@127
|
405 |
tstring delivery = utility::utf16_string(wrapped_delivery_key(dk));
|
vb@126
|
406 |
#else
|
vb@126
|
407 |
tstring delivery = wrapped_delivery_key(delivery_key());
|
vb@126
|
408 |
#endif
|
vb@124
|
409 |
tstring url = p.second;
|
vb@124
|
410 |
url += _T("&challenge=");
|
vb@124
|
411 |
url += delivery;
|
vb@124
|
412 |
tstring headers;
|
vb@124
|
413 |
HINTERNET hUrl = InternetOpenUrl(internet, url.c_str(), headers.c_str(), headers.length(),
|
vb@97
|
414 |
INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_UI | INTERNET_FLAG_SECURE, context);
|
vb@97
|
415 |
if (hUrl == NULL)
|
vb@97
|
416 |
return;
|
vb@94
|
417 |
|
vb@127
|
418 |
string crypted;
|
vb@127
|
419 |
string unencrypted;
|
vb@133
|
420 |
UCHAR iv[12];
|
vb@133
|
421 |
UCHAR nonce[sizeof(iv)];
|
vb@133
|
422 |
UCHAR tag[16];
|
vb@138
|
423 |
tstring filename;
|
vb@138
|
424 |
HANDLE hFile = NULL;
|
vb@138
|
425 |
char *unencrypted_buffer = NULL;
|
vb@107
|
426 |
|
vb@130
|
427 |
try {
|
vb@133
|
428 |
DWORD reading;
|
vb@133
|
429 |
InternetReadFile(hUrl, iv, sizeof(iv), &reading);
|
vb@133
|
430 |
|
vb@133
|
431 |
if (reading) do {
|
vb@130
|
432 |
static char buffer[1024*1024];
|
vb@130
|
433 |
BOOL bResult = InternetReadFile(hUrl, buffer, 1024*1024, &reading);
|
vb@130
|
434 |
if (!bResult || !reading)
|
vb@130
|
435 |
break;
|
vb@130
|
436 |
crypted += string(buffer, reading);
|
vb@130
|
437 |
} while (1);
|
vb@130
|
438 |
}
|
vb@138
|
439 |
catch (exception&) {
|
vb@138
|
440 |
goto closing;
|
vb@130
|
441 |
}
|
vb@133
|
442 |
|
vb@97
|
443 |
InternetCloseHandle(hUrl);
|
vb@126
|
444 |
hUrl = NULL;
|
vb@126
|
445 |
|
vb@133
|
446 |
memcpy(nonce, iv, sizeof(iv));
|
vb@133
|
447 |
|
vb@130
|
448 |
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
|
vb@130
|
449 |
BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
|
vb@130
|
450 |
authInfo.pbNonce = nonce;
|
vb@130
|
451 |
authInfo.cbNonce = sizeof(nonce);
|
vb@133
|
452 |
authInfo.pbTag = tag;
|
vb@133
|
453 |
authInfo.cbTag = sizeof(tag);
|
vb@128
|
454 |
|
vb@127
|
455 |
ULONG unencrypted_size;
|
vb@127
|
456 |
NTSTATUS status = BCryptDecrypt(dk, (PUCHAR) crypted.data(), crypted.size(),
|
vb@131
|
457 |
&authInfo, iv, sizeof(iv), NULL, 0, &unencrypted_size, 0);
|
vb@127
|
458 |
if (status)
|
vb@127
|
459 |
goto closing;
|
vb@127
|
460 |
|
vb@127
|
461 |
unencrypted_buffer = new char[unencrypted_size];
|
vb@131
|
462 |
PUCHAR crypted_data = (PUCHAR) crypted.data();
|
vb@133
|
463 |
ULONG crypted_size = (ULONG) crypted.size() - sizeof(tag);
|
vb@133
|
464 |
memcpy(tag, crypted_data + crypted_size, sizeof(tag));
|
vb@133
|
465 |
|
vb@131
|
466 |
status = BCryptDecrypt(dk, crypted_data, crypted_size,
|
vb@133
|
467 |
&authInfo, iv, sizeof(iv), (PUCHAR) unencrypted_buffer, unencrypted_size, &unencrypted_size, 0);
|
vb@129
|
468 |
if (status)
|
vb@127
|
469 |
goto closing;
|
vb@127
|
470 |
|
vb@134
|
471 |
BCryptDestroyKey(dk);
|
vb@134
|
472 |
|
vb@127
|
473 |
TCHAR temp_path[MAX_PATH + 1];
|
vb@127
|
474 |
GetTempPath(MAX_PATH, temp_path);
|
vb@127
|
475 |
filename = temp_path;
|
vb@127
|
476 |
filename += _T("\\pEp_");
|
vb@127
|
477 |
filename += delivery.substr(0, 32);
|
vb@127
|
478 |
filename += _T(".msi");
|
vb@127
|
479 |
|
vb@127
|
480 |
hFile = CreateFile(filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
vb@127
|
481 |
if (!hFile)
|
vb@127
|
482 |
goto closing;
|
vb@127
|
483 |
DWORD writing;
|
vb@127
|
484 |
WriteFile(hFile, unencrypted_buffer, unencrypted_size, &writing, NULL);
|
vb@127
|
485 |
CloseHandle(hFile);
|
vb@127
|
486 |
|
vb@126
|
487 |
install_msi(filename);
|
vb@127
|
488 |
|
vb@126
|
489 |
return;
|
vb@126
|
490 |
|
vb@126
|
491 |
closing:
|
vb@127
|
492 |
if (unencrypted_buffer)
|
vb@127
|
493 |
delete[] unencrypted_buffer;
|
vb@126
|
494 |
if (hFile)
|
vb@126
|
495 |
CloseHandle(hFile);
|
vb@126
|
496 |
if (hUrl)
|
vb@126
|
497 |
InternetCloseHandle(hUrl);
|
vb@127
|
498 |
BCryptDestroyKey(dk);
|
vb@96
|
499 |
}
|
vb@88
|
500 |
|
vb@96
|
501 |
void GateKeeper::keep_updated()
|
vb@96
|
502 |
{
|
vb@116
|
503 |
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAES, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
|
vb@116
|
504 |
assert(status == 0);
|
vb@116
|
505 |
if (status)
|
vb@116
|
506 |
goto closing;
|
vb@130
|
507 |
status = BCryptSetProperty(hAES, BCRYPT_CHAINING_MODE, (PUCHAR) BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
|
vb@128
|
508 |
if (status)
|
vb@128
|
509 |
goto closing;
|
vb@116
|
510 |
|
vb@116
|
511 |
status = BCryptOpenAlgorithmProvider(&hRSA, BCRYPT_RSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
|
vb@116
|
512 |
assert(status == 0);
|
vb@116
|
513 |
if (status)
|
vb@116
|
514 |
goto closing;
|
vb@116
|
515 |
|
vb@124
|
516 |
internet = InternetOpen(_T("pEp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
vb@124
|
517 |
if (!internet)
|
vb@124
|
518 |
goto closing;
|
vb@97
|
519 |
|
vb@96
|
520 |
product_list& products = registered_products();
|
vb@97
|
521 |
DWORD context = 0;
|
vb@138
|
522 |
|
vb@96
|
523 |
for (auto i = products.begin(); i != products.end(); i++) {
|
vb@126
|
524 |
try {
|
vb@126
|
525 |
update_product(*i, context++);
|
vb@126
|
526 |
}
|
vb@126
|
527 |
catch (exception&) {
|
vb@126
|
528 |
|
vb@126
|
529 |
}
|
vb@96
|
530 |
}
|
vb@97
|
531 |
|
vb@116
|
532 |
closing:
|
vb@116
|
533 |
if (internet)
|
vb@116
|
534 |
InternetCloseHandle(internet);
|
vb@116
|
535 |
if (hAES)
|
vb@116
|
536 |
BCryptCloseAlgorithmProvider(hAES, 0);
|
vb@116
|
537 |
if (hRSA)
|
vb@116
|
538 |
BCryptCloseAlgorithmProvider(hRSA, 0);
|
vb@97
|
539 |
internet = NULL;
|
vb@116
|
540 |
hAES = NULL;
|
vb@116
|
541 |
hRSA = NULL;
|
vb@96
|
542 |
}
|
vb@88
|
543 |
|
vb@96
|
544 |
} // namespace pEp
|