LCOV - code coverage report
Current view: top level - security/certverifier - CTObjectsExtractor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 169 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "CTObjectsExtractor.h"
       8             : 
       9             : #include "hasht.h"
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/Casting.h"
      12             : #include "mozilla/Move.h"
      13             : #include "mozilla/PodOperations.h"
      14             : #include "mozilla/RangedPtr.h"
      15             : #include "mozilla/Vector.h"
      16             : #include "pkix/pkixnss.h"
      17             : #include "pkixutil.h"
      18             : 
      19             : namespace mozilla { namespace ct {
      20             : 
      21             : using namespace mozilla::pkix;
      22             : 
      23             : // Holds a non-owning pointer to a byte buffer and allows writing chunks of data
      24             : // to the buffer, placing the later chunks after the earlier ones
      25             : // in a stream-like fashion.
      26             : // Note that writing to Output always succeeds. If the internal buffer
      27             : // overflows, an error flag is turned on and you won't be able to retrieve
      28             : // the final data.
      29             : class Output
      30             : {
      31             : public:
      32           0 :   Output(uint8_t* buffer, size_t length)
      33           0 :     : begin(buffer)
      34           0 :     , end(buffer + length)
      35             :     , current(buffer, begin, end)
      36           0 :     , overflowed(false)
      37             :   {
      38           0 :   }
      39             : 
      40             :   template <size_t N>
      41           0 :   explicit Output(uint8_t (&buffer)[N])
      42           0 :     : Output(buffer, N)
      43             :   {
      44           0 :   }
      45             : 
      46           0 :   void Write(Input data)
      47             :   {
      48           0 :     Write(data.UnsafeGetData(), data.GetLength());
      49           0 :   }
      50             : 
      51           0 :   void Write(uint8_t b)
      52             :   {
      53           0 :     Write(&b, 1);
      54           0 :   }
      55             : 
      56             :   bool IsOverflowed() const { return overflowed; }
      57             : 
      58           0 :   Result GetInput(/*out*/ Input& input) const
      59             :   {
      60           0 :     if (overflowed) {
      61           0 :       return Result::FATAL_ERROR_INVALID_STATE;
      62             :     }
      63           0 :     size_t length = AssertedCast<size_t>(current.get() - begin);
      64           0 :     return input.Init(begin, length);
      65             :   }
      66             : 
      67             : private:
      68             :   uint8_t* begin;
      69             :   uint8_t* end;
      70             :   RangedPtr<uint8_t> current;
      71             :   bool overflowed;
      72             : 
      73             :   Output(const Output&) = delete;
      74             :   void operator=(const Output&) = delete;
      75             : 
      76           0 :   void Write(const uint8_t* data, size_t length)
      77             :   {
      78           0 :     size_t available = AssertedCast<size_t>(end - current.get());
      79           0 :     if (available < length) {
      80           0 :       overflowed = true;
      81             :     }
      82           0 :     if (overflowed) {
      83           0 :       return;
      84             :     }
      85           0 :     PodCopy(current.get(), data, length);
      86           0 :     current += length;
      87             :   }
      88             : };
      89             : 
      90             : // For reference:
      91             : //
      92             : // Certificate  ::=  SEQUENCE  {
      93             : //      tbsCertificate       TBSCertificate,
      94             : //      signatureAlgorithm   AlgorithmIdentifier,
      95             : //      signatureValue       BIT STRING  }
      96             : //
      97             : // TBSCertificate  ::=  SEQUENCE  {
      98             : //      version         [0]  EXPLICIT Version DEFAULT v1,
      99             : //      serialNumber         CertificateSerialNumber,
     100             : //      signature            AlgorithmIdentifier,
     101             : //      issuer               Name,
     102             : //      validity             Validity,
     103             : //      subject              Name,
     104             : //      subjectPublicKeyInfo SubjectPublicKeyInfo,
     105             : //      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
     106             : //                           -- If present, version MUST be v2 or v3
     107             : //      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
     108             : //                           -- If present, version MUST be v2 or v3
     109             : //      extensions      [3]  EXPLICIT Extensions OPTIONAL
     110             : //                           -- If present, version MUST be v3
     111             : //      }
     112             : 
     113             : // python DottedOIDToCode.py id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
     114             : // See Section 3.3 of RFC 6962.
     115             : static const uint8_t EMBEDDED_SCT_LIST_OID[] = {
     116             :   0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
     117             : };
     118             : // Maximum length of DER TLV header
     119             : static const size_t MAX_TLV_HEADER_LENGTH = 4;
     120             : // DER tag of the "extensions [3]" field from TBSCertificate
     121             : static const uint8_t EXTENSIONS_CONTEXT_TAG =
     122             :   der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 3;
     123             : 
     124             : // Given a leaf certificate, extracts the DER-encoded TBSCertificate component
     125             : // of the corresponding Precertificate.
     126             : // Basically, the extractor needs to remove the embedded SCTs extension
     127             : // from the certificate and return its TBSCertificate. We do it in an ad hoc
     128             : // manner by breaking the source DER into several parts and then joining
     129             : // the right parts, taking care to update the relevant TLV headers.
     130             : // See WriteOutput for more details on the parts involved.
     131           0 : class PrecertTBSExtractor
     132             : {
     133             : public:
     134             :   // |buffer| is the buffer to be used for writing the output. Since the
     135             :   // required buffer size is not generally known in advance, it's best
     136             :   // to use at least the size of the input certificate DER.
     137           0 :   PrecertTBSExtractor(Input der, uint8_t* buffer, size_t bufferLength)
     138           0 :     : mDER(der)
     139           0 :     , mOutput(buffer, bufferLength)
     140             :   {
     141           0 :   }
     142             : 
     143             :   // Performs the extraction.
     144           0 :   Result Init()
     145             :   {
     146           0 :     Reader tbsReader;
     147           0 :     Result rv = GetTBSCertificate(tbsReader);
     148           0 :     if (rv != Success) {
     149           0 :       return rv;
     150             :     }
     151             : 
     152           0 :     rv = ExtractTLVsBeforeExtensions(tbsReader);
     153           0 :     if (rv != Success) {
     154           0 :       return rv;
     155             :     }
     156             : 
     157           0 :     rv = ExtractOptionalExtensionsExceptSCTs(tbsReader);
     158           0 :     if (rv != Success) {
     159           0 :       return rv;
     160             :     }
     161             : 
     162           0 :     return WriteOutput();
     163             :   }
     164             : 
     165             :   // Use to retrieve the result after a successful call to Init.
     166             :   // The returned Input points to the buffer supplied in the constructor.
     167           0 :   Input GetPrecertTBS()
     168             :   {
     169           0 :     return mPrecertTBS;
     170             :   }
     171             : 
     172             : private:
     173           0 :   Result GetTBSCertificate(Reader& tbsReader)
     174             :   {
     175           0 :     Reader certificateReader;
     176             :     Result rv = der::ExpectTagAndGetValueAtEnd(mDER, der::SEQUENCE,
     177           0 :                                                certificateReader);
     178           0 :     if (rv != Success) {
     179           0 :       return rv;
     180             :     }
     181           0 :     return ExpectTagAndGetValue(certificateReader, der::SEQUENCE, tbsReader);
     182             :   }
     183             : 
     184           0 :   Result ExtractTLVsBeforeExtensions(Reader& tbsReader)
     185             :   {
     186           0 :     Reader::Mark tbsBegin = tbsReader.GetMark();
     187           0 :     while (!tbsReader.AtEnd()) {
     188           0 :       if (tbsReader.Peek(EXTENSIONS_CONTEXT_TAG)) {
     189           0 :         break;
     190             :       }
     191             :       uint8_t tag;
     192           0 :       Input tagValue;
     193           0 :       Result rv = der::ReadTagAndGetValue(tbsReader, tag, tagValue);
     194           0 :       if (rv != Success) {
     195           0 :         return rv;
     196             :       }
     197             :     }
     198           0 :     return tbsReader.GetInput(tbsBegin, mTLVsBeforeExtensions);
     199             :   }
     200             : 
     201           0 :   Result ExtractOptionalExtensionsExceptSCTs(Reader& tbsReader)
     202             :   {
     203           0 :     if (!tbsReader.Peek(EXTENSIONS_CONTEXT_TAG)) {
     204           0 :       return Success;
     205             :     }
     206             : 
     207           0 :     Reader extensionsContextReader;
     208             :     Result rv = der::ExpectTagAndGetValueAtEnd(tbsReader,
     209             :                                                EXTENSIONS_CONTEXT_TAG,
     210           0 :                                                extensionsContextReader);
     211           0 :     if (rv != Success) {
     212           0 :       return rv;
     213             :     }
     214             : 
     215           0 :     Reader extensionsReader;
     216             :     rv = der::ExpectTagAndGetValueAtEnd(extensionsContextReader, der::SEQUENCE,
     217           0 :                                         extensionsReader);
     218           0 :     if (rv != Success) {
     219           0 :       return rv;
     220             :     }
     221             : 
     222           0 :     while (!extensionsReader.AtEnd()) {
     223           0 :       Reader::Mark extensionTLVBegin = extensionsReader.GetMark();
     224           0 :       Reader extension;
     225             :       rv = der::ExpectTagAndGetValue(extensionsReader, der::SEQUENCE,
     226           0 :                                      extension);
     227           0 :       if (rv != Success) {
     228           0 :         return rv;
     229             :       }
     230           0 :       Reader extensionID;
     231           0 :       rv = der::ExpectTagAndGetValue(extension, der::OIDTag, extensionID);
     232           0 :       if (rv != Success) {
     233           0 :         return rv;
     234             :       }
     235           0 :       if (!extensionID.MatchRest(EMBEDDED_SCT_LIST_OID)) {
     236           0 :         Input extensionTLV;
     237           0 :         rv = extensionsReader.GetInput(extensionTLVBegin, extensionTLV);
     238           0 :         if (rv != Success) {
     239           0 :           return rv;
     240             :         }
     241           0 :         if (!mExtensionTLVs.append(Move(extensionTLV))) {
     242           0 :           return Result::FATAL_ERROR_NO_MEMORY;
     243             :         }
     244             :       }
     245             :     }
     246           0 :     return Success;
     247             :   }
     248             : 
     249           0 :   Result WriteOutput()
     250             :   {
     251             :     // What should be written here:
     252             :     //
     253             :     // TBSCertificate ::= SEQUENCE (TLV with header |tbsHeader|)
     254             :     //   dump of |mTLVsBeforeExtensions|
     255             :     //   extensions [3] OPTIONAL (TLV with header |extensionsContextHeader|)
     256             :     //     SEQUENCE (TLV with with header |extensionsHeader|)
     257             :     //       dump of |mExtensionTLVs|
     258             : 
     259             :     Result rv;
     260           0 :     if (mExtensionTLVs.length() > 0) {
     261             :       uint8_t tbsHeaderBuffer[MAX_TLV_HEADER_LENGTH];
     262             :       uint8_t extensionsContextHeaderBuffer[MAX_TLV_HEADER_LENGTH];
     263             :       uint8_t extensionsHeaderBuffer[MAX_TLV_HEADER_LENGTH];
     264             : 
     265           0 :       Input tbsHeader;
     266           0 :       Input extensionsContextHeader;
     267           0 :       Input extensionsHeader;
     268             : 
     269             :       // Count the total size of the extensions. Note that since
     270             :       // the extensions data is contained within mDER (an Input),
     271             :       // their combined length won't overflow Input::size_type.
     272           0 :       Input::size_type extensionsValueLength = 0;
     273           0 :       for (auto& extensionTLV : mExtensionTLVs) {
     274           0 :         extensionsValueLength += extensionTLV.GetLength();
     275             :       }
     276             : 
     277           0 :       rv = MakeTLVHeader(der::SEQUENCE, extensionsValueLength,
     278           0 :                          extensionsHeaderBuffer, extensionsHeader);
     279           0 :       if (rv != Success) {
     280           0 :         return rv;
     281             :       }
     282             :       Input::size_type extensionsContextLength =
     283           0 :         AssertedCast<Input::size_type>(extensionsHeader.GetLength() +
     284           0 :                                        extensionsValueLength);
     285           0 :       rv = MakeTLVHeader(EXTENSIONS_CONTEXT_TAG,
     286             :                          extensionsContextLength,
     287             :                          extensionsContextHeaderBuffer,
     288           0 :                          extensionsContextHeader);
     289           0 :       if (rv != Success) {
     290           0 :         return rv;
     291             :       }
     292             :       Input::size_type tbsLength =
     293           0 :         AssertedCast<Input::size_type>(mTLVsBeforeExtensions.GetLength() +
     294           0 :                                        extensionsContextHeader.GetLength() +
     295           0 :                                        extensionsHeader.GetLength() +
     296           0 :                                        extensionsValueLength);
     297           0 :       rv = MakeTLVHeader(der::SEQUENCE, tbsLength, tbsHeaderBuffer, tbsHeader);
     298           0 :       if (rv != Success) {
     299           0 :         return rv;
     300             :       }
     301             : 
     302           0 :       mOutput.Write(tbsHeader);
     303           0 :       mOutput.Write(mTLVsBeforeExtensions);
     304           0 :       mOutput.Write(extensionsContextHeader);
     305           0 :       mOutput.Write(extensionsHeader);
     306           0 :       for (auto& extensionTLV : mExtensionTLVs) {
     307           0 :         mOutput.Write(extensionTLV);
     308             :       }
     309             :     } else {
     310             :       uint8_t tbsHeaderBuffer[MAX_TLV_HEADER_LENGTH];
     311           0 :       Input tbsHeader;
     312           0 :       rv = MakeTLVHeader(der::SEQUENCE, mTLVsBeforeExtensions.GetLength(),
     313           0 :                          tbsHeaderBuffer, tbsHeader);
     314           0 :       if (rv != Success) {
     315           0 :         return rv;
     316             :       }
     317           0 :       mOutput.Write(tbsHeader);
     318           0 :       mOutput.Write(mTLVsBeforeExtensions);
     319             :     }
     320             : 
     321           0 :     return mOutput.GetInput(mPrecertTBS);
     322             :   }
     323             : 
     324           0 :   Result MakeTLVHeader(uint8_t tag, size_t length,
     325             :                        uint8_t (&buffer)[MAX_TLV_HEADER_LENGTH],
     326             :                        /*out*/ Input& header)
     327             :   {
     328           0 :     Output output(buffer);
     329           0 :     output.Write(tag);
     330           0 :     if (length < 128) {
     331           0 :       output.Write(AssertedCast<uint8_t>(length));
     332           0 :     } else if (length < 256) {
     333           0 :       output.Write(0x81u);
     334           0 :       output.Write(AssertedCast<uint8_t>(length));
     335           0 :     } else if (length < 65536) {
     336           0 :       output.Write(0x82u);
     337           0 :       output.Write(AssertedCast<uint8_t>(length / 256));
     338           0 :       output.Write(AssertedCast<uint8_t>(length % 256));
     339             :     } else {
     340           0 :       return Result::FATAL_ERROR_INVALID_ARGS;
     341             :     }
     342           0 :     return output.GetInput(header);
     343             :   }
     344             : 
     345             :   Input mDER;
     346             :   Input mTLVsBeforeExtensions;
     347             :   Vector<Input, 16> mExtensionTLVs;
     348             :   Output mOutput;
     349             :   Input mPrecertTBS;
     350             : };
     351             : 
     352             : Result
     353           0 : GetPrecertLogEntry(Input leafCertificate, Input issuerSubjectPublicKeyInfo,
     354             :                    LogEntry& output)
     355             : {
     356           0 :   MOZ_ASSERT(leafCertificate.GetLength() > 0);
     357           0 :   MOZ_ASSERT(issuerSubjectPublicKeyInfo.GetLength() > 0);
     358           0 :   output.Reset();
     359             : 
     360           0 :   Buffer precertTBSBuffer;
     361           0 :   if (!precertTBSBuffer.resize(leafCertificate.GetLength())) {
     362           0 :     return Result::FATAL_ERROR_NO_MEMORY;
     363             :   }
     364             : 
     365             :   PrecertTBSExtractor extractor(leafCertificate,
     366             :                                 precertTBSBuffer.begin(),
     367           0 :                                 precertTBSBuffer.length());
     368           0 :   Result rv = extractor.Init();
     369           0 :   if (rv != Success) {
     370           0 :     return rv;
     371             :   }
     372           0 :   Input precertTBS(extractor.GetPrecertTBS());
     373           0 :   MOZ_ASSERT(precertTBS.UnsafeGetData() == precertTBSBuffer.begin());
     374           0 :   precertTBSBuffer.shrinkTo(precertTBS.GetLength());
     375             : 
     376           0 :   output.type = LogEntry::Type::Precert;
     377           0 :   output.tbsCertificate = Move(precertTBSBuffer);
     378             : 
     379           0 :   if (!output.issuerKeyHash.resizeUninitialized(SHA256_LENGTH)) {
     380           0 :     return Result::FATAL_ERROR_NO_MEMORY;
     381             :   }
     382           0 :   return DigestBufNSS(issuerSubjectPublicKeyInfo, DigestAlgorithm::sha256,
     383             :                       output.issuerKeyHash.begin(),
     384           0 :                       output.issuerKeyHash.length());
     385             : }
     386             : 
     387             : Result
     388           0 : GetX509LogEntry(Input leafCertificate, LogEntry& output)
     389             : {
     390           0 :   MOZ_ASSERT(leafCertificate.GetLength() > 0);
     391           0 :   output.Reset();
     392           0 :   output.type = LogEntry::Type::X509;
     393           0 :   return InputToBuffer(leafCertificate, output.leafCertificate);
     394             : }
     395             : 
     396             : } } // namespace mozilla::ct

Generated by: LCOV version 1.13