1 /*
2 *      Copyright (C) 2016 liberty-developer
3 *      https://github.com/liberty-developer
4 *
5 *  This Program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2, or (at your option)
8 *  any later version.
9 *
10 *  This Program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 *  GNU General Public License for more details.
14 *
15 *  <http://www.gnu.org/licenses/>.
16 *
17 */
18 
19 #include "jni/src/MediaDrm.h"
20 #include "jni/src/MediaDrmOnEventListener.h"
21 #include "jni/src/UUID.h"
22 #include "ClassLoader.h"
23 
24 #include "../src/helpers.h"
25 #include "../src/SSD_dll.h"
26 #include "../src/md5.h"
27 #include "jsmn.h"
28 #include "Ap4.h"
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <deque>
32 #include <chrono>
33 #include <thread>
34 
35 using namespace SSD;
36 
37 SSD_HOST *host = 0;
38 
39 #define LOCLICENSE 1
40 
Log(unsigned int loglevel,const char * format,...)41 void Log(unsigned int loglevel, const char *format, ...)
42 {
43   char buffer[16384];
44   va_list args;
45   va_start(args, format);
46   vsprintf(buffer, format, args);
47   va_end(args);
48   return host->Log(static_cast<SSD_HOST::LOGLEVEL>(loglevel), buffer);
49 }
50 
51 /*******************************************************
52 CDM
53 ********************************************************/
54 
55 enum WV_KEYSYSTEM
56 {
57   NONE,
58   WIDEVINE,
59   PLAYREADY,
60   WISEPLAY
61 };
62 
63 class WV_DRM
64 {
65 public:
66   WV_DRM(WV_KEYSYSTEM ks, const char* licenseURL, const AP4_DataBuffer &serverCert, jni::CJNIMediaDrmOnEventListener *listener);
67   ~WV_DRM();
68 
GetMediaDrm()69   jni::CJNIMediaDrm *GetMediaDrm() { return media_drm_; };
70 
GetLicenseURL() const71   const std::string &GetLicenseURL() const { return license_url_; };
72 
GetKeySystem() const73   const uint8_t *GetKeySystem() const
74   {
75     static const uint8_t keysystemId[3][16] = {
76       { 0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed },
77       { 0x9A, 0x04, 0xF0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xAB, 0x92, 0xE6, 0x5B, 0xE0, 0x88, 0x5F, 0x95 },
78       { 0x3d, 0x5e, 0x6d, 0x35, 0x9b, 0x9a, 0x41, 0xe8, 0xb8, 0x43, 0xdd, 0x3c, 0x6e, 0x72, 0xc4, 0x2c },
79     };
80     return keysystemId[key_system_-1];
81   }
GetKeySystemType() const82   WV_KEYSYSTEM GetKeySystemType() const { return key_system_; };
83   void SaveServiceCertificate();
84 
85 private:
86   void LoadServiceCertificate();
87 
88   WV_KEYSYSTEM key_system_;
89   jni::CJNIMediaDrm *media_drm_;
90   std::string license_url_;
91   std::string m_strBasePath;
92 };
93 
WV_DRM(WV_KEYSYSTEM ks,const char * licenseURL,const AP4_DataBuffer & serverCert,jni::CJNIMediaDrmOnEventListener * listener)94 WV_DRM::WV_DRM(WV_KEYSYSTEM ks, const char* licenseURL, const AP4_DataBuffer &serverCert, jni::CJNIMediaDrmOnEventListener *listener)
95   : key_system_(ks)
96   , media_drm_(0)
97   , license_url_(licenseURL)
98 {
99   std::string strBasePath = host->GetProfilePath();
100   char cSep = strBasePath.back();
101   strBasePath += ks == WIDEVINE ? "widevine" : ks == PLAYREADY ? "playready" : "wiseplay";
102   strBasePath += cSep;
103   host->CreateDir(strBasePath.c_str());
104 
105   //Build up a CDM path to store decrypter specific stuff. Each domain gets it own path
106   const char* bspos(strchr(license_url_.c_str(), ':'));
107   if (!bspos || bspos[1] != '/' || bspos[2] != '/' || !(bspos = strchr(bspos + 3, '/')))
108   {
109     Log(SSD_HOST::LL_ERROR, "Unable to find protocol inside license url - invalid");
110     return;
111   }
112   if (bspos - license_url_.c_str() > 256)
113   {
114     Log(SSD_HOST::LL_ERROR, "Length of license URL exeeds max. size of 256 - invalid");
115     return;
116   }
117   char buffer[1024];
118   buffer[(bspos - license_url_.c_str()) * 2] = 0;
119   AP4_FormatHex(reinterpret_cast<const uint8_t*>(license_url_.c_str()), bspos - license_url_.c_str(), buffer);
120 
121   strBasePath += buffer;
122   strBasePath += cSep;
123   host->CreateDir(strBasePath.c_str());
124   m_strBasePath = strBasePath;
125 
126   int64_t mostSigBits(0), leastSigBits(0);
127   const uint8_t *keySystem = GetKeySystem();
128   for (unsigned int i(0); i < 8; ++i)
129     mostSigBits = (mostSigBits << 8) | keySystem[i];
130   for (unsigned int i(8); i < 16; ++i)
131    leastSigBits = (leastSigBits << 8) | keySystem[i];
132 
133   jni::CJNIUUID uuid(mostSigBits, leastSigBits);
134   media_drm_ = new jni::CJNIMediaDrm(uuid);
135   if (xbmc_jnienv()->ExceptionCheck() || !*media_drm_)
136   {
137     Log(SSD_HOST::LL_ERROR, "Unable to initialize media_drm");
138     xbmc_jnienv()->ExceptionClear();
139     delete media_drm_, media_drm_ = nullptr;
140     return;
141   }
142 
143   media_drm_->setOnEventListener(*listener);
144   if (xbmc_jnienv()->ExceptionCheck())
145   {
146     Log(SSD_HOST::LL_ERROR, "Exception during installation of EventListener");
147     xbmc_jnienv()->ExceptionClear();
148     media_drm_->release();
149     delete media_drm_, media_drm_ = nullptr;
150     return;
151   }
152 
153   std::vector<char> strDeviceId = media_drm_->getPropertyByteArray("deviceUniqueId");
154   xbmc_jnienv()->ExceptionClear();
155   std::string strSecurityLevel = media_drm_->getPropertyString("securityLevel");
156   xbmc_jnienv()->ExceptionClear();
157   std::string strSystemId = media_drm_->getPropertyString("systemId");
158   xbmc_jnienv()->ExceptionClear();
159 
160 
161   if (key_system_ == WIDEVINE)
162   {
163     //media_drm_->setPropertyString("sessionSharing", "enable");
164     if (serverCert.GetDataSize())
165       media_drm_->setPropertyByteArray("serviceCertificate", std::vector<char>(serverCert.GetData(), serverCert.GetData() + serverCert.GetDataSize()));
166     else
167       LoadServiceCertificate();
168 
169     if (xbmc_jnienv()->ExceptionCheck())
170     {
171       Log(SSD_HOST::LL_ERROR, "Exception setting Service Certificate");
172       xbmc_jnienv()->ExceptionClear();
173       media_drm_->release();
174       delete media_drm_, media_drm_ = nullptr;
175       return;
176     }
177   }
178 
179   Log(SSD_HOST::LL_DEBUG, "Successful instanciated deviceUniqueIdSize: %ld,systemId: %s security-level: %s", strDeviceId.size(), strSystemId.c_str(), strSecurityLevel.c_str());
180 
181   if (license_url_.find('|') == std::string::npos)
182   {
183     if (key_system_ == WIDEVINE)
184       license_url_ += "|Content-Type=application%2Fx-www-form-urlencoded|widevine2Challenge=B{SSM}&includeHdcpTestKeyInLicense=false|JBlicense;hdcpEnforcementResolutionPixels";
185     else if (key_system_ == PLAYREADY)
186       license_url_ += "|Content-Type=text%2Fxml&SOAPAction=http%3A%2F%2Fschemas.microsoft.com%2FDRM%2F2007%2F03%2Fprotocols%2FAcquireLicense|R{SSM}|";
187     else
188       license_url_ += "|Content-Type=application/json|R{SSM}|";
189   }
190 }
191 
~WV_DRM()192 WV_DRM::~WV_DRM()
193 {
194   if (media_drm_)
195   {
196     media_drm_->release();
197     if (xbmc_jnienv()->ExceptionCheck())
198     {
199       Log(SSD_HOST::LL_ERROR, "Exception releasing media drm");
200       xbmc_jnienv()->ExceptionClear();
201     }
202     delete media_drm_, media_drm_ = nullptr;
203   }
204 }
205 
LoadServiceCertificate()206 void WV_DRM::LoadServiceCertificate()
207 {
208   std::string filename = m_strBasePath + "service_certificate";
209   char* data(nullptr);
210   size_t sz(0);
211   FILE *f = fopen(filename.c_str(), "rb");
212 
213   if (f)
214   {
215     fseek(f, 0L, SEEK_END);
216     sz = ftell(f);
217     fseek(f, 0L, SEEK_SET);
218     if (sz > 8 && (data = (char*)malloc(sz)))
219       fread(data, 1, sz, f);
220     fclose(f);
221   }
222   if (data)
223   {
224     auto now = std::chrono::system_clock::now();
225     uint64_t certTime = *((uint64_t*)data), nowTime = std::chrono::time_point_cast<std::chrono::seconds>(now).time_since_epoch().count();
226 
227     if (certTime < nowTime && nowTime - certTime < 86400)
228       media_drm_->setPropertyByteArray("serviceCertificate", std::vector<char>(data + 8, data + sz));
229     else
230       free(data), data = nullptr;
231   }
232   if (!data)
233   {
234     Log(SSD_HOST::LL_DEBUG, "Requesting new Service Certificate");
235     media_drm_->setPropertyString("privacyMode", "enable");
236   }
237   else
238   {
239     Log(SSD_HOST::LL_DEBUG, "Use stored Service Certificate");
240     free(data), data = nullptr;
241   }
242 }
243 
SaveServiceCertificate()244 void WV_DRM::SaveServiceCertificate()
245 {
246   std::vector<char> sc = media_drm_->getPropertyByteArray("serviceCertificate");
247   if (xbmc_jnienv()->ExceptionCheck())
248   {
249     Log(SSD_HOST::LL_INFO, "Exception retrieving Service Certificate");
250     xbmc_jnienv()->ExceptionClear();
251     return;
252   }
253 
254   if (sc.empty())
255   {
256     Log(SSD_HOST::LL_INFO, "Empty Service Certificate");
257     return;
258   }
259 
260   std::string filename = m_strBasePath + "service_certificate";
261   FILE *f = fopen(filename.c_str(), "wb");
262   if (f)
263   {
264     auto now = std::chrono::system_clock::now();
265     uint64_t nowTime = std::chrono::time_point_cast<std::chrono::seconds>(now).time_since_epoch().count();
266     fwrite((char*)&nowTime, 1, sizeof(uint64_t), f);
267     fwrite(sc.data(), 1, sc.size(), f);
268     fclose(f);
269   }
270 }
271 
272 /*----------------------------------------------------------------------
273 |   WV_CencSingleSampleDecrypter
274 +---------------------------------------------------------------------*/
275 class WV_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter
276 {
277 public:
278   // methods
279   WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t* defaultKeyId);
280   ~WV_CencSingleSampleDecrypter();
281 
StartSession(bool skipSessionMessage)282   bool StartSession(bool skipSessionMessage) { return KeyUpdateRequest(true, skipSessionMessage); };
GetSessionIdRaw()283   const std::vector<char> &GetSessionIdRaw() { return session_id_; };
284   virtual const char *GetSessionId() override;
285   std::vector<char> GetChallengeData();
286   virtual bool HasLicenseKey(const uint8_t *keyid);
287 
288   virtual AP4_Result SetFragmentInfo(AP4_UI32 pool_id, const AP4_UI08 *key, const AP4_UI08 nal_length_size, AP4_DataBuffer &annexb_sps_pps, AP4_UI32 flags)override;
289   virtual AP4_UI32 AddPool() override;
290   virtual void RemovePool(AP4_UI32 poolid) override;
291 
292   virtual AP4_Result DecryptSampleData(AP4_UI32 pool_id,
293     AP4_DataBuffer& data_in,
294     AP4_DataBuffer& data_out,
295 
296     // always 16 bytes
297     const AP4_UI08* iv,
298 
299     // pass 0 for full decryption
300     unsigned int    subsample_count,
301 
302     // array of <subsample_count> integers. NULL if subsample_count is 0
303     const AP4_UI16* bytes_of_cleartext_data,
304 
305     // array of <subsample_count> integers. NULL if subsample_count is 0
306     const AP4_UI32* bytes_of_encrypted_data) override;
307 
308   void GetCapabilities(const uint8_t *keyid, uint32_t media, SSD_DECRYPTER::SSD_CAPS &caps);
309 
RequestNewKeys()310   void RequestNewKeys() { keyUpdateRequested = true; };
311 
312 private:
313   bool ProvisionRequest();
314   bool GetKeyRequest(std::vector<char>& keyRequestData);
315   bool KeyUpdateRequest(bool waitForKeys, bool skipSessionMessage);
316   bool SendSessionMessage(const std::vector<char> &keyRequestData);
317 
318   WV_DRM &media_drm_;
319   std::vector<char> pssh_, initial_pssh_;
320   std::map<std::string, std::string> optParams_;
321 
322   std::vector<char> session_id_;
323   std::vector<char> keySetId_;
324   std::vector<char> keyRequestData_;
325 
326   char session_id_char_[128];
327   bool provisionRequested, keyUpdateRequested;
328 
329   uint8_t defaultKeyId_[16];
330 
331   struct FINFO
332   {
333     const AP4_UI08 *key_;
334     AP4_UI08 nal_length_size_;
335     AP4_UI16 decrypter_flags_;
336     AP4_DataBuffer annexb_sps_pps_;
337   };
338   std::vector<FINFO> fragment_pool_;
339   AP4_UI32 hdcp_limit_, resolution_limit_;
340 };
341 
342 /*----------------------------------------------------------------------
343 |   WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter
344 +---------------------------------------------------------------------*/
345 
WV_CencSingleSampleDecrypter(WV_DRM & drm,AP4_DataBuffer & pssh,const char * optionalKeyParameter,const uint8_t * defaultKeyId)346 WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t* defaultKeyId)
347   : AP4_CencSingleSampleDecrypter(0)
348   , media_drm_(drm)
349   , provisionRequested(false)
350   , keyUpdateRequested(false)
351   , hdcp_limit_(0)
352   , resolution_limit_(0)
353 {
354   SetParentIsOwner(false);
355 
356   if (pssh.GetDataSize() > 65535)
357   {
358     Log(SSD_HOST::LL_ERROR, "Init_data with length: %u seems not to be cenc init data!", pssh.GetDataSize());
359     return;
360   }
361 
362 #ifdef LOCLICENSE
363   std::string strDbg = host->GetProfilePath();
364   strDbg += "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED.init";
365   FILE*f = fopen(strDbg.c_str(), "wb");
366   fwrite(pssh.GetData(), 1, pssh.GetDataSize(), f);
367   fclose(f);
368 #endif
369 
370   pssh_.assign(pssh.GetData(), pssh.GetData() +  pssh.GetDataSize());
371 
372   if (memcmp(pssh.GetData() + 4, "pssh", 4) != 0)
373   {
374     const uint8_t atomheader[] = { 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x73, 0x68, 0x00, 0x00, 0x00, 0x00 };
375     uint8_t atom[32];
376     memcpy(atom, atomheader, 12);
377     memcpy(atom+12, media_drm_.GetKeySystem(), 16);
378     memset(atom+28, 0, 4);
379 
380     pssh_.insert(pssh_.begin(), reinterpret_cast<char*>(atom), reinterpret_cast<char*>(atom + sizeof(atom)));
381 
382     pssh_[3] = static_cast<uint8_t>(pssh_.size());
383     pssh_[2] = static_cast<uint8_t>(pssh_.size() >> 8);
384 
385     pssh_[sizeof(atom) - 1] = static_cast<uint8_t>(pssh_.size()) - sizeof(atom);
386     pssh_[sizeof(atom) - 2] = static_cast<uint8_t>((pssh_.size() - sizeof(atom)) >> 8);
387   }
388   initial_pssh_ = pssh_;
389 
390   if (defaultKeyId)
391     memcpy(defaultKeyId_, defaultKeyId, 16);
392   else
393     memset(defaultKeyId_, 0, 16);
394 
395   if (optionalKeyParameter)
396     optParams_["PRCustomData"] = optionalKeyParameter;
397 
398   /*
399   std::vector<char> pui = media_drm_.GetMediaDrm()->getPropertyByteArray("provisioningUniqueId");
400   xbmc_jnienv()->ExceptionClear();
401   if (pui.size() > 0)
402   {
403     std::string encoded = b64_encode(reinterpret_cast<const uint8_t*>(pui.data()), pui.size(), false);
404     optParams_["CDMID"] = encoded;;
405   }
406   */
407 
408   bool L3FallbackRequested = false;
409 RETRY_OPEN:
410   session_id_ = media_drm_.GetMediaDrm()->openSession();
411   if (xbmc_jnienv()->ExceptionCheck())
412   {
413     xbmc_jnienv()->ExceptionClear();
414     if (!provisionRequested)
415     {
416       Log(SSD_HOST::LL_ERROR, "Exception during open session - provisioning...");
417       provisionRequested = true;
418       if (!ProvisionRequest())
419       {
420         if (!L3FallbackRequested && media_drm_.GetMediaDrm()->getPropertyString("securityLevel") == "L1")
421         {
422           Log(SSD_HOST::LL_INFO, "L1 provisioning failed - retrying with L3...");
423           L3FallbackRequested = true;
424           provisionRequested = false;
425           media_drm_.GetMediaDrm()->setPropertyString("securityLevel", "L3");
426           goto RETRY_OPEN;
427         }
428         else
429           return;
430       }
431       goto RETRY_OPEN;
432     }
433     else
434     {
435       Log(SSD_HOST::LL_ERROR, "Exception during open session - abort");
436       return;
437     }
438   }
439 
440   if (session_id_.size() == 0)
441   {
442     Log(SSD_HOST::LL_ERROR, "Unable to open DRM session");
443     return;
444   }
445 
446   memcpy(session_id_char_, session_id_.data(), session_id_.size());
447   session_id_char_[session_id_.size()] = 0;
448 
449   if (media_drm_.GetKeySystemType() != PLAYREADY)
450   {
451     int maxSecuritylevel = media_drm_.GetMediaDrm()->getMaxSecurityLevel();
452     xbmc_jnienv()->ExceptionClear();
453 
454     Log(SSD_HOST::LL_DEBUG, "SessionId: %s, MaxSecurityLevel: %d",
455       session_id_char_, maxSecuritylevel);
456   }
457 }
458 
~WV_CencSingleSampleDecrypter()459 WV_CencSingleSampleDecrypter::~WV_CencSingleSampleDecrypter()
460 {
461   if (!session_id_.empty())
462   {
463     media_drm_.GetMediaDrm()->removeKeys(session_id_);
464     if (xbmc_jnienv()->ExceptionCheck())
465     {
466       Log(SSD_HOST::LL_ERROR, "Exception removeKeys");
467       xbmc_jnienv()->ExceptionClear();
468     }
469     media_drm_.GetMediaDrm()->closeSession(session_id_);
470     if (xbmc_jnienv()->ExceptionCheck())
471     {
472       Log(SSD_HOST::LL_ERROR, "Exception closeSession");
473       xbmc_jnienv()->ExceptionClear();
474     }
475   }
476 }
477 
GetSessionId()478 const char *WV_CencSingleSampleDecrypter::GetSessionId()
479 {
480   return session_id_char_;
481 }
482 
GetChallengeData()483 std::vector<char> WV_CencSingleSampleDecrypter::GetChallengeData()
484 {
485   return keyRequestData_;
486 }
487 
HasLicenseKey(const uint8_t * keyid)488 bool WV_CencSingleSampleDecrypter::HasLicenseKey(const uint8_t *keyid)
489 {
490   // true = one session for all streams, false = one sessions per stream
491   // false fixes pixaltion issues on some devices when manifest has multiple encrypted streams
492   return false;
493 }
494 
GetCapabilities(const uint8_t * keyid,uint32_t media,SSD_DECRYPTER::SSD_CAPS & caps)495 void WV_CencSingleSampleDecrypter::GetCapabilities(const uint8_t *keyid, uint32_t media, SSD_DECRYPTER::SSD_CAPS &caps)
496 {
497   caps = { SSD_DECRYPTER::SSD_CAPS::SSD_SECURE_PATH | SSD_DECRYPTER::SSD_CAPS::SSD_ANNEXB_REQUIRED, 0, hdcp_limit_ };
498 
499   if (caps.hdcpLimit == 0)
500     caps.hdcpLimit = resolution_limit_;
501 
502   if (media_drm_.GetMediaDrm()->getPropertyString("securityLevel") == "L1")
503   {
504     caps.hdcpLimit = resolution_limit_; //No restriction
505     caps.flags |= SSD_DECRYPTER::SSD_CAPS::SSD_SECURE_DECODER;
506   }
507   Log(SSD_HOST::LL_DEBUG, "GetCapabilities: hdcpLimit: %u", caps.hdcpLimit);
508 }
509 
ProvisionRequest()510 bool WV_CencSingleSampleDecrypter::ProvisionRequest()
511 {
512   Log(SSD_HOST::LL_ERROR, "PrivisionData request: drm:%p" , media_drm_.GetMediaDrm());
513 
514   jni::CJNIMediaDrmProvisionRequest request = media_drm_.GetMediaDrm()->getProvisionRequest();
515   if (xbmc_jnienv()->ExceptionCheck())
516   {
517     Log(SSD_HOST::LL_ERROR, "Exception on getProvisionRequest");
518     xbmc_jnienv()->ExceptionClear();
519     return false;
520   }
521 
522   std::vector<char> provData = request.getData();
523   std::string url = request.getDefaultUrl();
524 
525   Log(SSD_HOST::LL_DEBUG, "PrivisionData: size: %lu, url: %s", provData.size(), url.c_str());
526 
527   std::string tmp_str("{\"signedRequest\":\"");
528   tmp_str += std::string(provData.data(), provData.size());
529   tmp_str += "\"}";
530 
531   std::string encoded = b64_encode(reinterpret_cast<const uint8_t*>(tmp_str.data()), tmp_str.size(), false);
532 
533   void* file = host->CURLCreate(url.c_str());
534   host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "Content-Type", "application/json");
535   host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "seekable", "0");
536   host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "postdata", encoded.c_str());
537 
538   if (!host->CURLOpen(file))
539   {
540     Log(SSD_HOST::LL_ERROR, "Provisioning server returned failure");
541     return false;
542   }
543   provData.clear();
544   char buf[8192];
545   size_t nbRead;
546 
547   // read the file
548   while ((nbRead = host->ReadFile(file, buf, 8192)) > 0)
549     provData.insert(provData.end(), buf, buf + nbRead);
550 
551   media_drm_.GetMediaDrm()->provideProvisionResponse(provData);
552   if (xbmc_jnienv()->ExceptionCheck())
553   {
554     Log(SSD_HOST::LL_ERROR, "Exception on provideProvisionResponse");
555     xbmc_jnienv()->ExceptionClear();
556     return false;
557   }
558   return true;
559 }
560 
GetKeyRequest(std::vector<char> & keyRequestData)561 bool WV_CencSingleSampleDecrypter::GetKeyRequest(std::vector<char>& keyRequestData)
562 {
563   jni::CJNIMediaDrmKeyRequest keyRequest = media_drm_.GetMediaDrm()->getKeyRequest(
564       session_id_, pssh_, "video/mp4", jni::CJNIMediaDrm::KEY_TYPE_STREAMING, optParams_);
565 
566   if (xbmc_jnienv()->ExceptionCheck())
567   {
568     xbmc_jnienv()->ExceptionClear();
569     if (!provisionRequested)
570     {
571       Log(SSD_HOST::LL_INFO, "Key request not successful - trying provisioning");
572       provisionRequested = true;
573       return GetKeyRequest(keyRequestData);
574     }
575     else
576       Log(SSD_HOST::LL_ERROR, "Key request not successful");
577     return false;
578   }
579 
580   keyRequestData = keyRequest.getData();
581   Log(SSD_HOST::LL_DEBUG, "Key request successful size: %lu", keyRequestData.size());
582   return true;
583 }
584 
KeyUpdateRequest(bool waitKeys,bool skipSessionMessage)585 bool WV_CencSingleSampleDecrypter::KeyUpdateRequest(bool waitKeys, bool skipSessionMessage)
586 {
587   if (!GetKeyRequest(keyRequestData_))
588     return false;
589 
590   pssh_.clear();
591   optParams_.clear();
592 
593   if (skipSessionMessage)
594     return true;
595 
596   keyUpdateRequested = false;
597   if (!SendSessionMessage(keyRequestData_))
598     return false;
599 
600   if (waitKeys && keyRequestData_.size() == 2) // Service Certificate call
601   {
602     for (unsigned int i(0); i < 100 && !keyUpdateRequested; ++i)
603       std::this_thread::sleep_for(std::chrono::milliseconds(10));
604 
605     if (keyUpdateRequested)
606       KeyUpdateRequest(false, false);
607     else
608     {
609       Log(SSD_HOST::LL_ERROR, "Timeout waiting for EVENT_KEYS_REQUIRED!");
610       return false;
611     }
612   }
613   Log(SSD_HOST::LL_DEBUG, "License update successful");
614 
615   if (media_drm_.GetKeySystemType() != PLAYREADY)
616   {
617     int securityLevel = media_drm_.GetMediaDrm()->getSecurityLevel(session_id_);
618     xbmc_jnienv()->ExceptionClear();
619     Log(SSD_HOST::LL_DEBUG, "SecurityLevel: %d", securityLevel);
620 
621     std::map<std::string, std::string> keyStatus = media_drm_.GetMediaDrm()->queryKeyStatus(session_id_);
622     Log(SSD_HOST::LL_DEBUG, "Key Status (%ld):", keyStatus.size());
623     for (auto const& ks : keyStatus)
624       Log(SSD_HOST::LL_DEBUG, "-> %s -> %s", ks.first.c_str(), ks.second.c_str());
625   }
626   return true;
627 }
628 
SendSessionMessage(const std::vector<char> & keyRequestData)629 bool WV_CencSingleSampleDecrypter::SendSessionMessage(const std::vector<char> &keyRequestData)
630 {
631   std::vector<std::string> headers, header, blocks = split(media_drm_.GetLicenseURL(), '|');
632   if (blocks.size() != 4)
633   {
634     Log(SSD_HOST::LL_ERROR, "4 '|' separated blocks in licURL expected (req / header / body / response)");
635     return false;
636   }
637 
638 #ifdef LOCLICENSE
639   std::string strDbg = host->GetProfilePath();
640   strDbg += "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED.challenge";
641   FILE*f = fopen(strDbg.c_str(), "wb");
642   fwrite(keyRequestData.data(), 1, keyRequestData.size(), f);
643   fclose(f);
644 #endif
645 
646   //Process placeholder in GET String
647   std::string::size_type insPos(blocks[0].find("{SSM}"));
648   if (insPos != std::string::npos)
649   {
650     if (insPos>0 && blocks[0][insPos - 1] == 'B')
651     {
652       std::string msgEncoded = b64_encode(reinterpret_cast<const uint8_t*>(keyRequestData.data()), keyRequestData.size(), true);
653       blocks[0].replace(insPos - 1, 6, msgEncoded);
654     }
655     else
656     {
657       Log(SSD_HOST::LL_ERROR, "Unsupported License request template (cmd)");
658       return false;
659     }
660   }
661 
662   insPos = blocks[0].find("{HASH}");
663   if (insPos != std::string::npos)
664   {
665     MD5 md5;
666     md5.update(keyRequestData.data(), keyRequestData.size());
667     md5.finalize();
668     blocks[0].replace(insPos, 6, md5.hexdigest());
669   }
670 
671   void* file = host->CURLCreate(blocks[0].c_str());
672 
673   size_t nbRead;
674   std::string response, resLimit, contentType;
675   char buf[2048];
676 
677   //Set our std headers
678   host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "acceptencoding", "gzip, deflate");
679   host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "seekable", "0");
680 
681   //Process headers
682   headers = split(blocks[1], '&');
683   for (std::vector<std::string>::iterator b(headers.begin()), e(headers.end()); b != e; ++b)
684   {
685     header = split(*b, '=');
686     host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, trim(header[0]).c_str(), header.size() > 1 ? url_decode(trim(header[1])).c_str() : "");
687   }
688 
689   //Process body
690   if (!blocks[2].empty())
691   {
692     if (blocks[2][0] == '%')
693       blocks[2] = url_decode(blocks[2]);
694 
695     insPos = blocks[2].find("{SSM}");
696     if (insPos != std::string::npos)
697     {
698       std::string::size_type sidPos(blocks[2].find("{SID}"));
699       std::string::size_type kidPos(blocks[2].find("{KID}"));
700       std::string::size_type psshPos(blocks[2].find("{PSSH}"));
701 
702       char fullDecode = 0;
703       if (insPos > 1 && sidPos > 1 && kidPos > 1 && (blocks[2][0] == 'b' || blocks[2][0] == 'B') && blocks[2][1] == '{')
704       {
705         fullDecode = blocks[2][0];
706         blocks[2] = blocks[2].substr(2, blocks[2].size() - 3);
707         insPos -= 2;
708         if (kidPos != std::string::npos)
709           kidPos -= 2;
710         if (sidPos != std::string::npos)
711           sidPos -= 2;
712         if (psshPos != std::string::npos)
713           psshPos -= 2;
714       }
715 
716       size_t size_written(0);
717 
718       if (insPos > 0)
719       {
720         if (blocks[2][insPos - 1] == 'B' || blocks[2][insPos - 1] == 'b')
721         {
722           std::string msgEncoded = b64_encode(reinterpret_cast<const uint8_t*>(keyRequestData.data()), keyRequestData.size(), blocks[2][insPos - 1] == 'B');
723           blocks[2].replace(insPos - 1, 6, msgEncoded);
724           size_written = msgEncoded.size();
725         }
726         else if (blocks[2][insPos - 1] == 'D')
727         {
728           std::string msgEncoded = ToDecimal(reinterpret_cast<const uint8_t*>(keyRequestData.data()), keyRequestData.size());
729           blocks[2].replace(insPos - 1, 6, msgEncoded);
730           size_written = msgEncoded.size();
731         }
732         else
733         {
734           blocks[2].replace(insPos - 1, 6, keyRequestData.data(), keyRequestData.size());
735           size_written =  keyRequestData.size();
736         }
737       }
738       else
739       {
740         Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body / ?{SSM})");
741         goto SSMFAIL;
742       }
743 
744       if (sidPos != std::string::npos && insPos < sidPos)
745         sidPos += size_written, sidPos -= 6;
746 
747       if (kidPos != std::string::npos && insPos < kidPos)
748         kidPos += size_written, kidPos -= 6;
749 
750       if (psshPos != std::string::npos && insPos < psshPos)
751         psshPos += size_written, psshPos -= 6;
752 
753       size_written = 0;
754 
755       if (sidPos != std::string::npos)
756       {
757         if (sidPos > 0)
758         {
759           if (blocks[2][sidPos - 1] == 'B' || blocks[2][sidPos - 1] == 'b')
760           {
761             std::string msgEncoded = b64_encode(reinterpret_cast<const uint8_t*>(session_id_.data()), session_id_.size(), blocks[2][sidPos - 1] == 'B');
762             blocks[2].replace(sidPos - 1, 6, msgEncoded);
763             size_written = msgEncoded.size();
764           }
765           else
766           {
767             blocks[2].replace(sidPos - 1, 6, session_id_.data(), session_id_.size());
768             size_written = session_id_.size();
769           }
770         }
771         else
772         {
773           Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body / ?{SID})");
774           goto SSMFAIL;
775         }
776       }
777 
778       if (kidPos != std::string::npos && sidPos < kidPos)
779         kidPos += size_written, kidPos -= 6;
780 
781       if (psshPos != std::string::npos && sidPos < psshPos)
782         psshPos += size_written, psshPos -= 6;
783 
784       size_t kidPlaceholderLen = 6;
785       if (kidPos != std::string::npos)
786       {
787         char uuid[36];
788         if (blocks[2][kidPos - 1] == 'H')
789         {
790           AP4_FormatHex(defaultKeyId_, 16, uuid);
791           blocks[2].replace(kidPos - 1, 6, (const char*)uuid, 32);
792         }
793         else
794         {
795           KIDtoUUID(defaultKeyId_, uuid);
796           blocks[2].replace(kidPos, 5, (const char*)uuid, 36);
797           kidPlaceholderLen = 5;
798         }
799       }
800 
801       if (psshPos != std::string::npos && kidPos < psshPos)
802         psshPos += size_written, psshPos -= kidPlaceholderLen;
803 
804       if (psshPos != std::string::npos)
805       {
806         std::string msgEncoded = b64_encode(reinterpret_cast<const uint8_t*>(initial_pssh_.data()), initial_pssh_.size(), blocks[2][psshPos - 1] == 'B');
807         blocks[2].replace(psshPos - 1, 7, msgEncoded);
808         size_written = msgEncoded.size();
809       }
810 
811       if (fullDecode)
812         blocks[2] = b64_encode(reinterpret_cast<const unsigned char*>(blocks[2].data()), blocks[2].size(), fullDecode == 'B');
813 
814 #ifdef LOCLICENSE
815       std::string strDbg = host->GetProfilePath();
816       strDbg += "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED.postdata";
817       FILE*f = fopen(strDbg.c_str(), "wb");
818       fwrite(blocks[2].data(), 1, blocks[2].size(), f);
819       fclose(f);
820 #endif
821     }
822     std::string decoded = b64_encode(reinterpret_cast<const unsigned char*>(blocks[2].data()), blocks[2].size(), false);
823     host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "postdata", decoded.c_str());
824   }
825 
826   if (!host->CURLOpen(file))
827   {
828     Log(SSD_HOST::LL_ERROR, "License server returned failure");
829     goto SSMFAIL;
830   }
831 
832   // read the file
833   while ((nbRead = host->ReadFile(file, buf, 1024)) > 0)
834     response += std::string((const char*)buf, nbRead);
835 
836   resLimit = host->CURLGetProperty(file, SSD_HOST::CURLPROPERTY::PROPERTY_HEADER, "X-Limit-Video");
837   contentType = host->CURLGetProperty(file, SSD_HOST::CURLPROPERTY::PROPERTY_HEADER, "Content-Type");
838 
839   if (!resLimit.empty())
840   {
841     std::string::size_type posMax = resLimit.find("max=");
842     if (posMax != std::string::npos)
843       resolution_limit_ = atoi(resLimit.data() + (posMax + 4));
844   }
845 
846   host->CloseFile(file);
847   file = 0;
848 
849   if (nbRead != 0)
850   {
851     Log(SSD_HOST::LL_ERROR, "Could not read full SessionMessage response");
852     goto SSMFAIL;
853   }
854   else if (response.empty())
855   {
856     Log(SSD_HOST::LL_ERROR, "Empty SessionMessage response - invalid");
857     goto SSMFAIL;
858   }
859 
860   if (media_drm_.GetKeySystemType() == PLAYREADY && response.find("<LicenseNonce>") == std::string::npos)
861   {
862     std::string::size_type dstPos(response.find("</Licenses>"));
863     std::string challenge(keyRequestData.data(), keyRequestData.size());
864     std::string::size_type srcPosS(challenge.find("<LicenseNonce>"));
865     if (dstPos != std::string::npos && srcPosS != std::string::npos)
866     {
867       Log(SSD_HOST::LL_DEBUG, "Inserting <LicenseNonce>");
868       std::string::size_type srcPosE(challenge.find("</LicenseNonce>", srcPosS));
869       if (srcPosE != std::string::npos)
870         response.insert(dstPos + 11, challenge.c_str() + srcPosS, srcPosE - srcPosS + 15);
871     }
872   }
873 
874 #ifdef LOCLICENSE
875   strDbg = host->GetProfilePath();
876   strDbg += "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED.response";
877   f = fopen(strDbg.c_str(), "wb");
878   fwrite(response.data(), 1, response.size(), f);
879   fclose(f);
880 #endif
881 
882   if (!blocks[3].empty() && (keyRequestData.size() > 2 || contentType.find("application/octet-stream") == std::string::npos))
883   {
884     if (blocks[3][0] == 'J' || (blocks[3].size() > 1 && blocks[3][0] == 'B' && blocks[3][1] == 'J'))
885     {
886       int dataPos = 2;
887 
888       if (response.size() >= 3 && blocks[3][0] == 'B')
889       {
890         unsigned int decoded_size = 2048;
891         uint8_t decoded[2048];
892         b64_decode(response.c_str(), response.size(), decoded, decoded_size);
893         response = std::string(reinterpret_cast<const char*>(decoded), decoded_size);
894         dataPos = 3;
895       }
896 
897       jsmn_parser jsn;
898       jsmntok_t tokens[256];
899 
900       jsmn_init(&jsn);
901       int i(0), numTokens = jsmn_parse(&jsn, response.c_str(), response.size(), tokens, 256);
902 
903       std::vector<std::string> jsonVals = split(blocks[3].c_str() + dataPos, ';');
904 
905       // Find HDCP limit
906       if (jsonVals.size() > 1)
907       {
908         for (; i < numTokens; ++i)
909           if (tokens[i].type == JSMN_STRING && tokens[i].size == 1 && jsonVals[1].size() == static_cast<unsigned int>(tokens[i].end - tokens[i].start)
910             && strncmp(response.c_str() + tokens[i].start, jsonVals[1].c_str(), tokens[i].end - tokens[i].start) == 0)
911             break;
912         if (i < numTokens)
913           hdcp_limit_ = atoi((response.c_str() + tokens[i + 1].start));
914       }
915       // Find license key
916       if (jsonVals.size() > 0)
917       {
918         for (i = 0; i < numTokens; ++i)
919           if (tokens[i].type == JSMN_STRING && tokens[i].size == 1 && jsonVals[0].size() == static_cast<unsigned int>(tokens[i].end - tokens[i].start)
920             && strncmp(response.c_str() + tokens[i].start, jsonVals[0].c_str(), tokens[i].end - tokens[i].start) == 0)
921           {
922             if (i + 1 < numTokens && tokens[i + 1].type == JSMN_ARRAY && tokens[i + 1].size == 1)
923               ++i;
924             break;
925           }
926       }
927       else
928         i = numTokens;
929 
930       if (i < numTokens)
931       {
932         if (blocks[3][dataPos - 1] == 'B')
933         {
934           unsigned int decoded_size = 2048;
935           uint8_t decoded[2048];
936 
937           b64_decode(response.c_str() + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start, decoded, decoded_size);
938           response = std::string(reinterpret_cast<char*>(decoded), decoded_size);
939         }
940         else
941           response = std::string(response.c_str() + tokens[i + 1].start, response.c_str() + tokens[i + 1].end);
942       }
943       else
944       {
945         Log(SSD_HOST::LL_ERROR, "Unable to find %s in JSON string", blocks[3].c_str() + 2);
946         goto SSMFAIL;
947       }
948     }
949     else if (blocks[3][0] == 'H' && blocks[3].size() >= 2)
950     {
951       //Find the payload
952       std::string::size_type payloadPos = response.find("\r\n\r\n");
953       if (payloadPos != std::string::npos)
954       {
955         payloadPos += 4;
956         if (blocks[3][1] == 'B')
957           response = std::string(response.c_str() + payloadPos, response.c_str() + response.size());
958         else
959         {
960           Log(SSD_HOST::LL_ERROR, "Unsupported HTTP payload data type definition");
961           goto SSMFAIL;
962         }
963       }
964       else
965       {
966         Log(SSD_HOST::LL_ERROR, "Unable to find HTTP payload in response");
967         goto SSMFAIL;
968       }
969     }
970     else if (blocks[3][0] == 'B' && blocks[3].size() == 1)
971     {
972       unsigned int decoded_size = 2048;
973       uint8_t decoded[2048];
974       b64_decode(response.c_str(), response.size(), decoded, decoded_size);
975       response = std::string(reinterpret_cast<char*>(decoded), decoded_size);
976     }
977     else
978     {
979       Log(SSD_HOST::LL_ERROR, "Unsupported License request template (response)");
980       goto SSMFAIL;
981     }
982   }
983 
984   keySetId_ = media_drm_.GetMediaDrm()->provideKeyResponse(session_id_, std::vector<char>(response.data(), response.data() + response.size()));
985   if (xbmc_jnienv()->ExceptionCheck())
986   {
987     Log(SSD_HOST::LL_INFO, "Exception in provideKeyResponse");
988     xbmc_jnienv()->ExceptionClear();
989     return false;
990   }
991 
992   if (keyRequestData.size() == 2)
993    media_drm_.SaveServiceCertificate();
994 
995   return true;
996 
997 SSMFAIL:
998   if (file)
999     host->CloseFile(file);
1000   return false;
1001 }
1002 
1003 /*----------------------------------------------------------------------
1004 |   WV_CencSingleSampleDecrypter::SetKeyId
1005 +---------------------------------------------------------------------*/
1006 
SetFragmentInfo(AP4_UI32 pool_id,const AP4_UI08 * key,const AP4_UI08 nal_length_size,AP4_DataBuffer & annexb_sps_pps,AP4_UI32 flags)1007 AP4_Result WV_CencSingleSampleDecrypter::SetFragmentInfo(AP4_UI32 pool_id, const AP4_UI08 *key,
1008   const AP4_UI08 nal_length_size, AP4_DataBuffer &annexb_sps_pps, AP4_UI32 flags)
1009 {
1010   if (pool_id >= fragment_pool_.size())
1011     return AP4_ERROR_OUT_OF_RANGE;
1012 
1013   fragment_pool_[pool_id].key_ = key;
1014   fragment_pool_[pool_id].nal_length_size_ = nal_length_size;
1015   fragment_pool_[pool_id].annexb_sps_pps_.SetData(annexb_sps_pps.GetData(), annexb_sps_pps.GetDataSize());
1016   fragment_pool_[pool_id].decrypter_flags_ = flags;
1017 
1018   if (keyUpdateRequested)
1019     KeyUpdateRequest(false, false);
1020 
1021   return AP4_SUCCESS;
1022 }
1023 
AddPool()1024 AP4_UI32 WV_CencSingleSampleDecrypter::AddPool()
1025 {
1026   for (size_t i(0); i < fragment_pool_.size(); ++i)
1027     if (fragment_pool_[i].nal_length_size_ == 99)
1028     {
1029       fragment_pool_[i].nal_length_size_ = 0;
1030       return i;
1031     }
1032   fragment_pool_.push_back(FINFO());
1033   fragment_pool_.back().nal_length_size_ = 0;
1034   return static_cast<AP4_UI32>(fragment_pool_.size() - 1);
1035 }
1036 
1037 
RemovePool(AP4_UI32 poolid)1038 void WV_CencSingleSampleDecrypter::RemovePool(AP4_UI32 poolid)
1039 {
1040   fragment_pool_[poolid].nal_length_size_ = 99;
1041   fragment_pool_[poolid].key_ = nullptr;
1042 }
1043 
1044 /*----------------------------------------------------------------------
1045 |   WV_CencSingleSampleDecrypter::DecryptSampleData
1046 +---------------------------------------------------------------------*/
DecryptSampleData(AP4_UI32 pool_id,AP4_DataBuffer & data_in,AP4_DataBuffer & data_out,const AP4_UI08 * iv,unsigned int subsample_count,const AP4_UI16 * bytes_of_cleartext_data,const AP4_UI32 * bytes_of_encrypted_data)1047 AP4_Result WV_CencSingleSampleDecrypter::DecryptSampleData(AP4_UI32 pool_id,
1048   AP4_DataBuffer& data_in,
1049   AP4_DataBuffer& data_out,
1050   const AP4_UI08* iv,
1051   unsigned int    subsample_count,
1052   const AP4_UI16* bytes_of_cleartext_data,
1053   const AP4_UI32* bytes_of_encrypted_data)
1054 {
1055   if (!media_drm_.GetMediaDrm())
1056     return AP4_ERROR_INVALID_STATE;
1057 
1058   if (data_in.GetDataSize() > 0)
1059   {
1060     FINFO &fragInfo(fragment_pool_[pool_id]);
1061 
1062     if (fragInfo.nal_length_size_ > 4)
1063     {
1064       Log(SSD_HOST::LL_ERROR, "Nalu length size > 4 not supported");
1065       return AP4_ERROR_NOT_SUPPORTED;
1066     }
1067 
1068     AP4_UI16 dummyClear(0);
1069     AP4_UI32 dummyCipher(data_in.GetDataSize());
1070 
1071     if (iv)
1072     {
1073       if (!subsample_count)
1074       {
1075         subsample_count = 1;
1076         bytes_of_cleartext_data = &dummyClear;
1077         bytes_of_encrypted_data = &dummyCipher;
1078       }
1079 
1080       data_out.SetData(reinterpret_cast<const AP4_Byte*>(&subsample_count), sizeof(subsample_count));
1081       data_out.AppendData(reinterpret_cast<const AP4_Byte*>(bytes_of_cleartext_data), subsample_count * sizeof(AP4_UI16));
1082       data_out.AppendData(reinterpret_cast<const AP4_Byte*>(bytes_of_encrypted_data), subsample_count * sizeof(AP4_UI32));
1083       data_out.AppendData(reinterpret_cast<const AP4_Byte*>(iv), 16);
1084       data_out.AppendData(reinterpret_cast<const AP4_Byte*>(fragInfo.key_), 16);
1085     }
1086     else
1087     {
1088       data_out.SetDataSize(0);
1089       bytes_of_cleartext_data = &dummyClear;
1090       bytes_of_encrypted_data = &dummyCipher;
1091     }
1092 
1093     if (fragInfo.nal_length_size_ && (!iv || bytes_of_cleartext_data[0] > 0))
1094     {
1095       //Note that we assume that there is enough data in data_out to hold everything without reallocating.
1096 
1097       //check NAL / subsample
1098       const AP4_Byte *packet_in(data_in.GetData()), *packet_in_e(data_in.GetData() + data_in.GetDataSize());
1099       AP4_Byte *packet_out(data_out.UseData() + data_out.GetDataSize());
1100       AP4_UI16 *clrb_out(iv ? reinterpret_cast<AP4_UI16*>(data_out.UseData() + sizeof(subsample_count)) : nullptr);
1101       unsigned int nalunitcount(0), nalunitsum(0), configSize(0);
1102 
1103       while (packet_in < packet_in_e)
1104       {
1105         uint32_t nalsize(0);
1106         for (unsigned int i(0); i < fragInfo.nal_length_size_; ++i) { nalsize = (nalsize << 8) + *packet_in++; };
1107 
1108         //look if we have to inject sps / pps
1109         if (fragInfo.annexb_sps_pps_.GetDataSize() && (*packet_in & 0x1F) != 9 /*AVC_NAL_AUD*/)
1110         {
1111           memcpy(packet_out, fragInfo.annexb_sps_pps_.GetData(), fragInfo.annexb_sps_pps_.GetDataSize());
1112           packet_out += fragInfo.annexb_sps_pps_.GetDataSize();
1113           if (clrb_out) *clrb_out += fragInfo.annexb_sps_pps_.GetDataSize();
1114           configSize = fragInfo.annexb_sps_pps_.GetDataSize();
1115           fragInfo.annexb_sps_pps_.SetDataSize(0);
1116         }
1117 
1118         //Anex-B Start pos
1119         packet_out[0] = packet_out[1] = packet_out[2] = 0; packet_out[3] = 1;
1120         packet_out += 4;
1121         memcpy(packet_out, packet_in, nalsize);
1122         packet_in += nalsize;
1123         packet_out += nalsize;
1124         if (clrb_out) *clrb_out += (4 - fragInfo.nal_length_size_);
1125         ++nalunitcount;
1126 
1127         if (!iv)
1128         {
1129           nalunitsum = 0;
1130         }
1131         else if (nalsize + fragInfo.nal_length_size_ + nalunitsum >= *bytes_of_cleartext_data + *bytes_of_encrypted_data)
1132         {
1133           AP4_UI32 summedBytes(0);
1134           do
1135           {
1136             summedBytes += *bytes_of_cleartext_data + *bytes_of_encrypted_data;
1137             ++bytes_of_cleartext_data;
1138             ++bytes_of_encrypted_data;
1139             ++clrb_out;
1140             --subsample_count;
1141           } while (subsample_count && nalsize + fragInfo.nal_length_size_ + nalunitsum > summedBytes);
1142 
1143           if (nalsize + fragInfo.nal_length_size_ + nalunitsum > summedBytes)
1144           {
1145             Log(SSD_HOST::LL_ERROR, "NAL Unit exceeds subsample definition (nls: %u) %u -> %u ",
1146               static_cast<unsigned int>(fragInfo.nal_length_size_),
1147               static_cast<unsigned int>(nalsize + fragInfo.nal_length_size_ + nalunitsum),
1148               summedBytes);
1149             return AP4_ERROR_NOT_SUPPORTED;
1150           }
1151           nalunitsum = 0;
1152         }
1153         else
1154           nalunitsum += nalsize + fragInfo.nal_length_size_;
1155       }
1156       if (packet_in != packet_in_e || subsample_count)
1157       {
1158         Log(SSD_HOST::LL_ERROR, "NAL Unit definition incomplete (nls: %d) %d -> %u ", fragInfo.nal_length_size_, (int)(packet_in_e - packet_in), subsample_count);
1159         return AP4_ERROR_NOT_SUPPORTED;
1160       }
1161       data_out.SetDataSize(data_out.GetDataSize() + data_in.GetDataSize() + configSize + (4 - fragInfo.nal_length_size_) * nalunitcount);
1162     }
1163     else
1164     {
1165       data_out.AppendData(data_in.GetData(), data_in.GetDataSize());
1166       fragInfo.annexb_sps_pps_.SetDataSize(0);
1167     }
1168   }
1169   else
1170     data_out.SetDataSize(0);
1171   return AP4_SUCCESS;
1172 }
1173 
1174 /***********************************************************************************/
1175 
1176 class WVDecrypter : public SSD_DECRYPTER, public jni::CJNIMediaDrmOnEventListener
1177 {
1178 public:
WVDecrypter(const CJNIClassLoader * classLoader)1179   WVDecrypter(const CJNIClassLoader *classLoader)
1180     : CJNIMediaDrmOnEventListener(classLoader)
1181     , key_system_(NONE)
1182     , cdmsession_(nullptr)
1183   {
1184 #ifdef DRMTHREAD
1185     std::unique_lock<std::mutex> lk(jniMutex_);
1186     jniWorker = new std::thread(&WVDecrypter::JNIThread, this, reinterpret_cast<JavaVM*>(host->GetJNIEnv()));
1187     jniCondition_.wait(lk);
1188 #endif
1189     if (xbmc_jnienv()->ExceptionCheck())
1190     {
1191       Log(SSD_HOST::LL_ERROR, "Failed to load MediaDrmOnEventListener");
1192       xbmc_jnienv()->ExceptionDescribe();
1193       xbmc_jnienv()->ExceptionClear();
1194       return;
1195     }
1196     Log(SSD_HOST::LL_DEBUG, "WVDecrypter constructed");
1197   };
1198 
~WVDecrypter()1199   ~WVDecrypter()
1200   {
1201     delete cdmsession_;
1202     cdmsession_ = nullptr;
1203 
1204 #ifdef DRMTHREAD
1205     jniCondition_.notify_one();
1206     jniWorker->join();
1207     delete jniWorker;
1208 #endif
1209 
1210     Log(SSD_HOST::LL_DEBUG, "WVDecrypter destructed");
1211   };
1212 
1213 #ifdef DRMTHREAD
JNIThread(JavaVM * vm)1214   void JNIThread(JavaVM *vm)
1215   {
1216     jniCondition_.notify_one();
1217     std::unique_lock<std::mutex> lk(jniMutex_);
1218     jniCondition_.wait(lk);
1219 
1220     Log(SSD_HOST::LL_DEBUG, "JNI thread terminated");
1221   }
1222 #endif
1223 
SelectKeySytem(const char * keySystem)1224   virtual const char *SelectKeySytem(const char* keySystem) override
1225   {
1226     Log(SSD_HOST::LL_ERROR, "Key system request: %s", keySystem);
1227     if (strcmp(keySystem, "com.widevine.alpha") == 0)
1228     {
1229       key_system_ = WIDEVINE;
1230       return "urn:uuid:EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED";
1231     }
1232     else if (strcmp(keySystem, "com.huawei.wiseplay") == 0)
1233     {
1234       key_system_ = WISEPLAY;
1235       return "urn:uuid:3D5E6D35-9B9A-41E8-B843-DD3C6E72C42C";
1236     }
1237     else if (strcmp(keySystem, "com.microsoft.playready") == 0)
1238     {
1239       key_system_ = PLAYREADY;
1240       return "urn:uuid:9A04F079-9840-4286-AB92-E65BE0885F95";
1241     }
1242     else
1243       return nullptr;
1244   }
1245 
OpenDRMSystem(const char * licenseURL,const AP4_DataBuffer & serverCertificate,const uint8_t config)1246   virtual bool OpenDRMSystem(const char *licenseURL, const AP4_DataBuffer &serverCertificate, const uint8_t config) override
1247   {
1248     if (key_system_ == NONE)
1249       return false;
1250 
1251     cdmsession_ = new WV_DRM(key_system_, licenseURL, serverCertificate, this);
1252 
1253     return cdmsession_->GetMediaDrm();
1254   }
1255 
CreateSingleSampleDecrypter(AP4_DataBuffer & pssh,const char * optionalKeyParameter,const uint8_t * defaultkeyid,bool skipSessionMessage)1256   virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t *defaultkeyid, bool skipSessionMessage) override
1257   {
1258     WV_CencSingleSampleDecrypter *decrypter = new WV_CencSingleSampleDecrypter(*cdmsession_, pssh, optionalKeyParameter, defaultkeyid);
1259 
1260     {
1261       std::lock_guard<std::mutex> lk(decrypterListMutex);
1262       decrypterList.push_back(decrypter);
1263     }
1264 
1265     if (!(*decrypter->GetSessionId() && decrypter->StartSession(skipSessionMessage)))
1266     {
1267       DestroySingleSampleDecrypter(decrypter);
1268       return nullptr;
1269     }
1270     return decrypter;
1271   }
1272 
DestroySingleSampleDecrypter(AP4_CencSingleSampleDecrypter * decrypter)1273   virtual void DestroySingleSampleDecrypter(AP4_CencSingleSampleDecrypter* decrypter) override
1274   {
1275     if (decrypter)
1276     {
1277       std::vector<WV_CencSingleSampleDecrypter*>::const_iterator res = std::find(decrypterList.begin(),decrypterList.end(), decrypter);
1278       if (res != decrypterList.end())
1279       {
1280         std::lock_guard<std::mutex> lk(decrypterListMutex);
1281         decrypterList.erase(res);
1282       }
1283       delete static_cast<WV_CencSingleSampleDecrypter*>(decrypter);
1284     }
1285   }
1286 
GetCapabilities(AP4_CencSingleSampleDecrypter * decrypter,const uint8_t * keyid,uint32_t media,SSD_DECRYPTER::SSD_CAPS & caps)1287   virtual void GetCapabilities(AP4_CencSingleSampleDecrypter* decrypter, const uint8_t *keyid, uint32_t media, SSD_DECRYPTER::SSD_CAPS &caps) override
1288   {
1289     if (decrypter)
1290       static_cast<WV_CencSingleSampleDecrypter*>(decrypter)->GetCapabilities(keyid,media,caps);
1291     else
1292       caps = { 0, 0, 0};
1293   }
1294 
HasLicenseKey(AP4_CencSingleSampleDecrypter * decrypter,const uint8_t * keyid)1295   virtual bool HasLicenseKey(AP4_CencSingleSampleDecrypter* decrypter, const uint8_t *keyid) override
1296   {
1297     if (decrypter)
1298       return static_cast<WV_CencSingleSampleDecrypter*>(decrypter)->HasLicenseKey(keyid);
1299     return false;
1300   }
1301 
GetChallengeB64Data(AP4_CencSingleSampleDecrypter * decrypter)1302   virtual std::string GetChallengeB64Data(AP4_CencSingleSampleDecrypter* decrypter) override
1303   {
1304     if (!decrypter)
1305       return nullptr;
1306 
1307     std::vector<char> challengeData = static_cast<WV_CencSingleSampleDecrypter*>(decrypter)->GetChallengeData();
1308     // Keep b64_encode urlEncode enabled otherwise the data will not be sent correctly in the HTTP header
1309     return b64_encode(reinterpret_cast<const uint8_t*>(challengeData.data()), challengeData.size(), true);
1310   }
1311 
HasCdmSession()1312   virtual bool HasCdmSession()
1313   {
1314     return cdmsession_ != nullptr;
1315   }
1316 
OpenVideoDecoder(AP4_CencSingleSampleDecrypter * decrypter,const SSD_VIDEOINITDATA * initData)1317   virtual bool OpenVideoDecoder(AP4_CencSingleSampleDecrypter* decrypter, const SSD_VIDEOINITDATA *initData) override
1318   {
1319     return false;
1320   }
1321 
DecodeVideo(void * hostInstance,SSD_SAMPLE * sample,SSD_PICTURE * picture)1322   virtual SSD_DECODE_RETVAL DecodeVideo(void* hostInstance, SSD_SAMPLE *sample, SSD_PICTURE *picture) override
1323   {
1324     return VC_ERROR;
1325   }
1326 
ResetVideo()1327   virtual void ResetVideo() override
1328   {
1329   }
1330 
onEvent(const jni::CJNIMediaDrm & mediaDrm,const std::vector<char> & sessionId,int event,int extra,const std::vector<char> & data)1331   virtual void onEvent(const jni::CJNIMediaDrm &mediaDrm, const std::vector<char> &sessionId, int event, int extra, const std::vector<char> &data) override
1332   {
1333     Log(SSD_HOST::LL_DEBUG, "EVENT: %d arrived, #decrypter: %lu", event, decrypterList.size());
1334     //we have only one DRM system running (cdmsession_) so there is no need to compare mediaDrm
1335     std::lock_guard<std::mutex> lk(decrypterListMutex);
1336     for (std::vector<WV_CencSingleSampleDecrypter*>::iterator b(decrypterList.begin()), e(decrypterList.end()); b != e; ++b)
1337       if (sessionId.empty() || (*b)->GetSessionIdRaw() == sessionId)
1338       {
1339         switch (event)
1340         {
1341           case jni::CJNIMediaDrm::EVENT_KEY_REQUIRED:
1342             (*b)->RequestNewKeys();
1343             break;
1344           default:;
1345         }
1346       }
1347       else
1348       {
1349         Log(SSD_HOST::LL_DEBUG, "Session does not match: sizes: %lu -> %lu", sessionId.size(), (*b)->GetSessionIdRaw().size());
1350       }
1351   }
1352 
1353 private:
1354   WV_KEYSYSTEM key_system_;
1355   WV_DRM *cdmsession_;
1356   std::vector<WV_CencSingleSampleDecrypter*> decrypterList;
1357   std::mutex decrypterListMutex;
1358 #ifdef DRMTHREAD
1359   std::mutex jniMutex_;
1360   std::condition_variable jniCondition_;
1361   std::thread *jniWorker;
1362 #endif
1363 };
1364 
xbmc_jnienv()1365 JNIEnv* xbmc_jnienv()
1366 {
1367   return static_cast<JNIEnv*>(host->GetJNIEnv());
1368 }
1369 
1370 extern "C" {
1371 
1372 #ifdef _WIN32
1373 #define MODULE_API __declspec(dllexport)
1374 #else
1375 #define MODULE_API
1376 #endif
1377 
1378   CJNIClassLoader *classLoader;
1379 
CreateDecryptorInstance(class SSD_HOST * h,uint32_t host_version)1380   SSD_DECRYPTER MODULE_API *CreateDecryptorInstance(class SSD_HOST *h, uint32_t host_version)
1381   {
1382     if (host_version != SSD_HOST::version)
1383       return nullptr;
1384     host = h;
1385 
1386 
1387     CJNIBase::SetSDKVersion(host->GetSDKVersion());
1388     CJNIBase::SetBaseClassName(host->GetClassName());
1389 
1390     Log(SSD_HOST::LL_DEBUG, "WVDecrypter JNI, SDK version: %d, class: %s", CJNIBase::GetSDKVersion(), CJNIBase::GetBaseClassName().c_str());
1391 
1392     const char *apkEnv = getenv("XBMC_ANDROID_APK");
1393     if (!apkEnv)
1394       apkEnv = getenv("KODI_ANDROID_APK");
1395 
1396     if (!apkEnv)
1397       return nullptr;
1398 
1399     std::string apkPath = apkEnv;
1400 
1401     classLoader = new CJNIClassLoader(apkPath);
1402     if (xbmc_jnienv()->ExceptionCheck())
1403     {
1404       Log(SSD_HOST::LL_ERROR, "Failed to create JNI::ClassLoader");
1405       xbmc_jnienv()->ExceptionDescribe();
1406       xbmc_jnienv()->ExceptionClear();
1407 
1408       delete classLoader, classLoader = nullptr;
1409 
1410       return nullptr;
1411     }
1412     return new WVDecrypter(classLoader);
1413   };
1414 
DeleteDecryptorInstance(class SSD_DECRYPTER * d)1415   void MODULE_API DeleteDecryptorInstance(class SSD_DECRYPTER *d)
1416   {
1417     delete classLoader, classLoader = nullptr;
1418     delete static_cast<WVDecrypter*>(d);
1419   }
1420 };
1421