1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/maintenanceservice/registrycertificates.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,136 @@ 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 <stdio.h> 1.9 +#include <stdlib.h> 1.10 +#include <windows.h> 1.11 + 1.12 +#include "registrycertificates.h" 1.13 +#include "pathhash.h" 1.14 +#include "nsWindowsHelpers.h" 1.15 +#include "servicebase.h" 1.16 +#include "updatehelper.h" 1.17 +#define MAX_KEY_LENGTH 255 1.18 + 1.19 +/** 1.20 + * Verifies if the file path matches any certificate stored in the registry. 1.21 + * 1.22 + * @param filePath The file path of the application to check if allowed. 1.23 + * @return TRUE if the binary matches any of the allowed certificates. 1.24 + */ 1.25 +BOOL 1.26 +DoesBinaryMatchAllowedCertificates(LPCWSTR basePathForUpdate, LPCWSTR filePath) 1.27 +{ 1.28 + WCHAR maintenanceServiceKey[MAX_PATH + 1]; 1.29 + if (!CalculateRegistryPathFromFilePath(basePathForUpdate, 1.30 + maintenanceServiceKey)) { 1.31 + return FALSE; 1.32 + } 1.33 + 1.34 + // We use KEY_WOW64_64KEY to always force 64-bit view. 1.35 + // The user may have both x86 and x64 applications installed 1.36 + // which each register information. We need a consistent place 1.37 + // to put those certificate attributes in and hence why we always 1.38 + // force the non redirected registry under Wow6432Node. 1.39 + // This flag is ignored on 32bit systems. 1.40 + HKEY baseKeyRaw; 1.41 + LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1.42 + maintenanceServiceKey, 0, 1.43 + KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); 1.44 + if (retCode != ERROR_SUCCESS) { 1.45 + LOG_WARN(("Could not open key. (%d)", retCode)); 1.46 + // Our tests run with a different apply directory for each test. 1.47 + // We use this registry key on our test slaves to store the 1.48 + // allowed name/issuers. 1.49 + retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1.50 + TEST_ONLY_FALLBACK_KEY_PATH, 0, 1.51 + KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); 1.52 + if (retCode != ERROR_SUCCESS) { 1.53 + LOG_WARN(("Could not open fallback key. (%d)", retCode)); 1.54 + return FALSE; 1.55 + } 1.56 + } 1.57 + nsAutoRegKey baseKey(baseKeyRaw); 1.58 + 1.59 + // Get the number of subkeys. 1.60 + DWORD subkeyCount = 0; 1.61 + retCode = RegQueryInfoKeyW(baseKey, nullptr, nullptr, nullptr, &subkeyCount, 1.62 + nullptr, nullptr, nullptr, nullptr, nullptr, 1.63 + nullptr, nullptr); 1.64 + if (retCode != ERROR_SUCCESS) { 1.65 + LOG_WARN(("Could not query info key. (%d)", retCode)); 1.66 + return FALSE; 1.67 + } 1.68 + 1.69 + // Enumerate the subkeys, each subkey represents an allowed certificate. 1.70 + for (DWORD i = 0; i < subkeyCount; i++) { 1.71 + WCHAR subkeyBuffer[MAX_KEY_LENGTH]; 1.72 + DWORD subkeyBufferCount = MAX_KEY_LENGTH; 1.73 + retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer, 1.74 + &subkeyBufferCount, nullptr, 1.75 + nullptr, nullptr, nullptr); 1.76 + if (retCode != ERROR_SUCCESS) { 1.77 + LOG_WARN(("Could not enum certs. (%d)", retCode)); 1.78 + return FALSE; 1.79 + } 1.80 + 1.81 + // Open the subkey for the current certificate 1.82 + HKEY subKeyRaw; 1.83 + retCode = RegOpenKeyExW(baseKey, 1.84 + subkeyBuffer, 1.85 + 0, 1.86 + KEY_READ | KEY_WOW64_64KEY, 1.87 + &subKeyRaw); 1.88 + nsAutoRegKey subKey(subKeyRaw); 1.89 + if (retCode != ERROR_SUCCESS) { 1.90 + LOG_WARN(("Could not open subkey. (%d)", retCode)); 1.91 + continue; // Try the next subkey 1.92 + } 1.93 + 1.94 + const int MAX_CHAR_COUNT = 256; 1.95 + DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); 1.96 + WCHAR name[MAX_CHAR_COUNT] = { L'\0' }; 1.97 + WCHAR issuer[MAX_CHAR_COUNT] = { L'\0' }; 1.98 + 1.99 + // Get the name from the registry 1.100 + retCode = RegQueryValueExW(subKey, L"name", 0, nullptr, 1.101 + (LPBYTE)name, &valueBufSize); 1.102 + if (retCode != ERROR_SUCCESS) { 1.103 + LOG_WARN(("Could not obtain name from registry. (%d)", retCode)); 1.104 + continue; // Try the next subkey 1.105 + } 1.106 + 1.107 + // Get the issuer from the registry 1.108 + valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); 1.109 + retCode = RegQueryValueExW(subKey, L"issuer", 0, nullptr, 1.110 + (LPBYTE)issuer, &valueBufSize); 1.111 + if (retCode != ERROR_SUCCESS) { 1.112 + LOG_WARN(("Could not obtain issuer from registry. (%d)", retCode)); 1.113 + continue; // Try the next subkey 1.114 + } 1.115 + 1.116 + CertificateCheckInfo allowedCertificate = { 1.117 + name, 1.118 + issuer, 1.119 + }; 1.120 + 1.121 + retCode = CheckCertificateForPEFile(filePath, allowedCertificate); 1.122 + if (retCode != ERROR_SUCCESS) { 1.123 + LOG_WARN(("Error on certificate check. (%d)", retCode)); 1.124 + continue; // Try the next subkey 1.125 + } 1.126 + 1.127 + retCode = VerifyCertificateTrustForFile(filePath); 1.128 + if (retCode != ERROR_SUCCESS) { 1.129 + LOG_WARN(("Error on certificate trust check. (%d)", retCode)); 1.130 + continue; // Try the next subkey 1.131 + } 1.132 + 1.133 + // Raise the roof, we found a match! 1.134 + return TRUE; 1.135 + } 1.136 + 1.137 + // No certificates match, :'( 1.138 + return FALSE; 1.139 +}