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 
34 namespace android {
35 
checkPermission(const char * permissionString)36 static 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 
46 KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap;
47 KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap;
48 Mutex Drm::mMapLock;
49 
operator <(const Vector<uint8_t> & lhs,const Vector<uint8_t> & rhs)50 static 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 
Drm()60 Drm::Drm()
61     : mInitCheck(NO_INIT),
62       mListener(NULL),
63       mFactory(NULL),
64       mPlugin(NULL) {
65 }
66 
~Drm()67 Drm::~Drm() {
68     delete mPlugin;
69     mPlugin = NULL;
70     closeFactory();
71 }
72 
closeFactory()73 void Drm::closeFactory() {
74     delete mFactory;
75     mFactory = NULL;
76     mLibrary.clear();
77 }
78 
initCheck() const79 status_t Drm::initCheck() const {
80     return mInitCheck;
81 }
82 
setListener(const sp<IDrmClient> & listener)83 status_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 
sendEvent(DrmPlugin::EventType eventType,int extra,Vector<uint8_t> const * sessionId,Vector<uint8_t> const * data)96 void 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  */
findFactoryForScheme(const uint8_t uuid[16])138 void 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 
loadLibraryForScheme(const String8 & path,const uint8_t uuid[16])193 bool 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 
isCryptoSchemeSupported(const uint8_t uuid[16],const String8 & mimeType)226 bool 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 
createPlugin(const uint8_t uuid[16])244 status_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 
destroyPlugin()264 status_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 
openSession(Vector<uint8_t> & sessionId)281 status_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 
closeSession(Vector<uint8_t> const & sessionId)295 status_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 
getKeyRequest(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & initData,String8 const & mimeType,DrmPlugin::KeyType keyType,KeyedVector<String8,String8> const & optionalParameters,Vector<uint8_t> & request,String8 & defaultUrl)309 status_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 
provideKeyResponse(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & response,Vector<uint8_t> & keySetId)328 status_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 
removeKeys(Vector<uint8_t> const & keySetId)344 status_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 
restoreKeys(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keySetId)358 status_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 
queryKeyStatus(Vector<uint8_t> const & sessionId,KeyedVector<String8,String8> & infoMap) const373 status_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 
getProvisionRequest(String8 const & certType,String8 const & certAuthority,Vector<uint8_t> & request,String8 & defaultUrl)388 status_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 
provideProvisionResponse(Vector<uint8_t> const & response,Vector<uint8_t> & certificate,Vector<uint8_t> & wrappedKey)404 status_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 
unprovisionDevice()420 status_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 
getSecureStops(List<Vector<uint8_t>> & secureStops)438 status_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 
getSecureStop(Vector<uint8_t> const & ssid,Vector<uint8_t> & secureStop)452 status_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 
releaseSecureStops(Vector<uint8_t> const & ssRelease)466 status_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 
releaseAllSecureStops()480 status_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 
getPropertyString(String8 const & name,String8 & value) const494 status_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 
getPropertyByteArray(String8 const & name,Vector<uint8_t> & value) const508 status_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 
setPropertyString(String8 const & name,String8 const & value) const522 status_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 
setPropertyByteArray(String8 const & name,Vector<uint8_t> const & value) const536 status_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 
setCipherAlgorithm(Vector<uint8_t> const & sessionId,String8 const & algorithm)552 status_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 
setMacAlgorithm(Vector<uint8_t> const & sessionId,String8 const & algorithm)567 status_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 
encrypt(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & input,Vector<uint8_t> const & iv,Vector<uint8_t> & output)582 status_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 
decrypt(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & input,Vector<uint8_t> const & iv,Vector<uint8_t> & output)600 status_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 
sign(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & message,Vector<uint8_t> & signature)618 status_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 
verify(Vector<uint8_t> const & sessionId,Vector<uint8_t> const & keyId,Vector<uint8_t> const & message,Vector<uint8_t> const & signature,bool & match)635 status_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 
signRSA(Vector<uint8_t> const & sessionId,String8 const & algorithm,Vector<uint8_t> const & message,Vector<uint8_t> const & wrappedKey,Vector<uint8_t> & signature)653 status_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 
binderDied(const wp<IBinder> & the_late_who)675 void 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