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