From 0176d00e21e6a0b60f49be3ff9c031e2c05217e7 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 15:56:48 +0200 Subject: [PATCH 01/11] [DRM][ClearKey] Add support to licenseUrl by prop --- src/CompKodiProps.cpp | 29 +++++++++++-------- src/CompKodiProps.h | 10 ++++++- src/Session.cpp | 3 +- .../ClearKeyCencSingleSampleDecrypter.cpp | 7 ++++- .../ClearKeyCencSingleSampleDecrypter.h | 1 + src/decrypters/clearkey/ClearKeyDecrypter.cpp | 13 ++++++--- 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/CompKodiProps.cpp b/src/CompKodiProps.cpp index bb72a3487..25264706b 100644 --- a/src/CompKodiProps.cpp +++ b/src/CompKodiProps.cpp @@ -416,7 +416,7 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data) for (auto const& keyid : jDictLic["keyids"].GetObject()) { if (keyid.name.IsString() && keyid.value.IsString()) - drmCfg.m_keys[keyid.name.GetString()] = (keyid.value.GetString()); + drmCfg.license.keys[keyid.name.GetString()] = (keyid.value.GetString()); } } } @@ -460,15 +460,13 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmLegacyConfig(const std::string& da } m_licenseType = keySystem; - - // Clear existing value to prevent possible mix with other similar properties - m_licenseKey.clear(); + std::string licenseUrl; if (!licenseStr.empty()) { if (URL::IsValidUrl(licenseStr)) // License server URL { - m_licenseKey = licenseStr; + licenseUrl = licenseStr; } else // Assume are keyid's for ClearKey DRM { @@ -484,17 +482,24 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmLegacyConfig(const std::string& da LOG::LogF(LOGERROR, "Ignored malformed ClearKey kid/key pair"); continue; } - drmCfg.m_keys[STRING::Trim(keyPair[0])] = STRING::Trim(keyPair[1]); + drmCfg.license.keys[STRING::Trim(keyPair[0])] = STRING::Trim(keyPair[1]); } } } - //! @todo: temporary stored default DRM values here just for convenience - //! since we need to construct the "license key" string - //! these values are stored also on DRM's implementation, - //! they must be placed in an appropriate place with the future DRM config rework - if (licenseHeaders.empty()) + if (keySystem == DRM::KS_CLEARKEY) + { + DrmCfg& drmCfg = m_drmConfigs[keySystem]; + + drmCfg.license.serverUrl = licenseUrl; + ParseHeaderString(drmCfg.license.reqHeaders, licenseHeaders); + } + else if (licenseHeaders.empty()) { + //! @todo: temporary stored default DRM values here just for convenience + //! since we need to construct the "license key" string + //! these values are stored also on DRM's implementation, + //! they must be placed in an appropriate place with the future DRM config rework if (keySystem == DRM::KS_WIDEVINE) licenseHeaders = "Content-Type=application%2Foctet-stream"; else if (keySystem == DRM::KS_PLAYREADY) @@ -504,6 +509,6 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmLegacyConfig(const std::string& da licenseHeaders = "Content-Type=application/json"; } - m_licenseKey += "|" + licenseHeaders + "|R{SSM}|R"; + m_licenseKey = licenseUrl + "|" + licenseHeaders + "|R{SSM}|R"; return true; } diff --git a/src/CompKodiProps.h b/src/CompKodiProps.h index 69f37ca46..e207cd029 100644 --- a/src/CompKodiProps.h +++ b/src/CompKodiProps.h @@ -70,7 +70,15 @@ struct ManifestConfig struct DrmCfg { - std::map m_keys; + struct License + { + std::string serverUrl; + std::map reqHeaders; + + std::map keys; // Clearkeys kid / key + }; + + License license; // The license configuration }; class ATTR_DLL_LOCAL CCompKodiProps diff --git a/src/Session.cpp b/src/Session.cpp index d0856bff4..8ff6d7d8f 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -454,9 +454,10 @@ bool CSession::InitializeDRM(bool addDefaultKID /* = false */) // Use the init data provided by manifest (e.g. PSSH) initData = sessionPsshset.pssh_; } - else + else if (licenseType != DRM::KS_CLEARKEY) { // Try extract the PSSH/KID from the stream + // only if clearkeys are not used (use case e.g. Widevine manifest tested with ClearKey DRM) if (!ExtractStreamProtectionData(sessionPsshset, initData, m_adaptiveTree->m_supportedKeySystems)) LOG::Log(LOGERROR, "License data: Cannot extract PSSH/KID data from the stream"); } diff --git a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp index ee17c5d66..789837415 100644 --- a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp +++ b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp @@ -26,7 +26,10 @@ using namespace UTILS; CClearKeyCencSingleSampleDecrypter::CClearKeyCencSingleSampleDecrypter( - std::string_view licenseUrl, const std::vector& defaultKeyId, CClearKeyDecrypter* host) + std::string_view licenseUrl, + const std::map& licenseHeaders, + const std::vector& defaultKeyId, + CClearKeyDecrypter* host) : m_host(host) { if (licenseUrl.empty()) @@ -47,6 +50,8 @@ CClearKeyCencSingleSampleDecrypter::CClearKeyCencSingleSampleDecrypter( CURL::CUrl curl{licenseUrl}; curl.AddHeader("Accept", "application/json"); curl.AddHeader("Content-Type", "application/json"); + curl.AddHeaders(licenseHeaders); + curl.AddHeader("postdata", UTILS::BASE64::Encode(postData)); std::string response; diff --git a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.h b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.h index 724fae69b..f707859f3 100644 --- a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.h +++ b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.h @@ -17,6 +17,7 @@ class CClearKeyCencSingleSampleDecrypter : public Adaptive_CencSingleSampleDecry { public: CClearKeyCencSingleSampleDecrypter(std::string_view licenseUrl, + const std::map& licenseHeaders, const std::vector& defaultKeyId, CClearKeyDecrypter* host); CClearKeyCencSingleSampleDecrypter(const std::vector& initdata, diff --git a/src/decrypters/clearkey/ClearKeyDecrypter.cpp b/src/decrypters/clearkey/ClearKeyDecrypter.cpp index aea35c5b4..08944445c 100644 --- a/src/decrypters/clearkey/ClearKeyDecrypter.cpp +++ b/src/decrypters/clearkey/ClearKeyDecrypter.cpp @@ -40,15 +40,20 @@ Adaptive_CencSingleSampleDecrypter* CClearKeyDecrypter::CreateSingleSampleDecryp CryptoMode cryptoMode) { CClearKeyCencSingleSampleDecrypter* decrypter = nullptr; - auto& keys = CSrvBroker::GetKodiProps().GetDrmConfig(std::string(DRM::KS_CLEARKEY)).m_keys; + auto& cfgLic = CSrvBroker::GetKodiProps().GetDrmConfig(std::string(DRM::KS_CLEARKEY)).license; - if (!keys.empty() || !initData.empty()) // Keys provided from manifest or Kodi property + // If keys / license url are provided by Kodi property, those of the manifest will be overwritten + + if (!cfgLic.serverUrl.empty()) + licenseUrl = cfgLic.serverUrl; + + if ((!cfgLic.keys.empty() || !initData.empty()) && cfgLic.serverUrl.empty()) // Keys provided from manifest or Kodi property { - decrypter = new CClearKeyCencSingleSampleDecrypter(initData, defaultkeyid, keys, this); + decrypter = new CClearKeyCencSingleSampleDecrypter(initData, defaultkeyid, cfgLic.keys, this); } else // Clearkey license server URL provided { - decrypter = new CClearKeyCencSingleSampleDecrypter(licenseUrl, defaultkeyid, this); + decrypter = new CClearKeyCencSingleSampleDecrypter(licenseUrl, cfgLic.reqHeaders, defaultkeyid, this); } if (!decrypter->HasKeys()) From 275a4ae53e356ce79fb7dcfd62b5085dafaa43b2 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 15:57:35 +0200 Subject: [PATCH 02/11] [HLSTree] If ClearKey as KS, parse Widevine KID This should allow play Widevine streams by using ClearKey DRM untested since i havent found a sample --- src/parser/HLSTree.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index 978c8eda7..dee9a9c6a 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -1295,6 +1295,13 @@ PLAYLIST::EncryptionType adaptive::CHLSTree::ProcessEncryption( m_currentPssh = STRING::ToVecUint8(resp.data); } + if (uriUrl.empty()) // No kid provided, assume key == kid + m_currentDefaultKID = STRING::ToHexadecimal(uriData); + + } + else if (STRING::CompareNoCase(keyFormat, DRM::URN_WIDEVINE)) + { + // Take only the KID if (STRING::KeyExists(attribs, "KEYID")) { std::string keyid = attribs["KEYID"]; @@ -1305,16 +1312,14 @@ PLAYLIST::EncryptionType adaptive::CHLSTree::ProcessEncryption( else LOG::LogF(LOGERROR, "Incorret KEYID tag format"); } - else if (uriUrl.empty()) // No kid provided, assume key == kid - m_currentDefaultKID = STRING::ToHexadecimal(uriData); + } - if (encryptMethod == "SAMPLE-AES-CTR") - m_cryptoMode = CryptoMode::AES_CTR; - else if (encryptMethod == "SAMPLE-AES") - m_cryptoMode = CryptoMode::AES_CBC; + if (encryptMethod == "SAMPLE-AES-CTR") + m_cryptoMode = CryptoMode::AES_CTR; + else if (encryptMethod == "SAMPLE-AES") + m_cryptoMode = CryptoMode::AES_CBC; - return EncryptionType::CLEARKEY; - } + return EncryptionType::CLEARKEY; } // Unsupported encryption From 5ff652f409ce1187d3f4b4cd775adf2eeb990782 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 16:47:18 +0200 Subject: [PATCH 03/11] [DRM][ClearKey] Removed hardcoded key size and cast --- .../clearkey/ClearKeyCencSingleSampleDecrypter.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp index 789837415..9538ea504 100644 --- a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp +++ b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp @@ -88,10 +88,10 @@ CClearKeyCencSingleSampleDecrypter::CClearKeyCencSingleSampleDecrypter( return; } - std::vector keyBytes = BASE64::Decode(m_keyPairs[b64DefaultKeyId]); + const std::vector keyBytes = BASE64::Decode(m_keyPairs[b64DefaultKeyId]); if (AP4_FAILED(AP4_CencSingleSampleDecrypter::Create(AP4_CENC_CIPHER_AES_128_CTR, keyBytes.data(), - 16, 0, 0, nullptr, false, - m_singleSampleDecrypter))) + static_cast(keyBytes.size()), 0, 0, + nullptr, false, m_singleSampleDecrypter))) { LOG::LogF(LOGERROR, "Failed to create AP4_CencSingleSampleDecrypter"); } @@ -122,9 +122,9 @@ CClearKeyCencSingleSampleDecrypter::CClearKeyCencSingleSampleDecrypter( LOG::LogF(LOGERROR, "Missing KeyId \"%s\" on DRM configuration", defaultKeyId.data()); } - const AP4_UI08* ap4Key = reinterpret_cast(hexKey.data()); - AP4_CencSingleSampleDecrypter::Create(AP4_CENC_CIPHER_AES_128_CTR, ap4Key, 16, 0, 0, nullptr, - false, m_singleSampleDecrypter); + AP4_CencSingleSampleDecrypter::Create(AP4_CENC_CIPHER_AES_128_CTR, hexKey.data(), + static_cast(hexKey.size()), 0, 0, nullptr, false, + m_singleSampleDecrypter); SetParentIsOwner(false); AddSessionKey(defaultKeyId); } From f2e9bdd42d6cca645b6c956ad4affc54d9d3497c Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 16:53:33 +0200 Subject: [PATCH 04/11] [Base64Utils] Add Encode padding condition --- src/utils/Base64Utils.cpp | 36 ++++++++++++++++++++++-------------- src/utils/Base64Utils.h | 10 +++++----- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/utils/Base64Utils.cpp b/src/utils/Base64Utils.cpp index 0842e41cc..ca0a2db0f 100644 --- a/src/utils/Base64Utils.cpp +++ b/src/utils/Base64Utils.cpp @@ -44,7 +44,10 @@ constexpr unsigned char BASE64_TABLE[] = { // clang-format on } // namespace -void UTILS::BASE64::Encode(const uint8_t* input, const size_t length, std::string& output) +void UTILS::BASE64::Encode(const uint8_t* input, + const size_t length, + std::string& output, + const bool padding /* = true */) { if (input == nullptr || length == 0) return; @@ -68,40 +71,45 @@ void UTILS::BASE64::Encode(const uint8_t* input, const size_t length, std::strin output.push_back(CHARACTERS[(l >> 0) & 0x3F]); } - int left = 3 - (length % 3); - - if (length % 3) + if (padding) { - for (int i = 0; i < left; i++) - output.push_back(PADDING); + const int left = 3 - (length % 3); + + if (length % 3) + { + for (int i = 0; i < left; ++i) + output.push_back(PADDING); + } } } -std::string UTILS::BASE64::Encode(const uint8_t* input, const size_t length) +std::string UTILS::BASE64::Encode(const uint8_t* input, + const size_t length, + const bool padding /* = true */) { std::string output; - Encode(input, length, output); + Encode(input, length, output, padding); return output; } -std::string UTILS::BASE64::Encode(const std::vector& input) +std::string UTILS::BASE64::Encode(const std::vector& input, const bool padding /* = true */) { std::string output; - Encode(input.data(), input.size(), output); + Encode(input.data(), input.size(), output, padding); return output; } -std::string UTILS::BASE64::Encode(const std::vector& input) +std::string UTILS::BASE64::Encode(const std::vector& input, const bool padding /* = true */) { std::string output; - Encode(reinterpret_cast(input.data()), input.size(), output); + Encode(reinterpret_cast(input.data()), input.size(), output, padding); return output; } -std::string UTILS::BASE64::Encode(const std::string& inputStr) +std::string UTILS::BASE64::Encode(const std::string& inputStr, const bool padding /* = true */) { std::string output; - Encode(reinterpret_cast(inputStr.data()), inputStr.size(), output); + Encode(reinterpret_cast(inputStr.data()), inputStr.size(), output, padding); return output; } diff --git a/src/utils/Base64Utils.h b/src/utils/Base64Utils.h index 1b6457d95..c4fc602f6 100644 --- a/src/utils/Base64Utils.h +++ b/src/utils/Base64Utils.h @@ -18,11 +18,11 @@ namespace UTILS namespace BASE64 { -void Encode(const uint8_t* input, const size_t length, std::string& output); -std::string Encode(const uint8_t* input, const size_t length); -std::string Encode(const std::vector& input); -std::string Encode(const std::vector& input); -std::string Encode(const std::string& input); +void Encode(const uint8_t* input, const size_t length, std::string& output, const bool padding = true); +std::string Encode(const uint8_t* input, const size_t length, const bool padding = true); +std::string Encode(const std::vector& input, const bool padding = true); +std::string Encode(const std::vector& input, const bool padding = true); +std::string Encode(const std::string& input, const bool padding = true); void Decode(const char* input, const size_t length, std::vector& output); std::vector Decode(std::string_view input); From 219144e9196930fbb12d1276dc5e86d1e3187f56 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 16:55:20 +0200 Subject: [PATCH 05/11] [DRM][ClearKey] Encode KID without padding --- src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp index 9538ea504..6a798961e 100644 --- a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp +++ b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp @@ -178,8 +178,7 @@ std::string CClearKeyCencSingleSampleDecrypter::CreateLicenseRequest( * "type":"temporary" } */ - std::string b64Kid = UTILS::BASE64::Encode(defaultKeyId); - UTILS::STRING::ReplaceAll(b64Kid, "=", ""); + std::string b64Kid = UTILS::BASE64::Encode(defaultKeyId, false); rapidjson::Document jDoc; jDoc.SetObject(); From e4de8b22d326646ae482ec8027111f7067b292e8 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 17:12:26 +0200 Subject: [PATCH 06/11] [CurlUtils] Add constructor for POST request --- src/utils/CurlUtils.cpp | 9 +++++++++ src/utils/CurlUtils.h | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/utils/CurlUtils.cpp b/src/utils/CurlUtils.cpp index 2809db300..1f747ea52 100644 --- a/src/utils/CurlUtils.cpp +++ b/src/utils/CurlUtils.cpp @@ -8,6 +8,7 @@ #include "CurlUtils.h" +#include "Base64Utils.h" #include "StringUtils.h" #include "UrlUtils.h" #include "Utils.h" @@ -201,6 +202,14 @@ UTILS::CURL::CUrl::CUrl(std::string_view url) } } +UTILS::CURL::CUrl::CUrl(std::string_view url, const std::string& postData) : CUrl::CUrl(url) +{ + if (m_file.IsOpen() && !postData.empty()) + { + m_file.CURLAddOption(ADDON_CURL_OPTION_PROTOCOL, "postdata", BASE64::Encode(postData)); + } +} + UTILS::CURL::CUrl::~CUrl() { if (CSrvBroker::GetKodiProps().GetConfig().internalCookies) diff --git a/src/utils/CurlUtils.h b/src/utils/CurlUtils.h index 788a79f33..22759bb1d 100644 --- a/src/utils/CurlUtils.h +++ b/src/utils/CurlUtils.h @@ -42,6 +42,13 @@ class ATTR_DLL_LOCAL CUrl * \param url The url of the file to download */ CUrl(std::string_view url); + + /*! + * \brief Create CUrl for POST request, if the data are empty, GET will be performed. + * \param url The request url + * \param postData The data for the POST request + */ + CUrl(std::string_view url, const std::string& postData); ~CUrl(); /*! From c7c74d3fcb6c1833b1e9980ba8d8af6f7a7c5fbf Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Thu, 15 Aug 2024 17:16:02 +0200 Subject: [PATCH 07/11] [Cleanup] Use CUrl constructor for post requests --- src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp | 4 +--- src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp index 6a798961e..f3f96f87a 100644 --- a/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp +++ b/src/decrypters/clearkey/ClearKeyCencSingleSampleDecrypter.cpp @@ -47,13 +47,11 @@ CClearKeyCencSingleSampleDecrypter::CClearKeyCencSingleSampleDecrypter( FILESYS::SaveFile(debugFilePath, postData.c_str(), true); } - CURL::CUrl curl{licenseUrl}; + CURL::CUrl curl{licenseUrl, postData}; curl.AddHeader("Accept", "application/json"); curl.AddHeader("Content-Type", "application/json"); curl.AddHeaders(licenseHeaders); - curl.AddHeader("postdata", UTILS::BASE64::Encode(postData)); - std::string response; int statusCode = curl.Open(); if (statusCode == -1 || statusCode >= 400) diff --git a/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp b/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp index 7ea559640..51923e047 100644 --- a/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp +++ b/src/decrypters/widevine/WVCencSingleSampleDecrypter.cpp @@ -459,6 +459,7 @@ bool CWVCencSingleSampleDecrypter::SendSessionMessage() } std::string encData{BASE64::Encode(blocks[2])}; + //! @todo: inappropriate use of "postdata" header, use CURL::CUrl for post request file.AddHeader("postdata", encData.c_str()); } From a3cde33b4d0d14cfe2a831c6767ec806fc2e2acc Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Fri, 16 Aug 2024 15:41:01 +0200 Subject: [PATCH 08/11] [KodiProps] DrmLegacyConfig, dont set m_licenseKey with clearkey --- src/CompKodiProps.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CompKodiProps.cpp b/src/CompKodiProps.cpp index 25264706b..2594ea339 100644 --- a/src/CompKodiProps.cpp +++ b/src/CompKodiProps.cpp @@ -493,6 +493,9 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmLegacyConfig(const std::string& da drmCfg.license.serverUrl = licenseUrl; ParseHeaderString(drmCfg.license.reqHeaders, licenseHeaders); + // Until the future DRM config rework only the ClearKey DRM use the new properties + // so return now to keep m_licenseKey empty + return true; } else if (licenseHeaders.empty()) { From 51b72ce9d2a65b6f3e08e6c1338bb59092cfff84 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Mon, 19 Aug 2024 11:45:29 +0200 Subject: [PATCH 09/11] [KodiProps] Some cleanup/fixes Mainly: - Avoid use of mixed DRM properties - Make working new "drm" property, in a temporary limited way for test --- src/CompKodiProps.cpp | 21 ++++++++++++++++++++- src/utils/StringUtils.h | 6 ++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/CompKodiProps.cpp b/src/CompKodiProps.cpp index 2594ea339..0334b8b0a 100644 --- a/src/CompKodiProps.cpp +++ b/src/CompKodiProps.cpp @@ -72,6 +72,18 @@ ADP::KODI_PROPS::CCompKodiProps::CCompKodiProps(const std::map}, + * "license": dict, + * ... }, * "keysystem_name_2" : { ... }} */ rapidjson::Document jDoc; @@ -397,6 +410,9 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data) continue; } + //! @todo: m_licenseType temporarily assigned, to remove with the DRM config rework + m_licenseType = keySystem; + DrmCfg& drmCfg = m_drmConfigs[keySystem]; auto& jDictVal = jChildObj.value; @@ -420,6 +436,9 @@ bool ADP::KODI_PROPS::CCompKodiProps::ParseDrmConfig(const std::string& data) } } } + + //! @todo: temporary support only one DRM config + break; } return true; diff --git a/src/utils/StringUtils.h b/src/utils/StringUtils.h index fbe4918fb..aac37c2db 100644 --- a/src/utils/StringUtils.h +++ b/src/utils/StringUtils.h @@ -27,6 +27,12 @@ bool KeyExists(const T& container, const Key& key) return container.find(key) != std::end(container); } +template +bool KeyExists(const T& container, const std::string_view key) +{ + return container.find(key.data()) != std::end(container); +} + /*! * \brief Get map value of the specified key * \param map The map where find the value From 1db862304dd579d4511258dd110ad21e54d6ec67 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Sun, 18 Aug 2024 18:08:25 +0200 Subject: [PATCH 10/11] [DashTree] Workaround to always get KID for ClearKey --- src/parser/DASHTree.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index a0cd6b022..efb2a47ed 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -12,6 +12,7 @@ #include "PRProtectionParser.h" #include "SrvBroker.h" #include "common/Period.h" +#include "decrypters/Helpers.h" #include "utils/Base64Utils.h" #include "utils/CurlUtils.h" #include "utils/StringUtils.h" @@ -1336,6 +1337,34 @@ bool adaptive::CDashTree::GetProtectionData( } } + // Workaround for ClearKey: + // if license type ClearKey is set and a manifest dont contains ClearKey protection scheme + // in any case the KID is required to allow decryption (with clear keys or license URLs provided by Kodi props) + //! @todo: this should not be a task of parser, moreover missing an appropriate KID extraction from mp4 box + auto& kodiProps = CSrvBroker::GetKodiProps(); + ProtectionScheme ckProtScheme; + if (!protSelected && !protCommon && kodiProps.GetLicenseType() == DRM::KS_CLEARKEY) + { + for (const ProtectionScheme& protScheme : reprProtSchemes) + { + if (!protScheme.kid.empty()) + { + ckProtScheme.kid = protScheme.kid; + break; + } + } + if (ckProtScheme.kid.empty()) + { + for (const ProtectionScheme& protScheme : adpProtSchemes) + { + ckProtScheme.kid = protScheme.kid; + break; + } + } + if (!ckProtScheme.kid.empty()) + protCommon = &ckProtScheme; + } + bool isEncrypted{false}; std::string selectedKid; std::string selectedPssh; From 32eb73a889008421eed49f666710f694cf28b8c8 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Sun, 18 Aug 2024 18:14:55 +0200 Subject: [PATCH 11/11] [ClearKey] Allow only "cenc" encryption --- src/decrypters/clearkey/ClearKeyDecrypter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/decrypters/clearkey/ClearKeyDecrypter.cpp b/src/decrypters/clearkey/ClearKeyDecrypter.cpp index 08944445c..cceaf61cc 100644 --- a/src/decrypters/clearkey/ClearKeyDecrypter.cpp +++ b/src/decrypters/clearkey/ClearKeyDecrypter.cpp @@ -12,6 +12,7 @@ #include "CompKodiProps.h" #include "SrvBroker.h" #include "decrypters/Helpers.h" +#include "utils/log.h" std::vector CClearKeyDecrypter::SelectKeySystems(std::string_view keySystem) { @@ -39,6 +40,12 @@ Adaptive_CencSingleSampleDecrypter* CClearKeyDecrypter::CreateSingleSampleDecryp bool skipSessionMessage, CryptoMode cryptoMode) { + if (cryptoMode != CryptoMode::AES_CTR) + { + LOG::LogF(LOGERROR, "Cannot initialize ClearKey DRM. Only \"cenc\" encryption supported."); + return nullptr; + } + CClearKeyCencSingleSampleDecrypter* decrypter = nullptr; auto& cfgLic = CSrvBroker::GetKodiProps().GetDrmConfig(std::string(DRM::KS_CLEARKEY)).license;