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