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