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 "MockDrmCryptoPlugin"
19#include <utils/Log.h>
20
21
22#include "drm/DrmAPI.h"
23#include "MockDrmCryptoPlugin.h"
24#include "media/stagefright/MediaErrors.h"
25
26using namespace android;
27
28// Shared library entry point
29DrmFactory *createDrmFactory()
30{
31    return new MockDrmFactory();
32}
33
34// Shared library entry point
35CryptoFactory *createCryptoFactory()
36{
37    return new MockCryptoFactory();
38}
39
40const uint8_t mock_uuid[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
41                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
42
43namespace android {
44
45    // MockDrmFactory
46    bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16])
47    {
48        return (!memcmp(uuid, mock_uuid, sizeof(mock_uuid)));
49    }
50
51    bool MockDrmFactory::isContentTypeSupported(const String8 &mimeType)
52    {
53        if (mimeType != "video/mp4") {
54            return false;
55        }
56        return true;
57    }
58
59    status_t MockDrmFactory::createDrmPlugin(const uint8_t /* uuid */[16], DrmPlugin **plugin)
60    {
61        *plugin = new MockDrmPlugin();
62        return OK;
63    }
64
65    // MockCryptoFactory
66    bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const
67    {
68        return (!memcmp(uuid, mock_uuid, sizeof(mock_uuid)));
69    }
70
71    status_t MockCryptoFactory::createPlugin(const uint8_t /* uuid */[16],
72                                             const void * /* data */,
73                                             size_t /* size */, CryptoPlugin **plugin)
74    {
75        *plugin = new MockCryptoPlugin();
76        return OK;
77    }
78
79
80    // MockDrmPlugin methods
81
82    status_t MockDrmPlugin::openSession(Vector<uint8_t> &sessionId)
83    {
84        const size_t kSessionIdSize = 8;
85
86        Mutex::Autolock lock(mLock);
87        for (size_t i = 0; i < kSessionIdSize / sizeof(long); i++) {
88            long r = random();
89            sessionId.appendArray((uint8_t *)&r, sizeof(long));
90        }
91        mSessions.add(sessionId);
92
93        ALOGD("MockDrmPlugin::openSession() -> %s", vectorToString(sessionId).string());
94        return OK;
95    }
96
97    status_t MockDrmPlugin::closeSession(Vector<uint8_t> const &sessionId)
98    {
99        Mutex::Autolock lock(mLock);
100        ALOGD("MockDrmPlugin::closeSession(%s)", vectorToString(sessionId).string());
101        ssize_t index = findSession(sessionId);
102        if (index == kNotFound) {
103            ALOGD("Invalid sessionId");
104            return BAD_VALUE;
105        }
106        mSessions.removeAt(index);
107        return OK;
108    }
109
110
111    status_t MockDrmPlugin::getKeyRequest(Vector<uint8_t> const &sessionId,
112                                          Vector<uint8_t> const &initData,
113                                          String8 const &mimeType, KeyType keyType,
114                                          KeyedVector<String8, String8> const &optionalParameters,
115                                          Vector<uint8_t> &request, String8 &defaultUrl,
116                                          KeyRequestType *keyRequestType)
117    {
118        Mutex::Autolock lock(mLock);
119        ALOGD("MockDrmPlugin::getKeyRequest(sessionId=%s, initData=%s, mimeType=%s"
120              ", keyType=%d, optionalParameters=%s))",
121              vectorToString(sessionId).string(), vectorToString(initData).string(), mimeType.string(),
122              keyType, stringMapToString(optionalParameters).string());
123
124        ssize_t index = findSession(sessionId);
125        if (index == kNotFound) {
126            ALOGD("Invalid sessionId");
127            return BAD_VALUE;
128        }
129
130        // Properties used in mock test, set by mock plugin and verifed cts test app
131        //   byte[] initData           -> mock-initdata
132        //   string mimeType           -> mock-mimetype
133        //   string keyType            -> mock-keytype
134        //   string optionalParameters -> mock-optparams formatted as {key1,value1},{key2,value2}
135
136        mByteArrayProperties.add(String8("mock-initdata"), initData);
137        mStringProperties.add(String8("mock-mimetype"), mimeType);
138
139        String8 keyTypeStr;
140        keyTypeStr.appendFormat("%d", (int)keyType);
141        mStringProperties.add(String8("mock-keytype"), keyTypeStr);
142
143        String8 params;
144        for (size_t i = 0; i < optionalParameters.size(); i++) {
145            params.appendFormat("%s{%s,%s}", i ? "," : "",
146                                optionalParameters.keyAt(i).string(),
147                                optionalParameters.valueAt(i).string());
148        }
149        mStringProperties.add(String8("mock-optparams"), params);
150
151        // Properties used in mock test, set by cts test app returned from mock plugin
152        //   byte[] mock-request       -> request
153        //   string mock-default-url   -> defaultUrl
154        //   string mock-keyRequestType -> keyRequestType
155
156        index = mByteArrayProperties.indexOfKey(String8("mock-request"));
157        if (index < 0) {
158            ALOGD("Missing 'mock-request' parameter for mock");
159            return BAD_VALUE;
160        } else {
161            request = mByteArrayProperties.valueAt(index);
162        }
163
164        index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
165        if (index < 0) {
166            ALOGD("Missing 'mock-defaultUrl' parameter for mock");
167            return BAD_VALUE;
168        } else {
169            defaultUrl = mStringProperties.valueAt(index);
170        }
171
172        index = mStringProperties.indexOfKey(String8("mock-keyRequestType"));
173        if (index < 0) {
174            ALOGD("Missing 'mock-keyRequestType' parameter for mock");
175            return BAD_VALUE;
176        } else {
177            *keyRequestType = static_cast<KeyRequestType>(
178                atoi(mStringProperties.valueAt(index).string()));
179        }
180
181        return OK;
182    }
183
184    status_t MockDrmPlugin::provideKeyResponse(Vector<uint8_t> const &sessionId,
185                                               Vector<uint8_t> const &response,
186                                               Vector<uint8_t> &keySetId)
187    {
188        Mutex::Autolock lock(mLock);
189        ALOGD("MockDrmPlugin::provideKeyResponse(sessionId=%s, response=%s)",
190              vectorToString(sessionId).string(), vectorToString(response).string());
191        ssize_t index = findSession(sessionId);
192        if (index == kNotFound) {
193            ALOGD("Invalid sessionId");
194            return BAD_VALUE;
195        }
196        if (response.size() == 0) {
197            return BAD_VALUE;
198        }
199
200        // Properties used in mock test, set by mock plugin and verifed cts test app
201        //   byte[] response            -> mock-response
202        mByteArrayProperties.add(String8("mock-response"), response);
203
204        const size_t kKeySetIdSize = 8;
205
206        for (size_t i = 0; i < kKeySetIdSize / sizeof(long); i++) {
207            long r = random();
208            keySetId.appendArray((uint8_t *)&r, sizeof(long));
209        }
210        mKeySets.add(keySetId);
211
212        return OK;
213    }
214
215    status_t MockDrmPlugin::removeKeys(Vector<uint8_t> const &keySetId)
216    {
217        Mutex::Autolock lock(mLock);
218        ALOGD("MockDrmPlugin::removeKeys(keySetId=%s)",
219              vectorToString(keySetId).string());
220
221        ssize_t index = findKeySet(keySetId);
222        if (index == kNotFound) {
223            ALOGD("Invalid keySetId");
224            return BAD_VALUE;
225        }
226        mKeySets.removeAt(index);
227
228        return OK;
229    }
230
231    status_t MockDrmPlugin::restoreKeys(Vector<uint8_t> const &sessionId,
232                                        Vector<uint8_t> const &keySetId)
233    {
234        Mutex::Autolock lock(mLock);
235        ALOGD("MockDrmPlugin::restoreKeys(sessionId=%s, keySetId=%s)",
236              vectorToString(sessionId).string(),
237              vectorToString(keySetId).string());
238        ssize_t index = findSession(sessionId);
239        if (index == kNotFound) {
240            ALOGD("Invalid sessionId");
241            return BAD_VALUE;
242        }
243
244        index = findKeySet(keySetId);
245        if (index == kNotFound) {
246            ALOGD("Invalid keySetId");
247            return BAD_VALUE;
248        }
249
250        return OK;
251    }
252
253    status_t MockDrmPlugin::queryKeyStatus(Vector<uint8_t> const &sessionId,
254                                               KeyedVector<String8, String8> &infoMap) const
255    {
256        ALOGD("MockDrmPlugin::queryKeyStatus(sessionId=%s)",
257              vectorToString(sessionId).string());
258
259        ssize_t index = findSession(sessionId);
260        if (index == kNotFound) {
261            ALOGD("Invalid sessionId");
262            return BAD_VALUE;
263        }
264
265        infoMap.add(String8("purchaseDuration"), String8("1000"));
266        infoMap.add(String8("licenseDuration"), String8("100"));
267        return OK;
268    }
269
270    status_t MockDrmPlugin::getProvisionRequest(String8 const & /* certType */,
271                                                String8 const & /* certAuthority */,
272                                                Vector<uint8_t> &request,
273                                                String8 &defaultUrl)
274    {
275        Mutex::Autolock lock(mLock);
276        ALOGD("MockDrmPlugin::getProvisionRequest()");
277
278        // Properties used in mock test, set by cts test app returned from mock plugin
279        //   byte[] mock-request       -> request
280        //   string mock-default-url   -> defaultUrl
281
282        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-request"));
283        if (index < 0) {
284            ALOGD("Missing 'mock-request' parameter for mock");
285            return BAD_VALUE;
286        } else {
287            request = mByteArrayProperties.valueAt(index);
288        }
289
290        index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
291        if (index < 0) {
292            ALOGD("Missing 'mock-defaultUrl' parameter for mock");
293            return BAD_VALUE;
294        } else {
295            defaultUrl = mStringProperties.valueAt(index);
296        }
297        return OK;
298    }
299
300    status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response,
301                                                     Vector<uint8_t> & /* certificate */,
302                                                     Vector<uint8_t> & /* wrappedKey */)
303    {
304        Mutex::Autolock lock(mLock);
305        ALOGD("MockDrmPlugin::provideProvisionResponse(%s)",
306              vectorToString(response).string());
307
308        // Properties used in mock test, set by mock plugin and verifed cts test app
309        //   byte[] response            -> mock-response
310
311        mByteArrayProperties.add(String8("mock-response"), response);
312        return OK;
313    }
314
315    status_t MockDrmPlugin::unprovisionDevice()
316    {
317        ALOGD("MockDrmPlugin::unprovisionDevice()");
318        return OK;
319    }
320
321    status_t MockDrmPlugin::getSecureStop(Vector<uint8_t> const & /* ssid */,
322                                          Vector<uint8_t> & secureStop)
323    {
324        Mutex::Autolock lock(mLock);
325        ALOGD("MockDrmPlugin::getSecureStop()");
326
327        // Properties used in mock test, set by cts test app returned from mock plugin
328        //   byte[] mock-secure-stop  -> first secure stop in list
329
330        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop"));
331        if (index < 0) {
332            ALOGD("Missing 'mock-secure-stop' parameter for mock");
333            return BAD_VALUE;
334        } else {
335            secureStop = mByteArrayProperties.valueAt(index);
336        }
337        return OK;
338    }
339
340    status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
341    {
342        Mutex::Autolock lock(mLock);
343        ALOGD("MockDrmPlugin::getSecureStops()");
344
345        // Properties used in mock test, set by cts test app returned from mock plugin
346        //   byte[] mock-secure-stop1  -> first secure stop in list
347        //   byte[] mock-secure-stop2  -> second secure stop in list
348
349        Vector<uint8_t> ss1, ss2;
350        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop1"));
351        if (index < 0) {
352            ALOGD("Missing 'mock-secure-stop1' parameter for mock");
353            return BAD_VALUE;
354        } else {
355            ss1 = mByteArrayProperties.valueAt(index);
356        }
357
358        index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop2"));
359        if (index < 0) {
360            ALOGD("Missing 'mock-secure-stop2' parameter for mock");
361            return BAD_VALUE;
362        } else {
363            ss2 = mByteArrayProperties.valueAt(index);
364        }
365
366        secureStops.push_back(ss1);
367        secureStops.push_back(ss2);
368        return OK;
369    }
370
371    status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease)
372    {
373        Mutex::Autolock lock(mLock);
374        ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
375              vectorToString(ssRelease).string());
376
377        // Properties used in mock test, set by mock plugin and verifed cts test app
378        //   byte[] secure-stop-release  -> mock-ssrelease
379        mByteArrayProperties.add(String8("mock-ssrelease"), ssRelease);
380
381        return OK;
382    }
383
384    status_t MockDrmPlugin::releaseAllSecureStops()
385    {
386        Mutex::Autolock lock(mLock);
387        ALOGD("MockDrmPlugin::releaseAllSecureStops()");
388        return OK;
389    }
390
391    status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const
392    {
393        ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string());
394        ssize_t index = mStringProperties.indexOfKey(name);
395        if (index < 0) {
396            ALOGD("no property for '%s'", name.string());
397            return BAD_VALUE;
398        }
399        value = mStringProperties.valueAt(index);
400        return OK;
401    }
402
403    status_t MockDrmPlugin::getPropertyByteArray(String8 const &name,
404                                                 Vector<uint8_t> &value) const
405    {
406        ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string());
407        ssize_t index = mByteArrayProperties.indexOfKey(name);
408        if (index < 0) {
409            ALOGD("no property for '%s'", name.string());
410            return BAD_VALUE;
411        }
412        value = mByteArrayProperties.valueAt(index);
413        return OK;
414    }
415
416    status_t MockDrmPlugin::setPropertyString(String8 const &name,
417                                              String8 const &value)
418    {
419        Mutex::Autolock lock(mLock);
420        ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)",
421              name.string(), value.string());
422
423        if (name == "mock-send-event") {
424            unsigned code, extra;
425            sscanf(value.string(), "%d %d", &code, &extra);
426            DrmPlugin::EventType eventType = (DrmPlugin::EventType)code;
427
428            Vector<uint8_t> const *pSessionId = NULL;
429            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
430            if (index >= 0) {
431                pSessionId = &mByteArrayProperties[index];
432            }
433
434            Vector<uint8_t> const *pData = NULL;
435            index = mByteArrayProperties.indexOfKey(String8("mock-event-data"));
436            if (index >= 0) {
437                pData = &mByteArrayProperties[index];
438            }
439            ALOGD("sending event from mock drm plugin: %d %d %s %s",
440                  (int)code, extra, pSessionId ? vectorToString(*pSessionId) : "{}",
441                  pData ? vectorToString(*pData) : "{}");
442
443            sendEvent(eventType, extra, pSessionId, pData);
444        } else if (name == "mock-send-expiration-update") {
445            int64_t expiryTimeMS;
446            sscanf(value.string(), "%jd", &expiryTimeMS);
447
448            Vector<uint8_t> const *pSessionId = NULL;
449            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
450            if (index >= 0) {
451                pSessionId = &mByteArrayProperties[index];
452            }
453
454            ALOGD("sending expiration-update from mock drm plugin: %jd %s",
455                  expiryTimeMS, pSessionId ? vectorToString(*pSessionId) : "{}");
456
457            sendExpirationUpdate(pSessionId, expiryTimeMS);
458        } else if (name == "mock-send-keys-change") {
459            Vector<uint8_t> const *pSessionId = NULL;
460            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
461            if (index >= 0) {
462                pSessionId = &mByteArrayProperties[index];
463            }
464
465            ALOGD("sending keys-change from mock drm plugin: %s",
466                  pSessionId ? vectorToString(*pSessionId) : "{}");
467
468            Vector<DrmPlugin::KeyStatus> keyStatusList;
469            DrmPlugin::KeyStatus keyStatus;
470            uint8_t keyId1[] = {'k', 'e', 'y', '1'};
471            keyStatus.mKeyId.clear();
472            keyStatus.mKeyId.appendArray(keyId1, sizeof(keyId1));
473            keyStatus.mType = DrmPlugin::kKeyStatusType_Usable;
474            keyStatusList.add(keyStatus);
475
476            uint8_t keyId2[] = {'k', 'e', 'y', '2'};
477            keyStatus.mKeyId.clear();
478            keyStatus.mKeyId.appendArray(keyId2, sizeof(keyId2));
479            keyStatus.mType = DrmPlugin::kKeyStatusType_Expired;
480            keyStatusList.add(keyStatus);
481
482            uint8_t keyId3[] = {'k', 'e', 'y', '3'};
483            keyStatus.mKeyId.clear();
484            keyStatus.mKeyId.appendArray(keyId3, sizeof(keyId3));
485            keyStatus.mType = DrmPlugin::kKeyStatusType_OutputNotAllowed;
486            keyStatusList.add(keyStatus);
487
488            uint8_t keyId4[] = {'k', 'e', 'y', '4'};
489            keyStatus.mKeyId.clear();
490            keyStatus.mKeyId.appendArray(keyId4, sizeof(keyId4));
491            keyStatus.mType = DrmPlugin::kKeyStatusType_StatusPending;
492            keyStatusList.add(keyStatus);
493
494            uint8_t keyId5[] = {'k', 'e', 'y', '5'};
495            keyStatus.mKeyId.clear();
496            keyStatus.mKeyId.appendArray(keyId5, sizeof(keyId5));
497            keyStatus.mType = DrmPlugin::kKeyStatusType_InternalError;
498            keyStatusList.add(keyStatus);
499
500            sendKeysChange(pSessionId, &keyStatusList, true);
501        } else {
502            mStringProperties.add(name, value);
503        }
504        return OK;
505    }
506
507    status_t MockDrmPlugin::setPropertyByteArray(String8 const &name,
508                                                 Vector<uint8_t> const &value)
509    {
510        Mutex::Autolock lock(mLock);
511        ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)",
512              name.string(), vectorToString(value).string());
513        mByteArrayProperties.add(name, value);
514        return OK;
515    }
516
517    status_t MockDrmPlugin::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
518                                               String8 const &algorithm)
519    {
520        Mutex::Autolock lock(mLock);
521
522        ALOGD("MockDrmPlugin::setCipherAlgorithm(sessionId=%s, algorithm=%s)",
523              vectorToString(sessionId).string(), algorithm.string());
524
525        ssize_t index = findSession(sessionId);
526        if (index == kNotFound) {
527            ALOGD("Invalid sessionId");
528            return BAD_VALUE;
529        }
530
531        if (algorithm == "AES/CBC/NoPadding") {
532            return OK;
533        }
534        return BAD_VALUE;
535    }
536
537    status_t MockDrmPlugin::setMacAlgorithm(Vector<uint8_t> const &sessionId,
538                                            String8 const &algorithm)
539    {
540        Mutex::Autolock lock(mLock);
541
542        ALOGD("MockDrmPlugin::setMacAlgorithm(sessionId=%s, algorithm=%s)",
543              vectorToString(sessionId).string(), algorithm.string());
544
545        ssize_t index = findSession(sessionId);
546        if (index == kNotFound) {
547            ALOGD("Invalid sessionId");
548            return BAD_VALUE;
549        }
550
551        if (algorithm == "HmacSHA256") {
552            return OK;
553        }
554        return BAD_VALUE;
555    }
556
557    status_t MockDrmPlugin::encrypt(Vector<uint8_t> const &sessionId,
558                                    Vector<uint8_t> const &keyId,
559                                    Vector<uint8_t> const &input,
560                                    Vector<uint8_t> const &iv,
561                                    Vector<uint8_t> &output)
562    {
563        Mutex::Autolock lock(mLock);
564        ALOGD("MockDrmPlugin::encrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
565              vectorToString(sessionId).string(),
566              vectorToString(keyId).string(),
567              vectorToString(input).string(),
568              vectorToString(iv).string());
569
570        ssize_t index = findSession(sessionId);
571        if (index == kNotFound) {
572            ALOGD("Invalid sessionId");
573            return BAD_VALUE;
574        }
575
576        // Properties used in mock test, set by mock plugin and verifed cts test app
577        //   byte[] keyId              -> mock-keyid
578        //   byte[] input              -> mock-input
579        //   byte[] iv                 -> mock-iv
580        mByteArrayProperties.add(String8("mock-keyid"), keyId);
581        mByteArrayProperties.add(String8("mock-input"), input);
582        mByteArrayProperties.add(String8("mock-iv"), iv);
583
584        // Properties used in mock test, set by cts test app returned from mock plugin
585        //   byte[] mock-output        -> output
586        index = mByteArrayProperties.indexOfKey(String8("mock-output"));
587        if (index < 0) {
588            ALOGD("Missing 'mock-request' parameter for mock");
589            return BAD_VALUE;
590        } else {
591            output = mByteArrayProperties.valueAt(index);
592        }
593        return OK;
594    }
595
596    status_t MockDrmPlugin::decrypt(Vector<uint8_t> const &sessionId,
597                                    Vector<uint8_t> const &keyId,
598                                    Vector<uint8_t> const &input,
599                                    Vector<uint8_t> const &iv,
600                                    Vector<uint8_t> &output)
601    {
602        Mutex::Autolock lock(mLock);
603        ALOGD("MockDrmPlugin::decrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
604              vectorToString(sessionId).string(),
605              vectorToString(keyId).string(),
606              vectorToString(input).string(),
607              vectorToString(iv).string());
608
609        ssize_t index = findSession(sessionId);
610        if (index == kNotFound) {
611            ALOGD("Invalid sessionId");
612            return BAD_VALUE;
613        }
614
615        // Properties used in mock test, set by mock plugin and verifed cts test app
616        //   byte[] keyId              -> mock-keyid
617        //   byte[] input              -> mock-input
618        //   byte[] iv                 -> mock-iv
619        mByteArrayProperties.add(String8("mock-keyid"), keyId);
620        mByteArrayProperties.add(String8("mock-input"), input);
621        mByteArrayProperties.add(String8("mock-iv"), iv);
622
623        // Properties used in mock test, set by cts test app returned from mock plugin
624        //   byte[] mock-output        -> output
625        index = mByteArrayProperties.indexOfKey(String8("mock-output"));
626        if (index < 0) {
627            ALOGD("Missing 'mock-request' parameter for mock");
628            return BAD_VALUE;
629        } else {
630            output = mByteArrayProperties.valueAt(index);
631        }
632        return OK;
633    }
634
635    status_t MockDrmPlugin::sign(Vector<uint8_t> const &sessionId,
636                                 Vector<uint8_t> const &keyId,
637                                 Vector<uint8_t> const &message,
638                                 Vector<uint8_t> &signature)
639    {
640        Mutex::Autolock lock(mLock);
641        ALOGD("MockDrmPlugin::sign(sessionId=%s, keyId=%s, message=%s)",
642              vectorToString(sessionId).string(),
643              vectorToString(keyId).string(),
644              vectorToString(message).string());
645
646        ssize_t index = findSession(sessionId);
647        if (index == kNotFound) {
648            ALOGD("Invalid sessionId");
649            return BAD_VALUE;
650        }
651
652        // Properties used in mock test, set by mock plugin and verifed cts test app
653        //   byte[] keyId              -> mock-keyid
654        //   byte[] message            -> mock-message
655        mByteArrayProperties.add(String8("mock-keyid"), keyId);
656        mByteArrayProperties.add(String8("mock-message"), message);
657
658        // Properties used in mock test, set by cts test app returned from mock plugin
659        //   byte[] mock-signature        -> signature
660        index = mByteArrayProperties.indexOfKey(String8("mock-signature"));
661        if (index < 0) {
662            ALOGD("Missing 'mock-request' parameter for mock");
663            return BAD_VALUE;
664        } else {
665            signature = mByteArrayProperties.valueAt(index);
666        }
667        return OK;
668    }
669
670    status_t MockDrmPlugin::verify(Vector<uint8_t> const &sessionId,
671                                   Vector<uint8_t> const &keyId,
672                                   Vector<uint8_t> const &message,
673                                   Vector<uint8_t> const &signature,
674                                   bool &match)
675    {
676        Mutex::Autolock lock(mLock);
677        ALOGD("MockDrmPlugin::verify(sessionId=%s, keyId=%s, message=%s, signature=%s)",
678              vectorToString(sessionId).string(),
679              vectorToString(keyId).string(),
680              vectorToString(message).string(),
681              vectorToString(signature).string());
682
683        ssize_t index = findSession(sessionId);
684        if (index == kNotFound) {
685            ALOGD("Invalid sessionId");
686            return BAD_VALUE;
687        }
688
689        // Properties used in mock test, set by mock plugin and verifed cts test app
690        //   byte[] keyId              -> mock-keyid
691        //   byte[] message            -> mock-message
692        //   byte[] signature          -> mock-signature
693        mByteArrayProperties.add(String8("mock-keyid"), keyId);
694        mByteArrayProperties.add(String8("mock-message"), message);
695        mByteArrayProperties.add(String8("mock-signature"), signature);
696
697        // Properties used in mock test, set by cts test app returned from mock plugin
698        //   String mock-match "1" or "0"         -> match
699        index = mStringProperties.indexOfKey(String8("mock-match"));
700        if (index < 0) {
701            ALOGD("Missing 'mock-request' parameter for mock");
702            return BAD_VALUE;
703        } else {
704            match = atol(mStringProperties.valueAt(index).string());
705        }
706        return OK;
707    }
708
709    status_t MockDrmPlugin::signRSA(Vector<uint8_t> const &sessionId,
710                                    String8 const &algorithm,
711                                    Vector<uint8_t> const &message,
712                                    Vector<uint8_t> const &wrappedKey,
713                                    Vector<uint8_t> &signature)
714    {
715        Mutex::Autolock lock(mLock);
716        ALOGD("MockDrmPlugin::signRSA(sessionId=%s, algorithm=%s, keyId=%s, "
717              "message=%s, signature=%s)",
718              vectorToString(sessionId).string(),
719              algorithm.string(),
720              vectorToString(message).string(),
721              vectorToString(wrappedKey).string(),
722              vectorToString(signature).string());
723
724        // Properties used in mock test, set by mock plugin and verifed cts test app
725        //   byte[] wrappedKey         -> mock-wrappedkey
726        //   byte[] message            -> mock-message
727        //   byte[] signature          -> mock-signature
728        mByteArrayProperties.add(String8("mock-sessionid"), sessionId);
729        mStringProperties.add(String8("mock-algorithm"), algorithm);
730        mByteArrayProperties.add(String8("mock-message"), message);
731        mByteArrayProperties.add(String8("mock-wrappedkey"), wrappedKey);
732        mByteArrayProperties.add(String8("mock-signature"), signature);
733        return OK;
734    }
735
736    ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
737    {
738        ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
739        for (size_t i = 0; i < mSessions.size(); ++i) {
740            if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
741                return i;
742            }
743        }
744        return kNotFound;
745    }
746
747    ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
748    {
749        ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size());
750        for (size_t i = 0; i < mKeySets.size(); ++i) {
751            if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
752                return i;
753            }
754        }
755        return kNotFound;
756    }
757
758
759    // Conversion utilities
760    String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const
761    {
762        return arrayToString(vector.array(), vector.size());
763    }
764
765    String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const
766    {
767        String8 result("{ ");
768        for (size_t i = 0; i < len; i++) {
769            result.appendFormat("0x%02x ", array[i]);
770        }
771        result += "}";
772        return result;
773    }
774
775    String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
776    {
777        String8 result("{ ");
778        for (size_t i = 0; i < map.size(); i++) {
779            result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "",
780                                map.keyAt(i).string(), map.valueAt(i).string());
781        }
782        return result + " }";
783    }
784
785    bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) {
786        return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0);
787    }
788
789    //
790    // Crypto Plugin
791    //
792
793    bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
794    {
795        ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime);
796        return false;
797    }
798
799    ssize_t
800    MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
801                              Mode mode, const void *srcPtr, const SubSample *subSamples,
802                              size_t numSubSamples, void *dstPtr, AString * /* errorDetailMsg */)
803    {
804        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
805              "subSamples=%s, dst=%p)",
806              (int)secure,
807              arrayToString(key, sizeof(key)).string(),
808              arrayToString(iv, sizeof(iv)).string(),
809              (int)mode, srcPtr,
810              subSamplesToString(subSamples, numSubSamples).string(),
811              dstPtr);
812        return OK;
813    }
814
815    // Conversion utilities
816    String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const
817    {
818        String8 result("{ ");
819        for (size_t i = 0; i < len; i++) {
820            result.appendFormat("0x%02x ", array[i]);
821        }
822        result += "}";
823        return result;
824    }
825
826    String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples,
827                                                 size_t numSubSamples) const
828    {
829        String8 result;
830        for (size_t i = 0; i < numSubSamples; i++) {
831            result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i,
832                                subSamples[i].mNumBytesOfClearData,
833                                subSamples[i].mNumBytesOfEncryptedData);
834        }
835        return result;
836    }
837
838};
839