security/pkix/lib/pkixder.h

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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 /* Copyright 2013 Mozilla Foundation
     4  *
     5  * Licensed under the Apache License, Version 2.0 (the "License");
     6  * you may not use this file except in compliance with the License.
     7  * You may obtain a copy of the License at
     8  *
     9  *     http://www.apache.org/licenses/LICENSE-2.0
    10  *
    11  * Unless required by applicable law or agreed to in writing, software
    12  * distributed under the License is distributed on an "AS IS" BASIS,
    13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  * See the License for the specific language governing permissions and
    15  * limitations under the License.
    16  */
    18 #ifndef mozilla_pkix__pkixder_h
    19 #define mozilla_pkix__pkixder_h
    21 #include "pkix/nullptr.h"
    23 #include "prerror.h"
    24 #include "prlog.h"
    25 #include "secder.h"
    26 #include "secerr.h"
    27 #include "secoidt.h"
    28 #include "stdint.h"
    30 namespace mozilla { namespace pkix { namespace der {
    32 enum Class
    33 {
    34    UNIVERSAL = 0 << 6,
    35 // APPLICATION = 1 << 6, // unused
    36    CONTEXT_SPECIFIC = 2 << 6,
    37 // PRIVATE = 3 << 6 // unused
    38 };
    40 enum Constructed
    41 {
    42   CONSTRUCTED = 1 << 5
    43 };
    45 enum Tag
    46 {
    47   BOOLEAN = UNIVERSAL | 0x01,
    48   INTEGER = UNIVERSAL | 0x02,
    49   BIT_STRING = UNIVERSAL | 0x03,
    50   OCTET_STRING = UNIVERSAL | 0x04,
    51   NULLTag = UNIVERSAL | 0x05,
    52   OIDTag = UNIVERSAL | 0x06,
    53   ENUMERATED = UNIVERSAL | 0x0a,
    54   GENERALIZED_TIME = UNIVERSAL | 0x18,
    55   SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x30,
    56 };
    58 enum Result
    59 {
    60   Failure = -1,
    61   Success = 0
    62 };
    64 enum EmptyAllowed { MayBeEmpty = 0, MustNotBeEmpty = 1 };
    66 Result Fail(PRErrorCode errorCode);
    68 class Input
    69 {
    70 public:
    71   Input()
    72     : input(nullptr)
    73     , end(nullptr)
    74   {
    75   }
    77   Result Init(const uint8_t* data, size_t len)
    78   {
    79     if (input) {
    80       // already initialized
    81       return Fail(SEC_ERROR_INVALID_ARGS);
    82     }
    83     if (!data || len > 0xffffu) {
    84       // input too large
    85       return Fail(SEC_ERROR_BAD_DER);
    86     }
    88     // XXX: this->input = input bug was not caught by tests! Why not?
    89     //      this->end = end bug was not caught by tests! Why not?
    90     this->input = data;
    91     this->end = data + len;
    93     return Success;
    94   }
    96   Result Expect(const uint8_t* expected, uint16_t expectedLen)
    97   {
    98     if (EnsureLength(expectedLen) != Success) {
    99       return Fail(SEC_ERROR_BAD_DER);
   100     }
   101     if (memcmp(input, expected, expectedLen)) {
   102       return Fail(SEC_ERROR_BAD_DER);
   103     }
   104     input += expectedLen;
   105     return Success;
   106   }
   108   bool Peek(uint8_t expectedByte) const
   109   {
   110     return input < end && *input == expectedByte;
   111   }
   113   Result Read(uint8_t& out)
   114   {
   115     if (input == end) {
   116       return Fail(SEC_ERROR_BAD_DER);
   117     }
   118     out = *input++;
   119     return Success;
   120   }
   122   Result Read(uint16_t& out)
   123   {
   124     if (input == end || input + 1 == end) {
   125       return Fail(SEC_ERROR_BAD_DER);
   126     }
   127     out = *input++;
   128     out <<= 8u;
   129     out |= *input++;
   130     return Success;
   131   }
   133   Result Skip(uint16_t len)
   134   {
   135     if (EnsureLength(len) != Success) {
   136       return Fail(SEC_ERROR_BAD_DER);
   137     }
   138     input += len;
   139     return Success;
   140   }
   142   Result Skip(uint16_t len, Input& skippedInput)
   143   {
   144     if (EnsureLength(len) != Success) {
   145       return Fail(SEC_ERROR_BAD_DER);
   146     }
   147     if (skippedInput.Init(input, len) != Success) {
   148       return Failure;
   149     }
   150     input += len;
   151     return Success;
   152   }
   154   Result Skip(uint16_t len, SECItem& skippedItem)
   155   {
   156     if (EnsureLength(len) != Success) {
   157       return Fail(SEC_ERROR_BAD_DER);
   158     }
   159     skippedItem.type = siBuffer;
   160     skippedItem.data = const_cast<uint8_t*>(input);
   161     skippedItem.len = len;
   162     input += len;
   163     return Success;
   164   }
   166   void SkipToEnd()
   167   {
   168     input = end;
   169   }
   171   Result EnsureLength(uint16_t len)
   172   {
   173     if (static_cast<size_t>(end - input) < len) {
   174       return Fail(SEC_ERROR_BAD_DER);
   175     }
   176     return Success;
   177   }
   179   bool AtEnd() const { return input == end; }
   181   class Mark
   182   {
   183   private:
   184     friend class Input;
   185     explicit Mark(const uint8_t* mark) : mMark(mark) { }
   186     const uint8_t* const mMark;
   187     void operator=(const Mark&) /* = delete */;
   188   };
   190   Mark GetMark() const { return Mark(input); }
   192   bool GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
   193   {
   194     PR_ASSERT(mark.mMark < input);
   195     item.type = type;
   196     item.data = const_cast<uint8_t*>(mark.mMark);
   197     // TODO: Return false if bounds check fails
   198     item.len = input - mark.mMark;
   199     return true;
   200   }
   202 private:
   203   const uint8_t* input;
   204   const uint8_t* end;
   206   Input(const Input&) /* = delete */;
   207   void operator=(const Input&) /* = delete */;
   208 };
   210 inline Result
   211 ExpectTagAndLength(Input& input, uint8_t expectedTag, uint8_t expectedLength)
   212 {
   213   PR_ASSERT((expectedTag & 0x1F) != 0x1F); // high tag number form not allowed
   214   PR_ASSERT(expectedLength < 128); // must be a single-byte length
   216   uint16_t tagAndLength;
   217   if (input.Read(tagAndLength) != Success) {
   218     return Failure;
   219   }
   221   uint16_t expectedTagAndLength = static_cast<uint16_t>(expectedTag << 8);
   222   expectedTagAndLength |= expectedLength;
   224   if (tagAndLength != expectedTagAndLength) {
   225     return Fail(SEC_ERROR_BAD_DER);
   226   }
   228   return Success;
   229 }
   231 Result
   232 ExpectTagAndGetLength(Input& input, uint8_t expectedTag, uint16_t& length);
   234 inline Result
   235 ExpectTagAndIgnoreLength(Input& input, uint8_t expectedTag)
   236 {
   237   uint16_t ignored;
   238   return ExpectTagAndGetLength(input, expectedTag, ignored);
   239 }
   241 inline Result
   242 ExpectTagAndGetValue(Input& input, uint8_t tag, /*out*/ Input& value)
   243 {
   244   uint16_t length;
   245   if (ExpectTagAndGetLength(input, tag, length) != Success) {
   246     return Failure;
   247   }
   248   return input.Skip(length, value);
   249 }
   251 inline Result
   252 End(Input& input)
   253 {
   254   if (!input.AtEnd()) {
   255     return Fail(SEC_ERROR_BAD_DER);
   256   }
   258   return Success;
   259 }
   261 template <typename Decoder>
   262 inline Result
   263 Nested(Input& input, uint8_t tag, Decoder decoder)
   264 {
   265   uint16_t length;
   266   if (ExpectTagAndGetLength(input, tag, length) != Success) {
   267     return Failure;
   268   }
   270   Input nested;
   271   if (input.Skip(length, nested) != Success) {
   272     return Failure;
   273   }
   275   if (decoder(nested) != Success) {
   276     return Failure;
   277   }
   279   return End(nested);
   280 }
   282 template <typename Decoder>
   283 inline Result
   284 Nested(Input& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder)
   285 {
   286   // XXX: This doesn't work (in VS2010):
   287   // return Nested(input, outerTag, bind(Nested, _1, innerTag, decoder));
   289   uint16_t length;
   290   if (ExpectTagAndGetLength(input, outerTag, length) != Success) {
   291     return Failure;
   292   }
   293   Input nestedInput;
   294   if (input.Skip(length, nestedInput) != Success) {
   295     return Failure;
   296   }
   297   if (Nested(nestedInput, innerTag, decoder) != Success) {
   298     return Failure;
   299   }
   301   return End(nestedInput);
   302 }
   304 // This can be used to decode constructs like this:
   305 //
   306 //     ...
   307 //     foos SEQUENCE OF Foo,
   308 //     ...
   309 //     Foo ::= SEQUENCE {
   310 //     }
   311 //
   312 // using a call like this:
   313 //
   314 //    rv = NestedOf(input, SEQEUENCE, SEQUENCE, bind(_1, Foo));
   315 //
   316 //    Result Foo(Input& input) {
   317 //    }
   318 //
   319 // In this example, Foo will get called once for each element of foos.
   320 //
   321 template <typename Decoder>
   322 inline Result
   323 NestedOf(Input& input, uint8_t outerTag, uint8_t innerTag,
   324          EmptyAllowed mayBeEmpty, Decoder decoder)
   325 {
   326   uint16_t responsesLength;
   327   if (ExpectTagAndGetLength(input, outerTag, responsesLength) != Success) {
   328     return Failure;
   329   }
   331   Input inner;
   332   if (input.Skip(responsesLength, inner) != Success) {
   333     return Failure;
   334   }
   336   if (inner.AtEnd()) {
   337     if (mayBeEmpty != MayBeEmpty) {
   338       return Fail(SEC_ERROR_BAD_DER);
   339     }
   340     return Success;
   341   }
   343   do {
   344     if (Nested(inner, innerTag, decoder) != Success) {
   345       return Failure;
   346     }
   347   } while (!inner.AtEnd());
   349   return Success;
   350 }
   352 inline Result
   353 Skip(Input& input, uint8_t tag)
   354 {
   355   uint16_t length;
   356   if (ExpectTagAndGetLength(input, tag, length) != Success) {
   357     return Failure;
   358   }
   359   return input.Skip(length);
   360 }
   362 inline Result
   363 Skip(Input& input, uint8_t tag, /*out*/ SECItem& value)
   364 {
   365   uint16_t length;
   366   if (ExpectTagAndGetLength(input, tag, length) != Success) {
   367     return Failure;
   368   }
   369   return input.Skip(length, value);
   370 }
   372 // Universal types
   374 inline Result
   375 Boolean(Input& input, /*out*/ bool& value)
   376 {
   377   if (ExpectTagAndLength(input, BOOLEAN, 1) != Success) {
   378     return Failure;
   379   }
   381   uint8_t intValue;
   382   if (input.Read(intValue) != Success) {
   383     return Failure;
   384   }
   385   switch (intValue) {
   386     case 0: value = false; return Success;
   387     case 0xFF: value = true; return Success;
   388     default:
   389       PR_SetError(SEC_ERROR_BAD_DER, 0);
   390       return Failure;
   391   }
   392 }
   394 // This is for any BOOLEAN DEFAULT FALSE.
   395 // (If it is present and false, this is a bad encoding.)
   396 // TODO(bug 989518): For compatibility reasons, in some places we allow
   397 // invalid encodings with the explicit default value.
   398 inline Result
   399 OptionalBoolean(Input& input, bool allowInvalidExplicitEncoding,
   400                 /*out*/ bool& value)
   401 {
   402   value = false;
   403   if (input.Peek(BOOLEAN)) {
   404     if (Boolean(input, value) != Success) {
   405       return Failure;
   406     }
   407     if (!allowInvalidExplicitEncoding && !value) {
   408       return Fail(SEC_ERROR_BAD_DER);
   409     }
   410   }
   411   return Success;
   412 }
   414 inline Result
   415 Enumerated(Input& input, uint8_t& value)
   416 {
   417   if (ExpectTagAndLength(input, ENUMERATED | 0, 1) != Success) {
   418     return Failure;
   419   }
   420   return input.Read(value);
   421 }
   423 inline Result
   424 GeneralizedTime(Input& input, PRTime& time)
   425 {
   426   uint16_t length;
   427   SECItem encoded;
   428   if (ExpectTagAndGetLength(input, GENERALIZED_TIME, length) != Success) {
   429     return Failure;
   430   }
   431   if (input.Skip(length, encoded)) {
   432     return Failure;
   433   }
   434   if (DER_GeneralizedTimeToTime(&time, &encoded) != SECSuccess) {
   435     return Failure;
   436   }
   438   return Success;
   439 }
   441 inline Result
   442 Integer(Input& input, /*out*/ SECItem& value)
   443 {
   444   uint16_t length;
   445   if (ExpectTagAndGetLength(input, INTEGER, length) != Success) {
   446     return Failure;
   447   }
   449   if (input.Skip(length, value) != Success) {
   450     return Failure;
   451   }
   453   if (value.len == 0) {
   454     return Fail(SEC_ERROR_BAD_DER);
   455   }
   457   // Check for overly-long encodings. If the first byte is 0x00 then the high
   458   // bit on the second byte must be 1; otherwise the same *positive* value
   459   // could be encoded without the leading 0x00 byte. If the first byte is 0xFF
   460   // then the second byte must NOT have its high bit set; otherwise the same
   461   // *negative* value could be encoded without the leading 0xFF byte.
   462   if (value.len > 1) {
   463     if ((value.data[0] == 0x00 && (value.data[1] & 0x80) == 0) ||
   464         (value.data[0] == 0xff && (value.data[1] & 0x80) != 0)) {
   465       return Fail(SEC_ERROR_BAD_DER);
   466     }
   467   }
   469   return Success;
   470 }
   472 inline Result
   473 Null(Input& input)
   474 {
   475   return ExpectTagAndLength(input, NULLTag, 0);
   476 }
   478 template <uint16_t Len>
   479 Result
   480 OID(Input& input, const uint8_t (&expectedOid)[Len])
   481 {
   482   if (ExpectTagAndLength(input, OIDTag, Len) != Success) {
   483     return Failure;
   484   }
   486   return input.Expect(expectedOid, Len);
   487 }
   489 // PKI-specific types
   491 // AlgorithmIdentifier  ::=  SEQUENCE  {
   492 //         algorithm               OBJECT IDENTIFIER,
   493 //         parameters              ANY DEFINED BY algorithm OPTIONAL  }
   494 inline Result
   495 AlgorithmIdentifier(Input& input, SECAlgorithmID& algorithmID)
   496 {
   497   if (Skip(input, OIDTag, algorithmID.algorithm) != Success) {
   498     return Failure;
   499   }
   500   algorithmID.parameters.data = nullptr;
   501   algorithmID.parameters.len = 0;
   502   if (input.AtEnd()) {
   503     return Success;
   504   }
   505   return Null(input);
   506 }
   508 inline Result
   509 CertificateSerialNumber(Input& input, /*out*/ SECItem& serialNumber)
   510 {
   511   // http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
   512   //
   513   // * "The serial number MUST be a positive integer assigned by the CA to
   514   //   each certificate."
   515   // * "Certificate users MUST be able to handle serialNumber values up to 20
   516   //   octets. Conforming CAs MUST NOT use serialNumber values longer than 20
   517   //   octets."
   518   // * "Note: Non-conforming CAs may issue certificates with serial numbers
   519   //   that are negative or zero.  Certificate users SHOULD be prepared to
   520   //   gracefully handle such certificates."
   522   return Integer(input, serialNumber);
   523 }
   525 // x.509 and OCSP both use this same version numbering scheme, though OCSP
   526 // only supports v1.
   527 enum Version { v1 = 0, v2 = 1, v3 = 2 };
   529 // X.509 Certificate and OCSP ResponseData both use this
   530 // "[0] EXPLICIT Version DEFAULT <defaultVersion>" construct, but with
   531 // different default versions.
   532 inline Result
   533 OptionalVersion(Input& input, /*out*/ uint8_t& version)
   534 {
   535   const uint8_t tag = CONTEXT_SPECIFIC | CONSTRUCTED | 0;
   536   if (!input.Peek(tag)) {
   537     version = v1;
   538     return Success;
   539   }
   540   if (ExpectTagAndLength(input, tag, 3) != Success) {
   541     return Failure;
   542   }
   543   if (ExpectTagAndLength(input, INTEGER, 1) != Success) {
   544     return Failure;
   545   }
   546   if (input.Read(version) != Success) {
   547     return Failure;
   548   }
   549   if (version & 0x80) { // negative
   550     return Fail(SEC_ERROR_BAD_DER);
   551   }
   552   return Success;
   553 }
   555 } } } // namespace mozilla::pkix::der
   557 #endif // mozilla_pkix__pkixder_h

mercurial