1/* 2 * Copyright (C) 2013 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 "Drm" 19#include <utils/Log.h> 20 21#include <dirent.h> 22#include <dlfcn.h> 23 24#include "Drm.h" 25 26#include <media/drm/DrmAPI.h> 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/AString.h> 29#include <media/stagefright/foundation/hexdump.h> 30#include <media/stagefright/MediaErrors.h> 31#include <binder/IServiceManager.h> 32#include <binder/IPCThreadState.h> 33 34namespace android { 35 36static bool checkPermission(const char* permissionString) { 37#ifndef HAVE_ANDROID_OS 38 return true; 39#endif 40 if (getpid() == IPCThreadState::self()->getCallingPid()) return true; 41 bool ok = checkCallingPermission(String16(permissionString)); 42 if (!ok) ALOGE("Request requires %s", permissionString); 43 return ok; 44} 45 46KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap; 47KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap; 48Mutex Drm::mMapLock; 49 50static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) { 51 if (lhs.size() < rhs.size()) { 52 return true; 53 } else if (lhs.size() > rhs.size()) { 54 return false; 55 } 56 57 return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0; 58} 59 60Drm::Drm() 61 : mInitCheck(NO_INIT), 62 mListener(NULL), 63 mFactory(NULL), 64 mPlugin(NULL) { 65} 66 67Drm::~Drm() { 68 delete mPlugin; 69 mPlugin = NULL; 70 closeFactory(); 71} 72 73void Drm::closeFactory() { 74 delete mFactory; 75 mFactory = NULL; 76 mLibrary.clear(); 77} 78 79status_t Drm::initCheck() const { 80 return mInitCheck; 81} 82 83status_t Drm::setListener(const sp<IDrmClient>& listener) 84{ 85 Mutex::Autolock lock(mEventLock); 86 if (mListener != NULL){ 87 mListener->asBinder()->unlinkToDeath(this); 88 } 89 if (listener != NULL) { 90 listener->asBinder()->linkToDeath(this); 91 } 92 mListener = listener; 93 return NO_ERROR; 94} 95 96void Drm::sendEvent(DrmPlugin::EventType eventType, int extra, 97 Vector<uint8_t> const *sessionId, 98 Vector<uint8_t> const *data) 99{ 100 mEventLock.lock(); 101 sp<IDrmClient> listener = mListener; 102 mEventLock.unlock(); 103 104 if (listener != NULL) { 105 Parcel obj; 106 if (sessionId && sessionId->size()) { 107 obj.writeInt32(sessionId->size()); 108 obj.write(sessionId->array(), sessionId->size()); 109 } else { 110 obj.writeInt32(0); 111 } 112 113 if (data && data->size()) { 114 obj.writeInt32(data->size()); 115 obj.write(data->array(), data->size()); 116 } else { 117 obj.writeInt32(0); 118 } 119 120 Mutex::Autolock lock(mNotifyLock); 121 listener->notify(eventType, extra, &obj); 122 } 123} 124 125/* 126 * Search the plugins directory for a plugin that supports the scheme 127 * specified by uuid 128 * 129 * If found: 130 * mLibrary holds a strong pointer to the dlopen'd library 131 * mFactory is set to the library's factory method 132 * mInitCheck is set to OK 133 * 134 * If not found: 135 * mLibrary is cleared and mFactory are set to NULL 136 * mInitCheck is set to an error (!OK) 137 */ 138void Drm::findFactoryForScheme(const uint8_t uuid[16]) { 139 140 closeFactory(); 141 142 // lock static maps 143 Mutex::Autolock autoLock(mMapLock); 144 145 // first check cache 146 Vector<uint8_t> uuidVector; 147 uuidVector.appendArray(uuid, sizeof(uuid)); 148 ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector); 149 if (index >= 0) { 150 if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) { 151 mInitCheck = OK; 152 return; 153 } else { 154 ALOGE("Failed to load from cached library path!"); 155 mInitCheck = ERROR_UNSUPPORTED; 156 return; 157 } 158 } 159 160 // no luck, have to search 161 String8 dirPath("/vendor/lib/mediadrm"); 162 DIR* pDir = opendir(dirPath.string()); 163 164 if (pDir == NULL) { 165 mInitCheck = ERROR_UNSUPPORTED; 166 ALOGE("Failed to open plugin directory %s", dirPath.string()); 167 return; 168 } 169 170 171 struct dirent* pEntry; 172 while ((pEntry = readdir(pDir))) { 173 174 String8 pluginPath = dirPath + "/" + pEntry->d_name; 175 176 if (pluginPath.getPathExtension() == ".so") { 177 178 if (loadLibraryForScheme(pluginPath, uuid)) { 179 mUUIDToLibraryPathMap.add(uuidVector, pluginPath); 180 mInitCheck = OK; 181 closedir(pDir); 182 return; 183 } 184 } 185 } 186 187 closedir(pDir); 188 189 ALOGE("Failed to find drm plugin"); 190 mInitCheck = ERROR_UNSUPPORTED; 191} 192 193bool Drm::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) { 194 195 // get strong pointer to open shared library 196 ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path); 197 if (index >= 0) { 198 mLibrary = mLibraryPathToOpenLibraryMap[index].promote(); 199 } else { 200 index = mLibraryPathToOpenLibraryMap.add(path, NULL); 201 } 202 203 if (!mLibrary.get()) { 204 mLibrary = new SharedLibrary(path); 205 if (!*mLibrary) { 206 return false; 207 } 208 209 mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary); 210 } 211 212 typedef DrmFactory *(*CreateDrmFactoryFunc)(); 213 214 CreateDrmFactoryFunc createDrmFactory = 215 (CreateDrmFactoryFunc)mLibrary->lookup("createDrmFactory"); 216 217 if (createDrmFactory == NULL || 218 (mFactory = createDrmFactory()) == NULL || 219 !mFactory->isCryptoSchemeSupported(uuid)) { 220 closeFactory(); 221 return false; 222 } 223 return true; 224} 225 226bool Drm::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { 227 228 Mutex::Autolock autoLock(mLock); 229 230 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 231 findFactoryForScheme(uuid); 232 if (mInitCheck != OK) { 233 return false; 234 } 235 } 236 237 if (mimeType != "") { 238 return mFactory->isContentTypeSupported(mimeType); 239 } 240 241 return true; 242} 243 244status_t Drm::createPlugin(const uint8_t uuid[16]) { 245 Mutex::Autolock autoLock(mLock); 246 247 if (mPlugin != NULL) { 248 return -EINVAL; 249 } 250 251 if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) { 252 findFactoryForScheme(uuid); 253 } 254 255 if (mInitCheck != OK) { 256 return mInitCheck; 257 } 258 259 status_t result = mFactory->createDrmPlugin(uuid, &mPlugin); 260 mPlugin->setListener(this); 261 return result; 262} 263 264status_t Drm::destroyPlugin() { 265 Mutex::Autolock autoLock(mLock); 266 267 if (mInitCheck != OK) { 268 return mInitCheck; 269 } 270 271 if (mPlugin == NULL) { 272 return -EINVAL; 273 } 274 275 delete mPlugin; 276 mPlugin = NULL; 277 278 return OK; 279} 280 281status_t Drm::openSession(Vector<uint8_t> &sessionId) { 282 Mutex::Autolock autoLock(mLock); 283 284 if (mInitCheck != OK) { 285 return mInitCheck; 286 } 287 288 if (mPlugin == NULL) { 289 return -EINVAL; 290 } 291 292 return mPlugin->openSession(sessionId); 293} 294 295status_t Drm::closeSession(Vector<uint8_t> const &sessionId) { 296 Mutex::Autolock autoLock(mLock); 297 298 if (mInitCheck != OK) { 299 return mInitCheck; 300 } 301 302 if (mPlugin == NULL) { 303 return -EINVAL; 304 } 305 306 return mPlugin->closeSession(sessionId); 307} 308 309status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId, 310 Vector<uint8_t> const &initData, 311 String8 const &mimeType, DrmPlugin::KeyType keyType, 312 KeyedVector<String8, String8> const &optionalParameters, 313 Vector<uint8_t> &request, String8 &defaultUrl) { 314 Mutex::Autolock autoLock(mLock); 315 316 if (mInitCheck != OK) { 317 return mInitCheck; 318 } 319 320 if (mPlugin == NULL) { 321 return -EINVAL; 322 } 323 324 return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType, 325 optionalParameters, request, defaultUrl); 326} 327 328status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId, 329 Vector<uint8_t> const &response, 330 Vector<uint8_t> &keySetId) { 331 Mutex::Autolock autoLock(mLock); 332 333 if (mInitCheck != OK) { 334 return mInitCheck; 335 } 336 337 if (mPlugin == NULL) { 338 return -EINVAL; 339 } 340 341 return mPlugin->provideKeyResponse(sessionId, response, keySetId); 342} 343 344status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) { 345 Mutex::Autolock autoLock(mLock); 346 347 if (mInitCheck != OK) { 348 return mInitCheck; 349 } 350 351 if (mPlugin == NULL) { 352 return -EINVAL; 353 } 354 355 return mPlugin->removeKeys(keySetId); 356} 357 358status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId, 359 Vector<uint8_t> const &keySetId) { 360 Mutex::Autolock autoLock(mLock); 361 362 if (mInitCheck != OK) { 363 return mInitCheck; 364 } 365 366 if (mPlugin == NULL) { 367 return -EINVAL; 368 } 369 370 return mPlugin->restoreKeys(sessionId, keySetId); 371} 372 373status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, 374 KeyedVector<String8, String8> &infoMap) const { 375 Mutex::Autolock autoLock(mLock); 376 377 if (mInitCheck != OK) { 378 return mInitCheck; 379 } 380 381 if (mPlugin == NULL) { 382 return -EINVAL; 383 } 384 385 return mPlugin->queryKeyStatus(sessionId, infoMap); 386} 387 388status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, 389 Vector<uint8_t> &request, String8 &defaultUrl) { 390 Mutex::Autolock autoLock(mLock); 391 392 if (mInitCheck != OK) { 393 return mInitCheck; 394 } 395 396 if (mPlugin == NULL) { 397 return -EINVAL; 398 } 399 400 return mPlugin->getProvisionRequest(certType, certAuthority, 401 request, defaultUrl); 402} 403 404status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, 405 Vector<uint8_t> &certificate, 406 Vector<uint8_t> &wrappedKey) { 407 Mutex::Autolock autoLock(mLock); 408 409 if (mInitCheck != OK) { 410 return mInitCheck; 411 } 412 413 if (mPlugin == NULL) { 414 return -EINVAL; 415 } 416 417 return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); 418} 419 420status_t Drm::unprovisionDevice() { 421 Mutex::Autolock autoLock(mLock); 422 423 if (mInitCheck != OK) { 424 return mInitCheck; 425 } 426 427 if (mPlugin == NULL) { 428 return -EINVAL; 429 } 430 431 if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) { 432 return -EPERM; 433 } 434 435 return mPlugin->unprovisionDevice(); 436} 437 438status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { 439 Mutex::Autolock autoLock(mLock); 440 441 if (mInitCheck != OK) { 442 return mInitCheck; 443 } 444 445 if (mPlugin == NULL) { 446 return -EINVAL; 447 } 448 449 return mPlugin->getSecureStops(secureStops); 450} 451 452status_t Drm::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) { 453 Mutex::Autolock autoLock(mLock); 454 455 if (mInitCheck != OK) { 456 return mInitCheck; 457 } 458 459 if (mPlugin == NULL) { 460 return -EINVAL; 461 } 462 463 return mPlugin->getSecureStop(ssid, secureStop); 464} 465 466status_t Drm::releaseSecureStops(Vector<uint8_t> const &ssRelease) { 467 Mutex::Autolock autoLock(mLock); 468 469 if (mInitCheck != OK) { 470 return mInitCheck; 471 } 472 473 if (mPlugin == NULL) { 474 return -EINVAL; 475 } 476 477 return mPlugin->releaseSecureStops(ssRelease); 478} 479 480status_t Drm::releaseAllSecureStops() { 481 Mutex::Autolock autoLock(mLock); 482 483 if (mInitCheck != OK) { 484 return mInitCheck; 485 } 486 487 if (mPlugin == NULL) { 488 return -EINVAL; 489 } 490 491 return mPlugin->releaseAllSecureStops(); 492} 493 494status_t Drm::getPropertyString(String8 const &name, String8 &value ) const { 495 Mutex::Autolock autoLock(mLock); 496 497 if (mInitCheck != OK) { 498 return mInitCheck; 499 } 500 501 if (mPlugin == NULL) { 502 return -EINVAL; 503 } 504 505 return mPlugin->getPropertyString(name, value); 506} 507 508status_t Drm::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const { 509 Mutex::Autolock autoLock(mLock); 510 511 if (mInitCheck != OK) { 512 return mInitCheck; 513 } 514 515 if (mPlugin == NULL) { 516 return -EINVAL; 517 } 518 519 return mPlugin->getPropertyByteArray(name, value); 520} 521 522status_t Drm::setPropertyString(String8 const &name, String8 const &value ) const { 523 Mutex::Autolock autoLock(mLock); 524 525 if (mInitCheck != OK) { 526 return mInitCheck; 527 } 528 529 if (mPlugin == NULL) { 530 return -EINVAL; 531 } 532 533 return mPlugin->setPropertyString(name, value); 534} 535 536status_t Drm::setPropertyByteArray(String8 const &name, 537 Vector<uint8_t> const &value ) const { 538 Mutex::Autolock autoLock(mLock); 539 540 if (mInitCheck != OK) { 541 return mInitCheck; 542 } 543 544 if (mPlugin == NULL) { 545 return -EINVAL; 546 } 547 548 return mPlugin->setPropertyByteArray(name, value); 549} 550 551 552status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId, 553 String8 const &algorithm) { 554 Mutex::Autolock autoLock(mLock); 555 556 if (mInitCheck != OK) { 557 return mInitCheck; 558 } 559 560 if (mPlugin == NULL) { 561 return -EINVAL; 562 } 563 564 return mPlugin->setCipherAlgorithm(sessionId, algorithm); 565} 566 567status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId, 568 String8 const &algorithm) { 569 Mutex::Autolock autoLock(mLock); 570 571 if (mInitCheck != OK) { 572 return mInitCheck; 573 } 574 575 if (mPlugin == NULL) { 576 return -EINVAL; 577 } 578 579 return mPlugin->setMacAlgorithm(sessionId, algorithm); 580} 581 582status_t Drm::encrypt(Vector<uint8_t> const &sessionId, 583 Vector<uint8_t> const &keyId, 584 Vector<uint8_t> const &input, 585 Vector<uint8_t> const &iv, 586 Vector<uint8_t> &output) { 587 Mutex::Autolock autoLock(mLock); 588 589 if (mInitCheck != OK) { 590 return mInitCheck; 591 } 592 593 if (mPlugin == NULL) { 594 return -EINVAL; 595 } 596 597 return mPlugin->encrypt(sessionId, keyId, input, iv, output); 598} 599 600status_t Drm::decrypt(Vector<uint8_t> const &sessionId, 601 Vector<uint8_t> const &keyId, 602 Vector<uint8_t> const &input, 603 Vector<uint8_t> const &iv, 604 Vector<uint8_t> &output) { 605 Mutex::Autolock autoLock(mLock); 606 607 if (mInitCheck != OK) { 608 return mInitCheck; 609 } 610 611 if (mPlugin == NULL) { 612 return -EINVAL; 613 } 614 615 return mPlugin->decrypt(sessionId, keyId, input, iv, output); 616} 617 618status_t Drm::sign(Vector<uint8_t> const &sessionId, 619 Vector<uint8_t> const &keyId, 620 Vector<uint8_t> const &message, 621 Vector<uint8_t> &signature) { 622 Mutex::Autolock autoLock(mLock); 623 624 if (mInitCheck != OK) { 625 return mInitCheck; 626 } 627 628 if (mPlugin == NULL) { 629 return -EINVAL; 630 } 631 632 return mPlugin->sign(sessionId, keyId, message, signature); 633} 634 635status_t Drm::verify(Vector<uint8_t> const &sessionId, 636 Vector<uint8_t> const &keyId, 637 Vector<uint8_t> const &message, 638 Vector<uint8_t> const &signature, 639 bool &match) { 640 Mutex::Autolock autoLock(mLock); 641 642 if (mInitCheck != OK) { 643 return mInitCheck; 644 } 645 646 if (mPlugin == NULL) { 647 return -EINVAL; 648 } 649 650 return mPlugin->verify(sessionId, keyId, message, signature, match); 651} 652 653status_t Drm::signRSA(Vector<uint8_t> const &sessionId, 654 String8 const &algorithm, 655 Vector<uint8_t> const &message, 656 Vector<uint8_t> const &wrappedKey, 657 Vector<uint8_t> &signature) { 658 Mutex::Autolock autoLock(mLock); 659 660 if (mInitCheck != OK) { 661 return mInitCheck; 662 } 663 664 if (mPlugin == NULL) { 665 return -EINVAL; 666 } 667 668 if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { 669 return -EPERM; 670 } 671 672 return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); 673} 674 675void Drm::binderDied(const wp<IBinder> &the_late_who) 676{ 677 mEventLock.lock(); 678 mListener.clear(); 679 mEventLock.unlock(); 680 681 Mutex::Autolock autoLock(mLock); 682 delete mPlugin; 683 mPlugin = NULL; 684 closeFactory(); 685} 686 687} // namespace android 688