LCOV - code coverage report
Current view: top level - security/pkix/lib - pkixder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 42 270 15.6 %
Date: 2017-07-14 16:53:18 Functions: 3 15 20.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 code is made available to you under your choice of the following sets
       4             :  * of licensing terms:
       5             :  */
       6             : /* This Source Code Form is subject to the terms of the Mozilla Public
       7             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       8             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       9             :  */
      10             : /* Copyright 2013 Mozilla Contributors
      11             :  *
      12             :  * Licensed under the Apache License, Version 2.0 (the "License");
      13             :  * you may not use this file except in compliance with the License.
      14             :  * You may obtain a copy of the License at
      15             :  *
      16             :  *     http://www.apache.org/licenses/LICENSE-2.0
      17             :  *
      18             :  * Unless required by applicable law or agreed to in writing, software
      19             :  * distributed under the License is distributed on an "AS IS" BASIS,
      20             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      21             :  * See the License for the specific language governing permissions and
      22             :  * limitations under the License.
      23             :  */
      24             : 
      25             : #include "pkixder.h"
      26             : 
      27             : #include "pkixutil.h"
      28             : 
      29             : namespace mozilla { namespace pkix { namespace der {
      30             : 
      31             : // Too complicated to be inline
      32             : Result
      33          87 : ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag, /*out*/ Input& value)
      34             : {
      35             :   Result rv;
      36             : 
      37          87 :   rv = input.Read(tag);
      38          87 :   if (rv != Success) {
      39           0 :     return rv;
      40             :   }
      41          87 :   if ((tag & 0x1F) == 0x1F) {
      42           0 :     return Result::ERROR_BAD_DER; // high tag number form not allowed
      43             :   }
      44             : 
      45             :   uint16_t length;
      46             : 
      47             :   // The short form of length is a single byte with the high order bit set
      48             :   // to zero. The long form of length is one byte with the high order bit
      49             :   // set, followed by N bytes, where N is encoded in the lowest 7 bits of
      50             :   // the first byte.
      51             :   uint8_t length1;
      52          87 :   rv = input.Read(length1);
      53          87 :   if (rv != Success) {
      54           0 :     return rv;
      55             :   }
      56          87 :   if (!(length1 & 0x80)) {
      57          71 :     length = length1;
      58          16 :   } else if (length1 == 0x81) {
      59             :     uint8_t length2;
      60           0 :     rv = input.Read(length2);
      61           0 :     if (rv != Success) {
      62           0 :       return rv;
      63             :     }
      64           0 :     if (length2 < 128) {
      65             :       // Not shortest possible encoding
      66           0 :       return Result::ERROR_BAD_DER;
      67             :     }
      68           0 :     length = length2;
      69          16 :   } else if (length1 == 0x82) {
      70          16 :     rv = input.Read(length);
      71          16 :     if (rv != Success) {
      72           0 :       return rv;
      73             :     }
      74          16 :     if (length < 256) {
      75             :       // Not shortest possible encoding
      76           0 :       return Result::ERROR_BAD_DER;
      77             :     }
      78             :   } else {
      79             :     // We don't support lengths larger than 2^16 - 1.
      80           0 :     return Result::ERROR_BAD_DER;
      81             :   }
      82             : 
      83          87 :   return input.Skip(length, value);
      84             : }
      85             : 
      86             : static Result
      87           0 : OptionalNull(Reader& input)
      88             : {
      89           0 :   if (input.Peek(NULLTag)) {
      90           0 :     return Null(input);
      91             :   }
      92           0 :   return Success;
      93             : }
      94             : 
      95             : namespace {
      96             : 
      97             : Result
      98           0 : AlgorithmIdentifierValue(Reader& input, /*out*/ Reader& algorithmOIDValue)
      99             : {
     100           0 :   Result rv = ExpectTagAndGetValue(input, der::OIDTag, algorithmOIDValue);
     101           0 :   if (rv != Success) {
     102           0 :     return rv;
     103             :   }
     104           0 :   return OptionalNull(input);
     105             : }
     106             : 
     107             : } // namespace
     108             : 
     109             : Result
     110           0 : SignatureAlgorithmIdentifierValue(Reader& input,
     111             :                                  /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
     112             :                                  /*out*/ DigestAlgorithm& digestAlgorithm)
     113             : {
     114             :   // RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279 Section 2.2.3
     115             :   // (ECDSA with SHA-1) say that parameters must be omitted.
     116             :   //
     117             :   // RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
     118             :   // RSA must be encoded as NULL; we relax that requirement by allowing the
     119             :   // NULL to be omitted, to match all the other signature algorithms we support
     120             :   // and for compatibility.
     121           0 :   Reader algorithmID;
     122           0 :   Result rv = AlgorithmIdentifierValue(input, algorithmID);
     123           0 :   if (rv != Success) {
     124           0 :     return rv;
     125             :   }
     126             : 
     127             :   // RFC 5758 Section 3.2 (ecdsa-with-SHA224 is intentionally excluded)
     128             :   // python DottedOIDToCode.py ecdsa-with-SHA256 1.2.840.10045.4.3.2
     129             :   static const uint8_t ecdsa_with_SHA256[] = {
     130             :     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02
     131             :   };
     132             :   // python DottedOIDToCode.py ecdsa-with-SHA384 1.2.840.10045.4.3.3
     133             :   static const uint8_t ecdsa_with_SHA384[] = {
     134             :     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03
     135             :   };
     136             :   // python DottedOIDToCode.py ecdsa-with-SHA512 1.2.840.10045.4.3.4
     137             :   static const uint8_t ecdsa_with_SHA512[] = {
     138             :     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
     139             :   };
     140             : 
     141             :   // RFC 4055 Section 5 (sha224WithRSAEncryption is intentionally excluded)
     142             :   // python DottedOIDToCode.py sha256WithRSAEncryption 1.2.840.113549.1.1.11
     143             :   static const uint8_t sha256WithRSAEncryption[] = {
     144             :     0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
     145             :   };
     146             :   // python DottedOIDToCode.py sha384WithRSAEncryption 1.2.840.113549.1.1.12
     147             :   static const uint8_t sha384WithRSAEncryption[] = {
     148             :     0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c
     149             :   };
     150             :   // python DottedOIDToCode.py sha512WithRSAEncryption 1.2.840.113549.1.1.13
     151             :   static const uint8_t sha512WithRSAEncryption[] = {
     152             :     0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d
     153             :   };
     154             : 
     155             :   // RFC 3279 Section 2.2.1
     156             :   // python DottedOIDToCode.py sha-1WithRSAEncryption 1.2.840.113549.1.1.5
     157             :   static const uint8_t sha_1WithRSAEncryption[] = {
     158             :     0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05
     159             :   };
     160             : 
     161             :   // NIST Open Systems Environment (OSE) Implementor's Workshop (OIW)
     162             :   // http://www.oiw.org/agreements/stable/12s-9412.txt (no longer works).
     163             :   // http://www.imc.org/ietf-pkix/old-archive-97/msg01166.html
     164             :   // We need to support this this non-PKIX OID for compatibility.
     165             :   // python DottedOIDToCode.py sha1WithRSASignature 1.3.14.3.2.29
     166             :   static const uint8_t sha1WithRSASignature[] = {
     167             :     0x2b, 0x0e, 0x03, 0x02, 0x1d
     168             :   };
     169             : 
     170             :   // RFC 3279 Section 2.2.3
     171             :   // python DottedOIDToCode.py ecdsa-with-SHA1 1.2.840.10045.4.1
     172             :   static const uint8_t ecdsa_with_SHA1[] = {
     173             :     0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
     174             :   };
     175             : 
     176             :   // Matching is attempted based on a rough estimate of the commonality of the
     177             :   // algorithm, to minimize the number of MatchRest calls.
     178           0 :   if (algorithmID.MatchRest(sha256WithRSAEncryption)) {
     179           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
     180           0 :     digestAlgorithm = DigestAlgorithm::sha256;
     181           0 :   } else if (algorithmID.MatchRest(ecdsa_with_SHA256)) {
     182           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
     183           0 :     digestAlgorithm = DigestAlgorithm::sha256;
     184           0 :   } else if (algorithmID.MatchRest(sha_1WithRSAEncryption)) {
     185           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
     186           0 :     digestAlgorithm = DigestAlgorithm::sha1;
     187           0 :   } else if (algorithmID.MatchRest(ecdsa_with_SHA1)) {
     188           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
     189           0 :     digestAlgorithm = DigestAlgorithm::sha1;
     190           0 :   } else if (algorithmID.MatchRest(ecdsa_with_SHA384)) {
     191           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
     192           0 :     digestAlgorithm = DigestAlgorithm::sha384;
     193           0 :   } else if (algorithmID.MatchRest(ecdsa_with_SHA512)) {
     194           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
     195           0 :     digestAlgorithm = DigestAlgorithm::sha512;
     196           0 :   } else if (algorithmID.MatchRest(sha384WithRSAEncryption)) {
     197           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
     198           0 :     digestAlgorithm = DigestAlgorithm::sha384;
     199           0 :   } else if (algorithmID.MatchRest(sha512WithRSAEncryption)) {
     200           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
     201           0 :     digestAlgorithm = DigestAlgorithm::sha512;
     202           0 :   } else if (algorithmID.MatchRest(sha1WithRSASignature)) {
     203             :     // XXX(bug 1042479): recognize this old OID for compatibility.
     204           0 :     publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
     205           0 :     digestAlgorithm = DigestAlgorithm::sha1;
     206             :   } else {
     207           0 :     return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
     208             :   }
     209             : 
     210           0 :   return Success;
     211             : }
     212             : 
     213             : Result
     214           0 : DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm)
     215             : {
     216           0 :   Reader r;
     217           0 :   return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result {
     218           0 :     Reader algorithmID;
     219           0 :     Result rv = AlgorithmIdentifierValue(r, algorithmID);
     220           0 :     if (rv != Success) {
     221           0 :       return rv;
     222             :     }
     223             : 
     224             :     // RFC 4055 Section 2.1
     225             :     // python DottedOIDToCode.py id-sha1 1.3.14.3.2.26
     226             :     static const uint8_t id_sha1[] = {
     227             :       0x2b, 0x0e, 0x03, 0x02, 0x1a
     228             :     };
     229             :     // python DottedOIDToCode.py id-sha256 2.16.840.1.101.3.4.2.1
     230             :     static const uint8_t id_sha256[] = {
     231             :       0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
     232             :     };
     233             :     // python DottedOIDToCode.py id-sha384 2.16.840.1.101.3.4.2.2
     234             :     static const uint8_t id_sha384[] = {
     235             :       0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
     236             :     };
     237             :     // python DottedOIDToCode.py id-sha512 2.16.840.1.101.3.4.2.3
     238             :     static const uint8_t id_sha512[] = {
     239             :       0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
     240             :     };
     241             : 
     242             :     // Matching is attempted based on a rough estimate of the commonality of the
     243             :     // algorithm, to minimize the number of MatchRest calls.
     244           0 :     if (algorithmID.MatchRest(id_sha1)) {
     245           0 :       algorithm = DigestAlgorithm::sha1;
     246           0 :     } else if (algorithmID.MatchRest(id_sha256)) {
     247           0 :       algorithm = DigestAlgorithm::sha256;
     248           0 :     } else if (algorithmID.MatchRest(id_sha384)) {
     249           0 :       algorithm = DigestAlgorithm::sha384;
     250           0 :     } else if (algorithmID.MatchRest(id_sha512)) {
     251           0 :       algorithm = DigestAlgorithm::sha512;
     252             :     } else {
     253           0 :       return Result::ERROR_INVALID_ALGORITHM;
     254             :     }
     255             : 
     256           0 :     return Success;
     257           0 :   });
     258             : }
     259             : 
     260             : Result
     261           0 : SignedData(Reader& input, /*out*/ Reader& tbs,
     262             :            /*out*/ SignedDataWithSignature& signedData)
     263             : {
     264           0 :   Reader::Mark mark(input.GetMark());
     265             : 
     266             :   Result rv;
     267           0 :   rv = ExpectTagAndGetValue(input, SEQUENCE, tbs);
     268           0 :   if (rv != Success) {
     269           0 :     return rv;
     270             :   }
     271             : 
     272           0 :   rv = input.GetInput(mark, signedData.data);
     273           0 :   if (rv != Success) {
     274           0 :     return rv;
     275             :   }
     276             : 
     277           0 :   rv = ExpectTagAndGetValue(input, der::SEQUENCE, signedData.algorithm);
     278           0 :   if (rv != Success) {
     279           0 :     return rv;
     280             :   }
     281             : 
     282           0 :   rv = BitStringWithNoUnusedBits(input, signedData.signature);
     283           0 :   if (rv == Result::ERROR_BAD_DER) {
     284           0 :     rv = Result::ERROR_BAD_SIGNATURE;
     285             :   }
     286           0 :   return rv;
     287             : }
     288             : 
     289             : Result
     290          15 : BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value)
     291             : {
     292          15 :   Reader valueWithUnusedBits;
     293          15 :   Result rv = ExpectTagAndGetValue(input, BIT_STRING, valueWithUnusedBits);
     294          15 :   if (rv != Success) {
     295           0 :     return rv;
     296             :   }
     297             : 
     298             :   uint8_t unusedBitsAtEnd;
     299          15 :   if (valueWithUnusedBits.Read(unusedBitsAtEnd) != Success) {
     300           0 :     return Result::ERROR_BAD_DER;
     301             :   }
     302             :   // XXX: Really the constraint should be that unusedBitsAtEnd must be less
     303             :   // than 7. But, we suspect there are no real-world values in OCSP responses
     304             :   // or certificates with non-zero unused bits. It seems like NSS assumes this
     305             :   // in various places, so we enforce it too in order to simplify this code. If
     306             :   // we find compatibility issues, we'll know we're wrong and we'll have to
     307             :   // figure out how to shift the bits around.
     308          15 :   if (unusedBitsAtEnd != 0) {
     309           0 :     return Result::ERROR_BAD_DER;
     310             :   }
     311          15 :   return valueWithUnusedBits.SkipToEnd(value);
     312             : }
     313             : 
     314             : static inline Result
     315           0 : ReadDigit(Reader& input, /*out*/ unsigned int& value)
     316             : {
     317             :   uint8_t b;
     318           0 :   if (input.Read(b) != Success) {
     319           0 :     return Result::ERROR_INVALID_DER_TIME;
     320             :   }
     321           0 :   if (b < '0' || b > '9') {
     322           0 :     return Result::ERROR_INVALID_DER_TIME;
     323             :   }
     324           0 :   value = static_cast<unsigned int>(b - static_cast<uint8_t>('0'));
     325           0 :   return Success;
     326             : }
     327             : 
     328             : static inline Result
     329           0 : ReadTwoDigits(Reader& input, unsigned int minValue, unsigned int maxValue,
     330             :               /*out*/ unsigned int& value)
     331             : {
     332             :   unsigned int hi;
     333           0 :   Result rv = ReadDigit(input, hi);
     334           0 :   if (rv != Success) {
     335           0 :     return rv;
     336             :   }
     337             :   unsigned int lo;
     338           0 :   rv = ReadDigit(input, lo);
     339           0 :   if (rv != Success) {
     340           0 :     return rv;
     341             :   }
     342           0 :   value = (hi * 10) + lo;
     343           0 :   if (value < minValue || value > maxValue) {
     344           0 :     return Result::ERROR_INVALID_DER_TIME;
     345             :   }
     346           0 :   return Success;
     347             : }
     348             : 
     349             : namespace internal {
     350             : 
     351             : // We parse GeneralizedTime and UTCTime according to RFC 5280 and we do not
     352             : // accept all time formats allowed in the ASN.1 spec. That is,
     353             : // GeneralizedTime must always be in the format YYYYMMDDHHMMSSZ and UTCTime
     354             : // must always be in the format YYMMDDHHMMSSZ. Timezone formats of the form
     355             : // +HH:MM or -HH:MM or NOT accepted.
     356             : Result
     357           0 : TimeChoice(Reader& tagged, uint8_t expectedTag, /*out*/ Time& time)
     358             : {
     359             :   unsigned int days;
     360             : 
     361           0 :   Reader input;
     362           0 :   Result rv = ExpectTagAndGetValue(tagged, expectedTag, input);
     363           0 :   if (rv != Success) {
     364           0 :     return rv;
     365             :   }
     366             : 
     367             :   unsigned int yearHi;
     368             :   unsigned int yearLo;
     369           0 :   if (expectedTag == GENERALIZED_TIME) {
     370           0 :     rv = ReadTwoDigits(input, 0, 99, yearHi);
     371           0 :     if (rv != Success) {
     372           0 :       return rv;
     373             :     }
     374           0 :     rv = ReadTwoDigits(input, 0, 99, yearLo);
     375           0 :     if (rv != Success) {
     376           0 :       return rv;
     377             :     }
     378           0 :   } else if (expectedTag == UTCTime) {
     379           0 :     rv = ReadTwoDigits(input, 0, 99, yearLo);
     380           0 :     if (rv != Success) {
     381           0 :       return rv;
     382             :     }
     383           0 :     yearHi = yearLo >= 50u ? 19u : 20u;
     384             :   } else {
     385             :     return NotReached("invalid tag given to TimeChoice",
     386           0 :                       Result::ERROR_INVALID_DER_TIME);
     387             :   }
     388           0 :   unsigned int year = (yearHi * 100u) + yearLo;
     389           0 :   if (year < 1970u) {
     390             :     // We don't support dates before January 1, 1970 because that is the epoch.
     391           0 :     return Result::ERROR_INVALID_DER_TIME;
     392             :   }
     393           0 :   days = DaysBeforeYear(year);
     394             : 
     395             :   unsigned int month;
     396           0 :   rv = ReadTwoDigits(input, 1u, 12u, month);
     397           0 :   if (rv != Success) {
     398           0 :     return rv;
     399             :   }
     400             :   unsigned int daysInMonth;
     401             :   static const unsigned int jan = 31u;
     402           0 :   const unsigned int feb = ((year % 4u == 0u) &&
     403           0 :                            ((year % 100u != 0u) || (year % 400u == 0u)))
     404           0 :                          ? 29u
     405           0 :                          : 28u;
     406             :   static const unsigned int mar = 31u;
     407             :   static const unsigned int apr = 30u;
     408             :   static const unsigned int may = 31u;
     409             :   static const unsigned int jun = 30u;
     410             :   static const unsigned int jul = 31u;
     411             :   static const unsigned int aug = 31u;
     412             :   static const unsigned int sep = 30u;
     413             :   static const unsigned int oct = 31u;
     414             :   static const unsigned int nov = 30u;
     415             :   static const unsigned int dec = 31u;
     416           0 :   switch (month) {
     417           0 :     case 1:  daysInMonth = jan; break;
     418           0 :     case 2:  daysInMonth = feb; days += jan; break;
     419           0 :     case 3:  daysInMonth = mar; days += jan + feb; break;
     420           0 :     case 4:  daysInMonth = apr; days += jan + feb + mar; break;
     421           0 :     case 5:  daysInMonth = may; days += jan + feb + mar + apr; break;
     422           0 :     case 6:  daysInMonth = jun; days += jan + feb + mar + apr + may; break;
     423           0 :     case 7:  daysInMonth = jul; days += jan + feb + mar + apr + may + jun;
     424           0 :              break;
     425           0 :     case 8:  daysInMonth = aug; days += jan + feb + mar + apr + may + jun +
     426           0 :                                         jul;
     427           0 :              break;
     428           0 :     case 9:  daysInMonth = sep; days += jan + feb + mar + apr + may + jun +
     429           0 :                                         jul + aug;
     430           0 :              break;
     431           0 :     case 10: daysInMonth = oct; days += jan + feb + mar + apr + may + jun +
     432           0 :                                         jul + aug + sep;
     433           0 :              break;
     434           0 :     case 11: daysInMonth = nov; days += jan + feb + mar + apr + may + jun +
     435           0 :                                         jul + aug + sep + oct;
     436           0 :              break;
     437           0 :     case 12: daysInMonth = dec; days += jan + feb + mar + apr + may + jun +
     438           0 :                                         jul + aug + sep + oct + nov;
     439           0 :              break;
     440             :     default:
     441             :       return NotReached("month already bounds-checked by ReadTwoDigits",
     442           0 :                         Result::FATAL_ERROR_INVALID_STATE);
     443             :   }
     444             : 
     445             :   unsigned int dayOfMonth;
     446           0 :   rv = ReadTwoDigits(input, 1u, daysInMonth, dayOfMonth);
     447           0 :   if (rv != Success) {
     448           0 :     return rv;
     449             :   }
     450           0 :   days += dayOfMonth - 1;
     451             : 
     452             :   unsigned int hours;
     453           0 :   rv = ReadTwoDigits(input, 0u, 23u, hours);
     454           0 :   if (rv != Success) {
     455           0 :     return rv;
     456             :   }
     457             :   unsigned int minutes;
     458           0 :   rv = ReadTwoDigits(input, 0u, 59u, minutes);
     459           0 :   if (rv != Success) {
     460           0 :     return rv;
     461             :   }
     462             :   unsigned int seconds;
     463           0 :   rv = ReadTwoDigits(input, 0u, 59u, seconds);
     464           0 :   if (rv != Success) {
     465           0 :     return rv;
     466             :   }
     467             : 
     468             :   uint8_t b;
     469           0 :   if (input.Read(b) != Success) {
     470           0 :     return Result::ERROR_INVALID_DER_TIME;
     471             :   }
     472           0 :   if (b != 'Z') {
     473           0 :     return Result::ERROR_INVALID_DER_TIME;
     474             :   }
     475           0 :   if (End(input) != Success) {
     476           0 :     return Result::ERROR_INVALID_DER_TIME;
     477             :   }
     478             : 
     479           0 :   uint64_t totalSeconds = (static_cast<uint64_t>(days) * 24u * 60u * 60u) +
     480           0 :                           (static_cast<uint64_t>(hours)      * 60u * 60u) +
     481           0 :                           (static_cast<uint64_t>(minutes)          * 60u) +
     482           0 :                           seconds;
     483             : 
     484           0 :   time = TimeFromElapsedSecondsAD(totalSeconds);
     485           0 :   return Success;
     486             : }
     487             : 
     488             : Result
     489           8 : IntegralBytes(Reader& input, uint8_t tag,
     490             :               IntegralValueRestriction valueRestriction,
     491             :               /*out*/ Input& value,
     492             :               /*optional out*/ Input::size_type* significantBytes)
     493             : {
     494           8 :   Result rv = ExpectTagAndGetValue(input, tag, value);
     495           8 :   if (rv != Success) {
     496           0 :     return rv;
     497             :   }
     498           8 :   Reader reader(value);
     499             : 
     500             :   // There must be at least one byte in the value. (Zero is encoded with a
     501             :   // single 0x00 value byte.)
     502             :   uint8_t firstByte;
     503           8 :   rv = reader.Read(firstByte);
     504           8 :   if (rv != Success) {
     505           0 :     if (rv == Result::ERROR_BAD_DER) {
     506           0 :       return Result::ERROR_INVALID_INTEGER_ENCODING;
     507             :     }
     508             : 
     509           0 :     return rv;
     510             :   }
     511             : 
     512             :   // If there is a byte after an initial 0x00/0xFF, then the initial byte
     513             :   // indicates a positive/negative integer value with its high bit set/unset.
     514           8 :   bool prefixed = !reader.AtEnd() && (firstByte == 0 || firstByte == 0xff);
     515             : 
     516           8 :   if (prefixed) {
     517             :     uint8_t nextByte;
     518           4 :     if (reader.Read(nextByte) != Success) {
     519             :       return NotReached("Read of one byte failed but not at end.",
     520           0 :                         Result::FATAL_ERROR_LIBRARY_FAILURE);
     521             :     }
     522           4 :     if ((firstByte & 0x80) == (nextByte & 0x80)) {
     523           0 :       return Result::ERROR_INVALID_INTEGER_ENCODING;
     524             :     }
     525             :   }
     526             : 
     527           8 :   switch (valueRestriction) {
     528             :     case IntegralValueRestriction::MustBe0To127:
     529           0 :       if (value.GetLength() != 1 || (firstByte & 0x80) != 0) {
     530           0 :         return Result::ERROR_INVALID_INTEGER_ENCODING;
     531             :       }
     532           0 :       break;
     533             : 
     534             :     case IntegralValueRestriction::MustBePositive:
     535          16 :       if ((value.GetLength() == 1 && firstByte == 0) ||
     536           8 :           (firstByte & 0x80) != 0) {
     537           0 :         return Result::ERROR_INVALID_INTEGER_ENCODING;
     538             :       }
     539           8 :       break;
     540             : 
     541             :     case IntegralValueRestriction::NoRestriction:
     542           0 :       break;
     543             :   }
     544             : 
     545           8 :   if (significantBytes) {
     546           4 :     *significantBytes = value.GetLength();
     547           4 :     if (prefixed) {
     548           4 :       assert(*significantBytes > 1);
     549           4 :       --*significantBytes;
     550             :     }
     551             : 
     552           4 :     assert(*significantBytes > 0);
     553             :   }
     554             : 
     555           8 :   return Success;
     556             : }
     557             : 
     558             : // This parser will only parse values between 0..127. If this range is
     559             : // increased then callers will need to be changed.
     560             : Result
     561           0 : IntegralValue(Reader& input, uint8_t tag, /*out*/ uint8_t& value)
     562             : {
     563             :   // Conveniently, all the Integers that we actually have to be able to parse
     564             :   // are positive and very small. Consequently, this parser is *much* simpler
     565             :   // than a general Integer parser would need to be.
     566           0 :   Input valueBytes;
     567           0 :   Result rv = IntegralBytes(input, tag, IntegralValueRestriction::MustBe0To127,
     568           0 :                             valueBytes, nullptr);
     569           0 :   if (rv != Success) {
     570           0 :     return rv;
     571             :   }
     572           0 :   Reader valueReader(valueBytes);
     573           0 :   rv = valueReader.Read(value);
     574           0 :   if (rv != Success) {
     575           0 :     return NotReached("IntegralBytes already validated the value.", rv);
     576             :   }
     577           0 :   rv = End(valueReader);
     578           0 :   assert(rv == Success); // guaranteed by IntegralBytes's range checks.
     579           0 :   return rv;
     580             : }
     581             : 
     582             : } // namespace internal
     583             : 
     584             : Result
     585           0 : OptionalVersion(Reader& input, /*out*/ Version& version)
     586             : {
     587             :   static const uint8_t TAG = CONTEXT_SPECIFIC | CONSTRUCTED | 0;
     588           0 :   if (!input.Peek(TAG)) {
     589           0 :     version = Version::v1;
     590           0 :     return Success;
     591             :   }
     592           0 :   return Nested(input, TAG, [&version](Reader& value) -> Result {
     593             :     uint8_t integerValue;
     594           0 :     Result rv = Integer(value, integerValue);
     595           0 :     if (rv != Success) {
     596           0 :       return rv;
     597             :     }
     598             :     // XXX(bug 1031093): We shouldn't accept an explicit encoding of v1,
     599             :     // but we do here for compatibility reasons.
     600           0 :     switch (integerValue) {
     601           0 :       case static_cast<uint8_t>(Version::v3): version = Version::v3; break;
     602           0 :       case static_cast<uint8_t>(Version::v2): version = Version::v2; break;
     603           0 :       case static_cast<uint8_t>(Version::v1): version = Version::v1; break;
     604           0 :       case static_cast<uint8_t>(Version::v4): version = Version::v4; break;
     605             :       default:
     606           0 :         return Result::ERROR_BAD_DER;
     607             :     }
     608           0 :     return Success;
     609           0 :   });
     610             : }
     611             : 
     612             : } } } // namespace mozilla::pkix::der

Generated by: LCOV version 1.13