tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PsshParser.cpp (4999B)


      1 /*
      2 * Copyright 2015, Mozilla Foundation and contributors
      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 #include "PsshParser.h"
     18 
     19 #include <assert.h>
     20 #include <memory.h>
     21 
     22 #include <algorithm>
     23 #include <limits>
     24 #include <utility>
     25 
     26 #include "mozilla/Assertions.h"
     27 #include "mozilla/EndianUtils.h"
     28 
     29 // Stripped down version of mp4_demuxer::ByteReader, stripped down to make it
     30 // easier to link into ClearKey DLL and gtest.
     31 class ByteReader {
     32 public:
     33  ByteReader(const uint8_t* aData, size_t aSize)
     34      : mPtr(aData), mRemaining(aSize), mLength(aSize) {}
     35 
     36  size_t Offset() const { return mLength - mRemaining; }
     37 
     38  size_t Remaining() const { return mRemaining; }
     39 
     40  size_t Length() const { return mLength; }
     41 
     42  bool CanRead8() const { return mRemaining >= 1; }
     43 
     44  uint8_t ReadU8() {
     45    auto ptr = Read(1);
     46    if (!ptr) {
     47      MOZ_ASSERT(false);
     48      return 0;
     49    }
     50    return *ptr;
     51  }
     52 
     53  bool CanRead32() const { return mRemaining >= 4; }
     54 
     55  uint32_t ReadU32() {
     56    auto ptr = Read(4);
     57    if (!ptr) {
     58      MOZ_ASSERT(false);
     59      return 0;
     60    }
     61    return mozilla::BigEndian::readUint32(ptr);
     62  }
     63 
     64  const uint8_t* Read(size_t aCount) {
     65    if (aCount > mRemaining) {
     66      mRemaining = 0;
     67      return nullptr;
     68    }
     69    mRemaining -= aCount;
     70 
     71    const uint8_t* result = mPtr;
     72    mPtr += aCount;
     73 
     74    return result;
     75  }
     76 
     77  const uint8_t* Seek(size_t aOffset) {
     78    if (aOffset > mLength) {
     79      MOZ_ASSERT(false);
     80      return nullptr;
     81    }
     82 
     83    mPtr = mPtr - Offset() + aOffset;
     84    mRemaining = mLength - aOffset;
     85    return mPtr;
     86  }
     87 
     88 private:
     89  const uint8_t* mPtr;
     90  size_t mRemaining;
     91  const size_t mLength;
     92 };
     93 
     94 #define FOURCC(a, b, c, d) ((a << 24) + (b << 16) + (c << 8) + d)
     95 
     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};
    100 
    101 bool ParseCENCInitData(const uint8_t* aInitData, uint32_t aInitDataSize,
    102                       std::vector<std::vector<uint8_t>>& aOutKeyIds) {
    103  aOutKeyIds.clear();
    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.
    113      return false;
    114    }
    115    const size_t end = start + size;
    116    if (end > reader.Length()) {
    117      // Ridiculous sized box.
    118      return false;
    119    }
    120 
    121    // PSSH box type.
    122    if (!reader.CanRead32()) {
    123      return false;
    124    }
    125    uint32_t box = reader.ReadU32();
    126    if (box != FOURCC('p', 's', 's', 'h')) {
    127      return false;
    128    }
    129 
    130    // 1 byte version, 3 bytes flags.
    131    if (!reader.CanRead32()) {
    132      return false;
    133    }
    134    uint8_t version = reader.ReadU8();
    135    if (version != 1) {
    136      // Ignore pssh boxes with wrong version.
    137      reader.Seek(std::max<size_t>(reader.Offset(), end));
    138      continue;
    139    }
    140    reader.Read(3);  // skip flags.
    141 
    142    // SystemID
    143    const uint8_t* sid = reader.Read(sizeof(kSystemID));
    144    if (!sid) {
    145      // Insufficient bytes to read SystemID.
    146      return false;
    147    }
    148 
    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));
    152      continue;
    153    }
    154 
    155    if (!reader.CanRead32()) {
    156      return false;
    157    }
    158    uint32_t kidCount = reader.ReadU32();
    159 
    160    if (kidCount * CENC_KEY_LEN > reader.Remaining()) {
    161      // Not enough bytes remaining to read all keys.
    162      return false;
    163    }
    164 
    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));
    168    }
    169 
    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()) {
    174      return false;
    175    }
    176    reader.ReadU32();
    177 
    178    // Jump forwards to the end of the box, skipping any padding.
    179    if (size) {
    180      reader.Seek(end);
    181    }
    182  }
    183  aOutKeyIds = std::move(keyIds);
    184  return true;
    185 }