mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1038837: Factor out mozilla::pkix::Input into a separate header, r=mmc
--HG-- rename : security/pkix/lib/pkixder.h => security/pkix/include/pkix/Input.h rename : security/pkix/lib/pkixutil.h => security/pkix/include/pkix/Result.h extra : rebase_source : 09bac0a183932f721cdfd32936595867e4dc26ce
This commit is contained in:
parent
96c220acca
commit
8483b958ad
240
security/pkix/include/pkix/Input.h
Normal file
240
security/pkix/include/pkix/Input.h
Normal file
@ -0,0 +1,240 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef mozilla_pkix__Input_h
|
||||
#define mozilla_pkix__Input_h
|
||||
|
||||
#include "pkix/nullptr.h"
|
||||
#include "pkix/Result.h"
|
||||
#include "stdint.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
// Expect* functions advance the input mark and return Success if the input
|
||||
// matches the given criteria; they fail with the input mark in an undefined
|
||||
// state if the input does not match the criteria.
|
||||
//
|
||||
// Match* functions advance the input mark and return true if the input matches
|
||||
// the given criteria; they return false without changing the input mark if the
|
||||
// input does not match the criteria.
|
||||
//
|
||||
// Skip* functions unconditionally advance the input mark and return Success if
|
||||
// they are able to do so; otherwise they fail with the input mark in an
|
||||
// undefined state.
|
||||
class Input
|
||||
{
|
||||
public:
|
||||
Input()
|
||||
: input(nullptr)
|
||||
, end(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Result Init(const uint8_t* data, size_t len)
|
||||
{
|
||||
if (input) {
|
||||
// already initialized
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
if (!data || len > 0xffffu) {
|
||||
// input too large
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
|
||||
// XXX: this->input = input bug was not caught by tests! Why not?
|
||||
// this->end = end bug was not caught by tests! Why not?
|
||||
this->input = data;
|
||||
this->end = data + len;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Expect(const uint8_t* expected, uint16_t expectedLen)
|
||||
{
|
||||
Result rv = EnsureLength(expectedLen);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (memcmp(input, expected, expectedLen)) {
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
input += expectedLen;
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool Peek(uint8_t expectedByte) const
|
||||
{
|
||||
return input < end && *input == expectedByte;
|
||||
}
|
||||
|
||||
Result Read(uint8_t& out)
|
||||
{
|
||||
Result rv = EnsureLength(1);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
out = *input++;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Read(uint16_t& out)
|
||||
{
|
||||
Result rv = EnsureLength(2);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
out = *input++;
|
||||
out <<= 8u;
|
||||
out |= *input++;
|
||||
return Success;
|
||||
}
|
||||
|
||||
template <uint16_t N>
|
||||
bool MatchRest(const uint8_t (&toMatch)[N])
|
||||
{
|
||||
// Normally we use EnsureLength which compares (input + len < end), but
|
||||
// here we want to be sure that there is nothing following the matched
|
||||
// bytes
|
||||
if (static_cast<size_t>(end - input) != N) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(input, toMatch, N)) {
|
||||
return false;
|
||||
}
|
||||
input += N;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <uint16_t N>
|
||||
bool MatchTLV(uint8_t tag, uint16_t len, const uint8_t (&value)[N])
|
||||
{
|
||||
static_assert(N <= 127, "buffer larger than largest length supported");
|
||||
if (len > N) {
|
||||
PR_NOT_REACHED("overflow prevented dynamically instead of statically");
|
||||
return false;
|
||||
}
|
||||
uint16_t totalLen = 2u + len;
|
||||
if (EnsureLength(totalLen) != Success) {
|
||||
return false;
|
||||
}
|
||||
if (*input != tag) {
|
||||
return false;
|
||||
}
|
||||
if (*(input + 1) != len) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(input + 2, value, len)) {
|
||||
return false;
|
||||
}
|
||||
input += totalLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len, Input& skippedInput)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
rv = skippedInput.Init(input, len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len, SECItem& skippedItem)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
skippedItem.type = siBuffer;
|
||||
skippedItem.data = const_cast<uint8_t*>(input);
|
||||
skippedItem.len = len;
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
void SkipToEnd()
|
||||
{
|
||||
input = end;
|
||||
}
|
||||
|
||||
Result EnsureLength(uint16_t len)
|
||||
{
|
||||
if (static_cast<size_t>(end - input) < len) {
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool AtEnd() const { return input == end; }
|
||||
|
||||
class Mark
|
||||
{
|
||||
private:
|
||||
friend class Input;
|
||||
Mark(const Input& input, const uint8_t* mark) : input(input), mark(mark) { }
|
||||
const Input& input;
|
||||
const uint8_t* const mark;
|
||||
void operator=(const Mark&) /* = delete */;
|
||||
};
|
||||
|
||||
Mark GetMark() const { return Mark(*this, input); }
|
||||
|
||||
Result GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
|
||||
{
|
||||
if (&mark.input != this || mark.mark > input) {
|
||||
PR_NOT_REACHED("invalid mark");
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
item.type = type;
|
||||
item.data = const_cast<uint8_t*>(mark.mark);
|
||||
item.len = static_cast<decltype(item.len)>(input - mark.mark);
|
||||
return Success;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t* input;
|
||||
const uint8_t* end;
|
||||
|
||||
Input(const Input&) /* = delete */;
|
||||
void operator=(const Input&) /* = delete */;
|
||||
};
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
#endif // mozilla_pkix__Input_h
|
@ -76,6 +76,14 @@ MapSECStatus(SECStatus srv)
|
||||
return RecoverableError;
|
||||
}
|
||||
|
||||
inline Result
|
||||
Fail(PRErrorCode errorCode)
|
||||
{
|
||||
PR_ASSERT(errorCode != 0);
|
||||
PR_SetError(errorCode, 0);
|
||||
return mozilla::pkix::MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
#endif // mozilla_pkix__Result_h
|
||||
|
@ -37,17 +37,17 @@ BackCert::Init()
|
||||
// signatureAlgorithm AlgorithmIdentifier,
|
||||
// signatureValue BIT STRING }
|
||||
|
||||
der::Input tbsCertificate;
|
||||
Input tbsCertificate;
|
||||
|
||||
// The scope of |input| and |certificate| are limited to this block so we
|
||||
// don't accidentally confuse them for tbsCertificate later.
|
||||
{
|
||||
der::Input input;
|
||||
Input input;
|
||||
rv = input.Init(der.data, der.len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
der::Input certificate;
|
||||
Input certificate;
|
||||
rv = der::ExpectTagAndGetValue(input, der::SEQUENCE, certificate);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
@ -163,7 +163,7 @@ BackCert::Init()
|
||||
}
|
||||
|
||||
Result
|
||||
BackCert::RememberExtension(der::Input& extnID, const SECItem& extnValue,
|
||||
BackCert::RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
/*out*/ bool& understood)
|
||||
{
|
||||
understood = false;
|
||||
@ -243,11 +243,11 @@ BackCert::RememberExtension(der::Input& extnID, const SECItem& extnValue,
|
||||
// Don't allow an empty value for any extension we understand. This way, we
|
||||
// can test out->len to check for duplicates.
|
||||
if (extnValue.len == 0) {
|
||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
if (out->len != 0) {
|
||||
// Duplicate extension
|
||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
*out = extnValue;
|
||||
understood = true;
|
||||
|
@ -35,7 +35,7 @@ namespace mozilla { namespace pkix {
|
||||
Result
|
||||
CheckValidity(const SECItem& encodedValidity, PRTime time)
|
||||
{
|
||||
der::Input validity;
|
||||
Input validity;
|
||||
if (validity.Init(encodedValidity.data, encodedValidity.len) != Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
@ -87,11 +87,11 @@ CheckKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedKeyUsage,
|
||||
return Success;
|
||||
}
|
||||
|
||||
der::Input input;
|
||||
Input input;
|
||||
if (input.Init(encodedKeyUsage->data, encodedKeyUsage->len) != Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
|
||||
}
|
||||
der::Input value;
|
||||
Input value;
|
||||
if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
|
||||
}
|
||||
@ -203,7 +203,7 @@ bool CertPolicyId::IsAnyPolicy() const
|
||||
// policyQualifiers SEQUENCE SIZE (1..MAX) OF
|
||||
// PolicyQualifierInfo OPTIONAL }
|
||||
inline Result
|
||||
CheckPolicyInformation(der::Input& input, EndEntityOrCA endEntityOrCA,
|
||||
CheckPolicyInformation(Input& input, EndEntityOrCA endEntityOrCA,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*in/out*/ bool& found)
|
||||
{
|
||||
@ -271,7 +271,7 @@ CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
|
||||
|
||||
bool found = false;
|
||||
|
||||
der::Input input;
|
||||
Input input;
|
||||
if (input.Init(encodedCertificatePolicies->data,
|
||||
encodedCertificatePolicies->len) != Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
|
||||
@ -297,7 +297,7 @@ static const long UNLIMITED_PATH_LEN = -1; // must be less than zero
|
||||
// cA BOOLEAN DEFAULT FALSE,
|
||||
// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
||||
static Result
|
||||
DecodeBasicConstraints(der::Input& input, /*out*/ bool& isCA,
|
||||
DecodeBasicConstraints(Input& input, /*out*/ bool& isCA,
|
||||
/*out*/ long& pathLenConstraint)
|
||||
{
|
||||
// TODO(bug 989518): cA is by default false. According to DER, default
|
||||
@ -307,15 +307,15 @@ DecodeBasicConstraints(der::Input& input, /*out*/ bool& isCA,
|
||||
// enforce this yet (hence passing true for allowInvalidExplicitEncoding
|
||||
// to der::OptionalBoolean).
|
||||
if (der::OptionalBoolean(input, true, isCA) != Success) {
|
||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
|
||||
// TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT
|
||||
// be included (as per RFC 5280 section 4.2.1.9), but for compatibility
|
||||
// reasons, we don't check this for now.
|
||||
if (OptionalInteger(input, UNLIMITED_PATH_LEN, pathLenConstraint)
|
||||
if (der::OptionalInteger(input, UNLIMITED_PATH_LEN, pathLenConstraint)
|
||||
!= Success) {
|
||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
|
||||
return Success;
|
||||
@ -332,7 +332,7 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
|
||||
long pathLenConstraint = UNLIMITED_PATH_LEN;
|
||||
|
||||
if (encodedBasicConstraints) {
|
||||
der::Input input;
|
||||
Input input;
|
||||
if (input.Init(encodedBasicConstraints->data,
|
||||
encodedBasicConstraints->len) != Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
@ -462,7 +462,7 @@ CheckNameConstraints(const SECItem& encodedNameConstraints,
|
||||
// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage)
|
||||
|
||||
static Result
|
||||
MatchEKU(der::Input& value, KeyPurposeId requiredEKU,
|
||||
MatchEKU(Input& value, KeyPurposeId requiredEKU,
|
||||
EndEntityOrCA endEntityOrCA, /*in/out*/ bool& found,
|
||||
/*in/out*/ bool& foundOCSPSigning)
|
||||
{
|
||||
@ -522,11 +522,11 @@ MatchEKU(der::Input& value, KeyPurposeId requiredEKU,
|
||||
|
||||
case KeyPurposeId::anyExtendedKeyUsage:
|
||||
PR_NOT_REACHED("anyExtendedKeyUsage should start with found==true");
|
||||
return der::Fail(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return Fail(SEC_ERROR_LIBRARY_FAILURE);
|
||||
|
||||
default:
|
||||
PR_NOT_REACHED("unrecognized EKU");
|
||||
return der::Fail(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return Fail(SEC_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,7 +559,7 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
if (encodedExtendedKeyUsage) {
|
||||
bool found = requiredEKU == KeyPurposeId::anyExtendedKeyUsage;
|
||||
|
||||
der::Input input;
|
||||
Input input;
|
||||
if (input.Init(encodedExtendedKeyUsage->data,
|
||||
encodedExtendedKeyUsage->len) != Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
|
||||
|
@ -28,14 +28,6 @@
|
||||
|
||||
namespace mozilla { namespace pkix { namespace der {
|
||||
|
||||
// not inline
|
||||
Result
|
||||
Fail(PRErrorCode errorCode)
|
||||
{
|
||||
PR_SetError(errorCode, 0);
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Too complicated to be inline
|
||||
|
@ -38,12 +38,10 @@
|
||||
// undefined state.
|
||||
|
||||
#include "pkix/enumclass.h"
|
||||
#include "pkix/Input.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkix/Result.h"
|
||||
#include "prtime.h"
|
||||
#include "secerr.h"
|
||||
#include "secoidt.h"
|
||||
#include "stdint.h"
|
||||
|
||||
typedef struct CERTSignedDataStr CERTSignedData;
|
||||
|
||||
@ -78,201 +76,6 @@ enum Tag
|
||||
|
||||
MOZILLA_PKIX_ENUM_CLASS EmptyAllowed { No = 0, Yes = 1 };
|
||||
|
||||
Result Fail(PRErrorCode errorCode);
|
||||
|
||||
class Input
|
||||
{
|
||||
public:
|
||||
Input()
|
||||
: input(nullptr)
|
||||
, end(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Result Init(const uint8_t* data, size_t len)
|
||||
{
|
||||
if (input) {
|
||||
// already initialized
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
if (!data || len > 0xffffu) {
|
||||
// input too large
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
|
||||
// XXX: this->input = input bug was not caught by tests! Why not?
|
||||
// this->end = end bug was not caught by tests! Why not?
|
||||
this->input = data;
|
||||
this->end = data + len;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Expect(const uint8_t* expected, uint16_t expectedLen)
|
||||
{
|
||||
Result rv = EnsureLength(expectedLen);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (memcmp(input, expected, expectedLen)) {
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
input += expectedLen;
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool Peek(uint8_t expectedByte) const
|
||||
{
|
||||
return input < end && *input == expectedByte;
|
||||
}
|
||||
|
||||
Result Read(uint8_t& out)
|
||||
{
|
||||
Result rv = EnsureLength(1);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
out = *input++;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Read(uint16_t& out)
|
||||
{
|
||||
Result rv = EnsureLength(2);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
out = *input++;
|
||||
out <<= 8u;
|
||||
out |= *input++;
|
||||
return Success;
|
||||
}
|
||||
|
||||
template <uint16_t N>
|
||||
bool MatchRest(const uint8_t (&toMatch)[N])
|
||||
{
|
||||
// Normally we use EnsureLength which compares (input + len < end), but
|
||||
// here we want to be sure that there is nothing following the matched
|
||||
// bytes
|
||||
if (static_cast<size_t>(end - input) != N) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(input, toMatch, N)) {
|
||||
return false;
|
||||
}
|
||||
input += N;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <uint16_t N>
|
||||
bool MatchTLV(uint8_t tag, uint16_t len, const uint8_t (&value)[N])
|
||||
{
|
||||
static_assert(N <= 127, "buffer larger than largest length supported");
|
||||
if (len > N) {
|
||||
PR_NOT_REACHED("overflow prevented dynamically instead of statically");
|
||||
return false;
|
||||
}
|
||||
uint16_t totalLen = 2u + len;
|
||||
if (EnsureLength(totalLen) != Success) {
|
||||
return false;
|
||||
}
|
||||
if (*input != tag) {
|
||||
return false;
|
||||
}
|
||||
if (*(input + 1) != len) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(input + 2, value, len)) {
|
||||
return false;
|
||||
}
|
||||
input += totalLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len, Input& skippedInput)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
rv = skippedInput.Init(input, len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len, SECItem& skippedItem)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
skippedItem.type = siBuffer;
|
||||
skippedItem.data = const_cast<uint8_t*>(input);
|
||||
skippedItem.len = len;
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
void SkipToEnd()
|
||||
{
|
||||
input = end;
|
||||
}
|
||||
|
||||
Result EnsureLength(uint16_t len)
|
||||
{
|
||||
if (static_cast<size_t>(end - input) < len) {
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool AtEnd() const { return input == end; }
|
||||
|
||||
class Mark
|
||||
{
|
||||
private:
|
||||
friend class Input;
|
||||
Mark(const Input& input, const uint8_t* mark) : input(input), mark(mark) { }
|
||||
const Input& input;
|
||||
const uint8_t* const mark;
|
||||
void operator=(const Mark&) /* = delete */;
|
||||
};
|
||||
|
||||
Mark GetMark() const { return Mark(*this, input); }
|
||||
|
||||
Result GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
|
||||
{
|
||||
if (&mark.input != this || mark.mark > input) {
|
||||
PR_NOT_REACHED("invalid mark");
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
item.type = type;
|
||||
item.data = const_cast<uint8_t*>(mark.mark);
|
||||
item.len = static_cast<decltype(item.len)>(input - mark.mark);
|
||||
return Success;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t* input;
|
||||
const uint8_t* end;
|
||||
|
||||
Input(const Input&) /* = delete */;
|
||||
void operator=(const Input&) /* = delete */;
|
||||
};
|
||||
|
||||
inline Result
|
||||
ExpectTagAndLength(Input& input, uint8_t expectedTag, uint8_t expectedLength)
|
||||
{
|
||||
|
@ -153,19 +153,19 @@ MOZILLA_PKIX_ENUM_CLASS ResponderIDType : uint8_t
|
||||
byKey = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 2
|
||||
};
|
||||
|
||||
static inline Result OCSPResponse(der::Input&, Context&);
|
||||
static inline Result ResponseBytes(der::Input&, Context&);
|
||||
static inline Result BasicResponse(der::Input&, Context&);
|
||||
static inline Result OCSPResponse(Input&, Context&);
|
||||
static inline Result ResponseBytes(Input&, Context&);
|
||||
static inline Result BasicResponse(Input&, Context&);
|
||||
static inline Result ResponseData(
|
||||
der::Input& tbsResponseData,
|
||||
Input& tbsResponseData,
|
||||
Context& context,
|
||||
const SignedDataWithSignature& signedResponseData,
|
||||
/*const*/ SECItem* certs, size_t numCerts);
|
||||
static inline Result SingleResponse(der::Input& input, Context& context);
|
||||
static Result ExtensionNotUnderstood(der::Input& extnID,
|
||||
static inline Result SingleResponse(Input& input, Context& context);
|
||||
static Result ExtensionNotUnderstood(Input& extnID,
|
||||
const SECItem& extnValue,
|
||||
/*out*/ bool& understood);
|
||||
static inline Result CertID(der::Input& input,
|
||||
static inline Result CertID(Input& input,
|
||||
const Context& context,
|
||||
/*out*/ bool& match);
|
||||
static Result MatchKeyHash(TrustDomain& trustDomain,
|
||||
@ -195,7 +195,7 @@ MatchResponderID(TrustDomain& trustDomain,
|
||||
|
||||
case ResponderIDType::byKey:
|
||||
{
|
||||
der::Input responderID;
|
||||
Input responderID;
|
||||
Result rv = responderID.Init(responderIDItem.data, responderIDItem.len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
@ -308,7 +308,7 @@ VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
// Always initialize this to something reasonable.
|
||||
expired = false;
|
||||
|
||||
der::Input input;
|
||||
Input input;
|
||||
if (input.Init(encodedResponse.data, encodedResponse.len) != Success) {
|
||||
SetErrorToMalformedResponseOnBadDERError();
|
||||
return SECFailure;
|
||||
@ -354,7 +354,7 @@ VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
// responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
|
||||
//
|
||||
static inline Result
|
||||
OCSPResponse(der::Input& input, Context& context)
|
||||
OCSPResponse(Input& input, Context& context)
|
||||
{
|
||||
// OCSPResponseStatus ::= ENUMERATED {
|
||||
// successful (0), -- Response has valid confirmations
|
||||
@ -373,12 +373,12 @@ OCSPResponse(der::Input& input, Context& context)
|
||||
}
|
||||
switch (responseStatus) {
|
||||
case 0: break; // successful
|
||||
case 1: return der::Fail(SEC_ERROR_OCSP_MALFORMED_REQUEST);
|
||||
case 2: return der::Fail(SEC_ERROR_OCSP_SERVER_ERROR);
|
||||
case 3: return der::Fail(SEC_ERROR_OCSP_TRY_SERVER_LATER);
|
||||
case 5: return der::Fail(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
|
||||
case 6: return der::Fail(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
|
||||
default: return der::Fail(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
|
||||
case 1: return Fail(SEC_ERROR_OCSP_MALFORMED_REQUEST);
|
||||
case 2: return Fail(SEC_ERROR_OCSP_SERVER_ERROR);
|
||||
case 3: return Fail(SEC_ERROR_OCSP_TRY_SERVER_LATER);
|
||||
case 5: return Fail(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
|
||||
case 6: return Fail(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
|
||||
default: return Fail(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
|
||||
}
|
||||
|
||||
return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
|
||||
@ -389,7 +389,7 @@ OCSPResponse(der::Input& input, Context& context)
|
||||
// responseType OBJECT IDENTIFIER,
|
||||
// response OCTET STRING }
|
||||
static inline Result
|
||||
ResponseBytes(der::Input& input, Context& context)
|
||||
ResponseBytes(Input& input, Context& context)
|
||||
{
|
||||
static const uint8_t id_pkix_ocsp_basic[] = {
|
||||
0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
|
||||
@ -410,9 +410,9 @@ ResponseBytes(der::Input& input, Context& context)
|
||||
// signature BIT STRING,
|
||||
// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
|
||||
Result
|
||||
BasicResponse(der::Input& input, Context& context)
|
||||
BasicResponse(Input& input, Context& context)
|
||||
{
|
||||
der::Input tbsResponseData;
|
||||
Input tbsResponseData;
|
||||
SignedDataWithSignature signedData;
|
||||
Result rv = der::SignedData(input, tbsResponseData, signedData);
|
||||
if (rv != Success) {
|
||||
@ -448,7 +448,7 @@ BasicResponse(der::Input& input, Context& context)
|
||||
// sequence of certificates
|
||||
while (!input.AtEnd()) {
|
||||
if (numCerts == PR_ARRAY_SIZE(certs)) {
|
||||
return der::Fail(SEC_ERROR_BAD_DER);
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
|
||||
rv = der::ExpectTagAndGetTLV(input, der::SEQUENCE, certs[numCerts]);
|
||||
@ -469,7 +469,7 @@ BasicResponse(der::Input& input, Context& context)
|
||||
// responses SEQUENCE OF SingleResponse,
|
||||
// responseExtensions [1] EXPLICIT Extensions OPTIONAL }
|
||||
static inline Result
|
||||
ResponseData(der::Input& input, Context& context,
|
||||
ResponseData(Input& input, Context& context,
|
||||
const SignedDataWithSignature& signedResponseData,
|
||||
/*const*/ SECItem* certs, size_t numCerts)
|
||||
{
|
||||
@ -480,7 +480,7 @@ ResponseData(der::Input& input, Context& context,
|
||||
}
|
||||
if (version != der::Version::v1) {
|
||||
// TODO: more specific error code for bad version?
|
||||
return der::Fail(SEC_ERROR_BAD_DER);
|
||||
return Fail(SEC_ERROR_BAD_DER);
|
||||
}
|
||||
|
||||
// ResponderID ::= CHOICE {
|
||||
@ -491,8 +491,8 @@ ResponseData(der::Input& input, Context& context,
|
||||
= input.Peek(static_cast<uint8_t>(ResponderIDType::byName))
|
||||
? ResponderIDType::byName
|
||||
: ResponderIDType::byKey;
|
||||
rv = ExpectTagAndGetValue(input, static_cast<uint8_t>(responderIDType),
|
||||
responderID);
|
||||
rv = der::ExpectTagAndGetValue(input, static_cast<uint8_t>(responderIDType),
|
||||
responderID);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -538,7 +538,7 @@ ResponseData(der::Input& input, Context& context,
|
||||
// CrlEntryExtensions, ...}
|
||||
// } OPTIONAL }
|
||||
static inline Result
|
||||
SingleResponse(der::Input& input, Context& context)
|
||||
SingleResponse(Input& input, Context& context)
|
||||
{
|
||||
bool match = false;
|
||||
Result rv = der::Nested(input, der::SEQUENCE,
|
||||
@ -567,7 +567,8 @@ SingleResponse(der::Input& input, Context& context)
|
||||
// * revoked overrides good and unknown
|
||||
// * good overrides unknown
|
||||
if (input.Peek(static_cast<uint8_t>(CertStatus::Good))) {
|
||||
rv = ExpectTagAndLength(input, static_cast<uint8_t>(CertStatus::Good), 0);
|
||||
rv = der::ExpectTagAndLength(input, static_cast<uint8_t>(CertStatus::Good),
|
||||
0);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -586,8 +587,8 @@ SingleResponse(der::Input& input, Context& context)
|
||||
}
|
||||
context.certStatus = CertStatus::Revoked;
|
||||
} else {
|
||||
rv = ExpectTagAndLength(input, static_cast<uint8_t>(CertStatus::Unknown),
|
||||
0);
|
||||
rv = der::ExpectTagAndLength(input,
|
||||
static_cast<uint8_t>(CertStatus::Unknown), 0);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -610,7 +611,7 @@ SingleResponse(der::Input& input, Context& context)
|
||||
}
|
||||
|
||||
if (thisUpdate > context.time + SLOP) {
|
||||
return der::Fail(SEC_ERROR_OCSP_FUTURE_RESPONSE);
|
||||
return Fail(SEC_ERROR_OCSP_FUTURE_RESPONSE);
|
||||
}
|
||||
|
||||
PRTime notAfter;
|
||||
@ -625,7 +626,7 @@ SingleResponse(der::Input& input, Context& context)
|
||||
}
|
||||
|
||||
if (nextUpdate < thisUpdate) {
|
||||
return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
|
||||
return Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
|
||||
}
|
||||
if (nextUpdate - thisUpdate <= maxLifetime) {
|
||||
notAfter = nextUpdate;
|
||||
@ -639,7 +640,7 @@ SingleResponse(der::Input& input, Context& context)
|
||||
}
|
||||
|
||||
if (context.time < SLOP) { // prevent underflow
|
||||
return der::Fail(SEC_ERROR_INVALID_ARGS);
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
if (context.time - SLOP > notAfter) {
|
||||
@ -669,7 +670,7 @@ SingleResponse(der::Input& input, Context& context)
|
||||
// issuerKeyHash OCTET STRING, -- Hash of issuer's public key
|
||||
// serialNumber CertificateSerialNumber }
|
||||
static inline Result
|
||||
CertID(der::Input& input, const Context& context, /*out*/ bool& match)
|
||||
CertID(Input& input, const Context& context, /*out*/ bool& match)
|
||||
{
|
||||
match = false;
|
||||
|
||||
@ -719,7 +720,7 @@ CertID(der::Input& input, const Context& context, /*out*/ bool& match)
|
||||
}
|
||||
|
||||
if (issuerNameHash.len != TrustDomain::DIGEST_LENGTH) {
|
||||
return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
|
||||
return Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
|
||||
}
|
||||
|
||||
// From http://tools.ietf.org/html/rfc6960#section-4.1.1:
|
||||
@ -782,12 +783,12 @@ KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
|
||||
// algorithm AlgorithmIdentifier,
|
||||
// subjectPublicKey BIT STRING }
|
||||
|
||||
der::Input spki;
|
||||
Input spki;
|
||||
|
||||
{
|
||||
// The scope of input is limited to reduce the possibility of confusing it
|
||||
// with spki in places we need to be using spki below.
|
||||
der::Input input;
|
||||
Input input;
|
||||
if (input.Init(subjectPublicKeyInfo.data, subjectPublicKeyInfo.len)
|
||||
!= Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
@ -831,7 +832,7 @@ KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
|
||||
}
|
||||
|
||||
Result
|
||||
ExtensionNotUnderstood(der::Input& /*extnID*/, const SECItem& /*extnValue*/,
|
||||
ExtensionNotUnderstood(Input& /*extnID*/, const SECItem& /*extnValue*/,
|
||||
/*out*/ bool& understood)
|
||||
{
|
||||
understood = false;
|
||||
|
@ -25,7 +25,6 @@
|
||||
#ifndef mozilla_pkix__pkixutil_h
|
||||
#define mozilla_pkix__pkixutil_h
|
||||
|
||||
#include "pkix/Result.h"
|
||||
#include "pkixder.h"
|
||||
#include "prerror.h"
|
||||
#include "seccomon.h"
|
||||
@ -144,7 +143,7 @@ private:
|
||||
NonOwningSECItem nameConstraints;
|
||||
NonOwningSECItem subjectAltName;
|
||||
|
||||
Result RememberExtension(der::Input& extnID, const SECItem& extnValue,
|
||||
Result RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
/*out*/ bool& understood);
|
||||
|
||||
BackCert(const BackCert&) /* = delete */;
|
||||
@ -171,7 +170,7 @@ public:
|
||||
Result Append(const SECItem& der)
|
||||
{
|
||||
if (numItems >= MAX_LENGTH) {
|
||||
return Fail(RecoverableError, SEC_ERROR_INVALID_ARGS);
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
items[numItems] = &der;
|
||||
++numItems;
|
||||
|
@ -163,10 +163,10 @@ public:
|
||||
PR_ASSERT(item->data);
|
||||
|
||||
if (numItems >= MaxSequenceItems) {
|
||||
return der::Fail(SEC_ERROR_INVALID_ARGS);
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
if (length + item->len > 65535) {
|
||||
return der::Fail(SEC_ERROR_INVALID_ARGS);
|
||||
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
contents[numItems] = item;
|
||||
|
Loading…
Reference in New Issue
Block a user