RDK Documentation (Open Sourced RDK Components)
playreadydrmsession.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 2018 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 playreadydrmsession.cpp
22  * @brief Playready Session management
23  */
24 #include "config.h"
25 #include "playreadydrmsession.h"
26 #include <gst/gst.h>
27 #include <assert.h>
28 #include <iostream>
29 #include <sstream>
30 #include <string>
31 #include <string.h>
32 #include <vector>
33 #include <sys/utsname.h>
34 #include "priv_aamp.h"
35 
36 #define NYI_KEYSYSTEM "keysystem-placeholder"
37 //#define TRACE_LOG 1
38 
39 extern DRM_CONST_STRING g_dstrDrmPath;
40 DRM_RESULT dr;
41 
42 // The default location of CDM DRM store.
43 // /opt/drm/playready/drmstore.dat
44 const DRM_WCHAR g_rgwchCDMDrmStoreName[] =
45 { WCHAR_CAST('/'), WCHAR_CAST('o'), WCHAR_CAST('p'), WCHAR_CAST('t'),
46  WCHAR_CAST('/'), WCHAR_CAST('d'), WCHAR_CAST('r'), WCHAR_CAST('m'),
47  WCHAR_CAST('/'), WCHAR_CAST('p'), WCHAR_CAST('l'), WCHAR_CAST('a'),
48  WCHAR_CAST('y'), WCHAR_CAST('r'), WCHAR_CAST('e'), WCHAR_CAST('a'),
49  WCHAR_CAST('d'), WCHAR_CAST('y'), WCHAR_CAST('/'), WCHAR_CAST('d'),
50  WCHAR_CAST('r'), WCHAR_CAST('m'), WCHAR_CAST('s'), WCHAR_CAST('t'),
51  WCHAR_CAST('o'), WCHAR_CAST('r'), WCHAR_CAST('e'), WCHAR_CAST('.'),
52  WCHAR_CAST('d'), WCHAR_CAST('a'), WCHAR_CAST('t'), WCHAR_CAST('\0') };
53 // default PR DRM path
54 // /opt/drm/playready
55 const DRM_WCHAR g_rgwchCDMDrmPath[] =
56 { WCHAR_CAST('/'), WCHAR_CAST('o'), WCHAR_CAST('p'), WCHAR_CAST('t'),
57  WCHAR_CAST('/'), WCHAR_CAST('d'), WCHAR_CAST('r'), WCHAR_CAST('m'),
58  WCHAR_CAST('/'), WCHAR_CAST('p'), WCHAR_CAST('l'), WCHAR_CAST('a'),
59  WCHAR_CAST('y'), WCHAR_CAST('r'), WCHAR_CAST('e'), WCHAR_CAST('a'),
60  WCHAR_CAST('d'), WCHAR_CAST('y'), WCHAR_CAST('\0') };
61 
62 const DRM_CONST_STRING g_dstChainTitle = CREATE_DRM_STRING(
63  g_rgwchCDMDrmStoreName);
64 const DRM_CONST_STRING g_dstrCDMDrmPath = CREATE_DRM_STRING(g_rgwchCDMDrmPath);
65 const DRM_CONST_STRING *g_rgpdstrRights[1] =
66 { &g_dstrWMDRM_RIGHT_PLAYBACK };
67 
68 
69 // The following function is missing from the official PK 2.5 release but
70 // will be available in the next PK release.
71 // It should be removed if the source is building with the next PK release.
72 /**
73  * @brief Read UUID from init data
74  * @param pbData : Pointer to initdata
75  * @param cbData : size of init data
76  * @param ibGuidOffset : offset to uuid
77  * @param pDrmGuid : Gets updated with uuid
78  * @retval DRM_SUCCESS if no errors encountered
79  */
80 
81 DRM_API DRM_RESULT DRM_CALL DRM_UTL_ReadNetworkBytesToNativeGUID(
82  const DRM_BYTE *pbData, const DRM_DWORD cbData, DRM_DWORD ibGuidOffset,
83  DRM_GUID *pDrmGuid)
84 {
85  DRM_RESULT drm_res = DRM_SUCCESS;
86  DRM_DWORD dwResult = 0;
87 
88  ChkArg(pbData != NULL);
89  ChkArg(pDrmGuid != NULL);
90  ChkOverflow(cbData, ibGuidOffset);
91  ChkDR(DRM_DWordSub(cbData, ibGuidOffset, &dwResult));
92  ChkBOOL(dwResult >= DRM_GUID_LEN, DRM_E_BUFFERTOOSMALL);
93 
94  // Convert field by field.
95  NETWORKBYTES_TO_DWORD(pDrmGuid->Data1, pbData, ibGuidOffset);
96  ChkDR(DRM_DWordAdd(ibGuidOffset, SIZEOF(DRM_DWORD), &ibGuidOffset));
97 
98  NETWORKBYTES_TO_WORD(pDrmGuid->Data2, pbData, ibGuidOffset);
99  ChkDR(DRM_DWordAdd(ibGuidOffset, SIZEOF(DRM_WORD), &ibGuidOffset));
100 
101  NETWORKBYTES_TO_WORD(pDrmGuid->Data3, pbData, ibGuidOffset);
102  ChkDR(DRM_DWordAdd(ibGuidOffset, SIZEOF(DRM_WORD), &ibGuidOffset));
103 
104  // Copy last 8 bytes.
105  DRM_BYT_CopyBytes(pDrmGuid->Data4, 0, pbData, ibGuidOffset, 8);
106 
107  ErrorExit: return drm_res;
108 }
109 
110 /**
111  * @brief PlayReadyDRMSession Constructor
112  */
114  AampDrmSession(logObj, PLAYREADY_KEY_SYSTEM_STRING), m_ptrAppContext(NULL), m_sbOpaBuf(NULL),
115  m_cbOpaBuf(0), m_sbRevocateBuf(NULL), m_eKeyState(KEY_INIT), m_fCommit(FALSE),
116  m_pbChallenge(NULL), m_cbChallenge(0), m_ptrDestURL(NULL), m_pbPRO(NULL), m_cbPRO(0)
117 {
118  pthread_mutex_init(&decryptMutex,NULL);
120 
121  // Get output protection pointer
123 }
124 
125 /**
126  * @brief Initialize PR DRM session, state will be set as KEY_INIT
127  * on success KEY_ERROR if failure.
128  */
130 {
131 
132  DRM_RESULT drm_res = DRM_SUCCESS;
133  DRM_ID aampSessionId;
134  DRM_DWORD cchEncSesID = SIZEOF(m_rgchSesnID);
135 
136  char *envParseInitData = NULL;
137 
138  ChkMem(
139  m_sbOpaBuf = (DRM_BYTE *) Oem_MemAlloc(
140  MINIMUM_APPCONTEXT_OPAQUE_BUFFER_SIZE));
141  m_cbOpaBuf = MINIMUM_APPCONTEXT_OPAQUE_BUFFER_SIZE;
142 
143  ChkMem(
144  m_ptrAppContext = (DRM_APP_CONTEXT *) Oem_MemAlloc(
145  SIZEOF(DRM_APP_CONTEXT)));
146 
147  g_dstrDrmPath = g_dstrCDMDrmPath;
148 
149  /* Initialize DRM app context.
150  Mutex lock is added as it runs in to deadlock sometimes
151  when initialization is called for both Audio and Video
152  */
153 
154  static pthread_mutex_t sessionMutex = PTHREAD_MUTEX_INITIALIZER;
155  pthread_mutex_lock(&sessionMutex);
156  drm_res = Drm_Initialize(m_ptrAppContext,
157  NULL, m_sbOpaBuf, m_cbOpaBuf, &g_dstChainTitle);
158  pthread_mutex_unlock(&sessionMutex);
159 
160 #ifdef TRACE_LOG
161  AAMPLOG_WARN("Printing initialization result : %08x ", drm_res);
162 #endif
163 
164  ChkDR(drm_res);
165 
166  if (DRM_REVOCATION_IsRevocationSupported())
167  {
168  ChkMem(
169  m_sbRevocateBuf = (DRM_BYTE *) Oem_MemAlloc(
170  REVOCATION_BUFFER_SIZE));
171 
172  ChkDR(
173  Drm_Revocation_SetBuffer(m_ptrAppContext, m_sbRevocateBuf,
174  REVOCATION_BUFFER_SIZE));
175  }
176 
177  // Generate a random media session ID.
178  ChkDR(
179  Oem_Random_GetBytes(NULL, (DRM_BYTE *) &aampSessionId,
180  SIZEOF(aampSessionId)));
181 
182  ZEROMEM(m_rgchSesnID, SIZEOF(m_rgchSesnID));
183  // Store the generated media session ID in base64 encoded form.
184  ChkDR(
185  DRM_B64_EncodeA((DRM_BYTE *) &aampSessionId, SIZEOF(aampSessionId),
186  m_rgchSesnID, &cchEncSesID, 0));
187 
188  AAMPLOG_WARN("initAampDRMSession :: Playready initialized with session id : %s",m_rgchSesnID);
189  // The current state MUST be KEY_INIT otherwise error out.
190  ChkBOOL(m_eKeyState == KEY_INIT, DRM_E_INVALIDARG);
191  return;
192  ErrorExit:
193  AAMPLOG_ERR("Playready initialization failed code : %08x ", drm_res);
194  m_eKeyState = KEY_ERROR;
195 }
196 
197 /**
198  * @brief Create drm session with given init data
199  * state will be KEY_INIT on success KEY_ERROR if failed
200  */
201 void PlayReadyDRMSession::generateAampDRMSession(const uint8_t *f_pbInitData,
202  uint32_t f_cbInitData, std::string &customData)
203 {
204  DRM_RESULT drm_res = DRM_SUCCESS;
205 
206  if (f_pbInitData != NULL)
207  {
208 #ifdef TRACE_LOG
209  cout << "parseinitdata..." << endl;
210 #endif
211  ChkDR(_ParseInitData(f_pbInitData, f_cbInitData));
212  // }
213  }
214 
215 
216  if (m_cbPRO > 0)
217  {
219  {
220  AAMPLOG_WARN("PRO found in initdata!");
221  }
222  // If PRO is supplied (via init data) then it is used
223  // to create the content header inside of the app context.
224  drm_res = Drm_Content_SetProperty(m_ptrAppContext, DRM_CSP_AUTODETECT_HEADER,
225  m_pbPRO, m_cbPRO);
226  } else
227  {
229  {
230  AAMPLOG_WARN("PRO not found in initdata!");
231  }
232  drm_res = Drm_Content_SetProperty(m_ptrAppContext, DRM_CSP_AUTODETECT_HEADER,
233  f_pbInitData, f_cbInitData);
234  }
235 
236 #ifdef TRACE_LOG
237  AAMPLOG_TRACE("initAampDRMSession :: Printing SetProperty result : %08x ", drm_res);
238 #endif
239 
240  ChkDR(drm_res);
241 
242  // The current state MUST be KEY_INIT otherwise error out.
243  ChkBOOL(m_eKeyState == KEY_INIT, DRM_E_INVALIDARG);
244  return;
245 
246  ErrorExit:
247  AAMPLOG_ERR("Playready init data binding failed : Error code : %08x ",drm_res);
248  m_eKeyState = KEY_ERROR;
249 }
250 
251 
252 /**
253  * @brief PlayReadyDRMSession Destructor
254  */
256 {
257  pthread_mutex_destroy(&decryptMutex);
258  SAFE_OEM_FREE(m_pbChallenge);
259  SAFE_OEM_FREE(m_ptrDestURL);
260  if(m_pbPRO != NULL)
261  {
262  SAFE_OEM_FREE(m_pbPRO);
263  }
264  m_pbPRO = NULL;
265  if (DRM_REVOCATION_IsRevocationSupported())
266  SAFE_OEM_FREE(m_sbRevocateBuf);
267 
268  SAFE_OEM_FREE(m_sbOpaBuf);
269  SAFE_OEM_FREE(m_ptrAppContext);
270  m_eKeyState = KEY_CLOSED;
271 
272  if(m_pOutputProtection)
273  {
274  m_pOutputProtection->Release();
275  }
276 }
277 
278 // The standard PlayReady protection system ID.
279 static DRM_ID CLSID_PlayReadyProtectionSystemID =
280 { 0x79, 0xf0, 0x04, 0x9a, 0x40, 0x98, 0x86, 0x42, 0xab, 0x92, 0xe6, 0x5b, 0xe0,
281  0x88, 0x5f, 0x95 };
282 
283 // The standard ID of the PSSH box wrapped inside of a UUID box.
284 static DRM_ID PSSH_BOX_GUID =
285 { 0x18, 0x4f, 0x8a, 0xd0, 0xf3, 0x10, 0x82, 0x4a, 0xb6, 0xc8, 0x32, 0xd8, 0xab,
286  0xa1, 0x83, 0xd3 };
287 
288 
289 /**
290  * @brief Retrieve PlayReady Object(PRO) from init data
291  */
292 int PlayReadyDRMSession::_GetPROFromInitData(const DRM_BYTE *f_pbInitData,
293  DRM_DWORD f_cbInitData, DRM_DWORD *f_pibPRO, DRM_DWORD *f_pcbPRO)
294 {
295  DRM_RESULT drm_res = DRM_SUCCESS;
296  DRM_DWORD ibCur = 0;
297  DRM_DWORD cbSize = 0;
298  DRM_DWORD dwType = 0;
299  DRM_WORD wVersion = 0;
300  DRM_WORD wFlags = 0;
301  DRM_GUID guidSystemID = EMPTY_DRM_GUID;
302  DRM_GUID guidUUID = EMPTY_DRM_GUID;
303  DRM_DWORD cbSystemSize = 0;
304  DRM_BOOL fFound = FALSE;
305  DRM_BOOL fUUIDBox = FALSE;
306  DRM_DWORD cbMultiKid = 0;
307  DRM_DWORD dwResult = 0;
308 
309  ChkArg(f_pbInitData != NULL);
310  ChkArg(f_cbInitData > 0);
311  ChkArg(f_pibPRO != NULL);
312  ChkArg(f_pcbPRO != NULL);
313 
314  *f_pibPRO = 0;
315  *f_pcbPRO = 0;
316 
317  while (ibCur < f_cbInitData && !fFound)
318  {
319  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_DWORD), &dwResult));
320  ChkBufferSize(dwResult, f_cbInitData);
321  NETWORKBYTES_TO_DWORD(cbSize, f_pbInitData, ibCur);
322  ibCur = dwResult;
323 
324  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_DWORD), &dwResult));
325  ChkBufferSize(dwResult, f_cbInitData);
326  NETWORKBYTES_TO_DWORD(dwType, f_pbInitData, ibCur);
327  ibCur = dwResult;
328 
329  // 0x64697575 in big endian stands for "uuid".
330  if (dwType == 0x75756964)
331  {
332  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_GUID), &dwResult));
333  ChkBufferSize(dwResult, f_cbInitData);
334 
335  ChkDR(
337  f_cbInitData, ibCur, &guidUUID));
338  ibCur = dwResult;
339 
340  ChkBOOL(MEMCMP(&guidUUID, &PSSH_BOX_GUID, SIZEOF(DRM_ID)) == 0,
341  DRM_E_FAIL);
342  fUUIDBox = TRUE;
343  } else
344  {
345  // 0x68737370 in big endian stands for "pssh".
346  ChkBOOL(dwType == 0x70737368, DRM_E_FAIL);
347  }
348 
349  // Read "version" of PSSH box.
350  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_WORD), &dwResult));
351  ChkBufferSize(dwResult, f_cbInitData);
352  NETWORKBYTES_TO_WORD(wVersion, f_pbInitData, ibCur);
353  ibCur = dwResult;
354 
355  // Read "flags" of PSSH box.
356  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_WORD), &dwResult));
357  ChkBufferSize(dwResult, f_cbInitData);
358  NETWORKBYTES_TO_WORD(wFlags, f_pbInitData, ibCur);
359  ibCur = dwResult;
360 
361  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_GUID), &dwResult));
362  ChkBufferSize(dwResult, f_cbInitData);
363 
364  // Read "system ID" of PSSH box.
365  ChkDR(
366  DRM_UTL_ReadNetworkBytesToNativeGUID(f_pbInitData, f_cbInitData,
367  ibCur, &guidSystemID));
368  ibCur = dwResult;
369 
370  // Handle multi-KIDs pssh box.
371  if (wVersion > 0)
372  {
373  DRM_DWORD cKids = 0;
374 
375  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_DWORD), &dwResult));
376  ChkBufferSize(dwResult, f_cbInitData);
377  NETWORKBYTES_TO_DWORD(cKids, f_pbInitData, ibCur);
378  ibCur = dwResult;
379 
380  // Ignore the KIDs.
381  // ibCur + cKids * sizeof( GUID )
382  ChkDR(DRM_DWordMult(cKids, SIZEOF(DRM_GUID), &dwResult));
383  ChkDR(DRM_DWordAdd(ibCur, dwResult, &dwResult));
384  ChkBufferSize(dwResult, f_cbInitData);
385  ibCur = dwResult;
386 
387  cbMultiKid = SIZEOF(DRM_DWORD) + (cKids * SIZEOF(DRM_GUID));
388  }
389 
390  ChkDR(DRM_DWordAdd(ibCur, SIZEOF(DRM_DWORD), &dwResult));
391  ChkBufferSize(dwResult, f_cbInitData);
392  NETWORKBYTES_TO_DWORD(cbSystemSize, f_pbInitData, ibCur);
393  ibCur = dwResult;
394 
395  // Make sure the payload is still within the limit.
396  ChkDR(DRM_DWordAdd(ibCur, cbSystemSize, &dwResult));
397  ChkBufferSize(dwResult, f_cbInitData);
398 
399  // Check whether the "system ID" just read is for PlayReady.
400  if (MEMCMP(&guidSystemID, &CLSID_PlayReadyProtectionSystemID,
401  SIZEOF(DRM_GUID)) == 0)
402  {
403  fFound = TRUE;
404  } else
405  {
406  ibCur = dwResult;
407  }
408  }
409 
410  if (!fFound)
411  {
412  ChkDR (DRM_E_FAIL);
413  }
414 
415  // Make sure the total size of all components
416  // match the overall size.
417  if (fUUIDBox)
418  {
419  ChkBOOL(
420  cbSystemSize + SIZEOF(cbSize) + SIZEOF(dwType)
421  + SIZEOF(DRM_GUID) + SIZEOF(wVersion) + SIZEOF(wFlags)
422  + SIZEOF(DRM_GUID) + SIZEOF(cbSystemSize) == cbSize,
423  DRM_E_FAIL);
424  } else
425  {
426  ChkBOOL(
427  cbSystemSize + SIZEOF(cbSize) + SIZEOF(dwType)
428  + SIZEOF(wVersion) + SIZEOF(wFlags) + SIZEOF(DRM_GUID)
429  + SIZEOF(cbSystemSize) + cbMultiKid == cbSize,
430  DRM_E_FAIL);
431  }
432 
433  *f_pibPRO = ibCur;
434  *f_pcbPRO = cbSystemSize;
435 
436  ErrorExit: return drm_res;
437 }
438 
439 /**
440  * @brief Parse init data to retrieve PRO from it
441  */
442 int PlayReadyDRMSession::_ParseInitData(const uint8_t *f_pbInitData,
443  uint32_t f_cbInitData)
444 {
445  DRM_RESULT drm_res = DRM_SUCCESS;
446  DRM_DWORD ibPRO = 0;
447  DRM_BYTE *pbPRO = NULL;
448  DRM_DWORD cbPRO = 0;
449 
450  ChkArg(f_pbInitData != NULL && f_cbInitData > 0);
451 
452  // If key ID is already specified by CDM data then PRO is
453  // not allowed to be specified in init data.
454  // In the current implementation this should never happen
455  // since init data is always processed before CDM data.
456  //DRMASSERT(!m_fKeyIdSet);
457 
458  // Parse init data to retrieve PRO.
459  ChkDR(_GetPROFromInitData(f_pbInitData, f_cbInitData, &ibPRO, &cbPRO));
460  ChkBOOL(cbPRO > 0, DRM_E_FAIL);
461  ChkMem(pbPRO = (DRM_BYTE *) Oem_MemAlloc(cbPRO));
462 
463  MEMCPY(pbPRO, f_pbInitData + ibPRO, cbPRO);
464 
465  m_cbPRO = cbPRO;
466  m_pbPRO = pbPRO;
467 
468  ErrorExit:
469  return drm_res;
470 }
471 
472 /**
473  * @brief Generate key request from DRM session
474  * Caller function should free the returned memory.
475  */
476 DrmData * PlayReadyDRMSession::aampGenerateKeyRequest(string& destinationURL, uint32_t timeout)
477 {
478 
479  DrmData * result = NULL;
480  DRM_RESULT drm_res = DRM_SUCCESS;
481  DRM_DWORD cchDestURL = 0;
482  DRM_ANSI_STRING dastrCustomData = EMPTY_DRM_STRING;
483 
484 
485  // Try to figure out the size of the license acquisition
486  // challenge to be returned.
487  //cout << "aampGenerateKeyRequest :: going for playeady generate request" << endl;
488  drm_res = Drm_LicenseAcq_GenerateChallenge(m_ptrAppContext, g_rgpdstrRights,
489  sizeof(g_rgpdstrRights) / sizeof(DRM_CONST_STRING *),
490  NULL,
491  NULL,
492  0,
493  NULL, &cchDestURL,
494  NULL,
495  NULL,
496  NULL, &m_cbChallenge);
497 
498  if (drm_res == DRM_E_BUFFERTOOSMALL)
499  {
500  if (cchDestURL > 0)
501  {
502  ChkMem(
503  m_ptrDestURL = (DRM_CHAR *) Oem_MemAlloc(
504  cchDestURL + 1));
505  ZEROMEM(m_ptrDestURL, cchDestURL + 1);
506  }
507 
508  // Allocate buffer that is sufficient to store the license acquisition
509  // challenge.
510  if (m_cbChallenge > 0)
511  ChkMem(m_pbChallenge = (DRM_BYTE *) Oem_MemAlloc(m_cbChallenge));
512 
513  drm_res = DRM_SUCCESS;
514  } else
515  {
516  ChkDR(drm_res);
517 #ifdef TRACE_LOG
518  cout << "aampGenerateKeyRequest :: Playready challenge generated" << endl;
519 #endif
520  }
521  // Supply a buffer to receive the license acquisition challenge.
522  ChkDR(
523  Drm_LicenseAcq_GenerateChallenge(m_ptrAppContext, g_rgpdstrRights,
524  sizeof(g_rgpdstrRights) / sizeof(DRM_CONST_STRING *),
525  NULL,
526  NULL,
527  0,
528  m_ptrDestURL, &cchDestURL,
529  NULL,
530  NULL, m_pbChallenge, &m_cbChallenge));
531 #ifdef TRACE_LOG
532  AAMPLOG_WARN("aampGenerateKeyRequest :: Playready destination URL : %s ", m_ptrDestURL);
533 #endif
534  m_eKeyState = KEY_PENDING;
535 
536  result = new DrmData(m_pbChallenge, m_cbChallenge);
537  destinationURL = static_cast<string>(m_ptrDestURL);
538  return result;
539 
540  ErrorExit:
541  if (DRM_FAILED(drm_res))
542  {
543  AAMPLOG_WARN("aampGenerateKeyRequest :: Playread DRM key request generation failed error code : %08x ", drm_res);
544  m_eKeyState = KEY_ERROR;
545  }
546  return NULL;
547 }
548 
549 /**
550  * @brief Updates the received key to DRM session
551  */
553 {
554  if(!key)
555  {
556  AAMPLOG_ERR("PlayReadyDRMSession: Cannot Process Null Key ");
557  return 0; //err
558  }
559 
560 #ifdef TRACE_LOG
561  cout << "aampDRMProcessKey :: Playready Update" << endl;
562 #endif
563  DRM_RESULT drm_res = DRM_SUCCESS;
564  DRM_LICENSE_RESPONSE oLicenseResp =
565  { eUnknownProtocol, 0 };
566 
567  //cout << "aampDRMProcessKey :: Playready key state check if pending" << endl;
568  // The current state MUST be KEY_PENDING otherwise error out.
569  ChkBOOL(m_eKeyState == KEY_PENDING, DRM_E_INVALIDARG);
570 #ifdef TRACE_LOG
571  cout << "aampDRMProcessKey :: Playready check if msg is null" << endl;
572 #endif
573  ChkArg(!key->getData().empty() && key->getDataLength() > 0);
574 
575  //cout << "PlayreadyProcessResponse" << endl;
576  drm_res = Drm_LicenseAcq_ProcessResponse(m_ptrAppContext,
577  DRM_PROCESS_LIC_RESPONSE_SIGNATURE_NOT_REQUIRED,
578  NULL,
579  NULL, (DRM_BYTE *)(key->getData().c_str()),
580  key->getDataLength(), &oLicenseResp);
581 #ifdef TRACE_LOG
582  printf("aampDRMProcessKey :: Drm_LicenseAcq_ProcessResponse result : %08x ", drm_res);
583 #endif
584  ChkDR(drm_res);
585 
586 
587  drm_res = Drm_Reader_Bind(m_ptrAppContext, g_rgpdstrRights,
588  NO_OF(g_rgpdstrRights), m_pOutputProtection->PR_OP_Callback,
589  m_pOutputProtection->getPlayReadyLevels(), &m_oDecryptContext);
590 #ifdef TRACE_LOG
591  AAMPLOG_WARN("aampDRMProcessKey :: Printing bind result : %08x ", drm_res);
592 #endif
593  ChkDR(drm_res);
594  m_eKeyState = KEY_READY;
595 
596  AAMPLOG_WARN("aampDRMProcessKey :: Key processed, now ready for content decryption");
597 
598  return 1;
599 
600  ErrorExit: if (DRM_FAILED(drm_res))
601  {
602  AAMPLOG_ERR("aampDRMProcessKey :: Playready failed processing license response : error code : %08x ", drm_res);
603  m_eKeyState = KEY_ERROR;
604  }
605  return 0;
606 
607 }
608 
609 /**
610  * @brief Function to decrypt stream buffer.
611  */
612 int PlayReadyDRMSession::decrypt(const uint8_t *f_pbIV, uint32_t f_cbIV,
613  const uint8_t *payloadData, uint32_t payloadDataSize, uint8_t **ppOpaqueData)
614 {
615 
616  int status = 1;
617  DRM_AES_COUNTER_MODE_CONTEXT oAESContext =
618  { 0 };
619  DRM_RESULT drm_res = DRM_SUCCESS;
620  DRM_RESULT err = DRM_SUCCESS;
621 #ifdef TRACE_LOG
622  cout << "PR decrypt :: Playready Decrypt invoked" << endl;
623 #endif
624  uint8_t *ivData = (uint8_t *) f_pbIV;
625  uint8_t temp;
626 
627  // Verify output protection parameters
628  if(m_pOutputProtection->IsSourceUHD()) {
629  // Source material is UHD
630  if(!m_pOutputProtection->isHDCPConnection2_2()) {
631  // UHD and not HDCP 2.2
632  AAMPLOG_WARN("UHD source but not HDCP 2.2. FAILING decrypt\n");
633  return HDCP_COMPLIANCE_CHECK_FAILURE;
634  }
635  }
636 
637  pthread_mutex_lock(&decryptMutex);
638  ChkDR(Drm_Reader_InitDecrypt(&m_oDecryptContext, NULL, 0));
639  //cout << "PR decrypt :: Playready Decrypt swap IV" << endl;
640  // FIXME: IV bytes need to be swapped ???
641  for (uint32_t i = 0; i < f_cbIV / 2; i++)
642  {
643  temp = ivData[i];
644  ivData[i] = ivData[f_cbIV - i - 1];
645  ivData[f_cbIV - i - 1] = temp;
646  }
647 
648  MEMCPY(&oAESContext.qwInitializationVector, ivData, f_cbIV);
649 
650 #ifdef USE_SAGE_SVP
651  // Make this a run time decision.
652  {
653 #ifdef TRACE_LOG
654  AAMPLOG_TRACE("data len = %d\n", payloadDataSize);
655 #endif
656  OEM_OPAQUE_BUFFER_HANDLE hOpaqueBufferIn;
657  OEM_OPAQUE_BUFFER_HANDLE hOpaqueBufferOut;
658  OEM_HAL_OpaqueBufferCreateWithPointer((DRM_BYTE *)payloadData, payloadDataSize, &hOpaqueBufferIn);
659  OEM_HAL_OpaqueBufferCreate(&hOpaqueBufferOut);
660 
661  err = Drm_Reader_DecryptOpaque(&m_oDecryptContext,
662  &oAESContext,
663  hOpaqueBufferIn,
664  hOpaqueBufferOut,
665  payloadDataSize);
666  // Assign the opaque pointer from the decryptor.
667  DRM_RESULT errHandle = OEM_HAL_OpaqueBufferGetDataHandle(hOpaqueBufferOut, ppOpaqueData);
668  if (DRM_FAILED(errHandle)) {
669  AAMPLOG_ERR("AampDRMSession::decrypt --> OEM_HAL_OpaqueBufferGetDataHandle FAILED errHandle = %X, opaqueData = %p",
670  errHandle, *ppOpaqueData);
671  }
672 
673  OEM_HAL_OpaqueBufferDestroy(&hOpaqueBufferIn);
674  OEM_HAL_OpaqueBufferDestroy(&hOpaqueBufferOut); // Will not delete the data handle
675  }
676 #else
677  {
678  err = Drm_Reader_Decrypt(&m_oDecryptContext, &oAESContext,
679  (DRM_BYTE *) payloadData, payloadDataSize);
680  *ppOpaqueData = NULL;
681  }
682 #endif
683  ChkDR(err);
684 
685  //cout << "PR decrypt :: Playready Decrypt commit" << endl;
686  // Call commit during the decryption of the first sample.
687  if (!m_fCommit)
688  {
689  ChkDR(Drm_Reader_Commit(m_ptrAppContext, m_pOutputProtection->PR_OP_Callback, m_pOutputProtection->getPlayReadyLevels() ));
690  m_fCommit = TRUE;
691  }
692  pthread_mutex_unlock(&decryptMutex);
693 #ifdef TRACE_LOG
694  cout << "Playready Decrypt return clear content" << endl;
695 #endif
696  // Return clear content.
697  status = 0;
698 
699  return status;
700 
701  ErrorExit:
702  pthread_mutex_unlock(&decryptMutex);
703  AAMPLOG_ERR("PR decrypt :: Play ready session : Decrypt Error");
704  return status;
705 
706 }
707 
708 /**
709  * @brief Get the current state of DRM Session.
710  */
712 {
713  return m_eKeyState;
714 }
715 
716 /**
717  * @brief Clear the current session context
718  * So that new init data can be bound.
719  */
721 {
722  Drm_Reader_Close(&m_oDecryptContext);
723  Drm_Reinitialize(m_ptrAppContext);
724  SAFE_OEM_FREE(m_pbChallenge);
725  SAFE_OEM_FREE(m_ptrDestURL);
726  m_pbChallenge = NULL;
727  m_ptrDestURL = NULL;
728  m_fCommit = false;
729  m_cbChallenge = 0;
730  if(m_pbPRO != NULL)
731  {
732  SAFE_OEM_FREE(m_pbPRO);
733  }
734  m_pbPRO = NULL;
735  m_cbPRO = 0;
736  m_eKeyState = KEY_INIT;
737 }
AampConfig::logging
AampLogManager logging
Definition: AampConfig.h:462
DrmData
To hold DRM key, license request etc.
Definition: AampDrmData.h:32
PlayReadyDRMSession::_ParseInitData
int _ParseInitData(const uint8_t *f_pbInitData, uint32_t f_cbInitData)
Parse init data to retrieve PRO from it.
Definition: playreadydrmsession.cpp:442
PlayReadyDRMSession::clearDecryptContext
void clearDecryptContext()
Clear the current session context So that new init data can be bound.
Definition: playreadydrmsession.cpp:720
PlayReadyDRMSession::_GetPROFromInitData
int _GetPROFromInitData(const DRM_BYTE *f_pbInitData, DRM_DWORD f_cbInitData, DRM_DWORD *f_pibPRO, DRM_DWORD *f_pcbPRO)
Retrieve PlayReady Object(PRO) from init data.
Definition: playreadydrmsession.cpp:292
gpGlobalConfig
AampConfig * gpGlobalConfig
Global configuration.
Definition: main_aamp.cpp:48
playreadydrmsession.h
Playready Session management.
AampLogManager
AampLogManager Class.
Definition: AampLogManager.h:150
KEY_PENDING
@ KEY_PENDING
Definition: AampDrmSession.h:57
AampOutputProtection::IsSourceUHD
bool IsSourceUHD()
Check if source is UHD using video decoder dimensions.
Definition: aampoutputprotection.cpp:102
AampLogManager::debug
bool debug
Definition: AampLogManager.h:155
PlayReadyDRMSession::PlayReadyDRMSession
PlayReadyDRMSession(AampLogManager *logObj)
PlayReadyDRMSession Constructor.
Definition: playreadydrmsession.cpp:113
DrmData::getDataLength
int getDataLength()
Getter method for dataLength.
Definition: AampDRMutils.cpp:83
PlayReadyDRMSession::aampDRMProcessKey
int aampDRMProcessKey(DrmData *key, uint32_t timeout)
Updates the received key to DRM session.
Definition: playreadydrmsession.cpp:552
PlayReadyDRMSession::getState
KeyState getState()
Get the current state of DRM Session.
Definition: playreadydrmsession.cpp:711
PlayReadyDRMSession::initAampDRMSession
void initAampDRMSession()
Initialize PR DRM session, state will be set as KEY_INIT on success KEY_ERROR if failure.
Definition: playreadydrmsession.cpp:129
PlayReadyDRMSession::aampGenerateKeyRequest
DrmData * aampGenerateKeyRequest(string &destinationURL, uint32_t timeout)
Generate key request from DRM session Caller function should free the returned memory.
Definition: playreadydrmsession.cpp:476
AampDrmSession
Base class for DRM sessions.
Definition: AampDrmSession.h:69
AampOutputProtection::GetAampOutputProcectionInstance
static AampOutputProtection * GetAampOutputProcectionInstance()
Singleton for object creation.
Definition: aampoutputprotection.cpp:441
AampOutputProtection::isHDCPConnection2_2
bool isHDCPConnection2_2()
Get PlayRedy OP levels.
Definition: aampoutputprotection.h:230
priv_aamp.h
Private functions and types used internally by AAMP.
AAMPLOG_TRACE
#define AAMPLOG_TRACE(FORMAT,...)
AAMP logging defines, this can be enabled through setLogLevel() as per the need.
Definition: AampLogManager.h:83
KEY_INIT
@ KEY_INIT
Definition: AampDrmSession.h:56
PlayReadyDRMSession::generateAampDRMSession
void generateAampDRMSession(const uint8_t *f_pbInitData, uint32_t f_cbInitData, std::string &customData)
Create drm session with given init data state will be KEY_INIT on success KEY_ERROR if failed.
Definition: playreadydrmsession.cpp:201
KEY_READY
@ KEY_READY
Definition: AampDrmSession.h:58
PlayReadyDRMSession::decrypt
int decrypt(const uint8_t *f_pbIV, uint32_t f_cbIV, const uint8_t *payloadData, uint32_t payloadDataSize, uint8_t **ppOpaqueData)
Function to decrypt stream buffer.
Definition: playreadydrmsession.cpp:612
KeyState
KeyState
DRM session states.
Definition: AampDrmSession.h:54
PlayReadyDRMSession::~PlayReadyDRMSession
~PlayReadyDRMSession()
PlayReadyDRMSession Destructor.
Definition: playreadydrmsession.cpp:255
DrmData::getData
const std::string & getData()
Getter method for data.
Definition: AampDRMutils.cpp:75
DRM_UTL_ReadNetworkBytesToNativeGUID
DRM_API DRM_RESULT DRM_CALL DRM_UTL_ReadNetworkBytesToNativeGUID(const DRM_BYTE *pbData, const DRM_DWORD cbData, DRM_DWORD ibGuidOffset, DRM_GUID *pDrmGuid)
Read UUID from init data.
Definition: playreadydrmsession.cpp:81
TRUE
#define TRUE
Defines for TRUE/FALSE/ENABLE flags.
Definition: wifi_common_hal.h:199
KEY_ERROR
@ KEY_ERROR
Definition: AampDrmSession.h:59
KEY_CLOSED
@ KEY_CLOSED
Definition: AampDrmSession.h:60