security/pkix/lib/pkixder.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/pkix/lib/pkixder.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,557 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* Copyright 2013 Mozilla Foundation
     1.7 + *
     1.8 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.9 + * you may not use this file except in compliance with the License.
    1.10 + * You may obtain a copy of the License at
    1.11 + *
    1.12 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.13 + *
    1.14 + * Unless required by applicable law or agreed to in writing, software
    1.15 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.17 + * See the License for the specific language governing permissions and
    1.18 + * limitations under the License.
    1.19 + */
    1.20 +
    1.21 +#ifndef mozilla_pkix__pkixder_h
    1.22 +#define mozilla_pkix__pkixder_h
    1.23 +
    1.24 +#include "pkix/nullptr.h"
    1.25 +
    1.26 +#include "prerror.h"
    1.27 +#include "prlog.h"
    1.28 +#include "secder.h"
    1.29 +#include "secerr.h"
    1.30 +#include "secoidt.h"
    1.31 +#include "stdint.h"
    1.32 +
    1.33 +namespace mozilla { namespace pkix { namespace der {
    1.34 +
    1.35 +enum Class
    1.36 +{
    1.37 +   UNIVERSAL = 0 << 6,
    1.38 +// APPLICATION = 1 << 6, // unused
    1.39 +   CONTEXT_SPECIFIC = 2 << 6,
    1.40 +// PRIVATE = 3 << 6 // unused
    1.41 +};
    1.42 +
    1.43 +enum Constructed
    1.44 +{
    1.45 +  CONSTRUCTED = 1 << 5
    1.46 +};
    1.47 +
    1.48 +enum Tag
    1.49 +{
    1.50 +  BOOLEAN = UNIVERSAL | 0x01,
    1.51 +  INTEGER = UNIVERSAL | 0x02,
    1.52 +  BIT_STRING = UNIVERSAL | 0x03,
    1.53 +  OCTET_STRING = UNIVERSAL | 0x04,
    1.54 +  NULLTag = UNIVERSAL | 0x05,
    1.55 +  OIDTag = UNIVERSAL | 0x06,
    1.56 +  ENUMERATED = UNIVERSAL | 0x0a,
    1.57 +  GENERALIZED_TIME = UNIVERSAL | 0x18,
    1.58 +  SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x30,
    1.59 +};
    1.60 +
    1.61 +enum Result
    1.62 +{
    1.63 +  Failure = -1,
    1.64 +  Success = 0
    1.65 +};
    1.66 +
    1.67 +enum EmptyAllowed { MayBeEmpty = 0, MustNotBeEmpty = 1 };
    1.68 +
    1.69 +Result Fail(PRErrorCode errorCode);
    1.70 +
    1.71 +class Input
    1.72 +{
    1.73 +public:
    1.74 +  Input()
    1.75 +    : input(nullptr)
    1.76 +    , end(nullptr)
    1.77 +  {
    1.78 +  }
    1.79 +
    1.80 +  Result Init(const uint8_t* data, size_t len)
    1.81 +  {
    1.82 +    if (input) {
    1.83 +      // already initialized
    1.84 +      return Fail(SEC_ERROR_INVALID_ARGS);
    1.85 +    }
    1.86 +    if (!data || len > 0xffffu) {
    1.87 +      // input too large
    1.88 +      return Fail(SEC_ERROR_BAD_DER);
    1.89 +    }
    1.90 +
    1.91 +    // XXX: this->input = input bug was not caught by tests! Why not?
    1.92 +    //      this->end = end bug was not caught by tests! Why not?
    1.93 +    this->input = data;
    1.94 +    this->end = data + len;
    1.95 +
    1.96 +    return Success;
    1.97 +  }
    1.98 +
    1.99 +  Result Expect(const uint8_t* expected, uint16_t expectedLen)
   1.100 +  {
   1.101 +    if (EnsureLength(expectedLen) != Success) {
   1.102 +      return Fail(SEC_ERROR_BAD_DER);
   1.103 +    }
   1.104 +    if (memcmp(input, expected, expectedLen)) {
   1.105 +      return Fail(SEC_ERROR_BAD_DER);
   1.106 +    }
   1.107 +    input += expectedLen;
   1.108 +    return Success;
   1.109 +  }
   1.110 +
   1.111 +  bool Peek(uint8_t expectedByte) const
   1.112 +  {
   1.113 +    return input < end && *input == expectedByte;
   1.114 +  }
   1.115 +
   1.116 +  Result Read(uint8_t& out)
   1.117 +  {
   1.118 +    if (input == end) {
   1.119 +      return Fail(SEC_ERROR_BAD_DER);
   1.120 +    }
   1.121 +    out = *input++;
   1.122 +    return Success;
   1.123 +  }
   1.124 +
   1.125 +  Result Read(uint16_t& out)
   1.126 +  {
   1.127 +    if (input == end || input + 1 == end) {
   1.128 +      return Fail(SEC_ERROR_BAD_DER);
   1.129 +    }
   1.130 +    out = *input++;
   1.131 +    out <<= 8u;
   1.132 +    out |= *input++;
   1.133 +    return Success;
   1.134 +  }
   1.135 +
   1.136 +  Result Skip(uint16_t len)
   1.137 +  {
   1.138 +    if (EnsureLength(len) != Success) {
   1.139 +      return Fail(SEC_ERROR_BAD_DER);
   1.140 +    }
   1.141 +    input += len;
   1.142 +    return Success;
   1.143 +  }
   1.144 +
   1.145 +  Result Skip(uint16_t len, Input& skippedInput)
   1.146 +  {
   1.147 +    if (EnsureLength(len) != Success) {
   1.148 +      return Fail(SEC_ERROR_BAD_DER);
   1.149 +    }
   1.150 +    if (skippedInput.Init(input, len) != Success) {
   1.151 +      return Failure;
   1.152 +    }
   1.153 +    input += len;
   1.154 +    return Success;
   1.155 +  }
   1.156 +
   1.157 +  Result Skip(uint16_t len, SECItem& skippedItem)
   1.158 +  {
   1.159 +    if (EnsureLength(len) != Success) {
   1.160 +      return Fail(SEC_ERROR_BAD_DER);
   1.161 +    }
   1.162 +    skippedItem.type = siBuffer;
   1.163 +    skippedItem.data = const_cast<uint8_t*>(input);
   1.164 +    skippedItem.len = len;
   1.165 +    input += len;
   1.166 +    return Success;
   1.167 +  }
   1.168 +
   1.169 +  void SkipToEnd()
   1.170 +  {
   1.171 +    input = end;
   1.172 +  }
   1.173 +
   1.174 +  Result EnsureLength(uint16_t len)
   1.175 +  {
   1.176 +    if (static_cast<size_t>(end - input) < len) {
   1.177 +      return Fail(SEC_ERROR_BAD_DER);
   1.178 +    }
   1.179 +    return Success;
   1.180 +  }
   1.181 +
   1.182 +  bool AtEnd() const { return input == end; }
   1.183 +
   1.184 +  class Mark
   1.185 +  {
   1.186 +  private:
   1.187 +    friend class Input;
   1.188 +    explicit Mark(const uint8_t* mark) : mMark(mark) { }
   1.189 +    const uint8_t* const mMark;
   1.190 +    void operator=(const Mark&) /* = delete */;
   1.191 +  };
   1.192 +
   1.193 +  Mark GetMark() const { return Mark(input); }
   1.194 +
   1.195 +  bool GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
   1.196 +  {
   1.197 +    PR_ASSERT(mark.mMark < input);
   1.198 +    item.type = type;
   1.199 +    item.data = const_cast<uint8_t*>(mark.mMark);
   1.200 +    // TODO: Return false if bounds check fails
   1.201 +    item.len = input - mark.mMark;
   1.202 +    return true;
   1.203 +  }
   1.204 +
   1.205 +private:
   1.206 +  const uint8_t* input;
   1.207 +  const uint8_t* end;
   1.208 +
   1.209 +  Input(const Input&) /* = delete */;
   1.210 +  void operator=(const Input&) /* = delete */;
   1.211 +};
   1.212 +
   1.213 +inline Result
   1.214 +ExpectTagAndLength(Input& input, uint8_t expectedTag, uint8_t expectedLength)
   1.215 +{
   1.216 +  PR_ASSERT((expectedTag & 0x1F) != 0x1F); // high tag number form not allowed
   1.217 +  PR_ASSERT(expectedLength < 128); // must be a single-byte length
   1.218 +
   1.219 +  uint16_t tagAndLength;
   1.220 +  if (input.Read(tagAndLength) != Success) {
   1.221 +    return Failure;
   1.222 +  }
   1.223 +
   1.224 +  uint16_t expectedTagAndLength = static_cast<uint16_t>(expectedTag << 8);
   1.225 +  expectedTagAndLength |= expectedLength;
   1.226 +
   1.227 +  if (tagAndLength != expectedTagAndLength) {
   1.228 +    return Fail(SEC_ERROR_BAD_DER);
   1.229 +  }
   1.230 +
   1.231 +  return Success;
   1.232 +}
   1.233 +
   1.234 +Result
   1.235 +ExpectTagAndGetLength(Input& input, uint8_t expectedTag, uint16_t& length);
   1.236 +
   1.237 +inline Result
   1.238 +ExpectTagAndIgnoreLength(Input& input, uint8_t expectedTag)
   1.239 +{
   1.240 +  uint16_t ignored;
   1.241 +  return ExpectTagAndGetLength(input, expectedTag, ignored);
   1.242 +}
   1.243 +
   1.244 +inline Result
   1.245 +ExpectTagAndGetValue(Input& input, uint8_t tag, /*out*/ Input& value)
   1.246 +{
   1.247 +  uint16_t length;
   1.248 +  if (ExpectTagAndGetLength(input, tag, length) != Success) {
   1.249 +    return Failure;
   1.250 +  }
   1.251 +  return input.Skip(length, value);
   1.252 +}
   1.253 +
   1.254 +inline Result
   1.255 +End(Input& input)
   1.256 +{
   1.257 +  if (!input.AtEnd()) {
   1.258 +    return Fail(SEC_ERROR_BAD_DER);
   1.259 +  }
   1.260 +
   1.261 +  return Success;
   1.262 +}
   1.263 +
   1.264 +template <typename Decoder>
   1.265 +inline Result
   1.266 +Nested(Input& input, uint8_t tag, Decoder decoder)
   1.267 +{
   1.268 +  uint16_t length;
   1.269 +  if (ExpectTagAndGetLength(input, tag, length) != Success) {
   1.270 +    return Failure;
   1.271 +  }
   1.272 +
   1.273 +  Input nested;
   1.274 +  if (input.Skip(length, nested) != Success) {
   1.275 +    return Failure;
   1.276 +  }
   1.277 +
   1.278 +  if (decoder(nested) != Success) {
   1.279 +    return Failure;
   1.280 +  }
   1.281 +
   1.282 +  return End(nested);
   1.283 +}
   1.284 +
   1.285 +template <typename Decoder>
   1.286 +inline Result
   1.287 +Nested(Input& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder)
   1.288 +{
   1.289 +  // XXX: This doesn't work (in VS2010):
   1.290 +  // return Nested(input, outerTag, bind(Nested, _1, innerTag, decoder));
   1.291 +
   1.292 +  uint16_t length;
   1.293 +  if (ExpectTagAndGetLength(input, outerTag, length) != Success) {
   1.294 +    return Failure;
   1.295 +  }
   1.296 +  Input nestedInput;
   1.297 +  if (input.Skip(length, nestedInput) != Success) {
   1.298 +    return Failure;
   1.299 +  }
   1.300 +  if (Nested(nestedInput, innerTag, decoder) != Success) {
   1.301 +    return Failure;
   1.302 +  }
   1.303 +
   1.304 +  return End(nestedInput);
   1.305 +}
   1.306 +
   1.307 +// This can be used to decode constructs like this:
   1.308 +//
   1.309 +//     ...
   1.310 +//     foos SEQUENCE OF Foo,
   1.311 +//     ...
   1.312 +//     Foo ::= SEQUENCE {
   1.313 +//     }
   1.314 +//
   1.315 +// using a call like this:
   1.316 +//
   1.317 +//    rv = NestedOf(input, SEQEUENCE, SEQUENCE, bind(_1, Foo));
   1.318 +//
   1.319 +//    Result Foo(Input& input) {
   1.320 +//    }
   1.321 +//
   1.322 +// In this example, Foo will get called once for each element of foos.
   1.323 +//
   1.324 +template <typename Decoder>
   1.325 +inline Result
   1.326 +NestedOf(Input& input, uint8_t outerTag, uint8_t innerTag,
   1.327 +         EmptyAllowed mayBeEmpty, Decoder decoder)
   1.328 +{
   1.329 +  uint16_t responsesLength;
   1.330 +  if (ExpectTagAndGetLength(input, outerTag, responsesLength) != Success) {
   1.331 +    return Failure;
   1.332 +  }
   1.333 +
   1.334 +  Input inner;
   1.335 +  if (input.Skip(responsesLength, inner) != Success) {
   1.336 +    return Failure;
   1.337 +  }
   1.338 +
   1.339 +  if (inner.AtEnd()) {
   1.340 +    if (mayBeEmpty != MayBeEmpty) {
   1.341 +      return Fail(SEC_ERROR_BAD_DER);
   1.342 +    }
   1.343 +    return Success;
   1.344 +  }
   1.345 +
   1.346 +  do {
   1.347 +    if (Nested(inner, innerTag, decoder) != Success) {
   1.348 +      return Failure;
   1.349 +    }
   1.350 +  } while (!inner.AtEnd());
   1.351 +
   1.352 +  return Success;
   1.353 +}
   1.354 +
   1.355 +inline Result
   1.356 +Skip(Input& input, uint8_t tag)
   1.357 +{
   1.358 +  uint16_t length;
   1.359 +  if (ExpectTagAndGetLength(input, tag, length) != Success) {
   1.360 +    return Failure;
   1.361 +  }
   1.362 +  return input.Skip(length);
   1.363 +}
   1.364 +
   1.365 +inline Result
   1.366 +Skip(Input& input, uint8_t tag, /*out*/ SECItem& value)
   1.367 +{
   1.368 +  uint16_t length;
   1.369 +  if (ExpectTagAndGetLength(input, tag, length) != Success) {
   1.370 +    return Failure;
   1.371 +  }
   1.372 +  return input.Skip(length, value);
   1.373 +}
   1.374 +
   1.375 +// Universal types
   1.376 +
   1.377 +inline Result
   1.378 +Boolean(Input& input, /*out*/ bool& value)
   1.379 +{
   1.380 +  if (ExpectTagAndLength(input, BOOLEAN, 1) != Success) {
   1.381 +    return Failure;
   1.382 +  }
   1.383 +
   1.384 +  uint8_t intValue;
   1.385 +  if (input.Read(intValue) != Success) {
   1.386 +    return Failure;
   1.387 +  }
   1.388 +  switch (intValue) {
   1.389 +    case 0: value = false; return Success;
   1.390 +    case 0xFF: value = true; return Success;
   1.391 +    default:
   1.392 +      PR_SetError(SEC_ERROR_BAD_DER, 0);
   1.393 +      return Failure;
   1.394 +  }
   1.395 +}
   1.396 +
   1.397 +// This is for any BOOLEAN DEFAULT FALSE.
   1.398 +// (If it is present and false, this is a bad encoding.)
   1.399 +// TODO(bug 989518): For compatibility reasons, in some places we allow
   1.400 +// invalid encodings with the explicit default value.
   1.401 +inline Result
   1.402 +OptionalBoolean(Input& input, bool allowInvalidExplicitEncoding,
   1.403 +                /*out*/ bool& value)
   1.404 +{
   1.405 +  value = false;
   1.406 +  if (input.Peek(BOOLEAN)) {
   1.407 +    if (Boolean(input, value) != Success) {
   1.408 +      return Failure;
   1.409 +    }
   1.410 +    if (!allowInvalidExplicitEncoding && !value) {
   1.411 +      return Fail(SEC_ERROR_BAD_DER);
   1.412 +    }
   1.413 +  }
   1.414 +  return Success;
   1.415 +}
   1.416 +
   1.417 +inline Result
   1.418 +Enumerated(Input& input, uint8_t& value)
   1.419 +{
   1.420 +  if (ExpectTagAndLength(input, ENUMERATED | 0, 1) != Success) {
   1.421 +    return Failure;
   1.422 +  }
   1.423 +  return input.Read(value);
   1.424 +}
   1.425 +
   1.426 +inline Result
   1.427 +GeneralizedTime(Input& input, PRTime& time)
   1.428 +{
   1.429 +  uint16_t length;
   1.430 +  SECItem encoded;
   1.431 +  if (ExpectTagAndGetLength(input, GENERALIZED_TIME, length) != Success) {
   1.432 +    return Failure;
   1.433 +  }
   1.434 +  if (input.Skip(length, encoded)) {
   1.435 +    return Failure;
   1.436 +  }
   1.437 +  if (DER_GeneralizedTimeToTime(&time, &encoded) != SECSuccess) {
   1.438 +    return Failure;
   1.439 +  }
   1.440 +
   1.441 +  return Success;
   1.442 +}
   1.443 +
   1.444 +inline Result
   1.445 +Integer(Input& input, /*out*/ SECItem& value)
   1.446 +{
   1.447 +  uint16_t length;
   1.448 +  if (ExpectTagAndGetLength(input, INTEGER, length) != Success) {
   1.449 +    return Failure;
   1.450 +  }
   1.451 +
   1.452 +  if (input.Skip(length, value) != Success) {
   1.453 +    return Failure;
   1.454 +  }
   1.455 +
   1.456 +  if (value.len == 0) {
   1.457 +    return Fail(SEC_ERROR_BAD_DER);
   1.458 +  }
   1.459 +
   1.460 +  // Check for overly-long encodings. If the first byte is 0x00 then the high
   1.461 +  // bit on the second byte must be 1; otherwise the same *positive* value
   1.462 +  // could be encoded without the leading 0x00 byte. If the first byte is 0xFF
   1.463 +  // then the second byte must NOT have its high bit set; otherwise the same
   1.464 +  // *negative* value could be encoded without the leading 0xFF byte.
   1.465 +  if (value.len > 1) {
   1.466 +    if ((value.data[0] == 0x00 && (value.data[1] & 0x80) == 0) ||
   1.467 +        (value.data[0] == 0xff && (value.data[1] & 0x80) != 0)) {
   1.468 +      return Fail(SEC_ERROR_BAD_DER);
   1.469 +    }
   1.470 +  }
   1.471 +
   1.472 +  return Success;
   1.473 +}
   1.474 +
   1.475 +inline Result
   1.476 +Null(Input& input)
   1.477 +{
   1.478 +  return ExpectTagAndLength(input, NULLTag, 0);
   1.479 +}
   1.480 +
   1.481 +template <uint16_t Len>
   1.482 +Result
   1.483 +OID(Input& input, const uint8_t (&expectedOid)[Len])
   1.484 +{
   1.485 +  if (ExpectTagAndLength(input, OIDTag, Len) != Success) {
   1.486 +    return Failure;
   1.487 +  }
   1.488 +
   1.489 +  return input.Expect(expectedOid, Len);
   1.490 +}
   1.491 +
   1.492 +// PKI-specific types
   1.493 +
   1.494 +// AlgorithmIdentifier  ::=  SEQUENCE  {
   1.495 +//         algorithm               OBJECT IDENTIFIER,
   1.496 +//         parameters              ANY DEFINED BY algorithm OPTIONAL  }
   1.497 +inline Result
   1.498 +AlgorithmIdentifier(Input& input, SECAlgorithmID& algorithmID)
   1.499 +{
   1.500 +  if (Skip(input, OIDTag, algorithmID.algorithm) != Success) {
   1.501 +    return Failure;
   1.502 +  }
   1.503 +  algorithmID.parameters.data = nullptr;
   1.504 +  algorithmID.parameters.len = 0;
   1.505 +  if (input.AtEnd()) {
   1.506 +    return Success;
   1.507 +  }
   1.508 +  return Null(input);
   1.509 +}
   1.510 +
   1.511 +inline Result
   1.512 +CertificateSerialNumber(Input& input, /*out*/ SECItem& serialNumber)
   1.513 +{
   1.514 +  // http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
   1.515 +  //
   1.516 +  // * "The serial number MUST be a positive integer assigned by the CA to
   1.517 +  //   each certificate."
   1.518 +  // * "Certificate users MUST be able to handle serialNumber values up to 20
   1.519 +  //   octets. Conforming CAs MUST NOT use serialNumber values longer than 20
   1.520 +  //   octets."
   1.521 +  // * "Note: Non-conforming CAs may issue certificates with serial numbers
   1.522 +  //   that are negative or zero.  Certificate users SHOULD be prepared to
   1.523 +  //   gracefully handle such certificates."
   1.524 +
   1.525 +  return Integer(input, serialNumber);
   1.526 +}
   1.527 +
   1.528 +// x.509 and OCSP both use this same version numbering scheme, though OCSP
   1.529 +// only supports v1.
   1.530 +enum Version { v1 = 0, v2 = 1, v3 = 2 };
   1.531 +
   1.532 +// X.509 Certificate and OCSP ResponseData both use this
   1.533 +// "[0] EXPLICIT Version DEFAULT <defaultVersion>" construct, but with
   1.534 +// different default versions.
   1.535 +inline Result
   1.536 +OptionalVersion(Input& input, /*out*/ uint8_t& version)
   1.537 +{
   1.538 +  const uint8_t tag = CONTEXT_SPECIFIC | CONSTRUCTED | 0;
   1.539 +  if (!input.Peek(tag)) {
   1.540 +    version = v1;
   1.541 +    return Success;
   1.542 +  }
   1.543 +  if (ExpectTagAndLength(input, tag, 3) != Success) {
   1.544 +    return Failure;
   1.545 +  }
   1.546 +  if (ExpectTagAndLength(input, INTEGER, 1) != Success) {
   1.547 +    return Failure;
   1.548 +  }
   1.549 +  if (input.Read(version) != Success) {
   1.550 +    return Failure;
   1.551 +  }
   1.552 +  if (version & 0x80) { // negative
   1.553 +    return Fail(SEC_ERROR_BAD_DER);
   1.554 +  }
   1.555 +  return Success;
   1.556 +}
   1.557 +
   1.558 +} } } // namespace mozilla::pkix::der
   1.559 +
   1.560 +#endif // mozilla_pkix__pkixder_h

mercurial