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