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