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 #include <stdio.h>
19 #include <string.h>
20 #include <vector>
21 #include <string>
22
23 #include "ClearKeyCDM.h"
24 #include "ClearKeySessionManager.h"
25 // This include is required in order for content_decryption_module to work
26 // on Unix systems.
27 #include "stddef.h"
28 #include "content_decryption_module.h"
29 #include "content_decryption_module_ext.h"
30 #include "nss.h"
31
32 #ifndef XP_WIN
33 # include <sys/types.h>
34 # include <sys/stat.h>
35 # include <unistd.h>
36 #endif
37
38 #ifdef ENABLE_WMF
39 # include "WMFUtils.h"
40 #endif // ENABLE_WMF
41
42 extern "C" {
43
44 CDM_API
INITIALIZE_CDM_MODULE()45 void INITIALIZE_CDM_MODULE() {}
46
47 static bool sCanReadHostVerificationFiles = false;
48
49 CDM_API
CreateCdmInstance(int cdm_interface_version,const char * key_system,uint32_t key_system_size,GetCdmHostFunc get_cdm_host_func,void * user_data)50 void* CreateCdmInstance(int cdm_interface_version, const char* key_system,
51 uint32_t key_system_size,
52 GetCdmHostFunc get_cdm_host_func, void* user_data) {
53 CK_LOGE("ClearKey CreateCDMInstance");
54
55 if (cdm_interface_version != cdm::ContentDecryptionModule_10::kVersion) {
56 CK_LOGE(
57 "ClearKey CreateCDMInstance failed due to requesting unsupported "
58 "version %d.",
59 cdm_interface_version);
60 return nullptr;
61 }
62 #ifdef ENABLE_WMF
63 if (!wmf::EnsureLibs()) {
64 CK_LOGE("Required libraries were not found");
65 return nullptr;
66 }
67 #endif
68
69 if (NSS_NoDB_Init(nullptr) == SECFailure) {
70 CK_LOGE("Unable to initialize NSS");
71 return nullptr;
72 }
73
74 #ifdef MOZILLA_OFFICIAL
75 // Test that we're able to read the host files.
76 if (!sCanReadHostVerificationFiles) {
77 return nullptr;
78 }
79 #endif
80
81 cdm::Host_10* host = static_cast<cdm::Host_10*>(
82 get_cdm_host_func(cdm_interface_version, user_data));
83 ClearKeyCDM* clearKey = new ClearKeyCDM(host);
84
85 CK_LOGE("Created ClearKeyCDM instance!");
86
87 return clearKey;
88 }
89
90 const size_t TEST_READ_SIZE = 16 * 1024;
91
CanReadSome(cdm::PlatformFile aFile)92 bool CanReadSome(cdm::PlatformFile aFile) {
93 std::vector<uint8_t> data;
94 data.resize(TEST_READ_SIZE);
95 #ifdef XP_WIN
96 DWORD bytesRead = 0;
97 return ReadFile(aFile, &data.front(), TEST_READ_SIZE, &bytesRead, nullptr) &&
98 bytesRead > 0;
99 #else
100 return read(aFile, &data.front(), TEST_READ_SIZE) > 0;
101 #endif
102 }
103
ClosePlatformFile(cdm::PlatformFile aFile)104 void ClosePlatformFile(cdm::PlatformFile aFile) {
105 #ifdef XP_WIN
106 CloseHandle(aFile);
107 #else
108 close(aFile);
109 #endif
110 }
111
NumExpectedHostFiles(const cdm::HostFile * aHostFiles,uint32_t aNumFiles)112 static uint32_t NumExpectedHostFiles(const cdm::HostFile* aHostFiles,
113 uint32_t aNumFiles) {
114 #if !defined(XP_WIN)
115 // We expect 4 binaries: clearkey, libxul, plugin-container, and Firefox.
116 return 4;
117 #else
118 // Windows running x64 or x86 natively should also have 4 as above.
119 // For Windows on ARM64, we run an x86 plugin-contianer process under
120 // emulation, and so we expect one additional binary; the x86
121 // xul.dll used by plugin-container.exe.
122 bool i686underAArch64 = false;
123 // Assume that we're running under x86 emulation on an aarch64 host if
124 // one of the paths ends with the x86 plugin-container path we'd expect.
125 const std::wstring plugincontainer = L"i686\\plugin-container.exe";
126 for (uint32_t i = 0; i < aNumFiles; i++) {
127 const cdm::HostFile& hostFile = aHostFiles[i];
128 if (hostFile.file != cdm::kInvalidPlatformFile) {
129 std::wstring path = hostFile.file_path;
130 auto offset = path.find(plugincontainer);
131 if (offset != std::string::npos &&
132 offset == path.size() - plugincontainer.size()) {
133 i686underAArch64 = true;
134 break;
135 }
136 }
137 }
138 return i686underAArch64 ? 5 : 4;
139 #endif
140 }
141
142 CDM_API
VerifyCdmHost_0(const cdm::HostFile * aHostFiles,uint32_t aNumFiles)143 bool VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles) {
144 // Check that we've received the expected number of host files.
145 bool rv = (aNumFiles == NumExpectedHostFiles(aHostFiles, aNumFiles));
146 // Verify that each binary is readable inside the sandbox,
147 // and close the handle.
148 for (uint32_t i = 0; i < aNumFiles; i++) {
149 const cdm::HostFile& hostFile = aHostFiles[i];
150 if (hostFile.file != cdm::kInvalidPlatformFile) {
151 if (!CanReadSome(hostFile.file)) {
152 rv = false;
153 }
154 ClosePlatformFile(hostFile.file);
155 }
156 if (hostFile.sig_file != cdm::kInvalidPlatformFile) {
157 ClosePlatformFile(hostFile.sig_file);
158 }
159 }
160 sCanReadHostVerificationFiles = rv;
161 return rv;
162 }
163
164 } // extern "C".
165