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