1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/mozapps/update/common/pathhash.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,139 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <windows.h> 1.9 +#include <wincrypt.h> 1.10 +#include "pathhash.h" 1.11 + 1.12 + 1.13 +/** 1.14 + * Converts a binary sequence into a hex string 1.15 + * 1.16 + * @param hash The binary data sequence 1.17 + * @param hashSize The size of the binary data sequence 1.18 + * @param hexString A buffer to store the hex string, must be of 1.19 + * size 2 * @hashSize 1.20 +*/ 1.21 +static void 1.22 +BinaryDataToHexString(const BYTE *hash, DWORD &hashSize, 1.23 + LPWSTR hexString) 1.24 +{ 1.25 + WCHAR *p = hexString; 1.26 + for (DWORD i = 0; i < hashSize; ++i) { 1.27 + wsprintfW(p, L"%.2x", hash[i]); 1.28 + p += 2; 1.29 + } 1.30 +} 1.31 + 1.32 +/** 1.33 + * Calculates an MD5 hash for the given input binary data 1.34 + * 1.35 + * @param data Any sequence of bytes 1.36 + * @param dataSize The number of bytes inside @data 1.37 + * @param hash Output buffer to store hash, must be freed by the caller 1.38 + * @param hashSize The number of bytes in the output buffer 1.39 + * @return TRUE on success 1.40 +*/ 1.41 +static BOOL 1.42 +CalculateMD5(const char *data, DWORD dataSize, 1.43 + BYTE **hash, DWORD &hashSize) 1.44 +{ 1.45 + HCRYPTPROV hProv = 0; 1.46 + HCRYPTHASH hHash = 0; 1.47 + 1.48 + if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, 1.49 + CRYPT_VERIFYCONTEXT)) { 1.50 + if (NTE_BAD_KEYSET != GetLastError()) { 1.51 + return FALSE; 1.52 + } 1.53 + 1.54 + // Maybe it doesn't exist, try to create it. 1.55 + if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, 1.56 + CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)) { 1.57 + return FALSE; 1.58 + } 1.59 + } 1.60 + 1.61 + if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { 1.62 + return FALSE; 1.63 + } 1.64 + 1.65 + if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(data), 1.66 + dataSize, 0)) { 1.67 + return FALSE; 1.68 + } 1.69 + 1.70 + DWORD dwCount = sizeof(DWORD); 1.71 + if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashSize, 1.72 + &dwCount, 0)) { 1.73 + return FALSE; 1.74 + } 1.75 + 1.76 + *hash = new BYTE[hashSize]; 1.77 + ZeroMemory(*hash, hashSize); 1.78 + if (!CryptGetHashParam(hHash, HP_HASHVAL, *hash, &hashSize, 0)) { 1.79 + return FALSE; 1.80 + } 1.81 + 1.82 + if (hHash) { 1.83 + CryptDestroyHash(hHash); 1.84 + } 1.85 + 1.86 + if (hProv) { 1.87 + CryptReleaseContext(hProv,0); 1.88 + } 1.89 + 1.90 + return TRUE; 1.91 +} 1.92 + 1.93 +/** 1.94 + * Converts a file path into a unique registry location for cert storage 1.95 + * 1.96 + * @param filePath The input file path to get a registry path from 1.97 + * @param registryPath A buffer to write the registry path to, must 1.98 + * be of size in WCHARs MAX_PATH + 1 1.99 + * @return TRUE if successful 1.100 +*/ 1.101 +BOOL 1.102 +CalculateRegistryPathFromFilePath(const LPCWSTR filePath, 1.103 + LPWSTR registryPath) 1.104 +{ 1.105 + size_t filePathLen = wcslen(filePath); 1.106 + if (!filePathLen) { 1.107 + return FALSE; 1.108 + } 1.109 + 1.110 + // If the file path ends in a slash, ignore that character 1.111 + if (filePath[filePathLen -1] == L'\\' || 1.112 + filePath[filePathLen - 1] == L'/') { 1.113 + filePathLen--; 1.114 + } 1.115 + 1.116 + // Copy in the full path into our own buffer. 1.117 + // Copying in the extra slash is OK because we calculate the hash 1.118 + // based on the filePathLen which excludes the slash. 1.119 + // +2 to account for the possibly trailing slash and the null terminator. 1.120 + WCHAR *lowercasePath = new WCHAR[filePathLen + 2]; 1.121 + memset(lowercasePath, 0, (filePathLen + 2) * sizeof(WCHAR)); 1.122 + wcsncpy(lowercasePath, filePath, filePathLen + 1); 1.123 + _wcslwr(lowercasePath); 1.124 + 1.125 + BYTE *hash; 1.126 + DWORD hashSize = 0; 1.127 + if (!CalculateMD5(reinterpret_cast<const char*>(lowercasePath), 1.128 + filePathLen * 2, 1.129 + &hash, hashSize)) { 1.130 + delete[] lowercasePath; 1.131 + return FALSE; 1.132 + } 1.133 + delete[] lowercasePath; 1.134 + 1.135 + LPCWSTR baseRegPath = L"SOFTWARE\\Mozilla\\" 1.136 + L"MaintenanceService\\"; 1.137 + wcsncpy(registryPath, baseRegPath, MAX_PATH); 1.138 + BinaryDataToHexString(hash, hashSize, 1.139 + registryPath + wcslen(baseRegPath)); 1.140 + delete[] hash; 1.141 + return TRUE; 1.142 +}