GateKeeper.cpp
author Volker Birk <vb@pep.foundation>
Fri, 03 Jul 2020 10:55:44 +0200
branchCOM-115
changeset 434 bf1832802558
parent 432 9ed5917614f6
child 447 18a75cc8b45f
permissions -rw-r--r--
use string table
     1 #include "stdafx.h"
     2 
     3 #include "GateKeeper.h"
     4 #include "pEpCOMServerAdapter.h"
     5 #include "CMainWindow.h"
     6 
     7 using namespace std;
     8 
     9 extern CMainWindow mainWindow;
    10 auto r = CMainWindow::r;
    11 
    12 // from https://msdn.microsoft.com/en-us/library/windows/desktop/dd388945(v=vs.85).aspx
    13 
    14 struct PUBLIC_KEY_VALUES {
    15     BLOBHEADER blobheader;
    16     RSAPUBKEY rsapubkey;
    17     BYTE modulus[4096];
    18 };
    19 
    20 static void ReverseMemCopy(
    21     _Out_ BYTE       *pbDest,
    22     _In_  BYTE const *pbSource,
    23     _In_  DWORD       cb
    24 )
    25 {
    26     for (DWORD i = 0; i < cb; i++) {
    27         pbDest[cb - 1 - i] = pbSource[i];
    28     }
    29 }
    30 
    31 static NTSTATUS ImportRsaPublicKey(
    32     _In_ BCRYPT_ALG_HANDLE  hAlg,    // CNG provider
    33     _In_ PUBLIC_KEY_VALUES *pKey,    // Pointer to the RSAPUBKEY blob.
    34     _In_ BCRYPT_KEY_HANDLE *phKey    // Receives a handle the imported public key.
    35 )
    36 {
    37     NTSTATUS hr = 0;
    38 
    39     BYTE *pbPublicKey = NULL;
    40     DWORD cbKey = 0;
    41 
    42     // Layout of the RSA public key blob:
    43 
    44     //  +----------------------------------------------------------------+
    45     //  |     BCRYPT_RSAKEY_BLOB    | BE( dwExp ) |   BE( Modulus )      |
    46     //  +----------------------------------------------------------------+
    47     //
    48     //  sizeof(BCRYPT_RSAKEY_BLOB)       cbExp           cbModulus 
    49     //  <--------------------------><------------><---------------------->
    50     //
    51     //   BE = Big Endian Format                                                     
    52 
    53     DWORD cbModulus = (pKey->rsapubkey.bitlen + 7) / 8;
    54     DWORD dwExp = pKey->rsapubkey.pubexp;
    55     DWORD cbExp = (dwExp & 0xFF000000) ? 4 :
    56         (dwExp & 0x00FF0000) ? 3 :
    57         (dwExp & 0x0000FF00) ? 2 : 1;
    58 
    59     BCRYPT_RSAKEY_BLOB *pRsaBlob;
    60     PBYTE pbCurrent;
    61 
    62     if (!SUCCEEDED(hr = DWordAdd(cbModulus, sizeof(BCRYPT_RSAKEY_BLOB), &cbKey))) {
    63         goto cleanup;
    64     }
    65 
    66     cbKey += cbExp;
    67 
    68     pbPublicKey = (PBYTE)CoTaskMemAlloc(cbKey);
    69     if (pbPublicKey == NULL) {
    70         hr = E_OUTOFMEMORY;
    71         goto cleanup;
    72     }
    73 
    74     ZeroMemory(pbPublicKey, cbKey);
    75     pRsaBlob = (BCRYPT_RSAKEY_BLOB *)(pbPublicKey);
    76 
    77     //
    78     // Make the Public Key Blob Header
    79     //
    80 
    81     pRsaBlob->Magic = BCRYPT_RSAPUBLIC_MAGIC;
    82     pRsaBlob->BitLength = pKey->rsapubkey.bitlen;
    83     pRsaBlob->cbPublicExp = cbExp;
    84     pRsaBlob->cbModulus = cbModulus;
    85     pRsaBlob->cbPrime1 = 0;
    86     pRsaBlob->cbPrime2 = 0;
    87 
    88     pbCurrent = (PBYTE)(pRsaBlob + 1);
    89 
    90     //
    91     // Copy pubExp Big Endian 
    92     //
    93 
    94     ReverseMemCopy(pbCurrent, (PBYTE)&dwExp, cbExp);
    95     pbCurrent += cbExp;
    96 
    97     //
    98     // Copy Modulus Big Endian 
    99     //
   100 
   101     ReverseMemCopy(pbCurrent, pKey->modulus, cbModulus);
   102 
   103     //
   104     // Import the public key
   105     //
   106 
   107     hr = BCryptImportKeyPair(hAlg, NULL, BCRYPT_RSAPUBLIC_BLOB, phKey, (PUCHAR)pbPublicKey, cbKey, 0);
   108 
   109 cleanup:
   110     CoTaskMemFree(pbPublicKey);
   111     return hr;
   112 }
   113 
   114 namespace pEp {
   115     const LPCTSTR GateKeeper::plugin_reg_path = _T("Software\\Microsoft\\Office\\Outlook\\Addins\\pEp");
   116     const LPCTSTR GateKeeper::plugin_reg_value_name = _T("LoadBehavior");
   117     const LPCTSTR GateKeeper::updater_reg_path = _T("Software\\pEp\\Updater");
   118 
   119     const time_t GateKeeper::cycle = 7200;   // 7200 sec is 2 h
   120     const time_t GateKeeper::fraction = 10;  // first update is at 10% of cycle
   121     const DWORD GateKeeper::waiting = 10000; //  10 sec
   122 
   123     GateKeeper::GateKeeper(CpEpCOMServerAdapterModule * self)
   124         : _self(self), now(time(NULL)), next(now /*+ time_diff()*/), hkUpdater(NULL),
   125         internet(NULL), hAES(NULL), hRSA(NULL)
   126     {
   127         if (the_gatekeeper)
   128             throw runtime_error("second instance of GateKeeper was initialized");
   129 
   130         DeleteFile(get_lockFile().c_str());
   131 
   132         LONG lResult = RegOpenCurrentUser(KEY_READ, &cu);
   133         assert(lResult == ERROR_SUCCESS);
   134         if (lResult == ERROR_SUCCESS)
   135             cu_open = true;
   136         else
   137             cu_open = false;
   138 
   139         if (cu_open) {
   140             LONG lResult = RegOpenKeyEx(cu, updater_reg_path, 0, KEY_READ, &hkUpdater);
   141             if (lResult != ERROR_SUCCESS)
   142                 RegCreateKeyEx(cu, updater_reg_path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hkUpdater, NULL);
   143         }
   144 
   145         the_gatekeeper = this;
   146     }
   147 
   148     GateKeeper::~GateKeeper()
   149     {
   150         the_gatekeeper = nullptr;
   151 
   152         if (cu_open) {
   153             if (hkUpdater)
   154                 RegCloseKey(hkUpdater);
   155             RegCloseKey(cu);
   156         }
   157     }
   158 
   159     time_t GateKeeper::time_diff()
   160     {
   161         try {
   162             static random_device rd;
   163             static mt19937 gen(rd());
   164 
   165             uniform_int_distribution<time_t> dist(0, cycle / fraction);
   166 
   167             return dist(gen);
   168         }
   169         catch (exception&) {
   170             assert(0);
   171             return 0;
   172         }
   173     }
   174 
   175     void GateKeeper::keep()
   176     {
   177         if (!cu_open)
   178             return;
   179 
   180         while (1) {
   181             keep_plugin();
   182 
   183             now = time(NULL);
   184             assert(now != -1);
   185 
   186             if (now > next) {
   187                 next = now + GateKeeper::cycle;
   188                 if (update_enabled())
   189                     update_now();
   190             }
   191 
   192             Sleep(waiting);
   193         }
   194     }
   195 
   196     void GateKeeper::keep_plugin()
   197     {
   198         HKEY hkPluginStart = NULL;
   199 
   200         LONG lResult = RegOpenKeyEx(cu, plugin_reg_path, 0, KEY_WRITE, &hkPluginStart);
   201         if (lResult != ERROR_SUCCESS)
   202             return;
   203 
   204         DWORD v = 3;
   205         lResult = RegSetValueEx(hkPluginStart, plugin_reg_value_name, 0, REG_DWORD, (const BYTE *)&v, sizeof(DWORD));
   206         assert(lResult == ERROR_SUCCESS);
   207 
   208         RegCloseKey(hkPluginStart);
   209     }
   210 
   211     string GateKeeper::update_key()
   212     {
   213         static string key;
   214 
   215         if (key.length() == 0) {
   216             HRSRC res = FindResource(_self->hModule(), MAKEINTRESOURCE(IRD_UPDATEKEY), RT_RCDATA);
   217             assert(res);
   218             if (!res)
   219                 throw runtime_error("FindResource: IRD_UPDATEKEY");
   220 
   221             HGLOBAL hRes = LoadResource(_self->hModule(), res);
   222             assert(hRes);
   223             if (!hRes)
   224                 throw runtime_error("LoadResource: IRD_UPDATEKEY");
   225 
   226             key = string((char *)LockResource(hRes), SizeofResource(_self->hModule(), res));
   227             UnlockResource(hRes);
   228         }
   229 
   230         return key;
   231     }
   232 
   233     BCRYPT_KEY_HANDLE GateKeeper::delivery_key()
   234     {
   235         aeskey_t key;
   236 
   237         static random_device rd;
   238         static mt19937 gen(rd());
   239 
   240         uniform_int_distribution<int64_t> dist(0, UINT32_MAX);
   241 
   242         for (int i = 0; i < 8; i++)
   243             key.dw_key[i] = (uint32_t)dist(gen);
   244 
   245         BCRYPT_KEY_HANDLE hKey;
   246 
   247         NTSTATUS status = BCryptGenerateSymmetricKey(hAES, &hKey, NULL, 0, (PUCHAR)&key, (ULONG) sizeof(aeskey_t), 0);
   248         assert(status == 0);
   249         if (status)
   250             throw runtime_error("BCryptGenerateSymmetricKey");
   251 
   252 #ifndef NDEBUG
   253         DWORD keylength = 0;
   254         ULONG copied = 0;
   255         status = BCryptGetProperty(hKey, BCRYPT_KEY_LENGTH, (PUCHAR)&keylength, sizeof(DWORD), &copied, 0);
   256         assert(keylength == 256);
   257 #endif
   258 
   259         return hKey;
   260     }
   261 
   262     string GateKeeper::wrapped_delivery_key(BCRYPT_KEY_HANDLE hDeliveryKey)
   263     {
   264         string result;
   265 
   266         BCRYPT_KEY_HANDLE hUpdateKey = NULL;
   267         string _update_key = update_key();
   268 
   269         PCERT_PUBLIC_KEY_INFO uk = NULL;
   270         DWORD uk_size = 0;
   271 
   272         BOOL bResult = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
   273             (const BYTE *)_update_key.data(), _update_key.size(), CRYPT_DECODE_ALLOC_FLAG, NULL, &uk, &uk_size);
   274         if (!bResult)
   275             throw runtime_error("CryptDecodeObjectEx: X509_PUBLIC_KEY_INFO");
   276 
   277         PUBLIC_KEY_VALUES *_uk = NULL;
   278         DWORD _uk_size = 0;
   279 
   280         bResult = CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
   281             uk->PublicKey.pbData, uk->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &_uk, &_uk_size);
   282         LocalFree(uk);
   283         if (!bResult)
   284             throw runtime_error("CryptDecodeObjectEx: X509_PUBLIC_KEY_INFO");
   285 
   286         HRESULT hResult = ImportRsaPublicKey(hRSA, _uk, &hUpdateKey);
   287         LocalFree(_uk);
   288         if (!hUpdateKey)
   289             throw runtime_error("ImportRsaPublicKey");
   290 
   291         ULONG psize;
   292         NTSTATUS status = BCryptGetProperty(hUpdateKey, BCRYPT_ALGORITHM_NAME, NULL, 0, &psize, 0);
   293         char *prop = new char[psize];
   294         TCHAR *_prop = (TCHAR *)prop;
   295         status = BCryptGetProperty(hUpdateKey, BCRYPT_ALGORITHM_NAME, (PUCHAR)prop, psize, &psize, 0);
   296         if (status)
   297             throw runtime_error("BCryptGetProperty: BCRYPT_ALGORITHM_NAME");
   298 
   299         ULONG export_size;
   300         status = BCryptExportKey(hDeliveryKey, NULL, BCRYPT_KEY_DATA_BLOB, NULL, NULL,
   301             &export_size, 0);
   302         if (status)
   303             throw runtime_error("BCryptExportKey: measuring export size");
   304 
   305         PUCHAR _delivery_key = new UCHAR[export_size];
   306         ULONG copied;
   307         status = BCryptExportKey(hDeliveryKey, NULL, BCRYPT_KEY_DATA_BLOB, _delivery_key, export_size,
   308             &copied, 0);
   309         if (status) {
   310             delete[] _delivery_key;
   311             throw runtime_error("BCryptExportKey: delivery_key");
   312         }
   313 
   314         BCRYPT_OAEP_PADDING_INFO pi;
   315         memset(&pi, 0, sizeof(BCRYPT_OAEP_PADDING_INFO));
   316         pi.pszAlgId = BCRYPT_SHA256_ALGORITHM;
   317 
   318         ULONG result_size = 0;
   319         PUCHAR _result = NULL;
   320         ULONG blob_size = export_size - sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
   321         PUCHAR blob = _delivery_key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
   322         status = BCryptEncrypt(hUpdateKey, blob, blob_size, &pi, NULL, 0, NULL, 0, &result_size, BCRYPT_PAD_OAEP);
   323         if (status) {
   324             delete[] _delivery_key;
   325             BCryptDestroyKey(hUpdateKey);
   326             throw runtime_error("BCryptEncrypt: calculating result size");
   327         }
   328 
   329         _result = new UCHAR[result_size + 1];
   330         status = BCryptEncrypt(hUpdateKey, blob, blob_size, &pi, NULL, 0, _result, result_size, &copied, BCRYPT_PAD_OAEP);
   331         delete[] _delivery_key;
   332         if (status) {
   333             BCryptDestroyKey(hUpdateKey);
   334             delete[] _result;
   335             throw runtime_error("BCryptEncrypt: encrypting using update_key");
   336         }
   337 
   338         BCryptDestroyKey(hUpdateKey);
   339 
   340         stringstream s;
   341         for (ULONG i = 0; i < copied; i++) {
   342             s << hex << setw(2) << setfill('0');
   343             s << (int)_result[i];
   344         }
   345         delete[] _result;
   346         s >> result;
   347 
   348         return result;
   349     }
   350 
   351     void GateKeeper::enable_update()
   352     {
   353         LONG lResult = RegOpenKeyEx(cu, updater_reg_path, 0, KEY_WRITE, &hkUpdater);
   354         if (lResult != ERROR_SUCCESS)
   355             return;
   356 
   357         lResult = RegSetValueExW(hkUpdater, NULL, 0, REG_SZ, (const BYTE *) _T("1"), sizeof(TCHAR)*2);
   358     }
   359 
   360     void GateKeeper::disable_update()
   361     {
   362         LONG lResult = RegOpenKeyEx(cu, updater_reg_path, 0, KEY_WRITE, &hkUpdater);
   363         if (lResult != ERROR_SUCCESS)
   364             return;
   365 
   366         lResult = RegSetValueEx(hkUpdater, NULL, 0, REG_SZ, (const BYTE *) _T("0"), sizeof(TCHAR) * 2);
   367     }
   368 
   369     bool GateKeeper::update_enabled()
   370     {
   371         bool enabled = true;
   372 
   373         DWORD esize;
   374         RegGetValue(cu, updater_reg_path, NULL, RRF_RT_REG_SZ, NULL, NULL, &esize);
   375         if (esize) {
   376             TCHAR* edata = new TCHAR[esize];
   377             RegGetValue(cu, updater_reg_path, NULL, RRF_RT_REG_SZ, NULL, edata, &esize);
   378             if (tstring(edata) == _T("0"))
   379                 enabled = false;
   380             delete[] edata;
   381         }
   382 
   383         return enabled;
   384     }
   385 
   386     GateKeeper::product_list GateKeeper::registered_products()
   387     {
   388         product_list products;
   389 
   390         // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872(v=vs.85).aspx
   391         static TCHAR value_name[16384];
   392         DWORD value_name_size;
   393         static TCHAR value[L_MAX_URL_LENGTH + 1];
   394         DWORD value_size;
   395 
   396         LONG lResult = ERROR_SUCCESS;
   397         for (DWORD i = 0; lResult == ERROR_SUCCESS; i++) {
   398             value_name_size = 16383;
   399             value_size = L_MAX_URL_LENGTH + 1;
   400             lResult = RegEnumValue(hkUpdater, i, value_name, &value_name_size, NULL, NULL, (LPBYTE)value, &value_size);
   401             if (lResult == ERROR_SUCCESS) {
   402                 products.push_back({ value_name, value });
   403             }
   404         }
   405 
   406         return products;
   407     }
   408 
   409     void GateKeeper::execute_file(tstring filename)
   410     {
   411         HANDLE hMutex = CreateMutex(NULL, TRUE, _T("PEPINSTALLERMUTEX"));
   412         if (hMutex) {
   413             CloseHandle(hMutex);
   414             ShellExecute(NULL, _T("open"), filename.c_str(), NULL, NULL, SW_SHOW);
   415         }
   416     }
   417 
   418     tstring GateKeeper::get_lockFile()
   419     {
   420         static const tstring _fileName = _T("\\pEpSetup.lck");
   421         static tstring fileName;
   422 
   423         if (fileName.length() == 0) {
   424             unique_ptr < TCHAR[] > _pathName(new TCHAR[MAX_PATH + 1]);
   425             DWORD size = GetTempPath(MAX_PATH, _pathName.get());
   426             if (size > MAX_PATH - _fileName.size())
   427                 throw runtime_error("TEMP path too long");
   428 
   429             fileName = _pathName.get();
   430             fileName += _fileName;
   431         }
   432 
   433         return fileName;
   434     }
   435 
   436     // Retrieving Headers Using HTTP_QUERY_CUSTOM
   437     static tstring httpQueryCustom(HINTERNET hHttp, tstring header)
   438     {
   439         DWORD dwResult = 0;
   440         LPTSTR lpOutBuffer = StrDup(header.c_str());
   441 
   442     retry:
   443 
   444         if (!HttpQueryInfo(hHttp, HTTP_QUERY_CUSTOM, (LPVOID)lpOutBuffer, &dwResult, NULL))
   445         {
   446             if (GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND)
   447             {
   448                 // Code to handle the case where the header isn't available.
   449                 LocalFree(lpOutBuffer);
   450                 throw(runtime_error("ERROR_HTTP_HEADER_NOT_FOUND"));
   451             }
   452             else
   453             {
   454                 // Check for an insufficient buffer.
   455                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
   456                 {
   457                     // Allocate the necessary buffer.
   458                     LocalFree(lpOutBuffer);
   459                     lpOutBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, dwResult + 1);
   460 
   461                     // Rewrite the header name in the buffer.
   462                     StringCchPrintf(lpOutBuffer, dwResult, header.c_str());
   463 
   464                     // Retry the call.
   465                     goto retry;
   466                 }
   467                 else
   468                 {
   469                     // Error handling code.
   470                     LocalFree(lpOutBuffer);
   471                     // FIXME: Add GetLastError()
   472                     throw(runtime_error("Unknown"));
   473                 }
   474             }
   475         }
   476 
   477         tstring result(lpOutBuffer);
   478         LocalFree(lpOutBuffer);
   479 
   480         return result;
   481     }
   482 
   483     bool GateKeeper::update_product(product p, DWORD context)
   484     {
   485         {
   486             HANDLE file = CreateFile(get_lockFile().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
   487             if (file == INVALID_HANDLE_VALUE) {
   488                 return false;
   489             }
   490             else {
   491                 CloseHandle(file);
   492                 DeleteFile(get_lockFile().c_str());
   493             }
   494         }
   495 
   496         BCRYPT_KEY_HANDLE dk = delivery_key();
   497 #ifdef UNICODE
   498         tstring delivery = utility::utf16_string(wrapped_delivery_key(dk));
   499 #else
   500         tstring delivery = wrapped_delivery_key(delivery_key());
   501 #endif
   502         tstring url = p.second;
   503         url += _T("&challenge=");
   504         url += delivery;
   505         tstring headers;
   506         HINTERNET hUrl = InternetOpenUrl(internet, url.c_str(), headers.c_str(), headers.length(),
   507             INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_UI | INTERNET_FLAG_SECURE, context);
   508         if (hUrl == NULL)
   509             return false;
   510 
   511         string crypted;
   512         string unencrypted;
   513         UCHAR iv[12];
   514         UCHAR nonce[sizeof(iv)];
   515         UCHAR tag[16];
   516         tstring filename;
   517         HANDLE hFile = NULL;
   518         char *unencrypted_buffer = NULL;
   519         bool result = false;
   520 
   521         try {
   522 
   523             DWORD reading;
   524             InternetReadFile(hUrl, iv, sizeof(iv), &reading);
   525 
   526             if (reading)
   527                 mainWindow.ShowNotificationInfo(r(IDS_DOWNLOADTITLE), r(IDS_DOWNLOADTEXT));
   528 
   529             if (reading) do {
   530                 static char buffer[1024 * 1024];
   531                 BOOL bResult = InternetReadFile(hUrl, buffer, 1024 * 1024, &reading);
   532                 if (!bResult || !reading)
   533                     break;
   534                 crypted += string(buffer, reading);
   535             } while (1);
   536 
   537             tstring contentDisposition = httpQueryCustom(hUrl, _T("Content-Disposition"));
   538 
   539             tregex filenameRegex(_T("filename=.([^\"]*)"), regex::extended); //FIXME: case insensitive
   540             tsmatch match;
   541 
   542             if (regex_search(contentDisposition, match, filenameRegex)) {
   543                 filename = match[1];
   544             }
   545 
   546             InternetCloseHandle(hUrl);
   547             hUrl = NULL;
   548 
   549             memcpy(nonce, iv, sizeof(iv));
   550 
   551             BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
   552             BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
   553             authInfo.pbNonce = nonce;
   554             authInfo.cbNonce = sizeof(nonce);
   555             authInfo.pbTag = tag;
   556             authInfo.cbTag = sizeof(tag);
   557 
   558             ULONG unencrypted_size;
   559             NTSTATUS status = BCryptDecrypt(dk, (PUCHAR)crypted.data(), crypted.size(),
   560                 &authInfo, iv, sizeof(iv), NULL, 0, &unencrypted_size, 0);
   561             if (status)
   562                 goto closing;
   563 
   564             unencrypted_buffer = new char[unencrypted_size];
   565 
   566             PUCHAR crypted_data = (PUCHAR)crypted.data();
   567             ULONG crypted_size = (ULONG)crypted.size() - sizeof(tag);
   568             memcpy(tag, crypted_data + crypted_size, sizeof(tag));
   569 
   570             status = BCryptDecrypt(dk, crypted_data, crypted_size,
   571                 &authInfo, iv, sizeof(iv), (PUCHAR)unencrypted_buffer, unencrypted_size, &unencrypted_size, 0);
   572             if (status)
   573                 goto closing;
   574 
   575             BCryptDestroyKey(dk);
   576 
   577             TCHAR download_path[MAX_PATH + 1];
   578             PWSTR _downloads;
   579             SHGetKnownFolderPath(FOLDERID_Downloads, 0, NULL, &_downloads);
   580             StringCchCopy(download_path, MAX_PATH, _downloads);
   581             CoTaskMemFree(_downloads);
   582 
   583             GetTempPath(MAX_PATH, download_path);
   584 
   585             if (filename == _T("")) {
   586                 filename = download_path;
   587                 filename += _T("\\pEp_");
   588                 filename += delivery.substr(0, 32);
   589                 filename += _T(".msi");
   590             }
   591             else {
   592                 filename = tstring(download_path) + _T("\\") + filename;
   593             }
   594 
   595             hFile = CreateFile(filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   596             if (!hFile)
   597                 goto closing;
   598             DWORD writing;
   599             WriteFile(hFile, unencrypted_buffer, unencrypted_size, &writing, NULL);
   600             CloseHandle(hFile);
   601             hFile = NULL;
   602             delete[] unencrypted_buffer;
   603             unencrypted_buffer = nullptr;
   604         }
   605         catch (exception&) {
   606             goto closing;
   607         }
   608 
   609         execute_file(filename);
   610         result = true;
   611 
   612     closing:
   613         if (unencrypted_buffer)
   614             delete[] unencrypted_buffer;
   615         if (hFile)
   616             CloseHandle(hFile);
   617         if (hUrl)
   618             InternetCloseHandle(hUrl);
   619         BCryptDestroyKey(dk);
   620 
   621         return result;
   622     }
   623 
   624     void GateKeeper::update_now()
   625     {
   626         NTSTATUS status = BCryptOpenAlgorithmProvider(&hAES, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
   627         assert(status == 0);
   628         if (status)
   629             goto closing;
   630         status = BCryptSetProperty(hAES, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
   631         if (status)
   632             goto closing;
   633 
   634         status = BCryptOpenAlgorithmProvider(&hRSA, BCRYPT_RSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
   635         assert(status == 0);
   636         if (status)
   637             goto closing;
   638 
   639         internet = InternetOpen(_T("pEp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
   640         if (!internet)
   641             goto closing;
   642 
   643         {
   644             product_list products = registered_products();
   645             DWORD context = 0;
   646 
   647             for (auto i = products.begin(); i != products.end(); i++) {
   648                 try {
   649                     update_product(*i, context++);
   650                 }
   651                 catch (exception&) {
   652 
   653                 }
   654             }
   655         }
   656 
   657     closing:
   658         if (internet)
   659             InternetCloseHandle(internet);
   660         if (hAES)
   661             BCryptCloseAlgorithmProvider(hAES, 0);
   662         if (hRSA)
   663             BCryptCloseAlgorithmProvider(hRSA, 0);
   664         internet = NULL;
   665         hAES = NULL;
   666         hRSA = NULL;
   667     }
   668 
   669     GateKeeper *GateKeeper::the_gatekeeper = nullptr;
   670 
   671 } // namespace pEp