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         sessionId->ptr = NULL;
385         sessionId->length = 0;
386         return translateStatus(status);
387     }
388     mObj->mIds.push_front(session);
389     List<idvec_t>::iterator iter = mObj->mIds.begin();
390     sessionId->ptr = iter->array();
391     sessionId->length = iter->size();
392     return AMEDIA_OK;
393 }
394 
395 EXPORT
AMediaDrm_closeSession(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId)396 media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
397     if (!mObj || mObj->mDrm == NULL) {
398         return AMEDIA_ERROR_INVALID_OBJECT;
399     }
400     if (!sessionId) {
401         return AMEDIA_ERROR_INVALID_PARAMETER;
402     }
403 
404     List<idvec_t>::iterator iter;
405     if (!findId(mObj, *sessionId, iter)) {
406         return AMEDIA_DRM_SESSION_NOT_OPENED;
407     }
408     mObj->mDrm->closeSession(*iter);
409     mObj->mIds.erase(iter);
410     return AMEDIA_OK;
411 }
412 
413 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)414 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
415         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
416         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
417         const uint8_t **keyRequest, size_t *keyRequestSize) {
418 
419     if (!mObj || mObj->mDrm == NULL) {
420         return AMEDIA_ERROR_INVALID_OBJECT;
421     }
422     if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
423         return AMEDIA_ERROR_INVALID_PARAMETER;
424     }
425 
426     List<idvec_t>::iterator iter;
427     if (!findId(mObj, *scope, iter)) {
428         return AMEDIA_DRM_SESSION_NOT_OPENED;
429     }
430 
431     Vector<uint8_t> mdInit;
432     mdInit.appendArray(init, initSize);
433     DrmPlugin::KeyType mdKeyType;
434     switch (keyType) {
435         case KEY_TYPE_STREAMING:
436             mdKeyType = DrmPlugin::kKeyType_Streaming;
437             break;
438         case KEY_TYPE_OFFLINE:
439             mdKeyType = DrmPlugin::kKeyType_Offline;
440             break;
441         case KEY_TYPE_RELEASE:
442             mdKeyType = DrmPlugin::kKeyType_Release;
443             break;
444         default:
445             return AMEDIA_ERROR_INVALID_PARAMETER;
446     }
447     KeyedVector<String8, String8> mdOptionalParameters;
448     for (size_t i = 0; i < numOptionalParameters; i++) {
449         mdOptionalParameters.add(String8(optionalParameters[i].mKey),
450                 String8(optionalParameters[i].mValue));
451     }
452     String8 defaultUrl;
453     DrmPlugin::KeyRequestType keyRequestType;
454     mObj->mKeyRequest.clear();
455     status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
456             mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
457             &keyRequestType);
458     if (status != OK) {
459         return translateStatus(status);
460     } else {
461         *keyRequest = mObj->mKeyRequest.array();
462         *keyRequestSize = mObj->mKeyRequest.size();
463     }
464     return AMEDIA_OK;
465 }
466 
467 EXPORT
AMediaDrm_provideKeyResponse(AMediaDrm * mObj,const AMediaDrmScope * scope,const uint8_t * response,size_t responseSize,AMediaDrmKeySetId * keySetId)468 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
469         const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
470 
471     if (!mObj || mObj->mDrm == NULL) {
472         return AMEDIA_ERROR_INVALID_OBJECT;
473     }
474     if (!scope || !response || !responseSize || !keySetId) {
475         return AMEDIA_ERROR_INVALID_PARAMETER;
476     }
477 
478     List<idvec_t>::iterator iter;
479     if (!findId(mObj, *scope, iter)) {
480         return AMEDIA_DRM_SESSION_NOT_OPENED;
481     }
482     Vector<uint8_t> mdResponse;
483     mdResponse.appendArray(response, responseSize);
484 
485     Vector<uint8_t> mdKeySetId;
486     status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
487     if (status == OK) {
488         mObj->mIds.push_front(mdKeySetId);
489         List<idvec_t>::iterator iter = mObj->mIds.begin();
490         keySetId->ptr = iter->array();
491         keySetId->length = iter->size();
492     } else {
493         keySetId->ptr = NULL;
494         keySetId->length = 0;
495         return translateStatus(status);
496     }
497     return AMEDIA_OK;
498 }
499 
500 EXPORT
AMediaDrm_restoreKeys(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,const AMediaDrmKeySetId * keySetId)501 media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
502         const AMediaDrmKeySetId *keySetId) {
503 
504     if (!mObj || mObj->mDrm == NULL) {
505         return AMEDIA_ERROR_INVALID_OBJECT;
506     }
507     if (!sessionId || !keySetId) {
508         return AMEDIA_ERROR_INVALID_PARAMETER;
509     }
510     List<idvec_t>::iterator iter;
511     if (!findId(mObj, *sessionId, iter)) {
512         return AMEDIA_DRM_SESSION_NOT_OPENED;
513     }
514     Vector<uint8_t> keySet;
515     keySet.appendArray(keySetId->ptr, keySetId->length);
516     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
517 }
518 
519 EXPORT
AMediaDrm_removeKeys(AMediaDrm * mObj,const AMediaDrmSessionId * keySetId)520 media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
521     if (!mObj || mObj->mDrm == NULL) {
522         return AMEDIA_ERROR_INVALID_OBJECT;
523     }
524     if (!keySetId) {
525         return AMEDIA_ERROR_INVALID_PARAMETER;
526     }
527     List<idvec_t>::iterator iter;
528     status_t status;
529     if (!findId(mObj, *keySetId, iter)) {
530         Vector<uint8_t> keySet;
531         keySet.appendArray(keySetId->ptr, keySetId->length);
532         status = mObj->mDrm->removeKeys(keySet);
533     } else {
534         status = mObj->mDrm->removeKeys(*iter);
535         mObj->mIds.erase(iter);
536     }
537     return translateStatus(status);
538 }
539 
540 EXPORT
AMediaDrm_queryKeyStatus(AMediaDrm * mObj,const AMediaDrmSessionId * sessionId,AMediaDrmKeyValue * keyValuePairs,size_t * numPairs)541 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
542         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
543 
544     if (!mObj || mObj->mDrm == NULL) {
545         return AMEDIA_ERROR_INVALID_OBJECT;
546     }
547     if (!sessionId || !numPairs) {
548         return AMEDIA_ERROR_INVALID_PARAMETER;
549     }
550     List<idvec_t>::iterator iter;
551     if (!findId(mObj, *sessionId, iter)) {
552         return AMEDIA_DRM_SESSION_NOT_OPENED;
553     }
554 
555     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
556     if (status != OK) {
557         *numPairs = 0;
558         return translateStatus(status);
559     }
560 
561     if (mObj->mQueryResults.size() > *numPairs) {
562         *numPairs = mObj->mQueryResults.size();
563         return AMEDIA_DRM_SHORT_BUFFER;
564     }
565 
566     for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
567         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
568         keyValuePairs[i].mValue = mObj->mQueryResults.valueAt(i).string();
569     }
570     *numPairs = mObj->mQueryResults.size();
571     return AMEDIA_OK;
572 }
573 
574 EXPORT
AMediaDrm_getProvisionRequest(AMediaDrm * mObj,const uint8_t ** provisionRequest,size_t * provisionRequestSize,const char ** serverUrl)575 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
576         size_t *provisionRequestSize, const char **serverUrl) {
577     if (!mObj || mObj->mDrm == NULL) {
578         return AMEDIA_ERROR_INVALID_OBJECT;
579     }
580     if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
581         return AMEDIA_ERROR_INVALID_PARAMETER;
582     }
583 
584     status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
585             mObj->mProvisionRequest, mObj->mProvisionUrl);
586     if (status != OK) {
587         return translateStatus(status);
588     } else {
589         *provisionRequest = mObj->mProvisionRequest.array();
590         *provisionRequestSize = mObj->mProvisionRequest.size();
591         *serverUrl = mObj->mProvisionUrl.string();
592     }
593     return AMEDIA_OK;
594 }
595 
596 EXPORT
AMediaDrm_provideProvisionResponse(AMediaDrm * mObj,const uint8_t * response,size_t responseSize)597 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
598         const uint8_t *response, size_t responseSize) {
599     if (!mObj || mObj->mDrm == NULL) {
600         return AMEDIA_ERROR_INVALID_OBJECT;
601     }
602     if (!response || !responseSize) {
603         return AMEDIA_ERROR_INVALID_PARAMETER;
604     }
605 
606     Vector<uint8_t> mdResponse;
607     mdResponse.appendArray(response, responseSize);
608 
609     Vector<uint8_t> unused;
610     return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
611 }
612 
613 EXPORT
AMediaDrm_getSecureStops(AMediaDrm * mObj,AMediaDrmSecureStop * secureStops,size_t * numSecureStops)614 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
615         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
616 
617     if (!mObj || mObj->mDrm == NULL) {
618         return AMEDIA_ERROR_INVALID_OBJECT;
619     }
620     if (!numSecureStops) {
621         return AMEDIA_ERROR_INVALID_PARAMETER;
622     }
623     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
624     if (status != OK) {
625         *numSecureStops = 0;
626         return translateStatus(status);
627     }
628     if (*numSecureStops < mObj->mSecureStops.size()) {
629         return AMEDIA_DRM_SHORT_BUFFER;
630     }
631     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
632     size_t i = 0;
633     while (iter != mObj->mSecureStops.end()) {
634         secureStops[i].ptr = iter->array();
635         secureStops[i].length = iter->size();
636         ++iter;
637         ++i;
638     }
639     *numSecureStops = mObj->mSecureStops.size();
640     return AMEDIA_OK;
641 }
642 
643 EXPORT
AMediaDrm_releaseSecureStops(AMediaDrm * mObj,const AMediaDrmSecureStop * ssRelease)644 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
645         const AMediaDrmSecureStop *ssRelease) {
646 
647     if (!mObj || mObj->mDrm == NULL) {
648         return AMEDIA_ERROR_INVALID_OBJECT;
649     }
650     if (!ssRelease) {
651         return AMEDIA_ERROR_INVALID_PARAMETER;
652     }
653 
654     Vector<uint8_t> release;
655     release.appendArray(ssRelease->ptr, ssRelease->length);
656     return translateStatus(mObj->mDrm->releaseSecureStops(release));
657 }
658 
659 
660 EXPORT
AMediaDrm_getPropertyString(AMediaDrm * mObj,const char * propertyName,const char ** propertyValue)661 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
662         const char **propertyValue) {
663 
664     if (!mObj || mObj->mDrm == NULL) {
665         return AMEDIA_ERROR_INVALID_OBJECT;
666     }
667     if (!propertyName || !propertyValue) {
668         return AMEDIA_ERROR_INVALID_PARAMETER;
669     }
670 
671     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
672             mObj->mPropertyString);
673 
674     if (status == OK) {
675         *propertyValue = mObj->mPropertyString.string();
676     } else {
677         *propertyValue = NULL;
678     }
679     return translateStatus(status);
680 }
681 
682 EXPORT
AMediaDrm_getPropertyByteArray(AMediaDrm * mObj,const char * propertyName,AMediaDrmByteArray * propertyValue)683 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
684         const char *propertyName, AMediaDrmByteArray *propertyValue) {
685     if (!mObj || mObj->mDrm == NULL) {
686         return AMEDIA_ERROR_INVALID_OBJECT;
687     }
688     if (!propertyName || !propertyValue) {
689         return AMEDIA_ERROR_INVALID_PARAMETER;
690     }
691 
692     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
693             mObj->mPropertyByteArray);
694 
695     if (status == OK) {
696         propertyValue->ptr = mObj->mPropertyByteArray.array();
697         propertyValue->length = mObj->mPropertyByteArray.size();
698     } else {
699         propertyValue->ptr = NULL;
700         propertyValue->length = 0;
701     }
702     return translateStatus(status);
703 }
704 
705 EXPORT
AMediaDrm_setPropertyString(AMediaDrm * mObj,const char * propertyName,const char * value)706 media_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
707         const char *propertyName, const char *value) {
708     if (!mObj || mObj->mDrm == NULL) {
709         return AMEDIA_ERROR_INVALID_OBJECT;
710     }
711 
712     return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
713                     String8(value)));
714 }
715 
716 EXPORT
AMediaDrm_setPropertyByteArray(AMediaDrm * mObj,const char * propertyName,const uint8_t * value,size_t valueSize)717 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
718         const char *propertyName, const uint8_t *value, size_t valueSize) {
719 
720     Vector<uint8_t> byteArray;
721     byteArray.appendArray(value, valueSize);
722 
723     return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName),
724                     byteArray));
725 }
726 
727 
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)728 static media_status_t encrypt_decrypt_common(AMediaDrm *mObj,
729         const AMediaDrmSessionId &sessionId,
730         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
731         const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
732 
733     if (!mObj || mObj->mDrm == NULL) {
734         return AMEDIA_ERROR_INVALID_OBJECT;
735     }
736     List<idvec_t>::iterator iter;
737     if (!findId(mObj, sessionId, iter)) {
738         return AMEDIA_DRM_SESSION_NOT_OPENED;
739     }
740 
741     status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
742     if (status != OK) {
743         return translateStatus(status);
744     }
745 
746     Vector<uint8_t> keyIdVec;
747     const size_t kKeyIdSize = 16;
748     keyIdVec.appendArray(keyId, kKeyIdSize);
749 
750     Vector<uint8_t> inputVec;
751     inputVec.appendArray(input, dataSize);
752 
753     Vector<uint8_t> ivVec;
754     const size_t kIvSize = 16;
755     ivVec.appendArray(iv, kIvSize);
756 
757     Vector<uint8_t> outputVec;
758     if (encrypt) {
759         status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
760     } else {
761         status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
762     }
763     if (status == OK) {
764         memcpy(output, outputVec.array(), outputVec.size());
765     }
766     return translateStatus(status);
767 }
768 
769 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)770 media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
771         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
772         const uint8_t *input, uint8_t *output, size_t dataSize) {
773     if (!sessionId) {
774         return AMEDIA_ERROR_INVALID_PARAMETER;
775     }
776     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
777             input, output, dataSize, true);
778 }
779 
780 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)781 media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
782         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
783         const uint8_t *input, uint8_t *output, size_t dataSize) {
784     if (!sessionId) {
785         return AMEDIA_ERROR_INVALID_PARAMETER;
786     }
787     return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
788             input, output, dataSize, false);
789 }
790 
791 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)792 media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
793         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
794         uint8_t *signature, size_t *signatureSize) {
795 
796     if (!mObj || mObj->mDrm == NULL) {
797         return AMEDIA_ERROR_INVALID_OBJECT;
798     }
799     if (!sessionId) {
800         return AMEDIA_ERROR_INVALID_PARAMETER;
801     }
802     List<idvec_t>::iterator iter;
803     if (!findId(mObj, *sessionId, iter)) {
804         return AMEDIA_DRM_SESSION_NOT_OPENED;
805     }
806 
807     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
808     if (status != OK) {
809         return translateStatus(status);
810     }
811 
812     Vector<uint8_t> keyIdVec;
813     const size_t kKeyIdSize = 16;
814     keyIdVec.appendArray(keyId, kKeyIdSize);
815 
816     Vector<uint8_t> messageVec;
817     messageVec.appendArray(message, messageSize);
818 
819     Vector<uint8_t> signatureVec;
820     status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
821     if (signatureVec.size() > *signatureSize) {
822         return AMEDIA_DRM_SHORT_BUFFER;
823     }
824     if (status == OK) {
825         memcpy(signature, signatureVec.array(), signatureVec.size());
826     }
827     return translateStatus(status);
828 }
829 
830 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)831 media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
832         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
833         const uint8_t *signature, size_t signatureSize) {
834 
835     if (!mObj || mObj->mDrm == NULL) {
836         return AMEDIA_ERROR_INVALID_OBJECT;
837     }
838     if (!sessionId) {
839         return AMEDIA_ERROR_INVALID_PARAMETER;
840     }
841     List<idvec_t>::iterator iter;
842     if (!findId(mObj, *sessionId, iter)) {
843         return AMEDIA_DRM_SESSION_NOT_OPENED;
844     }
845 
846     status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
847     if (status != OK) {
848         return translateStatus(status);
849     }
850 
851     Vector<uint8_t> keyIdVec;
852     const size_t kKeyIdSize = 16;
853     keyIdVec.appendArray(keyId, kKeyIdSize);
854 
855     Vector<uint8_t> messageVec;
856     messageVec.appendArray(message, messageSize);
857 
858     Vector<uint8_t> signatureVec;
859     signatureVec.appendArray(signature, signatureSize);
860 
861     bool match;
862     status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
863     if (status == OK) {
864         return match ? AMEDIA_OK : AMEDIA_DRM_VERIFY_FAILED;
865     }
866     return translateStatus(status);
867 }
868 
869 } // extern "C"
870