1 /* 2 * Copyright (C) 2014 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 "NdkMediaDrm" 19 20 #include <inttypes.h> 21 #include <unistd.h> 22 23 #include <media/NdkMediaDrm.h> 24 25 #include <cutils/properties.h> 26 #include <utils/Log.h> 27 #include <utils/StrongPointer.h> 28 #include <gui/Surface.h> 29 30 #include <android-base/properties.h> 31 #include <binder/PermissionController.h> 32 #include <media/IDrm.h> 33 #include <media/IDrmClient.h> 34 #include <media/stagefright/MediaErrors.h> 35 #include <binder/IServiceManager.h> 36 #include <media/IMediaDrmService.h> 37 #include <media/NdkMediaCrypto.h> 38 39 40 using namespace android; 41 42 typedef Vector<uint8_t> idvec_t; 43 44 struct DrmListener: virtual public BnDrmClient 45 { 46 private: 47 AMediaDrm *mObj; 48 AMediaDrmEventListener mEventListener; 49 AMediaDrmExpirationUpdateListener mExpirationUpdateListener; 50 AMediaDrmKeysChangeListener mKeysChangeListener; 51 52 public: 53 DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), 54 mEventListener(listener), mExpirationUpdateListener(NULL), mKeysChangeListener(NULL) {} 55 56 DrmListener(AMediaDrm *obj, AMediaDrmExpirationUpdateListener listener) : mObj(obj), 57 mEventListener(NULL), mExpirationUpdateListener(listener), mKeysChangeListener(NULL) {} 58 59 DrmListener(AMediaDrm *obj, AMediaDrmKeysChangeListener listener) : mObj(obj), 60 mEventListener(NULL), mExpirationUpdateListener(NULL), mKeysChangeListener(listener) {} 61 62 void setEventListener(AMediaDrmEventListener listener) { 63 mEventListener = listener; 64 } 65 66 void setExpirationUpdateListener(AMediaDrmExpirationUpdateListener listener) { 67 mExpirationUpdateListener = listener; 68 } 69 70 void setKeysChangeListener(AMediaDrmKeysChangeListener listener) { 71 mKeysChangeListener = listener; 72 } 73 74 void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj); 75 }; 76 77 struct AMediaDrm { 78 sp<IDrm> mDrm; 79 sp<IDrmClient> mDrmClient; 80 List<idvec_t> mIds; 81 KeyedVector<String8, String8> mQueryResults; 82 Vector<uint8_t> mKeyRequest; 83 Vector<uint8_t> mProvisionRequest; 84 String8 mProvisionUrl; 85 String8 mPropertyString; 86 Vector<uint8_t> mPropertyByteArray; 87 List<Vector<uint8_t> > mSecureStops; 88 sp<DrmListener> mListener; 89 }; 90 91 void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) { 92 if (!mEventListener && !mExpirationUpdateListener && !mKeysChangeListener) { 93 ALOGE("No listeners are specified"); 94 return; 95 } 96 97 obj->setDataPosition(0); 98 99 AMediaDrmSessionId sessionId = {NULL, 0}; 100 int32_t sessionIdSize = obj->readInt32(); 101 if (sessionIdSize <= 0) { 102 ALOGE("Invalid session id size"); 103 return; 104 } 105 106 std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]); 107 sessionId.ptr = sessionIdData.get(); 108 sessionId.length = sessionIdSize; 109 status_t err = obj->read(sessionIdData.get(), sessionId.length); 110 if (err != OK) { 111 ALOGE("Failed to read session id, error=%d", err); 112 return; 113 } 114 115 if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) { 116 int64_t expiryTimeInMS = obj->readInt64(); 117 if (expiryTimeInMS >= 0) { 118 (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS); 119 } else { 120 ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS); 121 } 122 return; 123 } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) { 124 int32_t numKeys = 0; 125 err = obj->readInt32(&numKeys); 126 if (err != OK) { 127 ALOGE("Failed to read number of keys status, error=%d", err); 128 return; 129 } 130 131 Vector<AMediaDrmKeyStatus> keysStatus; 132 std::vector<std::unique_ptr<uint8_t[]> > dataPointers; 133 AMediaDrmKeyStatus keyStatus; 134 135 for (size_t i = 0; i < numKeys; ++i) { 136 keyStatus.keyId.ptr = nullptr; 137 keyStatus.keyId.length = 0; 138 int32_t idSize = obj->readInt32(); 139 if (idSize > 0) { 140 std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]); 141 err = obj->read(data.get(), idSize); 142 if (err != OK) { 143 ALOGE("Failed to read key data, error=%d", err); 144 return; 145 } 146 keyStatus.keyId.ptr = data.get(); 147 keyStatus.keyId.length = idSize; 148 dataPointers.push_back(std::move(data)); 149 } 150 keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32()); 151 keysStatus.push(keyStatus); 152 } 153 154 bool hasNewUsableKey = obj->readInt32(); 155 (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey); 156 return; 157 } 158 159 // Handles AMediaDrmEventListener below: 160 // translates DrmPlugin event types into their NDK equivalents 161 AMediaDrmEventType ndkEventType; 162 switch(eventType) { 163 case DrmPlugin::kDrmPluginEventProvisionRequired: 164 ndkEventType = EVENT_PROVISION_REQUIRED; 165 break; 166 case DrmPlugin::kDrmPluginEventKeyNeeded: 167 ndkEventType = EVENT_KEY_REQUIRED; 168 break; 169 case DrmPlugin::kDrmPluginEventKeyExpired: 170 ndkEventType = EVENT_KEY_EXPIRED; 171 break; 172 case DrmPlugin::kDrmPluginEventVendorDefined: 173 ndkEventType = EVENT_VENDOR_DEFINED; 174 break; 175 case DrmPlugin::kDrmPluginEventSessionReclaimed: 176 ndkEventType = EVENT_SESSION_RECLAIMED; 177 break; 178 default: 179 ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType); 180 return; 181 } 182 183 int32_t dataSize = obj->readInt32(); 184 uint8_t *data = NULL; 185 if (dataSize > 0) { 186 data = new uint8_t[dataSize]; 187 err = obj->read(data, dataSize); 188 if (err == OK) { 189 (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize); 190 } else { 191 ALOGE("Failed to read event data, error=%d", err); 192 } 193 delete [] data; 194 } else { 195 ALOGE("Error reading parcel: invalid event data size=%d", dataSize); 196 } 197 } 198 199 extern "C" { 200 201 static media_status_t translateStatus(status_t status) { 202 media_status_t result = AMEDIA_ERROR_UNKNOWN; 203 switch (status) { 204 case OK: 205 result = AMEDIA_OK; 206 break; 207 case android::ERROR_DRM_NOT_PROVISIONED: 208 result = AMEDIA_DRM_NOT_PROVISIONED; 209 break; 210 case android::ERROR_DRM_RESOURCE_BUSY: 211 result = AMEDIA_DRM_RESOURCE_BUSY; 212 break; 213 case android::ERROR_DRM_DEVICE_REVOKED: 214 result = AMEDIA_DRM_DEVICE_REVOKED; 215 break; 216 case android::ERROR_DRM_CANNOT_HANDLE: 217 result = AMEDIA_ERROR_INVALID_PARAMETER; 218 break; 219 case android::ERROR_DRM_TAMPER_DETECTED: 220 result = AMEDIA_DRM_TAMPER_DETECTED; 221 break; 222 case android::ERROR_DRM_SESSION_NOT_OPENED: 223 result = AMEDIA_DRM_SESSION_NOT_OPENED; 224 break; 225 case android::ERROR_DRM_NO_LICENSE: 226 result = AMEDIA_DRM_NEED_KEY; 227 break; 228 case android::ERROR_DRM_LICENSE_EXPIRED: 229 result = AMEDIA_DRM_LICENSE_EXPIRED; 230 break; 231 default: 232 break; 233 } 234 return result; 235 } 236 237 static bool ShouldGetAppPackageName(void) { 238 // Check what this device's first API level was. 239 int32_t firstApiLevel = android::base::GetIntProperty<int32_t>("ro.product.first_api_level", 0); 240 if (firstApiLevel == 0) { 241 // First API Level is 0 on factory ROMs, but we can assume the current SDK 242 // version is the first if it's a factory ROM. 243 firstApiLevel = android::base::GetIntProperty<int32_t>("ro.build.version.sdk", 0); 244 } 245 return firstApiLevel >= 29; // Android Q 246 } 247 248 static status_t GetAppPackageName(String8 *packageName) { 249 sp<IServiceManager> serviceManager = defaultServiceManager(); 250 sp<IBinder> binder = serviceManager->getService(String16("permission")); 251 252 sp<IPermissionController> permissionContol = interface_cast<IPermissionController>(binder); 253 if (permissionContol == NULL) { 254 ALOGE("Failed to get permission service"); 255 return UNKNOWN_ERROR; 256 } 257 258 Vector<String16> packages; 259 permissionContol->getPackagesForUid(getuid(), packages); 260 261 if (packages.isEmpty()) { 262 ALOGE("Unable to get package name for current UID"); 263 return UNKNOWN_ERROR; 264 } 265 266 *packageName = String8(packages[0]); 267 return OK; 268 } 269 270 static sp<IDrm> CreateDrm() { 271 sp<IServiceManager> sm = defaultServiceManager(); 272 sp<IBinder> binder = sm->getService(String16("media.drm")); 273 274 sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder); 275 if (service == NULL) { 276 return NULL; 277 } 278 279 sp<IDrm> drm = service->makeDrm(); 280 if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) { 281 return NULL; 282 } 283 return drm; 284 } 285 286 287 static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) { 288 sp<IDrm> drm = CreateDrm(); 289 290 if (drm == NULL) { 291 return NULL; 292 } 293 294 String8 packageName; 295 if (ShouldGetAppPackageName()) { 296 status_t err = GetAppPackageName(&packageName); 297 298 if (err != OK) { 299 return NULL; 300 } 301 } 302 303 status_t err = drm->createPlugin(uuid, packageName); 304 305 if (err != OK) { 306 return NULL; 307 } 308 309 return drm; 310 } 311 312 EXPORT 313 bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) { 314 sp<IDrm> drm = CreateDrm(); 315 316 if (drm == NULL) { 317 return false; 318 } 319 320 String8 mimeStr = mimeType ? String8(mimeType) : String8(""); 321 bool isSupported = false; 322 status_t status = drm->isCryptoSchemeSupported(uuid, mimeStr, 323 DrmPlugin::kSecurityLevelUnknown, &isSupported); 324 return (status == OK) && isSupported; 325 } 326 327 EXPORT 328 AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) { 329 AMediaDrm *mObj = new AMediaDrm(); 330 mObj->mDrm = CreateDrmFromUUID(uuid); 331 332 mObj->mListener.clear(); 333 return mObj; 334 } 335 336 EXPORT 337 void AMediaDrm_release(AMediaDrm *mObj) { 338 if (mObj->mDrm != NULL) { 339 mObj->mDrm->setListener(NULL); 340 mObj->mDrm->destroyPlugin(); 341 mObj->mDrm.clear(); 342 } 343 delete mObj; 344 } 345 346 EXPORT 347 media_status_t AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) { 348 if (!mObj || mObj->mDrm == NULL) { 349 return AMEDIA_ERROR_INVALID_OBJECT; 350 } 351 352 if (mObj->mListener.get()) { 353 mObj->mListener->setEventListener(listener); 354 } else { 355 mObj->mListener = new DrmListener(mObj, listener); 356 } 357 mObj->mDrm->setListener(mObj->mListener); 358 return AMEDIA_OK; 359 } 360 361 EXPORT 362 media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *mObj, 363 AMediaDrmExpirationUpdateListener listener) { 364 if (!mObj || mObj->mDrm == NULL) { 365 return AMEDIA_ERROR_INVALID_OBJECT; 366 } 367 368 if (mObj->mListener.get()) { 369 mObj->mListener->setExpirationUpdateListener(listener); 370 } else { 371 mObj->mListener = new DrmListener(mObj, listener); 372 } 373 mObj->mDrm->setListener(mObj->mListener); 374 return AMEDIA_OK; 375 } 376 377 EXPORT 378 media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *mObj, 379 AMediaDrmKeysChangeListener listener) { 380 if (!mObj || mObj->mDrm == NULL) { 381 return AMEDIA_ERROR_INVALID_OBJECT; 382 } 383 384 if (mObj->mListener.get()) { 385 mObj->mListener->setKeysChangeListener(listener); 386 } else { 387 mObj->mListener = new DrmListener(mObj, listener); 388 } 389 mObj->mDrm->setListener(mObj->mListener); 390 return AMEDIA_OK; 391 } 392 393 static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) { 394 for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) { 395 if (id.length == iter->size() && memcmp(iter->array(), id.ptr, iter->size()) == 0) { 396 return true; 397 } 398 } 399 return false; 400 } 401 402 EXPORT 403 media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) { 404 if (!mObj || mObj->mDrm == NULL) { 405 return AMEDIA_ERROR_INVALID_OBJECT; 406 } 407 if (!sessionId) { 408 return AMEDIA_ERROR_INVALID_PARAMETER; 409 } 410 Vector<uint8_t> session; 411 status_t status = mObj->mDrm->openSession(DrmPlugin::kSecurityLevelMax, session); 412 if (status == OK) { 413 mObj->mIds.push_front(session); 414 List<idvec_t>::iterator iter = mObj->mIds.begin(); 415 sessionId->ptr = iter->array(); 416 sessionId->length = iter->size(); 417 } 418 return AMEDIA_OK; 419 } 420 421 EXPORT 422 media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) { 423 if (!mObj || mObj->mDrm == NULL) { 424 return AMEDIA_ERROR_INVALID_OBJECT; 425 } 426 if (!sessionId) { 427 return AMEDIA_ERROR_INVALID_PARAMETER; 428 } 429 430 List<idvec_t>::iterator iter; 431 if (!findId(mObj, *sessionId, iter)) { 432 return AMEDIA_DRM_SESSION_NOT_OPENED; 433 } 434 mObj->mDrm->closeSession(*iter); 435 mObj->mIds.erase(iter); 436 return AMEDIA_OK; 437 } 438 439 EXPORT 440 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope, 441 const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType, 442 const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters, 443 const uint8_t **keyRequest, size_t *keyRequestSize) { 444 445 if (!mObj || mObj->mDrm == NULL) { 446 return AMEDIA_ERROR_INVALID_OBJECT; 447 } 448 if (!mimeType || !scope || !keyRequest || !keyRequestSize) { 449 return AMEDIA_ERROR_INVALID_PARAMETER; 450 } 451 452 List<idvec_t>::iterator iter; 453 if (!findId(mObj, *scope, iter)) { 454 return AMEDIA_DRM_SESSION_NOT_OPENED; 455 } 456 457 Vector<uint8_t> mdInit; 458 mdInit.appendArray(init, initSize); 459 DrmPlugin::KeyType mdKeyType; 460 switch (keyType) { 461 case KEY_TYPE_STREAMING: 462 mdKeyType = DrmPlugin::kKeyType_Streaming; 463 break; 464 case KEY_TYPE_OFFLINE: 465 mdKeyType = DrmPlugin::kKeyType_Offline; 466 break; 467 case KEY_TYPE_RELEASE: 468 mdKeyType = DrmPlugin::kKeyType_Release; 469 break; 470 default: 471 return AMEDIA_ERROR_INVALID_PARAMETER; 472 } 473 KeyedVector<String8, String8> mdOptionalParameters; 474 for (size_t i = 0; i < numOptionalParameters; i++) { 475 mdOptionalParameters.add(String8(optionalParameters[i].mKey), 476 String8(optionalParameters[i].mValue)); 477 } 478 String8 defaultUrl; 479 DrmPlugin::KeyRequestType keyRequestType; 480 mObj->mKeyRequest.clear(); 481 status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType), 482 mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl, 483 &keyRequestType); 484 if (status != OK) { 485 return translateStatus(status); 486 } else { 487 *keyRequest = mObj->mKeyRequest.array(); 488 *keyRequestSize = mObj->mKeyRequest.size(); 489 } 490 return AMEDIA_OK; 491 } 492 493 EXPORT 494 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope, 495 const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) { 496 497 if (!mObj || mObj->mDrm == NULL) { 498 return AMEDIA_ERROR_INVALID_OBJECT; 499 } 500 if (!scope || !response || !responseSize || !keySetId) { 501 return AMEDIA_ERROR_INVALID_PARAMETER; 502 } 503 504 List<idvec_t>::iterator iter; 505 if (!findId(mObj, *scope, iter)) { 506 return AMEDIA_DRM_SESSION_NOT_OPENED; 507 } 508 Vector<uint8_t> mdResponse; 509 mdResponse.appendArray(response, responseSize); 510 511 Vector<uint8_t> mdKeySetId; 512 status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId); 513 if (status == OK) { 514 mObj->mIds.push_front(mdKeySetId); 515 List<idvec_t>::iterator iter = mObj->mIds.begin(); 516 keySetId->ptr = iter->array(); 517 keySetId->length = iter->size(); 518 } else { 519 keySetId->ptr = NULL; 520 keySetId->length = 0; 521 } 522 return AMEDIA_OK; 523 } 524 525 EXPORT 526 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 527 const AMediaDrmKeySetId *keySetId) { 528 529 if (!mObj || mObj->mDrm == NULL) { 530 return AMEDIA_ERROR_INVALID_OBJECT; 531 } 532 if (!sessionId || !keySetId) { 533 return AMEDIA_ERROR_INVALID_PARAMETER; 534 } 535 List<idvec_t>::iterator iter; 536 if (!findId(mObj, *sessionId, iter)) { 537 return AMEDIA_DRM_SESSION_NOT_OPENED; 538 } 539 Vector<uint8_t> keySet; 540 keySet.appendArray(keySetId->ptr, keySetId->length); 541 return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet)); 542 } 543 544 EXPORT 545 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) { 546 if (!mObj || mObj->mDrm == NULL) { 547 return AMEDIA_ERROR_INVALID_OBJECT; 548 } 549 if (!keySetId) { 550 return AMEDIA_ERROR_INVALID_PARAMETER; 551 } 552 List<idvec_t>::iterator iter; 553 status_t status; 554 if (!findId(mObj, *keySetId, iter)) { 555 Vector<uint8_t> keySet; 556 keySet.appendArray(keySetId->ptr, keySetId->length); 557 status = mObj->mDrm->removeKeys(keySet); 558 } else { 559 status = mObj->mDrm->removeKeys(*iter); 560 mObj->mIds.erase(iter); 561 } 562 return translateStatus(status); 563 } 564 565 EXPORT 566 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 567 AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) { 568 569 if (!mObj || mObj->mDrm == NULL) { 570 return AMEDIA_ERROR_INVALID_OBJECT; 571 } 572 if (!sessionId || !numPairs) { 573 return AMEDIA_ERROR_INVALID_PARAMETER; 574 } 575 List<idvec_t>::iterator iter; 576 if (!findId(mObj, *sessionId, iter)) { 577 return AMEDIA_DRM_SESSION_NOT_OPENED; 578 } 579 580 status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults); 581 if (status != OK) { 582 *numPairs = 0; 583 return translateStatus(status); 584 } 585 586 if (mObj->mQueryResults.size() > *numPairs) { 587 *numPairs = mObj->mQueryResults.size(); 588 return AMEDIA_DRM_SHORT_BUFFER; 589 } 590 591 for (size_t i = 0; i < mObj->mQueryResults.size(); i++) { 592 keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string(); 593 keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string(); 594 } 595 *numPairs = mObj->mQueryResults.size(); 596 return AMEDIA_OK; 597 } 598 599 EXPORT 600 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest, 601 size_t *provisionRequestSize, const char **serverUrl) { 602 if (!mObj || mObj->mDrm == NULL) { 603 return AMEDIA_ERROR_INVALID_OBJECT; 604 } 605 if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) { 606 return AMEDIA_ERROR_INVALID_PARAMETER; 607 } 608 609 status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""), 610 mObj->mProvisionRequest, mObj->mProvisionUrl); 611 if (status != OK) { 612 return translateStatus(status); 613 } else { 614 *provisionRequest = mObj->mProvisionRequest.array(); 615 *provisionRequestSize = mObj->mProvisionRequest.size(); 616 *serverUrl = mObj->mProvisionUrl.string(); 617 } 618 return AMEDIA_OK; 619 } 620 621 EXPORT 622 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj, 623 const uint8_t *response, size_t responseSize) { 624 if (!mObj || mObj->mDrm == NULL) { 625 return AMEDIA_ERROR_INVALID_OBJECT; 626 } 627 if (!response || !responseSize) { 628 return AMEDIA_ERROR_INVALID_PARAMETER; 629 } 630 631 Vector<uint8_t> mdResponse; 632 mdResponse.appendArray(response, responseSize); 633 634 Vector<uint8_t> unused; 635 return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused)); 636 } 637 638 EXPORT 639 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj, 640 AMediaDrmSecureStop *secureStops, size_t *numSecureStops) { 641 642 if (!mObj || mObj->mDrm == NULL) { 643 return AMEDIA_ERROR_INVALID_OBJECT; 644 } 645 if (!numSecureStops) { 646 return AMEDIA_ERROR_INVALID_PARAMETER; 647 } 648 status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops); 649 if (status != OK) { 650 *numSecureStops = 0; 651 return translateStatus(status); 652 } 653 if (*numSecureStops < mObj->mSecureStops.size()) { 654 return AMEDIA_DRM_SHORT_BUFFER; 655 } 656 List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin(); 657 size_t i = 0; 658 while (iter != mObj->mSecureStops.end()) { 659 secureStops[i].ptr = iter->array(); 660 secureStops[i].length = iter->size(); 661 ++iter; 662 ++i; 663 } 664 *numSecureStops = mObj->mSecureStops.size(); 665 return AMEDIA_OK; 666 } 667 668 EXPORT 669 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj, 670 const AMediaDrmSecureStop *ssRelease) { 671 672 if (!mObj || mObj->mDrm == NULL) { 673 return AMEDIA_ERROR_INVALID_OBJECT; 674 } 675 if (!ssRelease) { 676 return AMEDIA_ERROR_INVALID_PARAMETER; 677 } 678 679 Vector<uint8_t> release; 680 release.appendArray(ssRelease->ptr, ssRelease->length); 681 return translateStatus(mObj->mDrm->releaseSecureStops(release)); 682 } 683 684 685 EXPORT 686 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName, 687 const char **propertyValue) { 688 689 if (!mObj || mObj->mDrm == NULL) { 690 return AMEDIA_ERROR_INVALID_OBJECT; 691 } 692 if (!propertyName || !propertyValue) { 693 return AMEDIA_ERROR_INVALID_PARAMETER; 694 } 695 696 status_t status = mObj->mDrm->getPropertyString(String8(propertyName), 697 mObj->mPropertyString); 698 699 if (status == OK) { 700 *propertyValue = mObj->mPropertyString.string(); 701 } else { 702 *propertyValue = NULL; 703 } 704 return translateStatus(status); 705 } 706 707 EXPORT 708 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj, 709 const char *propertyName, AMediaDrmByteArray *propertyValue) { 710 if (!mObj || mObj->mDrm == NULL) { 711 return AMEDIA_ERROR_INVALID_OBJECT; 712 } 713 if (!propertyName || !propertyValue) { 714 return AMEDIA_ERROR_INVALID_PARAMETER; 715 } 716 717 status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName), 718 mObj->mPropertyByteArray); 719 720 if (status == OK) { 721 propertyValue->ptr = mObj->mPropertyByteArray.array(); 722 propertyValue->length = mObj->mPropertyByteArray.size(); 723 } else { 724 propertyValue->ptr = NULL; 725 propertyValue->length = 0; 726 } 727 return translateStatus(status); 728 } 729 730 EXPORT 731 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj, 732 const char *propertyName, const char *value) { 733 if (!mObj || mObj->mDrm == NULL) { 734 return AMEDIA_ERROR_INVALID_OBJECT; 735 } 736 737 return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName), 738 String8(value))); 739 } 740 741 EXPORT 742 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj, 743 const char *propertyName, const uint8_t *value, size_t valueSize) { 744 745 Vector<uint8_t> byteArray; 746 byteArray.appendArray(value, valueSize); 747 748 return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName), 749 byteArray)); 750 } 751 752 753 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj, 754 const AMediaDrmSessionId &sessionId, 755 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 756 const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) { 757 758 if (!mObj || mObj->mDrm == NULL) { 759 return AMEDIA_ERROR_INVALID_OBJECT; 760 } 761 List<idvec_t>::iterator iter; 762 if (!findId(mObj, sessionId, iter)) { 763 return AMEDIA_DRM_SESSION_NOT_OPENED; 764 } 765 766 status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm)); 767 if (status != OK) { 768 return translateStatus(status); 769 } 770 771 Vector<uint8_t> keyIdVec; 772 const size_t kKeyIdSize = 16; 773 keyIdVec.appendArray(keyId, kKeyIdSize); 774 775 Vector<uint8_t> inputVec; 776 inputVec.appendArray(input, dataSize); 777 778 Vector<uint8_t> ivVec; 779 const size_t kIvSize = 16; 780 ivVec.appendArray(iv, kIvSize); 781 782 Vector<uint8_t> outputVec; 783 if (encrypt) { 784 status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 785 } else { 786 status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec); 787 } 788 if (status == OK) { 789 memcpy(output, outputVec.array(), outputVec.size()); 790 } 791 return translateStatus(status); 792 } 793 794 EXPORT 795 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 796 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 797 const uint8_t *input, uint8_t *output, size_t dataSize) { 798 if (!sessionId) { 799 return AMEDIA_ERROR_INVALID_PARAMETER; 800 } 801 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv, 802 input, output, dataSize, true); 803 } 804 805 EXPORT 806 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 807 const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv, 808 const uint8_t *input, uint8_t *output, size_t dataSize) { 809 if (!sessionId) { 810 return AMEDIA_ERROR_INVALID_PARAMETER; 811 } 812 return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv, 813 input, output, dataSize, false); 814 } 815 816 EXPORT 817 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 818 const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize, 819 uint8_t *signature, size_t *signatureSize) { 820 821 if (!mObj || mObj->mDrm == NULL) { 822 return AMEDIA_ERROR_INVALID_OBJECT; 823 } 824 if (!sessionId) { 825 return AMEDIA_ERROR_INVALID_PARAMETER; 826 } 827 List<idvec_t>::iterator iter; 828 if (!findId(mObj, *sessionId, iter)) { 829 return AMEDIA_DRM_SESSION_NOT_OPENED; 830 } 831 832 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 833 if (status != OK) { 834 return translateStatus(status); 835 } 836 837 Vector<uint8_t> keyIdVec; 838 const size_t kKeyIdSize = 16; 839 keyIdVec.appendArray(keyId, kKeyIdSize); 840 841 Vector<uint8_t> messageVec; 842 messageVec.appendArray(message, messageSize); 843 844 Vector<uint8_t> signatureVec; 845 status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec); 846 if (signatureVec.size() > *signatureSize) { 847 return AMEDIA_DRM_SHORT_BUFFER; 848 } 849 if (status == OK) { 850 memcpy(signature, signatureVec.array(), signatureVec.size()); 851 } 852 return translateStatus(status); 853 } 854 855 EXPORT 856 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId, 857 const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize, 858 const uint8_t *signature, size_t signatureSize) { 859 860 if (!mObj || mObj->mDrm == NULL) { 861 return AMEDIA_ERROR_INVALID_OBJECT; 862 } 863 if (!sessionId) { 864 return AMEDIA_ERROR_INVALID_PARAMETER; 865 } 866 List<idvec_t>::iterator iter; 867 if (!findId(mObj, *sessionId, iter)) { 868 return AMEDIA_DRM_SESSION_NOT_OPENED; 869 } 870 871 status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm)); 872 if (status != OK) { 873 return translateStatus(status); 874 } 875 876 Vector<uint8_t> keyIdVec; 877 const size_t kKeyIdSize = 16; 878 keyIdVec.appendArray(keyId, kKeyIdSize); 879 880 Vector<uint8_t> messageVec; 881 messageVec.appendArray(message, messageSize); 882 883 Vector<uint8_t> signatureVec; 884 signatureVec.appendArray(signature, signatureSize); 885 886 bool match; 887 status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match); 888 if (status == OK) { 889 return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED; 890 } 891 return translateStatus(status); 892 } 893 894 } // extern "C" 895