RDK Documentation (Open Sourced RDK Components)
AampPlayReadyHelper.cpp
Go to the documentation of this file.
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2020 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 /**
21  * @file AampPlayReadyHelper.cpp
22  * @brief play Ready DRM helper Engine
23  */
24 
25 #include <uuid/uuid.h>
26 #include<algorithm>
27 
28 #include "AampPlayReadyHelper.h"
29 #include "AampJsonObject.h"
30 #include "AampDRMutils.h"
31 #include "AampConstants.h"
32 
33 #include "_base64.h"
34 
35 #define KEYID_TAG_START "<KID>"
36 #define KEYID_TAG_END "</KID>"
37 #define PLAYREADY_VERSION "4.0.0.0"
38 
39 static AampPlayReadyHelperFactory playready_helper_factory;
40 
41 const std::string AampPlayReadyHelper::PLAYREADY_OCDM_ID = "com.microsoft.playready";
42 
43 const std::string& AampPlayReadyHelper::ocdmSystemId() const
44 {
45  return PLAYREADY_OCDM_ID;
46 }
47 
48 void AampPlayReadyHelper::createInitData(std::vector<uint8_t>& initData) const
49 {
50  initData = this->mInitData;
51 }
52 
53 
54 /**< API Move to util class**/
55 /**
56  * @brief find sub string inbetween string
57  * @return substring
58  */
59 std::string AampPlayReadyHelper::findSubstr(std::string &data, std::string start, std::string end)
60 {
61  std::string retVal = "";
62  int first = data.find(start);
63  if ((first != std::string::npos))
64  {
65  std::string subStr = data.substr(first + start.size());
66  int last = subStr.find(end);
67  if ((last != std::string::npos))
68  {
69  retVal = subStr.substr (0,last);
70  }
71  }
72  return retVal;
73 }
74 
75 /**
76  * @brief Extract keyID from given PSSH data.
77  *
78  * @return std::string keyId - copy by value
79  */
80 #define PLAYREADY_VERSION_4_0_KID_START "<KID>" /**< KeyId represent as value for 4.0 version*/
81 #define PLAYREADY_VERSION_4_X_KID_START "<KID" /**< KeyId represent as attribute for 4.x version where x > 0 */
82 #define PLAYREADY_KID_END "</KID>" /**< KeyId node end **/
83 
84 #define PLAYREADY_VERSION_4_0 "4.0.0.0" /**< Playready versio 4.0 **/
85 #define PLAYREADY_VERSION_4_1 "4.1.0.0" /**< Playready versio 4.1 **/
86 #define PLAYREADY_VERSION_4_2 "4.2.0.0" /**< Playready versio 4.2 **/
87 #define PLAYREADY_VERSION_4_3 "4.3.0.0" /**< Playready versio 4.3 **/
88 std::string AampPlayReadyHelper::extrackKeyID()
89 {
90  std::string propValueEnd = "\"";
91  std::string version = findSubstr(mStrInitDataFormated, "version=\"", propValueEnd);
92  std::string keyId = "";
93 
94  AAMPLOG_WARN ("PlayReady Version [%s]", version.c_str());
95 
96  if(version == PLAYREADY_VERSION_4_0)
97  {
99  }
100  else if((version == PLAYREADY_VERSION_4_1))
101  {
102  /**< Key Id represent in protectinfo block without attribute; single keyId support
103  * <PROTECTINFO>
104  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
105  * </PROTECTINFO>
106  */
107 
108  std::string protectInfo = findSubstr(mStrInitDataFormated, "<PROTECTINFO>", "</PROTECTINFO>");
109  std::string keyTag = findSubstr(protectInfo, PLAYREADY_VERSION_4_X_KID_START, PLAYREADY_KID_END);
110  keyId = findSubstr(keyTag, "VALUE=\"", propValueEnd);
111  }
112  else if((version == PLAYREADY_VERSION_4_2))
113  {
114  /**< Key Id represent in protectinfo block without attribute; multiple keyIds support
115  * <PROTECTINFO>
116  * <KIDS>
117  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
118  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
119  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
120  * </KIDS>
121  * </PROTECTINFO>
122  */
123  std::string protectInfo = findSubstr(mStrInitDataFormated, "<PROTECTINFO>", "</PROTECTINFO>");
124  std::string kids = findSubstr(protectInfo, "<KIDS>", "</KIDS>");
125  /**< TODO: multiple keyIds support in AAMP; now taking first value only **/
126  std::string keyTag = findSubstr(kids, PLAYREADY_VERSION_4_X_KID_START, PLAYREADY_KID_END);
127  keyId = findSubstr(keyTag, "VALUE=\"", propValueEnd);
128  }
129  else if((version == PLAYREADY_VERSION_4_3))
130  {
131  /**< Key Id represent in protectinfo block with attribute; multiple keyIds support
132  * <PROTECTINFO LICENSEREQUESTED="true">
133  * <KIDS>
134  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
135  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
136  * <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
137  * </KIDS>
138  * </PROTECTINFO>
139  */
140  std::string protectInfo = findSubstr(mStrInitDataFormated, "<PROTECTINFO", "</PROTECTINFO>");
141  std::string kids = findSubstr(protectInfo, "<KIDS>", "</KIDS>");
142  /**< TODO: multiple keyIds support in AAMP; now taking first value only **/
143  std::string keyTag = findSubstr(kids, PLAYREADY_VERSION_4_X_KID_START, PLAYREADY_KID_END);
144  keyId = findSubstr(keyTag, "VALUE=\"", propValueEnd);
145  }
146  else
147  {
148  AAMPLOG_WARN ("Unsupported PSSH version MPD[%s]", version.c_str());
149  }
150 
151  AAMPLOG_INFO("Extracted Key ID: %s", keyId.c_str());
152  //DumpBlob((const unsigned char*)keyId.c_str(), keyId.size());
153  return keyId;
154 
155 }
156 
157 /**
158  * @brief Extract content meta data from given PSSH data.
159  * For example for content meta data,
160  * When strings are given as "ckm:policy xmlns:ckm="urn:ccp:ckm"" and "ckm:policy"
161  * <ckm:policy xmlns:ckm="urn:ccp:ckm">we need the contents from here</ckm:policy>
162  */
164 {
165  return findSubstr(mStrInitDataFormated, DRM_METADATA_TAG_START, DRM_METADATA_TAG_END);
166 }
167 
168 bool AampPlayReadyHelper::parsePssh(const uint8_t* initData, uint32_t initDataLen)
169 {
170  int keyIdLen = 0;
171  bool res = false;
172  // Extract key
173  if (initData != NULL && initDataLen > 0)
174  {
175  this->mInitData.assign(initData, initData + initDataLen);
176  std::string keyData = "";
177  char* cleanedPssh = (char*) malloc(initDataLen+1);
178  if (cleanedPssh)
179  {
180  int cleanedPsshLen = 0;
181  for(int itr = 0; itr < initDataLen; itr++)
182  {
183  if(initData[itr] != 0)
184  {
185  //cout<<psshData[itr];
186  cleanedPssh[cleanedPsshLen++] = initData[itr];
187  }
188  }
189  cleanedPssh[cleanedPsshLen] = 0;
190 
191  this->mStrInitDataFormated = std::string(cleanedPssh);
192  free(cleanedPssh);
193  cleanedPssh = NULL;
194  //Clear unwanted spaces from pssh data - time being not neeed
195  //std::remove(mStrInitDataFormated.begin(), mStrInitDataFormated.end(), ' ');
196 
197  keyData = extrackKeyID();
198  }
199  //AAMPLOG_INFO("pr keyid: %s keyIdlen: %d", keydata, keyIdLen);
200  if (!keyData.empty())
201  {
202  size_t decodedDataLen = 0;
203  unsigned char* decodedKeydata = base64_Decode(keyData.c_str(), &decodedDataLen, keyData.size());
204 
205  if (decodedDataLen != PLAYREADY_DECODED_KEY_ID_LEN)
206  {
207  AAMPLOG_ERR("Invalid key size found while extracting PR Decoded-KeyID-Length: %d (PR KeyID: %s KeyID-Length: %d)", decodedDataLen, keyData.c_str(), keyIdLen);
208  }
209  else
210  {
211  unsigned char swappedKeydata[PLAYREADY_DECODED_KEY_ID_LEN] = {0};
212  aamp_ConvertEndianness(decodedKeydata, swappedKeydata);
213  unsigned char keyId[PLAYREADY_KEY_ID_LEN] = {0};
214  uuid_t *keyiduuid = (uuid_t*)swappedKeydata;
215  uuid_unparse_lower(*keyiduuid, reinterpret_cast<char*>(keyId));
216  AAMPLOG_INFO("Extracted Key ID is %s", keyId);
217  mKeyID.assign(keyId, keyId + (PLAYREADY_KEY_ID_LEN-1)); /**< No need end null charector in vector **/
218  res = true;
219  }
220 
221  free(decodedKeydata);
222  }
223  else
224  {
225  AAMPLOG_WARN("Bad DRM init data with Empty KeyID has received : %s!!", friendlyName().c_str());
226  }
227 
228  /**< Extract the optional content metadata.
229  * No specification available based on version*/
230  mContentMetaData = extractMetaData();
231  }
232  else
233  {
234  AAMPLOG_ERR("Invalid PSSH Data Recieved : NULL");
235  }
236 
237  return res;
238 }
239 
240 void AampPlayReadyHelper::setDrmMetaData(const std::string& metaData)
241 {
242  if (mContentMetaData.empty())
243  {
244  mContentMetaData = metaData;
245  }
246 }
247 
248 void AampPlayReadyHelper::getKey(std::vector<uint8_t>& keyID) const
249 {
250  keyID = this->mKeyID;
251 }
252 
254 {
255  licenseRequest.method = AampLicenseRequest::POST;
256 
257  if (licenseRequest.url.empty())
258  {
259  licenseRequest.url = challengeInfo.url;
260  }
261 
262  licenseRequest.headers = {{"Content-Type:", {"text/xml; charset=utf-8"}}};
263 
264  if (!mContentMetaData.empty())
265  {
266  std::vector<uint8_t> challengeData(reinterpret_cast<const char*>(challengeInfo.data->getData().c_str()),reinterpret_cast<const char*>(challengeInfo.data->getData().c_str()) + challengeInfo.data->getDataLength());
267 
268  AampJsonObject comChallengeObj;
269  comChallengeObj.add("keySystem", "playReady");
270  comChallengeObj.add("mediaUsage", "stream");
271  comChallengeObj.add("licenseRequest", challengeData, AampJsonObject::ENCODING_BASE64);
272  comChallengeObj.add("contentMetadata", mContentMetaData, AampJsonObject::ENCODING_BASE64);
273 
274  if ((!challengeInfo.accessToken.empty()) && !licenseRequest.licenseAnonymousRequest)
275  {
276  comChallengeObj.add("accessToken", challengeInfo.accessToken);
277  }
278 
279  licenseRequest.payload = comChallengeObj.print();
280  }
281  else if (challengeInfo.data)
282  {
283  licenseRequest.payload = challengeInfo.data->getData();
284  }
285 }
286 
287 bool AampPlayReadyHelperFactory::isDRM(const struct DrmInfo& drmInfo) const
288 {
289  return (((drmInfo.systemUUID == PLAYREADY_UUID) || (drmInfo.keyFormat == AampPlayReadyHelper::PLAYREADY_OCDM_ID))
290  && ((drmInfo.mediaFormat == eMEDIAFORMAT_DASH) || (drmInfo.mediaFormat == eMEDIAFORMAT_HLS_MP4))
291  );
292 }
293 
294 std::shared_ptr<AampDrmHelper> AampPlayReadyHelperFactory::createHelper(const struct DrmInfo& drmInfo, AampLogManager *logObj) const
295 {
296  if (isDRM(drmInfo))
297  {
298  return std::make_shared<AampPlayReadyHelper>(drmInfo,logObj);
299  }
300  return NULL;
301 }
302 
303 void AampPlayReadyHelperFactory::appendSystemId(std::vector<std::string>& systemIds) const
304 {
305  systemIds.push_back(PLAYREADY_UUID);
306 }
AampPlayReadyHelper::generateLicenseRequest
void generateLicenseRequest(const AampChallengeInfo &challengeInfo, AampLicenseRequest &licenseRequest) const
Generate the request details for the DRM license.
Definition: AampPlayReadyHelper.cpp:253
PLAYREADY_KID_END
#define PLAYREADY_KID_END
Definition: AampPlayReadyHelper.cpp:82
AampPlayReadyHelperFactory
Handles operations to support play ready DRM.
Definition: AampPlayReadyHelper.h:93
PLAYREADY_VERSION_4_2
#define PLAYREADY_VERSION_4_2
Definition: AampPlayReadyHelper.cpp:86
PLAYREADY_VERSION_4_X_KID_START
#define PLAYREADY_VERSION_4_X_KID_START
Definition: AampPlayReadyHelper.cpp:81
DRM_METADATA_TAG_START
#define DRM_METADATA_TAG_START
start and end tags for DRM policy
Definition: AampDRMutils.h:50
PLAYREADY_VERSION_4_0
#define PLAYREADY_VERSION_4_0
Definition: AampPlayReadyHelper.cpp:84
aamp_ConvertEndianness
void aamp_ConvertEndianness(unsigned char *original, unsigned char *guidBytes)
Convert endianness of 16 byte block.
Definition: AampDRMutils.cpp:134
AampChallengeInfo::data
std::shared_ptr< DrmData > data
Definition: AampDrmHelper.h:46
AampPlayReadyHelperFactory::appendSystemId
void appendSystemId(std::vector< std::string > &systemIds) const
Adds the system IDs supported by the DRM to a vector Used by the GStreamer plugins to advertise the D...
Definition: AampPlayReadyHelper.cpp:303
AampJsonObject::ENCODING_BASE64
@ ENCODING_BASE64
Definition: AampJsonObject.h:49
AampChallengeInfo::accessToken
std::string accessToken
Definition: AampDrmHelper.h:49
PLAYREADY_VERSION_4_3
#define PLAYREADY_VERSION_4_3
Definition: AampPlayReadyHelper.cpp:87
AampPlayReadyHelperFactory::createHelper
std::shared_ptr< AampDrmHelper > createHelper(const struct DrmInfo &drmInfo, AampLogManager *logObj=NULL) const
Build a helper class to support the identified DRM.
Definition: AampPlayReadyHelper.cpp:294
eMEDIAFORMAT_DASH
@ eMEDIAFORMAT_DASH
Definition: AampDrmMediaFormat.h:35
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
AampPlayReadyHelper::createInitData
void createInitData(std::vector< uint8_t > &initData) const
AampPlayReadyHelper::mStrInitDataFormated
std::string mStrInitDataFormated
Definition: AampPlayReadyHelper.h:86
AampPlayReadyHelperFactory::isDRM
bool isDRM(const struct DrmInfo &drmInfo) const
Determines if a helper class provides the identified DRM.
Definition: AampPlayReadyHelper.cpp:287
AampLicenseRequest
Holds the data to get the License.
Definition: AampDrmHelper.h:57
DrmInfo::systemUUID
std::string systemUUID
Definition: AampDrmInfo.h:89
DrmInfo
DRM information required to decrypt.
Definition: AampDrmInfo.h:47
AampChallengeInfo::url
std::string url
Definition: AampDrmHelper.h:48
AampJsonObject.h
File to handle Json format.
DrmInfo::keyFormat
std::string keyFormat
Definition: AampDrmInfo.h:88
AampPlayReadyHelper::parsePssh
bool parsePssh(const uint8_t *initData, uint32_t initDataLen)
Parse the optional PSSH data.
Definition: AampPlayReadyHelper.cpp:168
_base64.h
base64 source Encoder/Decoder
AampJsonObject::print
std::string print()
Print the constructed JSON to a string.
Definition: AampJsonObject.cpp:365
AampDRMutils.h
Context-free common utility functions.
AampPlayReadyHelper::extractMetaData
std::string extractMetaData()
Extract content meta data from given PSSH data. For example for content meta data,...
Definition: AampPlayReadyHelper.cpp:163
AampPlayReadyHelper::setDrmMetaData
void setDrmMetaData(const std::string &metaData)
Sets the content specific DRM metadata.
Definition: AampPlayReadyHelper.cpp:240
AampJsonObject::add
bool add(const std::string &name, const std::string &value, const ENCODING encoding=ENCODING_STRING)
Add a string value.
Definition: AampJsonObject.cpp:69
AampLicenseRequest::POST
@ POST
Definition: AampDrmHelper.h:65
AampPlayReadyHelper::getKey
void getKey(std::vector< uint8_t > &keyID) const
Get the key ID.
Definition: AampPlayReadyHelper.cpp:248
AampPlayReadyHelper::ocdmSystemId
const std::string & ocdmSystemId() const
Returns the OCDM system ID of the helper.
Definition: AampPlayReadyHelper.cpp:43
PLAYREADY_VERSION_4_1
#define PLAYREADY_VERSION_4_1
Definition: AampPlayReadyHelper.cpp:85
PLAYREADY_VERSION_4_0_KID_START
#define PLAYREADY_VERSION_4_0_KID_START
Extract keyID from given PSSH data.
Definition: AampPlayReadyHelper.cpp:80
AampConstants.h
Constants in AAMP.
AampPlayReadyHelper::findSubstr
std::string findSubstr(std::string &data, std::string start, std::string end)
find sub string inbetween string
Definition: AampPlayReadyHelper.cpp:59
AampPlayReadyHelper::friendlyName
virtual const std::string & friendlyName() const override
Gets the friendly display name of the DRM.
Definition: AampPlayReadyHelper.h:62
eMEDIAFORMAT_HLS_MP4
@ eMEDIAFORMAT_HLS_MP4
Definition: AampDrmMediaFormat.h:37
AampChallengeInfo
Aamp challenge info to get the License.
Definition: AampDrmHelper.h:44
DrmInfo::mediaFormat
MediaFormat mediaFormat
Definition: AampDrmInfo.h:80
base64_Decode
unsigned char * base64_Decode(const char *src, size_t *len, size_t srcLen)
decode base64 encoded data to binary equivalent
Definition: _base64.cpp:91
AampPlayReadyHelper.h
Handles the operation for Play ready DRM operations.
AampJsonObject
Utility class to construct a JSON string.
Definition: AampJsonObject.h:37