1 /*
2 * Copyright (C) 2021 The Android Open Source Project
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 #include <utils/Log.h>
17
18 #include <sys/stat.h>
19 #include <string>
20
21 #include "DeviceFiles.h"
22 #include "protos/DeviceFiles.pb.h"
23
24 #include <openssl/sha.h>
25
26 // Protobuf generated classes.
27 using clearkeydrm::HashedFile;
28 using clearkeydrm::License;
29 using clearkeydrm::License_LicenseState_ACTIVE;
30 using clearkeydrm::License_LicenseState_RELEASING;
31 using clearkeydrm::OfflineFile;
32
33 namespace {
34 const char kLicenseFileNameExt[] = ".lic";
35
Hash(const std::string & data,std::string * hash)36 bool Hash(const std::string& data, std::string* hash) {
37 if (!hash) return false;
38
39 hash->resize(SHA256_DIGEST_LENGTH);
40
41 const unsigned char* input = reinterpret_cast<const unsigned char*>(data.data());
42 unsigned char* output = reinterpret_cast<unsigned char*>(&(*hash)[0]);
43 SHA256(input, data.size(), output);
44 return true;
45 }
46
47 } // namespace
48
49 namespace clearkeydrm {
50
StoreLicense(const std::string & keySetId,LicenseState state,const std::string & licenseResponse)51 bool DeviceFiles::StoreLicense(const std::string& keySetId, LicenseState state,
52 const std::string& licenseResponse) {
53 OfflineFile file;
54 file.set_type(OfflineFile::LICENSE);
55 file.set_version(OfflineFile::VERSION_1);
56
57 License* license = file.mutable_license();
58 switch (state) {
59 case kLicenseStateActive:
60 license->set_state(License_LicenseState_ACTIVE);
61 license->set_license(licenseResponse);
62 break;
63 case kLicenseStateReleasing:
64 license->set_state(License_LicenseState_RELEASING);
65 license->set_license(licenseResponse);
66 break;
67 default:
68 ALOGW("StoreLicense: Unknown license state: %u", state);
69 return false;
70 }
71
72 std::string serializedFile;
73 file.SerializeToString(&serializedFile);
74
75 return StoreFileWithHash(keySetId + kLicenseFileNameExt, serializedFile);
76 }
77
StoreFileWithHash(const std::string & fileName,const std::string & serializedFile)78 bool DeviceFiles::StoreFileWithHash(const std::string& fileName,
79 const std::string& serializedFile) {
80 std::string hash;
81 if (!Hash(serializedFile, &hash)) {
82 ALOGE("StoreFileWithHash: Failed to compute hash");
83 return false;
84 }
85
86 HashedFile hashFile;
87 hashFile.set_file(serializedFile);
88 hashFile.set_hash(hash);
89
90 std::string serializedHashFile;
91 hashFile.SerializeToString(&serializedHashFile);
92
93 return StoreFileRaw(fileName, serializedHashFile);
94 }
95
StoreFileRaw(const std::string & fileName,const std::string & serializedHashFile)96 bool DeviceFiles::StoreFileRaw(const std::string& fileName, const std::string& serializedHashFile) {
97 MemoryFileSystem::MemoryFile memFile;
98 memFile.setFileName(fileName);
99 memFile.setContent(serializedHashFile);
100 memFile.setFileSize(serializedHashFile.size());
101 size_t len = mFileHandle.Write(fileName, memFile);
102
103 if (len != static_cast<size_t>(serializedHashFile.size())) {
104 ALOGE("StoreFileRaw: Failed to write %s", fileName.c_str());
105 ALOGD("StoreFileRaw: expected=%zd, actual=%zu", serializedHashFile.size(), len);
106 return false;
107 }
108
109 ALOGD("StoreFileRaw: wrote %zu bytes to %s", serializedHashFile.size(), fileName.c_str());
110 return true;
111 }
112
RetrieveLicense(const std::string & keySetId,LicenseState * state,std::string * offlineLicense)113 bool DeviceFiles::RetrieveLicense(const std::string& keySetId, LicenseState* state,
114 std::string* offlineLicense) {
115 OfflineFile file;
116 if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
117 return false;
118 }
119
120 if (file.type() != OfflineFile::LICENSE) {
121 ALOGE("RetrieveLicense: Invalid file type");
122 return false;
123 }
124
125 if (file.version() != OfflineFile::VERSION_1) {
126 ALOGE("RetrieveLicense: Invalid file version");
127 return false;
128 }
129
130 if (!file.has_license()) {
131 ALOGE("RetrieveLicense: License not present");
132 return false;
133 }
134
135 License license = file.license();
136 switch (license.state()) {
137 case License_LicenseState_ACTIVE:
138 *state = kLicenseStateActive;
139 break;
140 case License_LicenseState_RELEASING:
141 *state = kLicenseStateReleasing;
142 break;
143 default:
144 ALOGW("RetrieveLicense: Unrecognized license state: %u", kLicenseStateUnknown);
145 *state = kLicenseStateUnknown;
146 break;
147 }
148 *offlineLicense = license.license();
149 return true;
150 }
151
DeleteLicense(const std::string & keySetId)152 bool DeviceFiles::DeleteLicense(const std::string& keySetId) {
153 return mFileHandle.RemoveFile(keySetId + kLicenseFileNameExt);
154 }
155
DeleteAllLicenses()156 bool DeviceFiles::DeleteAllLicenses() {
157 return mFileHandle.RemoveAllFiles();
158 }
159
LicenseExists(const std::string & keySetId)160 bool DeviceFiles::LicenseExists(const std::string& keySetId) {
161 return mFileHandle.FileExists(keySetId + kLicenseFileNameExt);
162 }
163
ListLicenses() const164 std::vector<std::string> DeviceFiles::ListLicenses() const {
165 std::vector<std::string> licenses = mFileHandle.ListFiles();
166 for (size_t i = 0; i < licenses.size(); i++) {
167 std::string& license = licenses[i];
168 license = license.substr(0, license.size() - strlen(kLicenseFileNameExt));
169 }
170 return licenses;
171 }
172
RetrieveHashedFile(const std::string & fileName,OfflineFile * deSerializedFile)173 bool DeviceFiles::RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile) {
174 if (!deSerializedFile) {
175 ALOGE("RetrieveHashedFile: invalid file parameter");
176 return false;
177 }
178
179 if (!FileExists(fileName)) {
180 ALOGE("RetrieveHashedFile: %s does not exist", fileName.c_str());
181 return false;
182 }
183
184 ssize_t bytes = GetFileSize(fileName);
185 if (bytes <= 0) {
186 ALOGE("RetrieveHashedFile: invalid file size: %s", fileName.c_str());
187 // Remove the corrupted file so the caller will not get the same error
188 // when trying to access the file repeatedly, causing the system to stall.
189 RemoveFile(fileName);
190 return false;
191 }
192
193 std::string serializedHashFile;
194 serializedHashFile.resize(bytes);
195 bytes = mFileHandle.Read(fileName, &serializedHashFile);
196
197 if (bytes != static_cast<ssize_t>(serializedHashFile.size())) {
198 ALOGE("RetrieveHashedFile: Failed to read from %s", fileName.c_str());
199 ALOGV("RetrieveHashedFile: expected: %zd, actual: %zd", serializedHashFile.size(), bytes);
200 // Remove the corrupted file so the caller will not get the same error
201 // when trying to access the file repeatedly, causing the system to stall.
202 RemoveFile(fileName);
203 return false;
204 }
205
206 ALOGV("RetrieveHashedFile: read %zd from %s", bytes, fileName.c_str());
207
208 HashedFile hashFile;
209 if (!hashFile.ParseFromString(serializedHashFile)) {
210 ALOGE("RetrieveHashedFile: Unable to parse hash file");
211 // Remove corrupt file.
212 RemoveFile(fileName);
213 return false;
214 }
215
216 std::string hash;
217 if (!Hash(hashFile.file(), &hash)) {
218 ALOGE("RetrieveHashedFile: Hash computation failed");
219 return false;
220 }
221
222 if (hash != hashFile.hash()) {
223 ALOGE("RetrieveHashedFile: Hash mismatch");
224 // Remove corrupt file.
225 RemoveFile(fileName);
226 return false;
227 }
228
229 if (!deSerializedFile->ParseFromString(hashFile.file())) {
230 ALOGE("RetrieveHashedFile: Unable to parse file");
231 // Remove corrupt file.
232 RemoveFile(fileName);
233 return false;
234 }
235
236 return true;
237 }
238
FileExists(const std::string & fileName) const239 bool DeviceFiles::FileExists(const std::string& fileName) const {
240 return mFileHandle.FileExists(fileName);
241 }
242
RemoveFile(const std::string & fileName)243 bool DeviceFiles::RemoveFile(const std::string& fileName) {
244 return mFileHandle.RemoveFile(fileName);
245 }
246
GetFileSize(const std::string & fileName) const247 ssize_t DeviceFiles::GetFileSize(const std::string& fileName) const {
248 return mFileHandle.GetFileSize(fileName);
249 }
250
251 } // namespace clearkeydrm
252