2 * Copyright 2015, Mozilla Foundation and contributors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "PsshParser.h"
26 #include "mozilla/Assertions.h"
27 #include "mozilla/EndianUtils.h"
29 // Stripped down version of mp4_demuxer::ByteReader, stripped down to make it
30 // easier to link into ClearKey DLL and gtest.
33 ByteReader(const uint8_t* aData
, size_t aSize
)
34 : mPtr(aData
), mRemaining(aSize
), mLength(aSize
) {}
36 size_t Offset() const { return mLength
- mRemaining
; }
38 size_t Remaining() const { return mRemaining
; }
40 size_t Length() const { return mLength
; }
42 bool CanRead8() const { return mRemaining
>= 1; }
53 bool CanRead32() const { return mRemaining
>= 4; }
61 return mozilla::BigEndian::readUint32(ptr
);
64 const uint8_t* Read(size_t aCount
) {
65 if (aCount
> mRemaining
) {
71 const uint8_t* result
= mPtr
;
77 const uint8_t* Seek(size_t aOffset
) {
78 if (aOffset
> mLength
) {
83 mPtr
= mPtr
- Offset() + aOffset
;
84 mRemaining
= mLength
- aOffset
;
94 #define FOURCC(a, b, c, d) ((a << 24) + (b << 16) + (c << 8) + d)
96 // System ID identifying the cenc v2 pssh box format; specified at:
97 // https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
98 const uint8_t kSystemID
[] = {0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
99 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b};
101 bool ParseCENCInitData(const uint8_t* aInitData
, uint32_t aInitDataSize
,
102 std::vector
<std::vector
<uint8_t>>& aOutKeyIds
) {
104 std::vector
<std::vector
<uint8_t>> keyIds
;
105 ByteReader
reader(aInitData
, aInitDataSize
);
106 while (reader
.CanRead32()) {
107 // Box size. For the common system Id, ignore this, as some useragents
108 // handle invalid box sizes.
109 const size_t start
= reader
.Offset();
110 const size_t size
= reader
.ReadU32();
111 if (size
> std::numeric_limits
<size_t>::max() - start
) {
112 // Ensure 'start + size' calculation below can't overflow.
115 const size_t end
= start
+ size
;
116 if (end
> reader
.Length()) {
117 // Ridiculous sized box.
122 if (!reader
.CanRead32()) {
125 uint32_t box
= reader
.ReadU32();
126 if (box
!= FOURCC('p', 's', 's', 'h')) {
130 // 1 byte version, 3 bytes flags.
131 if (!reader
.CanRead32()) {
134 uint8_t version
= reader
.ReadU8();
136 // Ignore pssh boxes with wrong version.
137 reader
.Seek(std::max
<size_t>(reader
.Offset(), end
));
140 reader
.Read(3); // skip flags.
143 const uint8_t* sid
= reader
.Read(sizeof(kSystemID
));
145 // Insufficient bytes to read SystemID.
149 if (memcmp(kSystemID
, sid
, sizeof(kSystemID
))) {
150 // Ignore pssh boxes with wrong system ID.
151 reader
.Seek(std::max
<size_t>(reader
.Offset(), end
));
155 if (!reader
.CanRead32()) {
158 uint32_t kidCount
= reader
.ReadU32();
160 if (kidCount
* CENC_KEY_LEN
> reader
.Remaining()) {
161 // Not enough bytes remaining to read all keys.
165 for (uint32_t i
= 0; i
< kidCount
; i
++) {
166 const uint8_t* kid
= reader
.Read(CENC_KEY_LEN
);
167 keyIds
.push_back(std::vector
<uint8_t>(kid
, kid
+ CENC_KEY_LEN
));
170 // Size of extra data. EME CENC format spec says datasize should
171 // always be 0. We explicitly read the datasize, in case the box
172 // size was 0, so that we get to the end of the box.
173 if (!reader
.CanRead32()) {
178 // Jump forwards to the end of the box, skipping any padding.
183 aOutKeyIds
= std::move(keyIds
);