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