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