/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "v1_0/media_key_session_service.h" #include "v1_0/media_key_system_types.h" #include "v1_0/media_decrypt_module_service.h" #include #include #include #include #include #include "base64_utils.h" #include "data_parser.h" #include "securec.h" #define HDF_LOG_TAG media_key_session_service namespace OHOS { namespace HDI { namespace Drm { namespace V1_0 { MediaKeySessionService::MediaKeySessionService() { HDF_LOGI("%{public}s: start", __func__); HDF_LOGI("%{public}s: end", __func__); } MediaKeySessionService::MediaKeySessionService(ContentProtectionLevel level) { HDF_LOGI("%{public}s: start", __func__); level_ = level; HDF_LOGI("%{public}s: end", __func__); } int32_t MediaKeySessionService::GenerateMediaKeyRequest(const MediaKeyRequestInfo &licenseRequestInfo, MediaKeyRequest &licenseRequest) { HDF_LOGI("%{public}s: start", __func__); int32_t ret = HDF_SUCCESS; licenseRequest.requestType = MEDIA_KEY_REQUEST_TYPE_INITIAL; licenseRequest.defaultUrl = "http://default.com"; if (vdiCallbackObj != nullptr) { std::string eventData = "KEY NEEDED"; std::vector data(eventData.begin(), eventData.end()); vdiCallbackObj->SendEvent(EVENTTYPE_KEYREQUIRED, 0, data); } ret = session_->getKeyRequest(licenseRequestInfo.initData, licenseRequestInfo.mimeType, licenseRequestInfo.mediaKeyType, licenseRequestInfo.optionalData, &licenseRequest.data); HDF_LOGI("%{public}s: end", __func__); return ret; } int32_t MediaKeySessionService::ProcessMediaKeyResponse(const std::vector &licenseResponse, std::vector &licenseId) { HDF_LOGI("%{public}s: start", __func__); licenseId.clear(); size_t commaPos = 0; std::vector> keyIdAndValuePairs; for (size_t i = 0; i < licenseResponse.size(); i++) { if (licenseResponse[i] == ',') { keyIdAndValuePairs.push_back( std::vector(licenseResponse.begin() + commaPos, licenseResponse.begin() + i)); commaPos = i + 1; } } keyIdAndValuePairs.push_back(std::vector(licenseResponse.begin() + commaPos, licenseResponse.end())); for (auto &keyIdAndValuePair : keyIdAndValuePairs) { size_t colonPos = 0; MediaKeyType mediaKeyType = MEDIA_KEY_TYPE_ONLINE; if (keyIdAndValuePair[0] == '0') { mediaKeyType = MEDIA_KEY_TYPE_ONLINE; } else if (keyIdAndValuePair[0] == '1') { mediaKeyType = MEDIA_KEY_TYPE_OFFLINE; } else { HDF_LOGE("%{public}s: without '0/1'", __func__); return HDF_ERR_INVALID_PARAM; } while (colonPos < keyIdAndValuePair.size() && keyIdAndValuePair[colonPos] != ':') { ++colonPos; } if (colonPos == keyIdAndValuePair.size()) { HDF_LOGE("%{public}s: without char ':'", __func__); return HDF_ERR_INVALID_PARAM; } std::string keyIdBase64(keyIdAndValuePair.begin() + 1, keyIdAndValuePair.begin() + colonPos); std::string keyValueBase64(keyIdAndValuePair.begin() + colonPos + 1, keyIdAndValuePair.end()); std::string keyIdString = Decode(keyIdBase64); std::string keyValueString = Decode(keyValueBase64); std::vector localKeyId(keyIdString.begin(), keyIdString.end()); std::vector value(keyValueString.begin(), keyValueString.end()); licenseId.assign(localKeyId.begin(), localKeyId.end()); int32_t ret = session_->setKeyIdAndKeyValue(localKeyId, value); if (ret != HDF_SUCCESS) { HDF_LOGE("%{public}s: setKeyIdAndKeyValue faild", __func__); return ret; } if (mediaKeyType == MEDIA_KEY_TYPE_OFFLINE) { offlineKeyMutex_.lock(); ret = GetOfflineKeyFromFile(); if (ret != HDF_SUCCESS) { offlineKeyMutex_.unlock(); HDF_LOGE("%{public}s: GetOfflineKeyFromFile faild", __func__); return ret; } offlineKeyIdAndKeyValueBase64_[keyIdBase64] = keyValueBase64; ret = SetOfflineKeyToFile(); if (ret != HDF_SUCCESS) { offlineKeyMutex_.unlock(); HDF_LOGE("%{public}s: SetOfflineKeyToFile faild", __func__); return ret; } session_->keyIdStatusMap[licenseId] = OFFLINE_MEDIA_KEY_STATUS_USABLE; offlineKeyMutex_.unlock(); } } if (vdiCallbackObj != nullptr) { std::vector licenseIdVec(licenseId.begin(), licenseId.end()); std::map, MediaKeySessionKeyStatus> keyStatus; MediaKeySessionKeyStatus status = MEDIA_KEY_SESSION_KEY_STATUS_USABLE; keyStatus.insert(std::make_pair(licenseIdVec, status)); vdiCallbackObj->SendEventKeyChange(keyStatus, true); } HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::CheckMediaKeyStatus(std::map& mediaKeyStatus) { HDF_LOGI("%{public}s: start", __func__); for (auto &keyValuePair : session_->keyIdAndKeyValue_) { std::string name = std::string(keyValuePair.first.begin(), keyValuePair.first.end()); std::string value = "MediaKey is OK"; mediaKeyStatus.insert(std::make_pair(name, value)); } HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::ClearMediaKeys() { HDF_LOGI("%{public}s: start", __func__); session_->keyIdAndKeyValue_.clear(); if (session_->keyIdAndKeyValue_.size() != 0) { return HDF_FAILURE; } if (vdiCallbackObj != nullptr) { std::string eventData = "KEY EXPIRED"; std::vector data(eventData.begin(), eventData.end()); vdiCallbackObj->SendEvent(EVENTTYPE_KEYEXPIRED, 0, data); } HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::GetOfflineReleaseRequest(const std::vector &licenseId, std::vector &releaseRequest) { HDF_LOGI("%{public}s: start", __func__); releaseRequest.clear(); std::string requestJson; std::vector> keyIds; keyIds.push_back(licenseId); if (generateRequest(MEDIA_KEY_TYPE_OFFLINE, keyIds, &requestJson) != HDF_SUCCESS) { HDF_LOGE("%{public}s: generateRequest failed", __func__); return HDF_ERR_INVALID_PARAM; } releaseRequest = std::vector(requestJson.begin(), requestJson.end()); HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::ProcessOfflineReleaseResponse(const std::vector &licenseId, const std::vector &response) { HDF_LOGI("%{public}s: start", __func__); std::string releaseResponseData(response.begin(), response.end()); HDF_LOGI("%{public}s: response: %{public}s", __func__, releaseResponseData.c_str()); offlineKeyMutex_.lock(); int32_t ret = GetOfflineKeyFromFile(); if (ret != HDF_SUCCESS) { offlineKeyMutex_.unlock(); return ret; } std::string keyIdString(licenseId.begin(), licenseId.end()); std::string keyIdBase64 = Encode(keyIdString); auto it = offlineKeyIdAndKeyValueBase64_.find(keyIdBase64); if (it != offlineKeyIdAndKeyValueBase64_.end()) { session_->keyIdStatusMap[licenseId] = OFFLINE_MEDIA_KEY_STATUS_INACTIVE; offlineKeyMutex_.unlock(); HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } offlineKeyMutex_.unlock(); HDF_LOGI("%{public}s: do not find offline license, keyId: %{public}s", __func__, licenseId.data()); HDF_LOGI("%{public}s: end", __func__); return HDF_FAILURE; } int32_t MediaKeySessionService::RestoreOfflineMediaKeys(const std::vector &licenseId) { HDF_LOGI("%{public}s: start", __func__); if (session_ == nullptr) { return HDF_FAILURE; } offlineKeyMutex_.lock(); int32_t ret = GetOfflineKeyFromFile(); if (ret != HDF_SUCCESS) { offlineKeyMutex_.unlock(); return ret; } std::string keyIdString(licenseId.begin(), licenseId.end()); std::string keyIdBase64 = Encode(keyIdString); keyIdBase64.erase(std::remove(keyIdBase64.begin(), keyIdBase64.end(), '\0'), keyIdBase64.end()); if (offlineKeyIdAndKeyValueBase64_.find(keyIdBase64) == offlineKeyIdAndKeyValueBase64_.end()) { offlineKeyMutex_.unlock(); HDF_LOGE("%{public}s: do not find offline license, licenseId: %{public}s", __func__, licenseId.data()); return HDF_FAILURE; } session_->keyIdStatusMap[licenseId] = OFFLINE_MEDIA_KEY_STATUS_USABLE; std::string keyValueString = Decode(offlineKeyIdAndKeyValueBase64_[keyIdBase64]); std::vector value(keyValueString.begin(), keyValueString.end()); offlineKeyIdAndKeyValueBase64_.clear(); offlineKeyMutex_.unlock(); if (vdiCallbackObj != nullptr) { std::string eventData = "KEY EXPIRATION UPDATE"; std::vector data(eventData.begin(), eventData.end()); vdiCallbackObj->SendEvent(EVENTTYPE_EXPIRATIONUPDATE, 0, data); } HDF_LOGI("%{public}s: end", __func__); return ret; } int32_t MediaKeySessionService::GetContentProtectionLevel(ContentProtectionLevel &level) { HDF_LOGI("%{public}s: start", __func__); level = level_; HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::RequiresSecureDecoderModule(const std::string &mimeType, bool &required) { HDF_LOGI("%{public}s: start", __func__); required = false; HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::SetCallback(const sptr &sessionCallback) { HDF_LOGI("%{public}s: start", __func__); vdiCallbackObj = new (std::nothrow) MediaKeySessionCallbackService(sessionCallback); if (vdiCallbackObj == nullptr) { HDF_LOGE("new MediaKeySessionCallbackService() failed"); return HDF_ERR_MALLOC_FAIL; } HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::GetMediaDecryptModule(sptr &decryptModule) { HDF_LOGI("%{public}s: start", __func__); if (decryptModule_ == nullptr) { return HDF_FAILURE; } decryptModule = decryptModule_; HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::Init() { HDF_LOGI("%{public}s: start", __func__); session_ = new (std::nothrow) Session(); if (session_ == nullptr) { return HDF_ERR_MALLOC_FAIL; } decryptModule_ = new (std::nothrow) MediaDecryptModuleService(session_); if (decryptModule_ == nullptr) { HDF_LOGE("new MediaDecryptModuleService() failed"); return HDF_ERR_MALLOC_FAIL; } HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::Destroy() { HDF_LOGI("%{public}s: start", __func__); offlineKeyMutex_.lock(); offlineKeyIdAndKeyValueBase64_.clear(); offlineKeyMutex_.unlock(); if (sessionCallback_ != nullptr) { sessionCallback_->CloseKeySessionService(this); } sessionCallback_ = nullptr; HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::SetKeySessionServiceCallback(sptr callback) { HDF_LOGI("%{public}s: start", __func__); if (callback == nullptr) { HDF_LOGE("SetKeySessionServiceCallback callback is null"); return HDF_ERR_INVALID_PARAM; } sessionCallback_ = callback; HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::GetDecryptNumber() { HDF_LOGI("%{public}s: start", __func__); HDF_LOGI("%{public}s: end", __func__); return decryptModule_->GetDecryptNumber(); } void MediaKeySessionService::GetDecryptMaxTimes(double time, std::vector &topThreeTimes) { if (topThreeTimes.size() < topThree) { topThreeTimes.push_back(time); } else { auto minIt = std::min_element(topThreeTimes.begin(), topThreeTimes.end()); if (time > *minIt) { *minIt = time; } } if (topThreeTimes.size() > topThree) { topThreeTimes.resize(topThree); } std::sort(topThreeTimes.begin(), topThreeTimes.end(), std::greater()); } int32_t MediaKeySessionService::GetDecryptTimes(std::vector &topThreeTimes) { HDF_LOGI("%{public}s: start", __func__); std::vector times; decryptModule_->GetDecryptTimes(times); for (auto time : times) { GetDecryptMaxTimes(time, topThreeTimes); } HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::GetErrorDecryptNumber() { HDF_LOGI("%{public}s: start", __func__); HDF_LOGI("%{public}s: end", __func__); return decryptModule_->GetErrorDecryptNumber(); } int32_t MediaKeySessionService::GetOfflineKeyFromFile() { HDF_LOGI("%{public}s: start", __func__); FILE *offlineKeyFile = fopen(offlineKeyFileName, "r+"); if (offlineKeyFile == NULL) { HDF_LOGE("%{public}s: open: \"%{public}s\" failed", __func__, offlineKeyFileName); // file do not exist, is allright return HDF_SUCCESS; } char keyIdBase64Chars[keyIdMaxLength]; char keyValueBase64Chars[keyIdMaxLength]; while (fscanf_s(offlineKeyFile, "%s %s", keyIdBase64Chars, sizeof(keyIdBase64Chars), keyValueBase64Chars, sizeof(keyValueBase64Chars)) != EOF) { std::string tempKeyIdBase64 = keyIdBase64Chars; std::string tempKeyValueBase64 = keyValueBase64Chars; tempKeyIdBase64.erase(std::remove(tempKeyIdBase64.begin(), tempKeyIdBase64.end(), '\0'), tempKeyIdBase64.end()); offlineKeyIdAndKeyValueBase64_[tempKeyIdBase64] = tempKeyValueBase64; } fclose(offlineKeyFile); HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } int32_t MediaKeySessionService::SetOfflineKeyToFile() { HDF_LOGI("%{public}s: start", __func__); FILE *offlineKeyFile = fopen(offlineKeyFileName, "w+"); if (offlineKeyFile == NULL) { offlineKeyIdAndKeyValueBase64_.clear(); HDF_LOGE("%{public}s: create failed, ret: %{public}s", __func__, strerror(errno)); return HDF_FAILURE; } for (auto &keyIdValueBase64Pair : offlineKeyIdAndKeyValueBase64_) { fprintf(offlineKeyFile, "%s %s\n", keyIdValueBase64Pair.first.c_str(), keyIdValueBase64Pair.second.c_str()); fflush(offlineKeyFile); } offlineKeyIdAndKeyValueBase64_.clear(); fclose(offlineKeyFile); HDF_LOGI("%{public}s: end", __func__); return HDF_SUCCESS; } } // V1_0 } // Drm } // HDI } // OHOS