Drm.cpp revision 3c1285e8f86bd497e14c14fb6df7b42072ef52bd
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    delete mPlugin;
678    mPlugin = NULL;
679    closeFactory();
680    mListener.clear();
681}
682
683}  // namespace android
684