1 /*
2  * Copyright (C) 2017 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 "NuPlayerDrm"
19 
20 #include "NuPlayerDrm.h"
21 
22 #include <binder/IServiceManager.h>
23 #include <mediadrm/IMediaDrmService.h>
24 #include <utils/Log.h>
25 
26 
27 namespace android {
28 
29 // static helpers - internal
30 
CreateDrm(status_t * pstatus)31 sp<IDrm> NuPlayerDrm::CreateDrm(status_t *pstatus)
32 {
33     status_t &status = *pstatus;
34     sp<IServiceManager> sm = defaultServiceManager();
35     sp<IBinder> binder = sm->getService(String16("media.drm"));
36     ALOGV("CreateDrm binder %p", (binder != NULL ? binder.get() : 0));
37 
38     sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
39     if (service == NULL) {
40         ALOGE("CreateDrm failed at IMediaDrmService");
41         return NULL;
42     }
43 
44     sp<IDrm> drm = service->makeDrm();
45     if (drm == NULL) {
46         ALOGE("CreateDrm failed at makeDrm");
47         return NULL;
48     }
49 
50     // this is before plugin creation so NO_INIT is fine
51     status = drm->initCheck();
52     if (status != OK && status != NO_INIT) {
53         ALOGE("CreateDrm failed drm->initCheck(): %d", status);
54         return NULL;
55     }
56     return drm;
57 }
58 
createCrypto(status_t * pstatus)59 sp<ICrypto> NuPlayerDrm::createCrypto(status_t *pstatus)
60 {
61     status_t &status = *pstatus;
62     sp<IServiceManager> sm = defaultServiceManager();
63     sp<IBinder> binder = sm->getService(String16("media.drm"));
64 
65     sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
66     if (service == NULL) {
67         status = UNKNOWN_ERROR;
68         ALOGE("CreateCrypto failed at IMediaDrmService");
69         return NULL;
70     }
71 
72     sp<ICrypto> crypto = service->makeCrypto();
73     if (crypto == NULL) {
74         status = UNKNOWN_ERROR;
75         ALOGE("createCrypto failed");
76         return NULL;
77     }
78 
79     // this is before plugin creation so NO_INIT is fine
80     status = crypto->initCheck();
81     if (status != OK && status != NO_INIT) {
82         ALOGE("createCrypto failed crypto->initCheck(): %d", status);
83         return NULL;
84     }
85 
86     return crypto;
87 }
88 
parsePSSH(const void * pssh,size_t psshsize)89 Vector<DrmUUID> NuPlayerDrm::parsePSSH(const void *pssh, size_t psshsize)
90 {
91     Vector<DrmUUID> drmSchemes, empty;
92     const int DATALEN_SIZE = 4;
93 
94     // the format of the buffer is 1 or more of:
95     //    {
96     //        16 byte uuid
97     //        4 byte data length N
98     //        N bytes of data
99     //    }
100     // Determine the number of entries in the source data.
101     // Since we got the data from stagefright, we trust it is valid and properly formatted.
102 
103     const uint8_t *data = (const uint8_t*)pssh;
104     size_t len = psshsize;
105     size_t numentries = 0;
106     while (len > 0) {
107         if (len < DrmUUID::UUID_SIZE) {
108             ALOGE("ParsePSSH: invalid PSSH data");
109             return empty;
110         }
111 
112         const uint8_t *uuidPtr = data;
113 
114         // skip uuid
115         data += DrmUUID::UUID_SIZE;
116         len -= DrmUUID::UUID_SIZE;
117 
118         // get data length
119         if (len < DATALEN_SIZE) {
120             ALOGE("ParsePSSH: invalid PSSH data");
121             return empty;
122         }
123 
124         uint32_t datalen = *((uint32_t*)data);
125         data += DATALEN_SIZE;
126         len -= DATALEN_SIZE;
127 
128         if (len < datalen) {
129             ALOGE("ParsePSSH: invalid PSSH data");
130             return empty;
131         }
132 
133         // skip the data
134         data += datalen;
135         len -= datalen;
136 
137         DrmUUID _uuid(uuidPtr);
138         drmSchemes.add(_uuid);
139 
140         ALOGV("ParsePSSH[%zu]: %s: %s", numentries,
141                 _uuid.toHexString().string(),
142                 DrmUUID::arrayToHex(data, datalen).string()
143              );
144 
145         numentries++;
146     }
147 
148     return drmSchemes;
149 }
150 
getSupportedDrmSchemes(const void * pssh,size_t psshsize)151 Vector<DrmUUID> NuPlayerDrm::getSupportedDrmSchemes(const void *pssh, size_t psshsize)
152 {
153     Vector<DrmUUID> psshDRMs = parsePSSH(pssh, psshsize);
154 
155     Vector<DrmUUID> supportedDRMs;
156      // temporary DRM object for crypto Scheme enquiry (without creating a plugin)
157     status_t status = OK;
158     sp<IDrm> drm = CreateDrm(&status);
159     if (drm != NULL) {
160         for (size_t i = 0; i < psshDRMs.size(); i++) {
161             DrmUUID uuid = psshDRMs[i];
162             bool isSupported = false;
163             status = drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
164                     DrmPlugin::kSecurityLevelUnknown, &isSupported);
165             if (status == OK && isSupported) {
166                 supportedDRMs.add(uuid);
167             }
168         }
169 
170         drm.clear();
171     } else {
172         ALOGE("getSupportedDrmSchemes: Can't create Drm obj: %d", status);
173     }
174 
175     ALOGV("getSupportedDrmSchemes: psshDRMs: %zu supportedDRMs: %zu",
176             psshDRMs.size(), supportedDRMs.size());
177 
178     return supportedDRMs;
179 }
180 
181 // static helpers - public
182 
createCryptoAndPlugin(const uint8_t uuid[16],const Vector<uint8_t> & drmSessionId,status_t & status)183 sp<ICrypto> NuPlayerDrm::createCryptoAndPlugin(const uint8_t uuid[16],
184         const Vector<uint8_t> &drmSessionId, status_t &status)
185 {
186     // Extra check
187     if (drmSessionId.isEmpty()) {
188         status = INVALID_OPERATION;
189         ALOGE("createCryptoAndPlugin: Failed. Empty drmSessionId. status: %d", status);
190         return NULL;
191     }
192 
193     status = OK;
194     sp<ICrypto> crypto = createCrypto(&status);
195     if (crypto == NULL) {
196         ALOGE("createCryptoAndPlugin: createCrypto failed. status: %d", status);
197         return NULL;
198     }
199     ALOGV("createCryptoAndPlugin: createCrypto succeeded");
200 
201     status = crypto->createPlugin(uuid, drmSessionId.array(), drmSessionId.size());
202     if (status != OK) {
203         ALOGE("createCryptoAndPlugin: createCryptoPlugin failed. status: %d", status);
204         // crypto will clean itself when leaving the current scope
205         return NULL;
206     }
207 
208     return crypto;
209 }
210 
211 // Parcel has only private copy constructor so passing it in rather than returning
retrieveDrmInfo(const void * pssh,size_t psshsize,Parcel * parcel)212 void NuPlayerDrm::retrieveDrmInfo(const void *pssh, size_t psshsize, Parcel *parcel)
213 {
214     // 1) PSSH bytes
215     parcel->writeUint32(psshsize);
216     parcel->writeByteArray(psshsize, (const uint8_t*)pssh);
217 
218     ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %zu %s", psshsize,
219             DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string());
220 
221     // 2) supportedDRMs
222     Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize);
223     parcel->writeUint32(supportedDRMs.size());
224     for (size_t i = 0; i < supportedDRMs.size(); i++) {
225         DrmUUID uuid = supportedDRMs[i];
226         parcel->writeByteArray(DrmUUID::UUID_SIZE, uuid.ptr());
227 
228         ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  supportedScheme[%zu] %s", i,
229                 uuid.toHexString().string());
230     }
231 }
232 
233 ////////////////////////////////////////////////////////////////////////////////////////////
234 /// Helpers for NuPlayerDecoder
235 ////////////////////////////////////////////////////////////////////////////////////////////
236 
makeCryptoInfo(int numSubSamples,uint8_t key[kBlockSize],uint8_t iv[kBlockSize],CryptoPlugin::Mode mode,size_t * clearbytes,size_t * encryptedbytes)237 NuPlayerDrm::CryptoInfo *NuPlayerDrm::makeCryptoInfo(
238         int numSubSamples,
239         uint8_t key[kBlockSize],
240         uint8_t iv[kBlockSize],
241         CryptoPlugin::Mode mode,
242         size_t *clearbytes,
243         size_t *encryptedbytes)
244 {
245     // size needed to store all the crypto data
246     size_t cryptosize;
247     // sizeof(CryptoInfo) + sizeof(CryptoPlugin::SubSample) * numSubSamples;
248     if (__builtin_mul_overflow(sizeof(CryptoPlugin::SubSample), numSubSamples, &cryptosize) ||
249             __builtin_add_overflow(cryptosize, sizeof(CryptoInfo), &cryptosize)) {
250         ALOGE("crypto size overflow");
251         return NULL;
252     }
253 
254     CryptoInfo *ret = (CryptoInfo*) malloc(cryptosize);
255     if (ret == NULL) {
256         ALOGE("couldn't allocate %zu bytes", cryptosize);
257         return NULL;
258     }
259     ret->numSubSamples = numSubSamples;
260     memcpy(ret->key, key, kBlockSize);
261     memcpy(ret->iv, iv, kBlockSize);
262     ret->mode = mode;
263     ret->pattern.mEncryptBlocks = 0;
264     ret->pattern.mSkipBlocks = 0;
265     ret->subSamples = (CryptoPlugin::SubSample*)(ret + 1);
266     CryptoPlugin::SubSample *subSamples = ret->subSamples;
267 
268     for (int i = 0; i < numSubSamples; i++) {
269         subSamples[i].mNumBytesOfClearData = (clearbytes == NULL) ? 0 : clearbytes[i];
270         subSamples[i].mNumBytesOfEncryptedData = (encryptedbytes == NULL) ?
271                                                   0 :
272                                                   encryptedbytes[i];
273     }
274 
275     return ret;
276 }
277 
getSampleCryptoInfo(MetaDataBase & meta)278 NuPlayerDrm::CryptoInfo *NuPlayerDrm::getSampleCryptoInfo(MetaDataBase &meta)
279 {
280     uint32_t type;
281     const void *crypteddata;
282     size_t cryptedsize;
283 
284     if (!meta.findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
285         return NULL;
286     }
287     size_t numSubSamples = cryptedsize / sizeof(size_t);
288 
289     if (numSubSamples <= 0) {
290         ALOGE("getSampleCryptoInfo INVALID numSubSamples: %zu", numSubSamples);
291         return NULL;
292     }
293 
294     const void *cleardata;
295     size_t clearsize;
296     if (meta.findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
297         if (clearsize != cryptedsize) {
298             // The two must be of the same length.
299             ALOGE("getSampleCryptoInfo mismatch cryptedsize: %zu != clearsize: %zu",
300                     cryptedsize, clearsize);
301             return NULL;
302         }
303     }
304 
305     const void *key;
306     size_t keysize;
307     if (meta.findData(kKeyCryptoKey, &type, &key, &keysize)) {
308         if (keysize != kBlockSize) {
309             ALOGE("getSampleCryptoInfo Keys must be %d bytes in length: %zu",
310                     kBlockSize, keysize);
311             // Keys must be 16 bytes in length.
312             return NULL;
313         }
314     }
315 
316     const void *iv;
317     size_t ivsize;
318     if (meta.findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
319         if (ivsize != kBlockSize) {
320             ALOGE("getSampleCryptoInfo IV must be %d bytes in length: %zu",
321                     kBlockSize, ivsize);
322             // IVs must be 16 bytes in length.
323             return NULL;
324         }
325     }
326 
327     int32_t mode;
328     if (!meta.findInt32(kKeyCryptoMode, &mode)) {
329         mode = CryptoPlugin::kMode_AES_CTR;
330     }
331 
332     return makeCryptoInfo(numSubSamples,
333             (uint8_t*) key,
334             (uint8_t*) iv,
335             (CryptoPlugin::Mode)mode,
336             (size_t*) cleardata,
337             (size_t*) crypteddata);
338 }
339 
340 }   // namespace android
341 
342