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::getSecureStop(Vector<uint8_t> const & /* ssid */,
316                                          Vector<uint8_t> & secureStop)
317    {
318        Mutex::Autolock lock(mLock);
319        ALOGD("MockDrmPlugin::getSecureStop()");
320
321        // Properties used in mock test, set by cts test app returned from mock plugin
322        //   byte[] mock-secure-stop  -> first secure stop in list
323
324        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop"));
325        if (index < 0) {
326            ALOGD("Missing 'mock-secure-stop' parameter for mock");
327            return BAD_VALUE;
328        } else {
329            secureStop = mByteArrayProperties.valueAt(index);
330        }
331        return OK;
332    }
333
334    status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
335    {
336        Mutex::Autolock lock(mLock);
337        ALOGD("MockDrmPlugin::getSecureStops()");
338
339        // Properties used in mock test, set by cts test app returned from mock plugin
340        //   byte[] mock-secure-stop1  -> first secure stop in list
341        //   byte[] mock-secure-stop2  -> second secure stop in list
342
343        Vector<uint8_t> ss1, ss2;
344        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop1"));
345        if (index < 0) {
346            ALOGD("Missing 'mock-secure-stop1' parameter for mock");
347            return BAD_VALUE;
348        } else {
349            ss1 = mByteArrayProperties.valueAt(index);
350        }
351
352        index = mByteArrayProperties.indexOfKey(String8("mock-secure-stop2"));
353        if (index < 0) {
354            ALOGD("Missing 'mock-secure-stop2' parameter for mock");
355            return BAD_VALUE;
356        } else {
357            ss2 = mByteArrayProperties.valueAt(index);
358        }
359
360        secureStops.push_back(ss1);
361        secureStops.push_back(ss2);
362        return OK;
363    }
364
365    status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease)
366    {
367        Mutex::Autolock lock(mLock);
368        ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
369              vectorToString(ssRelease).string());
370
371        // Properties used in mock test, set by mock plugin and verifed cts test app
372        //   byte[] secure-stop-release  -> mock-ssrelease
373        mByteArrayProperties.add(String8("mock-ssrelease"), ssRelease);
374
375        return OK;
376    }
377
378    status_t MockDrmPlugin::releaseAllSecureStops()
379    {
380        Mutex::Autolock lock(mLock);
381        ALOGD("MockDrmPlugin::releaseAllSecureStops()");
382        return OK;
383    }
384
385    status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const
386    {
387        ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string());
388        ssize_t index = mStringProperties.indexOfKey(name);
389        if (index < 0) {
390            ALOGD("no property for '%s'", name.string());
391            return BAD_VALUE;
392        }
393        value = mStringProperties.valueAt(index);
394        return OK;
395    }
396
397    status_t MockDrmPlugin::getPropertyByteArray(String8 const &name,
398                                                 Vector<uint8_t> &value) const
399    {
400        ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string());
401        ssize_t index = mByteArrayProperties.indexOfKey(name);
402        if (index < 0) {
403            ALOGD("no property for '%s'", name.string());
404            return BAD_VALUE;
405        }
406        value = mByteArrayProperties.valueAt(index);
407        return OK;
408    }
409
410    status_t MockDrmPlugin::setPropertyString(String8 const &name,
411                                              String8 const &value)
412    {
413        Mutex::Autolock lock(mLock);
414        ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)",
415              name.string(), value.string());
416
417        if (name == "mock-send-event") {
418            unsigned code, extra;
419            sscanf(value.string(), "%d %d", &code, &extra);
420            DrmPlugin::EventType eventType = (DrmPlugin::EventType)code;
421
422            Vector<uint8_t> const *pSessionId = NULL;
423            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
424            if (index >= 0) {
425                pSessionId = &mByteArrayProperties[index];
426            }
427
428            Vector<uint8_t> const *pData = NULL;
429            index = mByteArrayProperties.indexOfKey(String8("mock-event-data"));
430            if (index >= 0) {
431                pData = &mByteArrayProperties[index];
432            }
433            ALOGD("sending event from mock drm plugin: %d %d %s %s",
434                  (int)code, extra, pSessionId ? vectorToString(*pSessionId) : "{}",
435                  pData ? vectorToString(*pData) : "{}");
436
437            sendEvent(eventType, extra, pSessionId, pData);
438        } else if (name == "mock-send-expiration-update") {
439            int64_t expiryTimeMS;
440            sscanf(value.string(), "%jd", &expiryTimeMS);
441
442            Vector<uint8_t> const *pSessionId = NULL;
443            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
444            if (index >= 0) {
445                pSessionId = &mByteArrayProperties[index];
446            }
447
448            ALOGD("sending expiration-update from mock drm plugin: %jd %s",
449                  expiryTimeMS, pSessionId ? vectorToString(*pSessionId) : "{}");
450
451            sendExpirationUpdate(pSessionId, expiryTimeMS);
452        } else if (name == "mock-send-keys-change") {
453            Vector<uint8_t> const *pSessionId = NULL;
454            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
455            if (index >= 0) {
456                pSessionId = &mByteArrayProperties[index];
457            }
458
459            ALOGD("sending keys-change from mock drm plugin: %s",
460                  pSessionId ? vectorToString(*pSessionId) : "{}");
461
462            Vector<DrmPlugin::KeyStatus> keyStatusList;
463            DrmPlugin::KeyStatus keyStatus;
464            uint8_t keyId1[] = {'k', 'e', 'y', '1'};
465            keyStatus.mKeyId.clear();
466            keyStatus.mKeyId.appendArray(keyId1, sizeof(keyId1));
467            keyStatus.mType = DrmPlugin::kKeyStatusType_Usable;
468            keyStatusList.add(keyStatus);
469
470            uint8_t keyId2[] = {'k', 'e', 'y', '2'};
471            keyStatus.mKeyId.clear();
472            keyStatus.mKeyId.appendArray(keyId2, sizeof(keyId2));
473            keyStatus.mType = DrmPlugin::kKeyStatusType_Expired;
474            keyStatusList.add(keyStatus);
475
476            uint8_t keyId3[] = {'k', 'e', 'y', '3'};
477            keyStatus.mKeyId.clear();
478            keyStatus.mKeyId.appendArray(keyId3, sizeof(keyId3));
479            keyStatus.mType = DrmPlugin::kKeyStatusType_OutputNotAllowed;
480            keyStatusList.add(keyStatus);
481
482            uint8_t keyId4[] = {'k', 'e', 'y', '4'};
483            keyStatus.mKeyId.clear();
484            keyStatus.mKeyId.appendArray(keyId4, sizeof(keyId4));
485            keyStatus.mType = DrmPlugin::kKeyStatusType_StatusPending;
486            keyStatusList.add(keyStatus);
487
488            uint8_t keyId5[] = {'k', 'e', 'y', '5'};
489            keyStatus.mKeyId.clear();
490            keyStatus.mKeyId.appendArray(keyId5, sizeof(keyId5));
491            keyStatus.mType = DrmPlugin::kKeyStatusType_InternalError;
492            keyStatusList.add(keyStatus);
493
494            sendKeysChange(pSessionId, &keyStatusList, true);
495        } else {
496            mStringProperties.add(name, value);
497        }
498        return OK;
499    }
500
501    status_t MockDrmPlugin::setPropertyByteArray(String8 const &name,
502                                                 Vector<uint8_t> const &value)
503    {
504        Mutex::Autolock lock(mLock);
505        ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)",
506              name.string(), vectorToString(value).string());
507        mByteArrayProperties.add(name, value);
508        return OK;
509    }
510
511    status_t MockDrmPlugin::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
512                                               String8 const &algorithm)
513    {
514        Mutex::Autolock lock(mLock);
515
516        ALOGD("MockDrmPlugin::setCipherAlgorithm(sessionId=%s, algorithm=%s)",
517              vectorToString(sessionId).string(), algorithm.string());
518
519        ssize_t index = findSession(sessionId);
520        if (index == kNotFound) {
521            ALOGD("Invalid sessionId");
522            return BAD_VALUE;
523        }
524
525        if (algorithm == "AES/CBC/NoPadding") {
526            return OK;
527        }
528        return BAD_VALUE;
529    }
530
531    status_t MockDrmPlugin::setMacAlgorithm(Vector<uint8_t> const &sessionId,
532                                            String8 const &algorithm)
533    {
534        Mutex::Autolock lock(mLock);
535
536        ALOGD("MockDrmPlugin::setMacAlgorithm(sessionId=%s, algorithm=%s)",
537              vectorToString(sessionId).string(), algorithm.string());
538
539        ssize_t index = findSession(sessionId);
540        if (index == kNotFound) {
541            ALOGD("Invalid sessionId");
542            return BAD_VALUE;
543        }
544
545        if (algorithm == "HmacSHA256") {
546            return OK;
547        }
548        return BAD_VALUE;
549    }
550
551    status_t MockDrmPlugin::encrypt(Vector<uint8_t> const &sessionId,
552                                    Vector<uint8_t> const &keyId,
553                                    Vector<uint8_t> const &input,
554                                    Vector<uint8_t> const &iv,
555                                    Vector<uint8_t> &output)
556    {
557        Mutex::Autolock lock(mLock);
558        ALOGD("MockDrmPlugin::encrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
559              vectorToString(sessionId).string(),
560              vectorToString(keyId).string(),
561              vectorToString(input).string(),
562              vectorToString(iv).string());
563
564        ssize_t index = findSession(sessionId);
565        if (index == kNotFound) {
566            ALOGD("Invalid sessionId");
567            return BAD_VALUE;
568        }
569
570        // Properties used in mock test, set by mock plugin and verifed cts test app
571        //   byte[] keyId              -> mock-keyid
572        //   byte[] input              -> mock-input
573        //   byte[] iv                 -> mock-iv
574        mByteArrayProperties.add(String8("mock-keyid"), keyId);
575        mByteArrayProperties.add(String8("mock-input"), input);
576        mByteArrayProperties.add(String8("mock-iv"), iv);
577
578        // Properties used in mock test, set by cts test app returned from mock plugin
579        //   byte[] mock-output        -> output
580        index = mByteArrayProperties.indexOfKey(String8("mock-output"));
581        if (index < 0) {
582            ALOGD("Missing 'mock-request' parameter for mock");
583            return BAD_VALUE;
584        } else {
585            output = mByteArrayProperties.valueAt(index);
586        }
587        return OK;
588    }
589
590    status_t MockDrmPlugin::decrypt(Vector<uint8_t> const &sessionId,
591                                    Vector<uint8_t> const &keyId,
592                                    Vector<uint8_t> const &input,
593                                    Vector<uint8_t> const &iv,
594                                    Vector<uint8_t> &output)
595    {
596        Mutex::Autolock lock(mLock);
597        ALOGD("MockDrmPlugin::decrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
598              vectorToString(sessionId).string(),
599              vectorToString(keyId).string(),
600              vectorToString(input).string(),
601              vectorToString(iv).string());
602
603        ssize_t index = findSession(sessionId);
604        if (index == kNotFound) {
605            ALOGD("Invalid sessionId");
606            return BAD_VALUE;
607        }
608
609        // Properties used in mock test, set by mock plugin and verifed cts test app
610        //   byte[] keyId              -> mock-keyid
611        //   byte[] input              -> mock-input
612        //   byte[] iv                 -> mock-iv
613        mByteArrayProperties.add(String8("mock-keyid"), keyId);
614        mByteArrayProperties.add(String8("mock-input"), input);
615        mByteArrayProperties.add(String8("mock-iv"), iv);
616
617        // Properties used in mock test, set by cts test app returned from mock plugin
618        //   byte[] mock-output        -> output
619        index = mByteArrayProperties.indexOfKey(String8("mock-output"));
620        if (index < 0) {
621            ALOGD("Missing 'mock-request' parameter for mock");
622            return BAD_VALUE;
623        } else {
624            output = mByteArrayProperties.valueAt(index);
625        }
626        return OK;
627    }
628
629    status_t MockDrmPlugin::sign(Vector<uint8_t> const &sessionId,
630                                 Vector<uint8_t> const &keyId,
631                                 Vector<uint8_t> const &message,
632                                 Vector<uint8_t> &signature)
633    {
634        Mutex::Autolock lock(mLock);
635        ALOGD("MockDrmPlugin::sign(sessionId=%s, keyId=%s, message=%s)",
636              vectorToString(sessionId).string(),
637              vectorToString(keyId).string(),
638              vectorToString(message).string());
639
640        ssize_t index = findSession(sessionId);
641        if (index == kNotFound) {
642            ALOGD("Invalid sessionId");
643            return BAD_VALUE;
644        }
645
646        // Properties used in mock test, set by mock plugin and verifed cts test app
647        //   byte[] keyId              -> mock-keyid
648        //   byte[] message            -> mock-message
649        mByteArrayProperties.add(String8("mock-keyid"), keyId);
650        mByteArrayProperties.add(String8("mock-message"), message);
651
652        // Properties used in mock test, set by cts test app returned from mock plugin
653        //   byte[] mock-signature        -> signature
654        index = mByteArrayProperties.indexOfKey(String8("mock-signature"));
655        if (index < 0) {
656            ALOGD("Missing 'mock-request' parameter for mock");
657            return BAD_VALUE;
658        } else {
659            signature = mByteArrayProperties.valueAt(index);
660        }
661        return OK;
662    }
663
664    status_t MockDrmPlugin::verify(Vector<uint8_t> const &sessionId,
665                                   Vector<uint8_t> const &keyId,
666                                   Vector<uint8_t> const &message,
667                                   Vector<uint8_t> const &signature,
668                                   bool &match)
669    {
670        Mutex::Autolock lock(mLock);
671        ALOGD("MockDrmPlugin::verify(sessionId=%s, keyId=%s, message=%s, signature=%s)",
672              vectorToString(sessionId).string(),
673              vectorToString(keyId).string(),
674              vectorToString(message).string(),
675              vectorToString(signature).string());
676
677        ssize_t index = findSession(sessionId);
678        if (index == kNotFound) {
679            ALOGD("Invalid sessionId");
680            return BAD_VALUE;
681        }
682
683        // Properties used in mock test, set by mock plugin and verifed cts test app
684        //   byte[] keyId              -> mock-keyid
685        //   byte[] message            -> mock-message
686        //   byte[] signature          -> mock-signature
687        mByteArrayProperties.add(String8("mock-keyid"), keyId);
688        mByteArrayProperties.add(String8("mock-message"), message);
689        mByteArrayProperties.add(String8("mock-signature"), signature);
690
691        // Properties used in mock test, set by cts test app returned from mock plugin
692        //   String mock-match "1" or "0"         -> match
693        index = mStringProperties.indexOfKey(String8("mock-match"));
694        if (index < 0) {
695            ALOGD("Missing 'mock-request' parameter for mock");
696            return BAD_VALUE;
697        } else {
698            match = atol(mStringProperties.valueAt(index).string());
699        }
700        return OK;
701    }
702
703    status_t MockDrmPlugin::signRSA(Vector<uint8_t> const &sessionId,
704                                    String8 const &algorithm,
705                                    Vector<uint8_t> const &message,
706                                    Vector<uint8_t> const &wrappedKey,
707                                    Vector<uint8_t> &signature)
708    {
709        Mutex::Autolock lock(mLock);
710        ALOGD("MockDrmPlugin::signRSA(sessionId=%s, algorithm=%s, keyId=%s, "
711              "message=%s, signature=%s)",
712              vectorToString(sessionId).string(),
713              algorithm.string(),
714              vectorToString(message).string(),
715              vectorToString(wrappedKey).string(),
716              vectorToString(signature).string());
717
718        // Properties used in mock test, set by mock plugin and verifed cts test app
719        //   byte[] wrappedKey         -> mock-wrappedkey
720        //   byte[] message            -> mock-message
721        //   byte[] signature          -> mock-signature
722        mByteArrayProperties.add(String8("mock-sessionid"), sessionId);
723        mStringProperties.add(String8("mock-algorithm"), algorithm);
724        mByteArrayProperties.add(String8("mock-message"), message);
725        mByteArrayProperties.add(String8("mock-wrappedkey"), wrappedKey);
726        mByteArrayProperties.add(String8("mock-signature"), signature);
727        return OK;
728    }
729
730    ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
731    {
732        ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
733        for (size_t i = 0; i < mSessions.size(); ++i) {
734            if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
735                return i;
736            }
737        }
738        return kNotFound;
739    }
740
741    ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
742    {
743        ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size());
744        for (size_t i = 0; i < mKeySets.size(); ++i) {
745            if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
746                return i;
747            }
748        }
749        return kNotFound;
750    }
751
752
753    // Conversion utilities
754    String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const
755    {
756        return arrayToString(vector.array(), vector.size());
757    }
758
759    String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const
760    {
761        String8 result("{ ");
762        for (size_t i = 0; i < len; i++) {
763            result.appendFormat("0x%02x ", array[i]);
764        }
765        result += "}";
766        return result;
767    }
768
769    String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
770    {
771        String8 result("{ ");
772        for (size_t i = 0; i < map.size(); i++) {
773            result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "",
774                                map.keyAt(i).string(), map.valueAt(i).string());
775        }
776        return result + " }";
777    }
778
779    bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) {
780        return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0);
781    }
782
783    //
784    // Crypto Plugin
785    //
786
787    bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
788    {
789        ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime);
790        return false;
791    }
792
793    ssize_t
794    MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
795            Mode mode, const Pattern &pattern, const void *srcPtr,
796            const SubSample *subSamples, size_t numSubSamples,
797            void *dstPtr, AString * /* errorDetailMsg */)
798    {
799        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, "
800              "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, "
801              "subSamples=%s, dst=%p)",
802              (int)secure,
803              arrayToString(key, sizeof(key)).string(),
804              arrayToString(iv, sizeof(iv)).string(),
805              (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr,
806              subSamplesToString(subSamples, numSubSamples).string(),
807              dstPtr);
808        return OK;
809    }
810
811    // Conversion utilities
812    String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const
813    {
814        String8 result("{ ");
815        for (size_t i = 0; i < len; i++) {
816            result.appendFormat("0x%02x ", array[i]);
817        }
818        result += "}";
819        return result;
820    }
821
822    String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples,
823                                                 size_t numSubSamples) const
824    {
825        String8 result;
826        for (size_t i = 0; i < numSubSamples; i++) {
827            result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i,
828                                subSamples[i].mNumBytesOfClearData,
829                                subSamples[i].mNumBytesOfEncryptedData);
830        }
831        return result;
832    }
833
834};
835