LCOV - code coverage report
Current view: top level - media/psshparser - PsshParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 77 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "mozilla/Assertions.h"
      20             : #include "mozilla/EndianUtils.h"
      21             : #include "mozilla/Move.h"
      22             : #include <memory.h>
      23             : #include <algorithm>
      24             : #include <assert.h>
      25             : #include <limits>
      26             : 
      27             : // Stripped down version of mp4_demuxer::ByteReader, stripped down to make it
      28             : // easier to link into ClearKey DLL and gtest.
      29             : class ByteReader
      30             : {
      31             : public:
      32           0 :   ByteReader(const uint8_t* aData, size_t aSize)
      33           0 :     : mPtr(aData), mRemaining(aSize), mLength(aSize)
      34             :   {
      35           0 :   }
      36             : 
      37           0 :   size_t Offset() const
      38             :   {
      39           0 :     return mLength - mRemaining;
      40             :   }
      41             : 
      42           0 :   size_t Remaining() const { return mRemaining; }
      43             : 
      44           0 :   size_t Length() const { return mLength; }
      45             : 
      46             :   bool CanRead8() const { return mRemaining >= 1; }
      47             : 
      48           0 :   uint8_t ReadU8()
      49             :   {
      50           0 :     auto ptr = Read(1);
      51           0 :     if (!ptr) {
      52           0 :       MOZ_ASSERT(false);
      53             :       return 0;
      54             :     }
      55           0 :     return *ptr;
      56             :   }
      57             : 
      58           0 :   bool CanRead32() const { return mRemaining >= 4; }
      59             : 
      60           0 :   uint32_t ReadU32()
      61             :   {
      62           0 :     auto ptr = Read(4);
      63           0 :     if (!ptr) {
      64           0 :       MOZ_ASSERT(false);
      65             :       return 0;
      66             :     }
      67           0 :     return mozilla::BigEndian::readUint32(ptr);
      68             :   }
      69             : 
      70           0 :   const uint8_t* Read(size_t aCount)
      71             :   {
      72           0 :     if (aCount > mRemaining) {
      73           0 :       mRemaining = 0;
      74           0 :       return nullptr;
      75             :     }
      76           0 :     mRemaining -= aCount;
      77             : 
      78           0 :     const uint8_t* result = mPtr;
      79           0 :     mPtr += aCount;
      80             : 
      81           0 :     return result;
      82             :   }
      83             : 
      84           0 :   const uint8_t* Seek(size_t aOffset)
      85             :   {
      86           0 :     if (aOffset > mLength) {
      87           0 :       MOZ_ASSERT(false);
      88             :       return nullptr;
      89             :     }
      90             : 
      91           0 :     mPtr = mPtr - Offset() + aOffset;
      92           0 :     mRemaining = mLength - aOffset;
      93           0 :     return mPtr;
      94             :   }
      95             : 
      96             : private:
      97             :   const uint8_t* mPtr;
      98             :   size_t mRemaining;
      99             :   const size_t mLength;
     100             : };
     101             : 
     102             : #define FOURCC(a,b,c,d) ((a << 24) + (b << 16) + (c << 8) + d)
     103             : 
     104             :  // System ID identifying the cenc v2 pssh box format; specified at:
     105             :  // https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
     106             : const uint8_t kSystemID[] = {
     107             :   0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
     108             :   0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b
     109             : };
     110             : 
     111             : bool
     112           0 : ParseCENCInitData(const uint8_t* aInitData,
     113             :                   uint32_t aInitDataSize,
     114             :                   std::vector<std::vector<uint8_t>>& aOutKeyIds)
     115             : {
     116           0 :   aOutKeyIds.clear();
     117           0 :   std::vector<std::vector<uint8_t>> keyIds;
     118           0 :   ByteReader reader(aInitData, aInitDataSize);
     119           0 :   while (reader.CanRead32()) {
     120             :     // Box size. For the common system Id, ignore this, as some useragents
     121             :     // handle invalid box sizes.
     122           0 :     const size_t start = reader.Offset();
     123           0 :     const size_t size = reader.ReadU32();
     124           0 :     if (size > std::numeric_limits<size_t>::max() - start) {
     125             :       // Ensure 'start + size' calculation below can't overflow.
     126           0 :       return false;
     127             :     }
     128           0 :     const size_t end = start + size;
     129           0 :     if (end > reader.Length()) {
     130             :       // Ridiculous sized box.
     131           0 :       return false;
     132             :     }
     133             : 
     134             :     // PSSH box type.
     135           0 :     if (!reader.CanRead32()) {
     136           0 :       return false;
     137             :     }
     138           0 :     uint32_t box = reader.ReadU32();
     139           0 :     if (box != FOURCC('p','s','s','h')) {
     140           0 :       return false;
     141             :     }
     142             : 
     143             :     // 1 byte version, 3 bytes flags.
     144           0 :     if (!reader.CanRead32()) {
     145           0 :       return false;
     146             :     }
     147           0 :     uint8_t version = reader.ReadU8();
     148           0 :     if (version != 1) {
     149             :       // Ignore pssh boxes with wrong version.
     150           0 :       reader.Seek(std::max<size_t>(reader.Offset(), end));
     151           0 :       continue;
     152             :     }
     153           0 :     reader.Read(3); // skip flags.
     154             : 
     155             :     // SystemID
     156           0 :     const uint8_t* sid = reader.Read(sizeof(kSystemID));
     157           0 :     if (!sid) {
     158             :       // Insufficient bytes to read SystemID.
     159           0 :       return false;
     160             :     }
     161             : 
     162           0 :     if (memcmp(kSystemID, sid, sizeof(kSystemID))) {
     163             :       // Ignore pssh boxes with wrong system ID.
     164           0 :       reader.Seek(std::max<size_t>(reader.Offset(), end));
     165           0 :       continue;
     166             :     }
     167             : 
     168           0 :     if (!reader.CanRead32()) {
     169           0 :       return false;
     170             :     }
     171           0 :     uint32_t kidCount = reader.ReadU32();
     172             : 
     173           0 :     if (kidCount * CENC_KEY_LEN > reader.Remaining()) {
     174             :       // Not enough bytes remaining to read all keys.
     175           0 :       return false;
     176             :     }
     177             : 
     178           0 :     for (uint32_t i = 0; i < kidCount; i++) {
     179           0 :       const uint8_t* kid = reader.Read(CENC_KEY_LEN);
     180           0 :       keyIds.push_back(std::vector<uint8_t>(kid, kid + CENC_KEY_LEN));
     181             :     }
     182             : 
     183             :     // Size of extra data. EME CENC format spec says datasize should
     184             :     // always be 0. We explicitly read the datasize, in case the box
     185             :     // size was 0, so that we get to the end of the box.
     186           0 :     if (!reader.CanRead32()) {
     187           0 :       return false;
     188             :     }
     189           0 :     reader.ReadU32();
     190             : 
     191             :     // Jump forwards to the end of the box, skipping any padding.
     192           0 :     if (size) {
     193           0 :       reader.Seek(end);
     194             :     }
     195             :   }
     196           0 :   aOutKeyIds = mozilla::Move(keyIds);
     197           0 :   return true;
     198             : }

Generated by: LCOV version 1.13