1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ClearKeyCasPlugin"
19
20 #include "ClearKeyFetcher.h"
21 #include "ecm.h"
22 #include "ClearKeyLicenseFetcher.h"
23 #include "ClearKeyCasPlugin.h"
24 #include "ClearKeySessionLibrary.h"
25 #include <media/stagefright/foundation/ABuffer.h>
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/foundation/hexdump.h>
28 #include <media/stagefright/MediaErrors.h>
29 #include <utils/Log.h>
30
createCasFactory()31 android::CasFactory* createCasFactory() {
32 return new android::clearkeycas::ClearKeyCasFactory();
33 }
34
createDescramblerFactory()35 android::DescramblerFactory *createDescramblerFactory()
36 {
37 return new android::clearkeycas::ClearKeyDescramblerFactory();
38 }
39
40 namespace android {
41 namespace clearkeycas {
42
43 static const int32_t sClearKeySystemId = 0xF6D8;
44
isSystemIdSupported(int32_t CA_system_id) const45 bool ClearKeyCasFactory::isSystemIdSupported(int32_t CA_system_id) const {
46 return CA_system_id == sClearKeySystemId;
47 }
48
queryPlugins(std::vector<CasPluginDescriptor> * descriptors) const49 status_t ClearKeyCasFactory::queryPlugins(
50 std::vector<CasPluginDescriptor> *descriptors) const {
51 descriptors->clear();
52 descriptors->push_back({sClearKeySystemId, String8("Clear Key CAS")});
53 return OK;
54 }
55
createPlugin(int32_t CA_system_id,void * appData,CasPluginCallback callback,CasPlugin ** plugin)56 status_t ClearKeyCasFactory::createPlugin(
57 int32_t CA_system_id,
58 void *appData,
59 CasPluginCallback callback,
60 CasPlugin **plugin) {
61 if (!isSystemIdSupported(CA_system_id)) {
62 return BAD_VALUE;
63 }
64
65 *plugin = new ClearKeyCasPlugin(appData, callback);
66 return OK;
67 }
68
createPlugin(int32_t CA_system_id,void * appData,CasPluginCallbackExt callback,CasPlugin ** plugin)69 status_t ClearKeyCasFactory::createPlugin(
70 int32_t CA_system_id,
71 void *appData,
72 CasPluginCallbackExt callback,
73 CasPlugin **plugin) {
74 if (!isSystemIdSupported(CA_system_id)) {
75 return BAD_VALUE;
76 }
77
78 *plugin = new ClearKeyCasPlugin(appData, callback);
79 return OK;
80 }
81 ////////////////////////////////////////////////////////////////////////////////
isSystemIdSupported(int32_t CA_system_id) const82 bool ClearKeyDescramblerFactory::isSystemIdSupported(
83 int32_t CA_system_id) const {
84 return CA_system_id == sClearKeySystemId;
85 }
86
createPlugin(int32_t CA_system_id,DescramblerPlugin ** plugin)87 status_t ClearKeyDescramblerFactory::createPlugin(
88 int32_t CA_system_id, DescramblerPlugin** plugin) {
89 if (!isSystemIdSupported(CA_system_id)) {
90 return BAD_VALUE;
91 }
92
93 *plugin = new ClearKeyDescramblerPlugin();
94 return OK;
95 }
96
97 ///////////////////////////////////////////////////////////////////////////////
ClearKeyCasPlugin(void * appData,CasPluginCallback callback)98 ClearKeyCasPlugin::ClearKeyCasPlugin(
99 void *appData, CasPluginCallback callback)
100 : mCallback(callback), mCallbackExt(NULL), mStatusCallback(NULL),
101 mAppData(appData) {
102 ALOGV("CTOR");
103 }
104
ClearKeyCasPlugin(void * appData,CasPluginCallbackExt callback)105 ClearKeyCasPlugin::ClearKeyCasPlugin(
106 void *appData, CasPluginCallbackExt callback)
107 : mCallback(NULL), mCallbackExt(callback), mAppData(appData) {
108 ALOGV("CTOR");
109 }
110
~ClearKeyCasPlugin()111 ClearKeyCasPlugin::~ClearKeyCasPlugin() {
112 ALOGV("DTOR");
113 ClearKeySessionLibrary::get()->destroyPlugin(this);
114 }
115
setStatusCallback(CasPluginStatusCallback callback)116 status_t ClearKeyCasPlugin::setStatusCallback(
117 CasPluginStatusCallback callback) {
118 ALOGV("setStatusCallback");
119 mStatusCallback = callback;
120 return OK;
121 }
122
setPrivateData(const CasData &)123 status_t ClearKeyCasPlugin::setPrivateData(const CasData &/*data*/) {
124 ALOGV("setPrivateData");
125
126 return OK;
127 }
128
sessionIdToString(const std::vector<uint8_t> & array)129 static String8 sessionIdToString(const std::vector<uint8_t> &array) {
130 String8 result;
131 for (size_t i = 0; i < array.size(); i++) {
132 result.appendFormat("%02x ", array[i]);
133 }
134 if (result.isEmpty()) {
135 result.append("(null)");
136 }
137 return result;
138 }
139
openSession(CasSessionId * sessionId)140 status_t ClearKeyCasPlugin::openSession(CasSessionId* sessionId) {
141 ALOGV("openSession");
142
143 return ClearKeySessionLibrary::get()->addSession(this, sessionId);
144 }
145
openSession(uint32_t intent,uint32_t mode,CasSessionId * sessionId)146 status_t ClearKeyCasPlugin::openSession(uint32_t intent, uint32_t mode,
147 CasSessionId* sessionId) {
148 ALOGV("openSession with intent=%d, mode=%d", intent, mode);
149 // Echo the received information to the callback.
150 // Clear key plugin doesn't use any event, echo'ing for testing only.
151 if (mStatusCallback != NULL) {
152 mStatusCallback((void*)mAppData, intent, mode);
153 }
154
155 // Clear key plugin doesn't use intent and mode.
156 return ClearKeySessionLibrary::get()->addSession(this, sessionId);
157 }
158
closeSession(const CasSessionId & sessionId)159 status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
160 ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
161 std::shared_ptr<ClearKeyCasSession> session =
162 ClearKeySessionLibrary::get()->findSession(sessionId);
163 if (session.get() == nullptr) {
164 return ERROR_CAS_SESSION_NOT_OPENED;
165 }
166
167 ClearKeySessionLibrary::get()->destroySession(sessionId);
168 return OK;
169 }
170
setSessionPrivateData(const CasSessionId & sessionId,const CasData &)171 status_t ClearKeyCasPlugin::setSessionPrivateData(
172 const CasSessionId &sessionId, const CasData & /*data*/) {
173 ALOGV("setSessionPrivateData: sessionId=%s",
174 sessionIdToString(sessionId).string());
175 std::shared_ptr<ClearKeyCasSession> session =
176 ClearKeySessionLibrary::get()->findSession(sessionId);
177 if (session.get() == nullptr) {
178 return ERROR_CAS_SESSION_NOT_OPENED;
179 }
180 return OK;
181 }
182
processEcm(const CasSessionId & sessionId,const CasEcm & ecm)183 status_t ClearKeyCasPlugin::processEcm(
184 const CasSessionId &sessionId, const CasEcm& ecm) {
185 ALOGV("processEcm: sessionId=%s", sessionIdToString(sessionId).string());
186 std::shared_ptr<ClearKeyCasSession> session =
187 ClearKeySessionLibrary::get()->findSession(sessionId);
188 if (session.get() == nullptr) {
189 return ERROR_CAS_SESSION_NOT_OPENED;
190 }
191
192 Mutex::Autolock lock(mKeyFetcherLock);
193
194 return session->updateECM(mKeyFetcher.get(), (void*)ecm.data(), ecm.size());
195 }
196
processEmm(const CasEmm &)197 status_t ClearKeyCasPlugin::processEmm(const CasEmm& /*emm*/) {
198 ALOGV("processEmm");
199 Mutex::Autolock lock(mKeyFetcherLock);
200
201 return OK;
202 }
203
sendEvent(int32_t event,int32_t arg,const CasData & eventData)204 status_t ClearKeyCasPlugin::sendEvent(
205 int32_t event, int32_t arg, const CasData &eventData) {
206 ALOGV("sendEvent: event=%d, arg=%d", event, arg);
207 // Echo the received event to the callback.
208 // Clear key plugin doesn't use any event, echo'ing for testing only.
209 if (mCallback != NULL) {
210 mCallback((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
211 eventData.size());
212 } else if (mCallbackExt != NULL) {
213 mCallbackExt((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
214 eventData.size(), NULL);
215 }
216 return OK;
217 }
218
sendSessionEvent(const CasSessionId & sessionId,int32_t event,int arg,const CasData & eventData)219 status_t ClearKeyCasPlugin::sendSessionEvent(
220 const CasSessionId &sessionId, int32_t event,
221 int arg, const CasData &eventData) {
222 ALOGV("sendSessionEvent: sessionId=%s, event=%d, arg=%d",
223 sessionIdToString(sessionId).string(), event, arg);
224 // Echo the received event to the callback.
225 // Clear key plugin doesn't use any event, echo'ing for testing only.
226 if (mCallbackExt != NULL) {
227 mCallbackExt((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
228 eventData.size(), &sessionId);
229 }
230
231 return OK;
232 }
233
provision(const String8 & str)234 status_t ClearKeyCasPlugin::provision(const String8 &str) {
235 ALOGV("provision: provisionString=%s", str.string());
236 Mutex::Autolock lock(mKeyFetcherLock);
237
238 std::unique_ptr<ClearKeyLicenseFetcher> license_fetcher;
239 license_fetcher.reset(new ClearKeyLicenseFetcher());
240 status_t err = license_fetcher->Init(str.string());
241 if (err != OK) {
242 ALOGE("provision: failed to init ClearKeyLicenseFetcher (err=%d)", err);
243 return err;
244 }
245
246 std::unique_ptr<ClearKeyFetcher> key_fetcher;
247 key_fetcher.reset(new ClearKeyFetcher(std::move(license_fetcher)));
248 err = key_fetcher->Init();
249 if (err != OK) {
250 ALOGE("provision: failed to init ClearKeyFetcher (err=%d)", err);
251 return err;
252 }
253
254 ALOGV("provision: using ClearKeyFetcher");
255 mKeyFetcher = std::move(key_fetcher);
256
257 return OK;
258 }
259
refreshEntitlements(int32_t refreshType,const CasData &)260 status_t ClearKeyCasPlugin::refreshEntitlements(
261 int32_t refreshType, const CasData &/*refreshData*/) {
262 ALOGV("refreshEntitlements: refreshType=%d", refreshType);
263 Mutex::Autolock lock(mKeyFetcherLock);
264
265 return OK;
266 }
267
268 ///////////////////////////////////////////////////////////////////////
269
270 // AES-128 CBC-CTS decrypt optimized for Transport Packets. |key| is the AES
271 // key (odd key or even key), |length| is the data size, and |buffer| is the
272 // ciphertext to be decrypted in place.
TpBlockCtsDecrypt(const AES_KEY & key,size_t length,char * buffer)273 status_t TpBlockCtsDecrypt(const AES_KEY& key, size_t length, char* buffer) {
274 CHECK(buffer);
275
276 // Invariant: Packet must be at least 16 bytes.
277 CHECK(length >= AES_BLOCK_SIZE);
278
279 // OpenSSL uses unsigned char.
280 unsigned char* data = reinterpret_cast<unsigned char*>(buffer);
281
282 // Start with zero-filled initialization vector.
283 unsigned char iv[AES_BLOCK_SIZE];
284 memset(iv, 0, AES_BLOCK_SIZE);
285
286 // Size of partial last block handled via CTS.
287 int cts_byte_count = length % AES_BLOCK_SIZE;
288
289 // If there no is no partial last block, then process using normal CBC.
290 if (cts_byte_count == 0) {
291 AES_cbc_encrypt(data, data, length, &key, iv, 0);
292 return OK;
293 }
294
295 // Cipher text stealing (CTS) - Schneier Figure 9.5 p 196.
296 // In CTS mode, the last two blocks have been swapped. Block[n-1] is really
297 // the original block[n] combined with the low-order bytes of the original
298 // block[n-1], while block[n] is the high-order bytes of the original
299 // block[n-1] padded with zeros.
300
301 // Block[0] - block[n-2] are handled with normal CBC.
302 int cbc_byte_count = length - cts_byte_count - AES_BLOCK_SIZE;
303 if (cbc_byte_count > 0) {
304 AES_cbc_encrypt(data, data, cbc_byte_count, &key, iv, 0);
305 // |data| points to block[n-1].
306 data += cbc_byte_count;
307 }
308
309 // Save block[n] to use as IV when decrypting block[n-1].
310 unsigned char block_n[AES_BLOCK_SIZE];
311 memset(block_n, 0, AES_BLOCK_SIZE);
312 memcpy(block_n, data + AES_BLOCK_SIZE, cts_byte_count);
313
314 // Decrypt block[n-1] using block[n] as IV, consistent with the original
315 // block order.
316 AES_cbc_encrypt(data, data, AES_BLOCK_SIZE, &key, block_n, 0);
317
318 // Return the stolen ciphertext: swap the high-order bytes of block[n]
319 // and block[n-1].
320 for (int i = 0; i < cts_byte_count; i++) {
321 unsigned char temp = *(data + i);
322 *(data + i) = *(data + AES_BLOCK_SIZE + i);
323 *(data + AES_BLOCK_SIZE + i) = temp;
324 }
325
326 // Decrypt block[n-1] using previous IV.
327 AES_cbc_encrypt(data, data, AES_BLOCK_SIZE, &key, iv, 0);
328 return OK;
329 }
330
331 // PES header and ECM stream header layout
332 //
333 // processECM() receives the data_byte portion from the transport packet.
334 // Below is the layout of the first 16 bytes of the ECM PES packet. Here
335 // we don't parse them, we skip them and go to the ECM container directly.
336 // The layout is included here only for reference.
337 //
338 // 0-2: 0x00 00 01 = start code prefix.
339 // 3: 0xf0 = stream type (90 = ECM).
340 // 4-5: 0x00 00 = PES length (filled in later, this is the length of the
341 // PES header (16) plus the length of the ECM container).
342 // 6-7: 0x00 00 = ECM major version.
343 // 8-9: 0x00 01 = ECM minor version.
344 // 10-11: 0x00 00 = Crypto period ID (filled in later).
345 // 12-13: 0x00 00 = ECM container length (filled in later, either 84 or
346 // 166).
347 // 14-15: 0x00 00 = offset = 0.
348
349 const static size_t kEcmHeaderLength = 16;
350 const static size_t kUserKeyLength = 16;
351
updateECM(KeyFetcher * keyFetcher,void * ecm,size_t size)352 status_t ClearKeyCasSession::updateECM(
353 KeyFetcher *keyFetcher, void *ecm, size_t size) {
354 if (keyFetcher == nullptr) {
355 return ERROR_CAS_NOT_PROVISIONED;
356 }
357
358 if (size < kEcmHeaderLength) {
359 ALOGE("updateECM: invalid ecm size %zu", size);
360 return BAD_VALUE;
361 }
362
363 Mutex::Autolock _lock(mKeyLock);
364
365 if (mEcmBuffer != NULL && mEcmBuffer->capacity() == size
366 && !memcmp(mEcmBuffer->base(), ecm, size)) {
367 return OK;
368 }
369
370 mEcmBuffer = ABuffer::CreateAsCopy(ecm, size);
371 mEcmBuffer->setRange(kEcmHeaderLength, size - kEcmHeaderLength);
372
373 uint64_t asset_id;
374 std::vector<KeyFetcher::KeyInfo> keys;
375 status_t err = keyFetcher->ObtainKey(mEcmBuffer, &asset_id, &keys);
376 if (err != OK) {
377 ALOGE("updateECM: failed to obtain key (err=%d)", err);
378 return err;
379 }
380
381 ALOGV("updateECM: %zu key(s) found", keys.size());
382 for (size_t keyIndex = 0; keyIndex < keys.size(); keyIndex++) {
383 String8 str;
384
385 const sp<ABuffer>& keyBytes = keys[keyIndex].key_bytes;
386 CHECK(keyBytes->size() == kUserKeyLength);
387
388 int result = AES_set_decrypt_key(
389 reinterpret_cast<const uint8_t*>(keyBytes->data()),
390 AES_BLOCK_SIZE * 8, &mKeyInfo[keyIndex].contentKey);
391 mKeyInfo[keyIndex].valid = (result == 0);
392 if (!mKeyInfo[keyIndex].valid) {
393 ALOGE("updateECM: failed to set key %zu, key_id=%d",
394 keyIndex, keys[keyIndex].key_id);
395 }
396 }
397 return OK;
398 }
399
400 // Decryption of a set of sub-samples
decrypt(bool secure,DescramblerPlugin::ScramblingControl scramblingControl,size_t numSubSamples,const DescramblerPlugin::SubSample * subSamples,const void * srcPtr,void * dstPtr,AString *)401 ssize_t ClearKeyCasSession::decrypt(
402 bool secure, DescramblerPlugin::ScramblingControl scramblingControl,
403 size_t numSubSamples, const DescramblerPlugin::SubSample *subSamples,
404 const void *srcPtr, void *dstPtr, AString * /* errorDetailMsg */) {
405 if (secure) {
406 return ERROR_CAS_CANNOT_HANDLE;
407 }
408
409 scramblingControl = (DescramblerPlugin::ScramblingControl)
410 (scramblingControl & DescramblerPlugin::kScrambling_Mask_Key);
411
412 AES_KEY contentKey;
413
414 if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled) {
415 // Hold lock to get the key only to avoid contention for decryption
416 Mutex::Autolock _lock(mKeyLock);
417
418 int32_t keyIndex = (scramblingControl & 1);
419 if (!mKeyInfo[keyIndex].valid) {
420 ALOGE("decrypt: key %d is invalid", keyIndex);
421 return ERROR_CAS_DECRYPT;
422 }
423 contentKey = mKeyInfo[keyIndex].contentKey;
424 }
425
426 uint8_t *src = (uint8_t*)srcPtr;
427 uint8_t *dst = (uint8_t*)dstPtr;
428
429 for (size_t i = 0; i < numSubSamples; i++) {
430 size_t numBytesinSubSample = subSamples[i].mNumBytesOfClearData
431 + subSamples[i].mNumBytesOfEncryptedData;
432 if (src != dst) {
433 memcpy(dst, src, numBytesinSubSample);
434 }
435 status_t err = OK;
436 // Don't decrypt if len < AES_BLOCK_SIZE.
437 // The last chunk shorter than AES_BLOCK_SIZE is not encrypted.
438 if (scramblingControl != DescramblerPlugin::kScrambling_Unscrambled
439 && subSamples[i].mNumBytesOfEncryptedData >= AES_BLOCK_SIZE) {
440 err = decryptPayload(
441 contentKey,
442 numBytesinSubSample,
443 subSamples[i].mNumBytesOfClearData,
444 (char *)dst);
445 }
446
447 dst += numBytesinSubSample;
448 src += numBytesinSubSample;
449 }
450 return dst - (uint8_t *)dstPtr;
451 }
452
453 // Decryption of a TS payload
decryptPayload(const AES_KEY & key,size_t length,size_t offset,char * buffer) const454 status_t ClearKeyCasSession::decryptPayload(
455 const AES_KEY& key, size_t length, size_t offset, char* buffer) const {
456 CHECK(buffer);
457
458 // Invariant: only call decryptPayload with TS packets with at least 16
459 // bytes of payload (AES_BLOCK_SIZE).
460
461 CHECK(length >= offset + AES_BLOCK_SIZE);
462
463 return TpBlockCtsDecrypt(key, length - offset, buffer + offset);
464 }
465
466 ///////////////////////////////////////////////////////////////////////////
467 #undef LOG_TAG
468 #define LOG_TAG "ClearKeyDescramblerPlugin"
469
requiresSecureDecoderComponent(const char * mime) const470 bool ClearKeyDescramblerPlugin::requiresSecureDecoderComponent(
471 const char *mime) const {
472 ALOGV("requiresSecureDecoderComponent: mime=%s", mime);
473 return false;
474 }
475
setMediaCasSession(const CasSessionId & sessionId)476 status_t ClearKeyDescramblerPlugin::setMediaCasSession(
477 const CasSessionId &sessionId) {
478 ALOGV("setMediaCasSession: sessionId=%s", sessionIdToString(sessionId).string());
479
480 std::shared_ptr<ClearKeyCasSession> session =
481 ClearKeySessionLibrary::get()->findSession(sessionId);
482
483 if (session.get() == nullptr) {
484 ALOGE("ClearKeyDescramblerPlugin: session not found");
485 return ERROR_CAS_SESSION_NOT_OPENED;
486 }
487
488 std::atomic_store(&mCASSession, session);
489 return OK;
490 }
491
descramble(bool secure,ScramblingControl scramblingControl,size_t numSubSamples,const SubSample * subSamples,const void * srcPtr,int32_t srcOffset,void * dstPtr,int32_t dstOffset,AString * errorDetailMsg)492 ssize_t ClearKeyDescramblerPlugin::descramble(
493 bool secure,
494 ScramblingControl scramblingControl,
495 size_t numSubSamples,
496 const SubSample *subSamples,
497 const void *srcPtr,
498 int32_t srcOffset,
499 void *dstPtr,
500 int32_t dstOffset,
501 AString *errorDetailMsg) {
502
503 ALOGV("descramble: secure=%d, sctrl=%d, subSamples=%s, "
504 "srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d",
505 (int)secure, (int)scramblingControl,
506 subSamplesToString(subSamples, numSubSamples).string(),
507 srcPtr, dstPtr, srcOffset, dstOffset);
508
509 std::shared_ptr<ClearKeyCasSession> session = std::atomic_load(&mCASSession);
510
511 if (session.get() == nullptr) {
512 ALOGE("Uninitialized CAS session!");
513 return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
514 }
515
516 return session->decrypt(
517 secure, scramblingControl,
518 numSubSamples, subSamples,
519 (uint8_t*)srcPtr + srcOffset,
520 dstPtr == NULL ? NULL : ((uint8_t*)dstPtr + dstOffset),
521 errorDetailMsg);
522 }
523
524 // Conversion utilities
arrayToString(uint8_t const * array,size_t len) const525 String8 ClearKeyDescramblerPlugin::arrayToString(
526 uint8_t const *array, size_t len) const
527 {
528 String8 result("{ ");
529 for (size_t i = 0; i < len; i++) {
530 result.appendFormat("0x%02x ", array[i]);
531 }
532 result += "}";
533 return result;
534 }
535
subSamplesToString(SubSample const * subSamples,size_t numSubSamples) const536 String8 ClearKeyDescramblerPlugin::subSamplesToString(
537 SubSample const *subSamples, size_t numSubSamples) const
538 {
539 String8 result;
540 for (size_t i = 0; i < numSubSamples; i++) {
541 result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i,
542 subSamples[i].mNumBytesOfClearData,
543 subSamples[i].mNumBytesOfEncryptedData);
544 }
545 return result;
546 }
547
548 } // namespace clearkeycas
549 } // namespace android
550