gmp-clearkey.cpp (5121B)
1 /* 2 * Copyright 2015, Mozilla Foundation and contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <assert.h> 18 // This include is required in order for content_decryption_module to work 19 // on Unix systems. 20 #include <stddef.h> 21 #include <string.h> 22 23 #include <string> 24 #include <vector> 25 26 #include "content_decryption_module.h" 27 #include "content_decryption_module_ext.h" 28 #include "nss.h" 29 30 #include "ClearKeyCDM.h" 31 #include "ClearKeySessionManager.h" 32 #include "mozilla/dom/KeySystemNames.h" 33 34 #ifndef XP_WIN 35 # include <sys/types.h> 36 # include <sys/stat.h> 37 # include <unistd.h> 38 #endif 39 40 #ifdef ENABLE_WMF 41 # include "WMFUtils.h" 42 #endif // ENABLE_WMF 43 44 extern "C" { 45 46 CDM_API 47 void INITIALIZE_CDM_MODULE() {} 48 49 static bool sCanReadHostVerificationFiles = false; 50 51 CDM_API 52 void* CreateCdmInstance(int cdm_interface_version, const char* key_system, 53 uint32_t key_system_size, 54 GetCdmHostFunc get_cdm_host_func, void* user_data) { 55 CK_LOGE("ClearKey CreateCDMInstance"); 56 57 if (cdm_interface_version != cdm::ContentDecryptionModule_11::kVersion) { 58 CK_LOGE( 59 "ClearKey CreateCDMInstance failed due to requesting unsupported " 60 "version %d.", 61 cdm_interface_version); 62 return nullptr; 63 } 64 #ifdef ENABLE_WMF 65 if (!wmf::EnsureLibs()) { 66 CK_LOGE("Required libraries were not found"); 67 return nullptr; 68 } 69 #endif 70 71 if (NSS_NoDB_Init(nullptr) == SECFailure) { 72 CK_LOGE("Unable to initialize NSS"); 73 return nullptr; 74 } 75 76 #ifdef MOZILLA_OFFICIAL 77 // Test that we're able to read the host files. 78 if (!sCanReadHostVerificationFiles) { 79 return nullptr; 80 } 81 #endif 82 83 cdm::Host_11* host = static_cast<cdm::Host_11*>( 84 get_cdm_host_func(cdm_interface_version, user_data)); 85 ClearKeyCDM* clearKey = new ClearKeyCDM(host); 86 87 CK_LOGE("Created ClearKeyCDM instance!"); 88 89 if (strncmp(key_system, mozilla::kClearKeyWithProtectionQueryKeySystemName, 90 key_system_size) == 0) { 91 CK_LOGE("Enabling protection query on ClearKeyCDM instance!"); 92 clearKey->EnableProtectionQuery(); 93 } 94 95 return clearKey; 96 } 97 98 const size_t TEST_READ_SIZE = 16 * 1024; 99 100 bool CanReadSome(cdm::PlatformFile aFile) { 101 std::vector<uint8_t> data; 102 data.resize(TEST_READ_SIZE); 103 #ifdef XP_WIN 104 DWORD bytesRead = 0; 105 return ReadFile(aFile, &data.front(), TEST_READ_SIZE, &bytesRead, nullptr) && 106 bytesRead > 0; 107 #else 108 return read(aFile, &data.front(), TEST_READ_SIZE) > 0; 109 #endif 110 } 111 112 void ClosePlatformFile(cdm::PlatformFile aFile) { 113 #ifdef XP_WIN 114 CloseHandle(aFile); 115 #else 116 close(aFile); 117 #endif 118 } 119 120 static uint32_t NumExpectedHostFiles(const cdm::HostFile* aHostFiles, 121 uint32_t aNumFiles) { 122 #if defined(ANDROID) 123 // We expect 1 binary: clearkey 124 return 1; 125 #elif !defined(XP_WIN) 126 // We expect 4 binaries: clearkey, libxul, plugin-container, and Firefox. 127 return 4; 128 #else 129 // Windows running x64 or x86 natively should also have 4 as above. 130 // For Windows on ARM64, we run an x86 plugin-contianer process under 131 // emulation, and so we expect one additional binary; the x86 132 // xul.dll used by plugin-container.exe. 133 bool i686underAArch64 = false; 134 // Assume that we're running under x86 emulation on an aarch64 host if 135 // one of the paths ends with the x86 plugin-container path we'd expect. 136 const std::wstring plugincontainer = L"i686\\plugin-container.exe"; 137 for (uint32_t i = 0; i < aNumFiles; i++) { 138 const cdm::HostFile& hostFile = aHostFiles[i]; 139 if (hostFile.file != cdm::kInvalidPlatformFile) { 140 std::wstring path = hostFile.file_path; 141 auto offset = path.find(plugincontainer); 142 if (offset != std::string::npos && 143 offset == path.size() - plugincontainer.size()) { 144 i686underAArch64 = true; 145 break; 146 } 147 } 148 } 149 return i686underAArch64 ? 5 : 4; 150 #endif 151 } 152 153 CDM_API 154 bool VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles) { 155 // Check that we've received the expected number of host files. 156 bool rv = (aNumFiles == NumExpectedHostFiles(aHostFiles, aNumFiles)); 157 // Verify that each binary is readable inside the sandbox, 158 // and close the handle. 159 for (uint32_t i = 0; i < aNumFiles; i++) { 160 const cdm::HostFile& hostFile = aHostFiles[i]; 161 if (hostFile.file != cdm::kInvalidPlatformFile) { 162 if (!CanReadSome(hostFile.file)) { 163 rv = false; 164 } 165 ClosePlatformFile(hostFile.file); 166 } 167 if (hostFile.sig_file != cdm::kInvalidPlatformFile) { 168 ClosePlatformFile(hostFile.sig_file); 169 } 170 } 171 sCanReadHostVerificationFiles = rv; 172 return rv; 173 } 174 175 } // extern "C".