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