Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
roytam1 2021-03-16 10:32:41 +08:00
commit 4992a2fd18
38 changed files with 924 additions and 1420 deletions

View file

@ -292,6 +292,7 @@ AppTrustDomain::DigestBuf(Input item,
Result Result
AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
/*optional*/ const Input*,
/*optional*/ const Input*, /*optional*/ const Input*,
/*optional*/ const Input*) /*optional*/ const Input*)
{ {
@ -301,7 +302,8 @@ AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
} }
Result Result
AppTrustDomain::IsChainValid(const DERArray& certChain, Time time) AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
const CertPolicyId& requiredPolicy)
{ {
SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain, SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
mCertChain); mCertChain);

View file

@ -37,9 +37,11 @@ public:
mozilla::pkix::Time time, mozilla::pkix::Time time,
mozilla::pkix::Duration validityDuration, mozilla::pkix::Duration validityDuration,
/*optional*/ const mozilla::pkix::Input* stapledOCSPresponse, /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse,
/*optional*/ const mozilla::pkix::Input* aiaExtension) override; /*optional*/ const mozilla::pkix::Input* aiaExtension,
/*optional*/ const mozilla::pkix::Input* sctExtension) override;
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) override; mozilla::pkix::Time time,
const mozilla::pkix::CertPolicyId& requiredPolicy) override;
virtual Result CheckSignatureDigestAlgorithm( virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg, mozilla::pkix::DigestAlgorithm digestAlg,
mozilla::pkix::EndEntityOrCA endEntityOrCA, mozilla::pkix::EndEntityOrCA endEntityOrCA,

View file

@ -10,7 +10,7 @@
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "pkix/pkixnss.h" #include "pkix/pkixnss.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace ct { namespace mozilla { namespace ct {
@ -42,12 +42,12 @@ public:
} }
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
const Input*, const Input*) override const Input*, const Input*, const Input*) override
{ {
return Result::FATAL_ERROR_LIBRARY_FAILURE; return Result::FATAL_ERROR_LIBRARY_FAILURE;
} }
Result IsChainValid(const DERArray&, Time) override Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
{ {
return Result::FATAL_ERROR_LIBRARY_FAILURE; return Result::FATAL_ERROR_LIBRARY_FAILURE;
} }

View file

@ -13,7 +13,7 @@
#include "mozilla/RangedPtr.h" #include "mozilla/RangedPtr.h"
#include "mozilla/Vector.h" #include "mozilla/Vector.h"
#include "pkix/pkixnss.h" #include "pkix/pkixnss.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace ct { namespace mozilla { namespace ct {

View file

@ -348,7 +348,8 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
const CertID& certID, Time time, const CertID& certID, Time time,
Duration validityDuration, Duration validityDuration,
/*optional*/ const Input* stapledOCSPResponse, /*optional*/ const Input* stapledOCSPResponse,
/*optional*/ const Input* aiaExtension) /*optional*/ const Input* aiaExtension,
/*optional*/ const Input* sctExtension)
{ {
// Actively distrusted certificates will have already been blocked by // Actively distrusted certificates will have already been blocked by
// GetCertTrust. // GetCertTrust.
@ -788,7 +789,9 @@ CheckForStartComOrWoSign(const UniqueCERTCertList& certChain)
} }
Result Result
NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time) NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray,
Time time,
const CertPolicyId& requiredPolicy)
{ {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain: IsChainValid")); ("NSSCertDBTrustDomain: IsChainValid"));

View file

@ -134,11 +134,13 @@ public:
mozilla::pkix::Time time, mozilla::pkix::Time time,
mozilla::pkix::Duration validityDuration, mozilla::pkix::Duration validityDuration,
/*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse,
/*optional*/ const mozilla::pkix::Input* aiaExtension) /*optional*/ const mozilla::pkix::Input* aiaExtension,
/*optional*/ const mozilla::pkix::Input* sctExtension)
override; override;
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) override; mozilla::pkix::Time time,
const mozilla::pkix::CertPolicyId& requiredPolicy) override;
virtual void NoteAuxiliaryExtension( virtual void NoteAuxiliaryExtension(
mozilla::pkix::AuxiliaryExtension extension, mozilla::pkix::AuxiliaryExtension extension,

View file

@ -35,7 +35,7 @@ OCSPVerificationTrustDomain::FindIssuer(Input, IssuerChecker&, Time)
} }
Result Result
OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time) OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time, const CertPolicyId&)
{ {
// We do not expect this to be called for OCSP signers // We do not expect this to be called for OCSP signers
return Result::FATAL_ERROR_LIBRARY_FAILURE; return Result::FATAL_ERROR_LIBRARY_FAILURE;
@ -44,7 +44,7 @@ OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time)
Result Result
OCSPVerificationTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, OCSPVerificationTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&,
Time, Duration, const Input*, Time, Duration, const Input*,
const Input*) const Input*, const Input*)
{ {
// We do not expect this to be called for OCSP signers // We do not expect this to be called for OCSP signers
return Result::FATAL_ERROR_LIBRARY_FAILURE; return Result::FATAL_ERROR_LIBRARY_FAILURE;

View file

@ -68,11 +68,13 @@ public:
mozilla::pkix::Time time, mozilla::pkix::Time time,
mozilla::pkix::Duration validityDuration, mozilla::pkix::Duration validityDuration,
/*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse,
/*optional*/ const mozilla::pkix::Input* aiaExtension) /*optional*/ const mozilla::pkix::Input* aiaExtension,
/*optional*/ const mozilla::pkix::Input* sctExtension)
override; override;
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) override; mozilla::pkix::Time time,
const mozilla::pkix::CertPolicyId& requiredPolicy) override;
virtual void NoteAuxiliaryExtension( virtual void NoteAuxiliaryExtension(
mozilla::pkix::AuxiliaryExtension extension, mozilla::pkix::AuxiliaryExtension extension,

View file

@ -35,7 +35,6 @@ if not CONFIG['NSS_NO_EV_CERTS']:
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'/security/manager/ssl', '/security/manager/ssl',
'/security/pkix/include', '/security/pkix/include',
'/security/pkix/lib',
] ]
DIRS += [ DIRS += [

View file

@ -129,7 +129,8 @@ CSTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
const CertID& certID, Time time, const CertID& certID, Time time,
Duration validityDuration, Duration validityDuration,
/*optional*/ const Input* stapledOCSPresponse, /*optional*/ const Input* stapledOCSPresponse,
/*optional*/ const Input* aiaExtension) /*optional*/ const Input* aiaExtension,
/*optional*/ const Input* sctExtension)
{ {
// We're relying solely on the CertBlocklist for revocation - and we're // We're relying solely on the CertBlocklist for revocation - and we're
// performing checks on this in GetCertTrust (as per nsNSSCertDBTrustDomain) // performing checks on this in GetCertTrust (as per nsNSSCertDBTrustDomain)
@ -137,7 +138,8 @@ CSTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
} }
Result Result
CSTrustDomain::IsChainValid(const DERArray& certChain, Time time) CSTrustDomain::IsChainValid(const DERArray& certChain, Time time,
const CertPolicyId& requiredPolicy)
{ {
// Check that our chain is not empty // Check that our chain is not empty
if (certChain.GetLength() == 0) { if (certChain.GetLength() == 0) {

View file

@ -36,9 +36,11 @@ public:
const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time,
mozilla::pkix::Duration validityDuration, mozilla::pkix::Duration validityDuration,
/*optional*/ const mozilla::pkix::Input* stapledOCSPresponse, /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse,
/*optional*/ const mozilla::pkix::Input* aiaExtension) override; /*optional*/ const mozilla::pkix::Input* aiaExtension,
/*optional*/ const mozilla::pkix::Input* sctExtension) override;
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain, virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) override; mozilla::pkix::Time time,
const mozilla::pkix::CertPolicyId& requiredPolicy) override;
virtual Result CheckSignatureDigestAlgorithm( virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg, mozilla::pkix::DigestAlgorithm digestAlg,
mozilla::pkix::EndEntityOrCA endEntityOrCA, mozilla::pkix::EndEntityOrCA endEntityOrCA,

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
// This file provides some implementation-specific test utilities. This is only
// necessary because some PSM xpcshell test utilities overlap in functionality
// with these test utilities, so the underlying implementation is shared.
#ifndef mozilla_pkix_test_pkixtestnss_h
#define mozilla_pkix_test_pkixtestnss_h
#include <keyhi.h>
#include <keythi.h>
#include "nss_scoped_ptrs.h"
#include "pkix/test/pkixtestutil.h"
namespace mozilla {
namespace pkix {
namespace test {
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
const ScopedSECKEYPublicKey& publicKey,
const ScopedSECKEYPrivateKey& privateKey);
}
}
} // namespace mozilla::pkix::test
#endif // mozilla_pkix_test_pkixtestnss_h

View file

@ -1,47 +1,29 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_test_pkixtestutils_h #ifndef mozilla_pkix_test_pkixtestutil_h
#define mozilla_pkix_test_pkixtestutils_h #define mozilla_pkix_test_pkixtestutil_h
#include <ctime> #include <cstdint>
#include <stdint.h> // Some Mozilla-supported compilers lack <cstdint>
#include <string>
#include <cstring> #include <cstring>
#include <ctime>
#include <string>
#include "pkix/pkixtypes.h" #include "pkix/pkixtypes.h"
#include "../../lib/ScopedPtr.h"
namespace mozilla { namespace pkix { namespace test { namespace mozilla {
namespace pkix {
namespace test {
typedef std::basic_string<uint8_t> ByteString; typedef std::basic_string<uint8_t> ByteString;
inline bool ENCODING_FAILED(const ByteString& bs) { return bs.empty(); } inline bool ENCODING_FAILED(const ByteString& bs) { return bs.empty(); }
template <size_t L> template <size_t L>
inline ByteString inline ByteString BytesToByteString(const uint8_t (&bytes)[L]) {
BytesToByteString(const uint8_t (&bytes)[L])
{
return ByteString(bytes, L); return ByteString(bytes, L);
} }
@ -64,17 +46,14 @@ bool InputEqualsByteString(Input input, const ByteString& bs);
ByteString InputToByteString(Input input); ByteString InputToByteString(Input input);
// python DottedOIDToCode.py --tlv id-kp-OCSPSigning 1.3.6.1.5.5.7.3.9 // python DottedOIDToCode.py --tlv id-kp-OCSPSigning 1.3.6.1.5.5.7.3.9
static const uint8_t tlv_id_kp_OCSPSigning[] = { static const uint8_t tlv_id_kp_OCSPSigning[] = {0x06, 0x08, 0x2b, 0x06, 0x01,
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09 0x05, 0x05, 0x07, 0x03, 0x09};
};
// python DottedOIDToCode.py --tlv id-kp-serverAuth 1.3.6.1.5.5.7.3.1 // python DottedOIDToCode.py --tlv id-kp-serverAuth 1.3.6.1.5.5.7.3.1
static const uint8_t tlv_id_kp_serverAuth[] = { static const uint8_t tlv_id_kp_serverAuth[] = {0x06, 0x08, 0x2b, 0x06, 0x01,
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01 0x05, 0x05, 0x07, 0x03, 0x01};
};
enum class TestDigestAlgorithmID enum class TestDigestAlgorithmID {
{
MD2, MD2,
MD5, MD5,
SHA1, SHA1,
@ -84,12 +63,10 @@ enum class TestDigestAlgorithmID
SHA512, SHA512,
}; };
struct TestPublicKeyAlgorithm struct TestPublicKeyAlgorithm {
{ explicit TestPublicKeyAlgorithm(const ByteString& aAlgorithmIdentifier)
explicit TestPublicKeyAlgorithm(const ByteString& algorithmIdentifier) : algorithmIdentifier(aAlgorithmIdentifier) {}
: algorithmIdentifier(algorithmIdentifier) { } bool operator==(const TestPublicKeyAlgorithm& other) const {
bool operator==(const TestPublicKeyAlgorithm& other) const
{
return algorithmIdentifier == other.algorithmIdentifier; return algorithmIdentifier == other.algorithmIdentifier;
} }
ByteString algorithmIdentifier; ByteString algorithmIdentifier;
@ -102,12 +79,10 @@ ByteString DSS_G();
TestPublicKeyAlgorithm DSS(); TestPublicKeyAlgorithm DSS();
TestPublicKeyAlgorithm RSA_PKCS1(); TestPublicKeyAlgorithm RSA_PKCS1();
struct TestSignatureAlgorithm struct TestSignatureAlgorithm {
{
TestSignatureAlgorithm(const TestPublicKeyAlgorithm& publicKeyAlg, TestSignatureAlgorithm(const TestPublicKeyAlgorithm& publicKeyAlg,
TestDigestAlgorithmID digestAlg, TestDigestAlgorithmID digestAlg,
const ByteString& algorithmIdentifier, const ByteString& algorithmIdentifier, bool accepted);
bool accepted);
TestPublicKeyAlgorithm publicKeyAlg; TestPublicKeyAlgorithm publicKeyAlg;
TestDigestAlgorithmID digestAlg; TestDigestAlgorithmID digestAlg;
@ -126,9 +101,7 @@ mozilla::pkix::Time YMDHMS(uint16_t year, uint16_t month, uint16_t day,
ByteString TLV(uint8_t tag, size_t length, const ByteString& value); ByteString TLV(uint8_t tag, size_t length, const ByteString& value);
inline ByteString inline ByteString TLV(uint8_t tag, const ByteString& value) {
TLV(uint8_t tag, const ByteString& value)
{
return TLV(tag, value.length(), value); return TLV(tag, value.length(), value);
} }
@ -137,18 +110,14 @@ TLV(uint8_t tag, const ByteString& value)
// string literals as the last parameter to the following two functions. // string literals as the last parameter to the following two functions.
template <size_t N> template <size_t N>
inline ByteString inline ByteString TLV(uint8_t tag, const char (&value)[N]) {
TLV(uint8_t tag, const char(&value)[N])
{
static_assert(N > 0, "cannot have string literal of size 0"); static_assert(N > 0, "cannot have string literal of size 0");
assert(value[N - 1] == 0); assert(value[N - 1] == 0);
return TLV(tag, ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1)); return TLV(tag, ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1));
} }
template <size_t N> template <size_t N>
inline ByteString inline ByteString TLV(uint8_t tag, size_t length, const char (&value)[N]) {
TLV(uint8_t tag, size_t length, const char(&value)[N])
{
static_assert(N > 0, "cannot have string literal of size 0"); static_assert(N > 0, "cannot have string literal of size 0");
assert(value[N - 1] == 0); assert(value[N - 1] == 0);
return TLV(tag, length, return TLV(tag, length,
@ -160,29 +129,27 @@ ByteString Integer(long value);
ByteString CN(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/); ByteString CN(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
inline ByteString inline ByteString CN(const char* value,
CN(const char* value, uint8_t encodingTag = 0x0c /*UTF8String*/) uint8_t encodingTag = 0x0c /*UTF8String*/) {
{ return CN(
return CN(ByteString(reinterpret_cast<const uint8_t*>(value), ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)),
std::strlen(value)), encodingTag); encodingTag);
} }
ByteString OU(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/); ByteString OU(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/);
inline ByteString inline ByteString OU(const char* value,
OU(const char* value, uint8_t encodingTag = 0x0c /*UTF8String*/) uint8_t encodingTag = 0x0c /*UTF8String*/) {
{ return OU(
return OU(ByteString(reinterpret_cast<const uint8_t*>(value), ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)),
std::strlen(value)), encodingTag); encodingTag);
} }
ByteString emailAddress(const ByteString&); ByteString emailAddress(const ByteString&);
inline ByteString inline ByteString emailAddress(const char* value) {
emailAddress(const char* value) return emailAddress(
{ ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)));
return emailAddress(ByteString(reinterpret_cast<const uint8_t*>(value),
std::strlen(value)));
} }
// RelativeDistinguishedName ::= // RelativeDistinguishedName ::=
@ -197,17 +164,11 @@ ByteString RDN(const ByteString& avas);
// //
ByteString Name(const ByteString& rdns); ByteString Name(const ByteString& rdns);
inline ByteString inline ByteString CNToDERName(const ByteString& cn) {
CNToDERName(const ByteString& cn)
{
return Name(RDN(CN(cn))); return Name(RDN(CN(cn)));
} }
inline ByteString inline ByteString CNToDERName(const char* cn) { return Name(RDN(CN(cn))); }
CNToDERName(const char* cn)
{
return Name(RDN(CN(cn)));
}
// GeneralName ::= CHOICE { // GeneralName ::= CHOICE {
// otherName [0] OtherName, // otherName [0] OtherName,
@ -220,55 +181,40 @@ CNToDERName(const char* cn)
// iPAddress [7] OCTET STRING, // iPAddress [7] OCTET STRING,
// registeredID [8] OBJECT IDENTIFIER } // registeredID [8] OBJECT IDENTIFIER }
inline ByteString inline ByteString RFC822Name(const ByteString& name) {
RFC822Name(const ByteString& name)
{
// (2 << 6) means "context-specific", 1 is the GeneralName tag. // (2 << 6) means "context-specific", 1 is the GeneralName tag.
return TLV((2 << 6) | 1, name); return TLV((2 << 6) | 1, name);
} }
template <size_t L> template <size_t L>
inline ByteString inline ByteString RFC822Name(const char (&bytes)[L]) {
RFC822Name(const char (&bytes)[L]) return RFC822Name(
{ ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1));
return RFC822Name(ByteString(reinterpret_cast<const uint8_t*>(&bytes),
L - 1));
} }
inline ByteString inline ByteString DNSName(const ByteString& name) {
DNSName(const ByteString& name)
{
// (2 << 6) means "context-specific", 2 is the GeneralName tag. // (2 << 6) means "context-specific", 2 is the GeneralName tag.
return TLV((2 << 6) | 2, name); return TLV((2 << 6) | 2, name);
} }
template <size_t L> template <size_t L>
inline ByteString inline ByteString DNSName(const char (&bytes)[L]) {
DNSName(const char (&bytes)[L]) return DNSName(ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1));
{
return DNSName(ByteString(reinterpret_cast<const uint8_t*>(&bytes),
L - 1));
} }
inline ByteString inline ByteString DirectoryName(const ByteString& name) {
DirectoryName(const ByteString& name)
{
// (2 << 6) means "context-specific", (1 << 5) means "constructed", and 4 is // (2 << 6) means "context-specific", (1 << 5) means "constructed", and 4 is
// the DirectoryName tag. // the DirectoryName tag.
return TLV((2 << 6) | (1 << 5) | 4, name); return TLV((2 << 6) | (1 << 5) | 4, name);
} }
inline ByteString inline ByteString IPAddress() {
IPAddress()
{
// (2 << 6) means "context-specific", 7 is the GeneralName tag. // (2 << 6) means "context-specific", 7 is the GeneralName tag.
return TLV((2 << 6) | 7, ByteString()); return TLV((2 << 6) | 7, ByteString());
} }
template <size_t L> template <size_t L>
inline ByteString inline ByteString IPAddress(const uint8_t (&bytes)[L]) {
IPAddress(const uint8_t (&bytes)[L])
{
// (2 << 6) means "context-specific", 7 is the GeneralName tag. // (2 << 6) means "context-specific", 7 is the GeneralName tag.
return TLV((2 << 6) | 7, ByteString(bytes, L)); return TLV((2 << 6) | 7, ByteString(bytes, L));
} }
@ -282,10 +228,9 @@ IPAddress(const uint8_t (&bytes)[L])
ByteString CreateEncodedSubjectAltName(const ByteString& names); ByteString CreateEncodedSubjectAltName(const ByteString& names);
ByteString CreateEncodedEmptySubjectAltName(); ByteString CreateEncodedEmptySubjectAltName();
class TestKeyPair class TestKeyPair {
{ public:
public: virtual ~TestKeyPair() {}
virtual ~TestKeyPair() { }
const TestPublicKeyAlgorithm publicKeyAlg; const TestPublicKeyAlgorithm publicKeyAlg;
@ -302,8 +247,10 @@ public:
/*out*/ ByteString& signature) const = 0; /*out*/ ByteString& signature) const = 0;
virtual TestKeyPair* Clone() const = 0; virtual TestKeyPair* Clone() const = 0;
protected:
TestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg, const ByteString& spk); protected:
TestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg,
const ByteString& spk);
TestKeyPair(const TestKeyPair&) = delete; TestKeyPair(const TestKeyPair&) = delete;
void operator=(const TestKeyPair&) = delete; void operator=(const TestKeyPair&) = delete;
}; };
@ -312,7 +259,7 @@ TestKeyPair* CloneReusedKeyPair();
TestKeyPair* GenerateKeyPair(); TestKeyPair* GenerateKeyPair();
TestKeyPair* GenerateDSSKeyPair(); TestKeyPair* GenerateDSSKeyPair();
inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; } inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; }
typedef ScopedPtr<TestKeyPair, DeleteTestKeyPair> ScopedTestKeyPair; typedef std::unique_ptr<TestKeyPair> ScopedTestKeyPair;
Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest, Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo); Input subjectPublicKeyInfo);
@ -347,24 +294,21 @@ enum Version { v1 = 0, v2 = 1, v3 = 2 };
// extensions must point to an array of ByteStrings, terminated with an empty // extensions must point to an array of ByteStrings, terminated with an empty
// ByteString. (If the first item of the array is empty then an empty // ByteString. (If the first item of the array is empty then an empty
// Extensions sequence will be encoded.) // Extensions sequence will be encoded.)
ByteString CreateEncodedCertificate(long version, ByteString CreateEncodedCertificate(
const TestSignatureAlgorithm& signature, long version, const TestSignatureAlgorithm& signature,
const ByteString& serialNumber, const ByteString& serialNumber, const ByteString& issuerNameDER,
const ByteString& issuerNameDER, time_t notBefore, time_t notAfter, const ByteString& subjectNameDER,
time_t notBefore, time_t notAfter,
const ByteString& subjectNameDER,
const TestKeyPair& subjectKeyPair, const TestKeyPair& subjectKeyPair,
/*optional*/ const ByteString* extensions, /*optional*/ const ByteString* extensions, const TestKeyPair& issuerKeyPair,
const TestKeyPair& issuerKeyPair,
const TestSignatureAlgorithm& signatureAlgorithm); const TestSignatureAlgorithm& signatureAlgorithm);
ByteString CreateEncodedSerialNumber(long value); ByteString CreateEncodedSerialNumber(long value);
enum class Critical { No = 0, Yes = 1 }; enum class Critical { No = 0, Yes = 1 };
ByteString CreateEncodedBasicConstraints(bool isCA, ByteString CreateEncodedBasicConstraints(
/*optional*/ long* pathLenConstraint, bool isCA,
Critical critical); /*optional in*/ const long* pathLenConstraint, Critical critical);
// Creates a DER-encoded extKeyUsage extension with one EKU OID. // Creates a DER-encoded extKeyUsage extension with one EKU OID.
ByteString CreateEncodedEKUExtension(Input eku, Critical critical); ByteString CreateEncodedEKUExtension(Input eku, Critical critical);
@ -372,9 +316,8 @@ ByteString CreateEncodedEKUExtension(Input eku, Critical critical);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Encode OCSP responses // Encode OCSP responses
class OCSPResponseExtension final class OCSPResponseExtension final {
{ public:
public:
OCSPResponseExtension(); OCSPResponseExtension();
ByteString id; ByteString id;
@ -383,9 +326,8 @@ public:
OCSPResponseExtension* next; OCSPResponseExtension* next;
}; };
class OCSPResponseContext final class OCSPResponseContext final {
{ public:
public:
OCSPResponseContext(const CertID& certID, std::time_t time); OCSPResponseContext(const CertID& certID, std::time_t time);
const CertID& certID; const CertID& certID;
@ -393,8 +335,7 @@ public:
// The fields below are in the order that they appear in an OCSP response. // The fields below are in the order that they appear in an OCSP response.
enum OCSPResponseStatus enum OCSPResponseStatus {
{
successful = 0, successful = 0,
malformedRequest = 1, malformedRequest = 1,
internalError = 2, internalError = 2,
@ -427,8 +368,7 @@ public:
// The following fields are on a per-SingleResponse basis. In the future we // The following fields are on a per-SingleResponse basis. In the future we
// may support including multiple SingleResponses per response. // may support including multiple SingleResponses per response.
enum CertStatus enum CertStatus {
{
good = 0, good = 0,
revoked = 1, revoked = 1,
unknown = 2, unknown = 2,
@ -441,7 +381,8 @@ public:
}; };
ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context); ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context);
}
}
} // namespace mozilla::pkix::test
} } } // namespace mozilla::pkix::test #endif // mozilla_pkix_test_pkixtestutil_h
#endif // mozilla_pkix_test_pkixtestutils_h

View file

@ -1,25 +1,8 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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 #ifndef mozilla_pkix_Input_h
#define mozilla_pkix_Input_h #define mozilla_pkix_Input_h
@ -29,7 +12,8 @@
#include "pkix/Result.h" #include "pkix/Result.h"
#include "stdint.h" #include "stdint.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
class Reader; class Reader;
@ -48,9 +32,8 @@ class Reader;
// //
// Note that in the example, GoodExample has the same performance // Note that in the example, GoodExample has the same performance
// characteristics as WorseExample, but with much better safety guarantees. // characteristics as WorseExample, but with much better safety guarantees.
class Input final class Input final {
{ public:
public:
typedef uint16_t size_type; typedef uint16_t size_type;
// This constructor is useful for inputs that are statically known to be of a // This constructor is useful for inputs that are statically known to be of a
@ -65,37 +48,28 @@ public:
// Input expected; // Input expected;
// Result rv = expected.Init(EXPECTED_BYTES, sizeof EXPECTED_BYTES); // Result rv = expected.Init(EXPECTED_BYTES, sizeof EXPECTED_BYTES);
template <size_type N> template <size_type N>
explicit Input(const uint8_t (&data)[N]) explicit Input(const uint8_t (&aData)[N]) : data(aData), len(N) {}
: data(data)
, len(N)
{
}
// Construct a valid, empty, Init-able Input. // Construct a valid, empty, Init-able Input.
Input() Input() : data(nullptr), len(0u) {}
: data(nullptr)
, len(0u)
{
}
// This is intentionally not explicit in order to allow value semantics. // This is intentionally not explicit in order to allow value semantics.
Input(const Input&) = default; Input(const Input&) = default;
// Initialize the input. data must be non-null and len must be less than // Initialize the input. data must be non-null and len must be less than
// 65536. Init may not be called more than once. // 65536. Init may not be called more than once.
Result Init(const uint8_t* data, size_t len) Result Init(const uint8_t* aData, size_t aLen) {
{
if (this->data) { if (this->data) {
// already initialized // already initialized
return Result::FATAL_ERROR_INVALID_ARGS; return Result::FATAL_ERROR_INVALID_ARGS;
} }
if (!data || len > 0xffffu) { if (!aData || aLen > 0xffffu) {
// input too large // input too large
return Result::ERROR_BAD_DER; return Result::ERROR_BAD_DER;
} }
this->data = data; this->data = aData;
this->len = len; this->len = aLen;
return Success; return Success;
} }
@ -106,10 +80,7 @@ public:
// This is basically operator=, but it wasn't given that name because // This is basically operator=, but it wasn't given that name because
// normally callers do not check the result of operator=, and normally // normally callers do not check the result of operator=, and normally
// operator= can be used multiple times. // operator= can be used multiple times.
Result Init(Input other) Result Init(Input other) { return Init(other.data, other.len); }
{
return Init(other.data, other.len);
}
// Returns the length of the input. // Returns the length of the input.
// //
@ -121,18 +92,17 @@ public:
// don't want to declare in this header file. // don't want to declare in this header file.
const uint8_t* UnsafeGetData() const { return data; } const uint8_t* UnsafeGetData() const { return data; }
private: private:
const uint8_t* data; const uint8_t* data;
size_t len; size_t len;
void operator=(const Input&) = delete; // Use Init instead. void operator=(const Input&) = delete; // Use Init instead.
}; };
inline bool inline bool InputsAreEqual(const Input& a, const Input& b) {
InputsAreEqual(const Input& a, const Input& b)
{
return a.GetLength() == b.GetLength() && return a.GetLength() == b.GetLength() &&
std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(), b.UnsafeGetData()); std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(),
b.UnsafeGetData());
} }
// An Reader is a cursor/iterator through the contents of an Input, designed to // An Reader is a cursor/iterator through the contents of an Input, designed to
@ -143,38 +113,28 @@ InputsAreEqual(const Input& a, const Input& b)
// //
// In general, Reader allows for one byte of lookahead and no backtracking. // In general, Reader allows for one byte of lookahead and no backtracking.
// However, the Match* functions internally may have more lookahead. // However, the Match* functions internally may have more lookahead.
class Reader final class Reader final {
{ public:
public: Reader() : input(nullptr), end(nullptr) {}
Reader()
: input(nullptr)
, end(nullptr)
{
}
explicit Reader(Input input) explicit Reader(Input aInput)
: input(input.UnsafeGetData()) : input(aInput.UnsafeGetData()),
, end(input.UnsafeGetData() + input.GetLength()) end(aInput.UnsafeGetData() + aInput.GetLength()) {}
{
}
Result Init(Input input) Result Init(Input aInput) {
{
if (this->input) { if (this->input) {
return Result::FATAL_ERROR_INVALID_ARGS; return Result::FATAL_ERROR_INVALID_ARGS;
} }
this->input = input.UnsafeGetData(); this->input = aInput.UnsafeGetData();
this->end = input.UnsafeGetData() + input.GetLength(); this->end = aInput.UnsafeGetData() + aInput.GetLength();
return Success; return Success;
} }
bool Peek(uint8_t expectedByte) const bool Peek(uint8_t expectedByte) const {
{
return input < end && *input == expectedByte; return input < end && *input == expectedByte;
} }
Result Read(uint8_t& out) Result Read(uint8_t& out) {
{
Result rv = EnsureLength(1); Result rv = EnsureLength(1);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -183,8 +143,7 @@ public:
return Success; return Success;
} }
Result Read(uint16_t& out) Result Read(uint16_t& out) {
{
Result rv = EnsureLength(2); Result rv = EnsureLength(2);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -196,8 +155,7 @@ public:
} }
template <Input::size_type N> template <Input::size_type N>
bool MatchRest(const uint8_t (&toMatch)[N]) bool MatchRest(const uint8_t (&toMatch)[N]) {
{
// Normally we use EnsureLength which compares (input + len < end), but // Normally we use EnsureLength which compares (input + len < end), but
// here we want to be sure that there is nothing following the matched // here we want to be sure that there is nothing following the matched
// bytes // bytes
@ -211,8 +169,7 @@ public:
return true; return true;
} }
bool MatchRest(Input toMatch) bool MatchRest(Input toMatch) {
{
// Normally we use EnsureLength which compares (input + len < end), but // Normally we use EnsureLength which compares (input + len < end), but
// here we want to be sure that there is nothing following the matched // here we want to be sure that there is nothing following the matched
// bytes // bytes
@ -227,8 +184,7 @@ public:
return true; return true;
} }
Result Skip(Input::size_type len) Result Skip(Input::size_type len) {
{
Result rv = EnsureLength(len); Result rv = EnsureLength(len);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -237,8 +193,7 @@ public:
return Success; return Success;
} }
Result Skip(Input::size_type len, Reader& skipped) Result Skip(Input::size_type len, Reader& skipped) {
{
Result rv = EnsureLength(len); Result rv = EnsureLength(len);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -251,8 +206,7 @@ public:
return Success; return Success;
} }
Result Skip(Input::size_type len, /*out*/ Input& skipped) Result Skip(Input::size_type len, /*out*/ Input& skipped) {
{
Result rv = EnsureLength(len); Result rv = EnsureLength(len);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -265,18 +219,13 @@ public:
return Success; return Success;
} }
void SkipToEnd() void SkipToEnd() { input = end; }
{
input = end;
}
Result SkipToEnd(/*out*/ Input& skipped) Result SkipToEnd(/*out*/ Input& skipped) {
{
return Skip(static_cast<Input::size_type>(end - input), skipped); return Skip(static_cast<Input::size_type>(end - input), skipped);
} }
Result EnsureLength(Input::size_type len) Result EnsureLength(Input::size_type len) {
{
if (static_cast<size_t>(end - input) < len) { if (static_cast<size_t>(end - input) < len) {
return Result::ERROR_BAD_DER; return Result::ERROR_BAD_DER;
} }
@ -285,13 +234,13 @@ public:
bool AtEnd() const { return input == end; } bool AtEnd() const { return input == end; }
class Mark final class Mark final {
{
public: public:
Mark(const Mark&) = default; // Intentionally not explicit. Mark(const Mark&) = default; // Intentionally not explicit.
private: private:
friend class Reader; friend class Reader;
Mark(const Reader& input, const uint8_t* mark) : input(input), mark(mark) { } Mark(const Reader& aInput, const uint8_t* aMark)
: input(aInput), mark(aMark) {}
const Reader& input; const Reader& input;
const uint8_t* const mark; const uint8_t* const mark;
void operator=(const Mark&) = delete; void operator=(const Mark&) = delete;
@ -299,8 +248,7 @@ public:
Mark GetMark() const { return Mark(*this, input); } Mark GetMark() const { return Mark(*this, input); }
Result GetInput(const Mark& mark, /*out*/ Input& item) Result GetInput(const Mark& mark, /*out*/ Input& item) {
{
if (&mark.input != this || mark.mark > input) { if (&mark.input != this || mark.mark > input) {
return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS); return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS);
} }
@ -308,9 +256,8 @@ public:
static_cast<Input::size_type>(input - mark.mark)); static_cast<Input::size_type>(input - mark.mark));
} }
private: private:
Result Init(const uint8_t* data, Input::size_type len) Result Init(const uint8_t* data, Input::size_type len) {
{
if (input) { if (input) {
// already initialized // already initialized
return Result::FATAL_ERROR_INVALID_ARGS; return Result::FATAL_ERROR_INVALID_ARGS;
@ -327,9 +274,7 @@ private:
void operator=(const Reader&) = delete; void operator=(const Reader&) = delete;
}; };
inline bool inline bool InputContains(const Input& input, uint8_t toFind) {
InputContains(const Input& input, uint8_t toFind)
{
Reader reader(input); Reader reader(input);
for (;;) { for (;;) {
uint8_t b; uint8_t b;
@ -341,7 +286,7 @@ InputContains(const Input& input, uint8_t toFind)
} }
} }
} }
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_Input_h #endif // mozilla_pkix_Input_h

View file

@ -1,32 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_Result_h #ifndef mozilla_pkix_Result_h
#define mozilla_pkix_Result_h #define mozilla_pkix_Result_h
#include <cassert> #include <cassert>
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
static const unsigned int FATAL_ERROR_FLAG = 0x800; static const unsigned int FATAL_ERROR_FLAG = 0x800;
@ -84,20 +68,16 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
// NSS/NSPR error codes in pkixnss.cpp. // NSS/NSPR error codes in pkixnss.cpp.
#define MOZILLA_PKIX_MAP_LIST \ #define MOZILLA_PKIX_MAP_LIST \
MOZILLA_PKIX_MAP(Success, 0, 0) \ MOZILLA_PKIX_MAP(Success, 0, 0) \
MOZILLA_PKIX_MAP(ERROR_BAD_DER, 1, \ MOZILLA_PKIX_MAP(ERROR_BAD_DER, 1, SEC_ERROR_BAD_DER) \
SEC_ERROR_BAD_DER) \ MOZILLA_PKIX_MAP(ERROR_CA_CERT_INVALID, 2, SEC_ERROR_CA_CERT_INVALID) \
MOZILLA_PKIX_MAP(ERROR_CA_CERT_INVALID, 2, \ MOZILLA_PKIX_MAP(ERROR_BAD_SIGNATURE, 3, SEC_ERROR_BAD_SIGNATURE) \
SEC_ERROR_CA_CERT_INVALID) \
MOZILLA_PKIX_MAP(ERROR_BAD_SIGNATURE, 3, \
SEC_ERROR_BAD_SIGNATURE) \
MOZILLA_PKIX_MAP(ERROR_CERT_BAD_ACCESS_LOCATION, 4, \ MOZILLA_PKIX_MAP(ERROR_CERT_BAD_ACCESS_LOCATION, 4, \
SEC_ERROR_CERT_BAD_ACCESS_LOCATION) \ SEC_ERROR_CERT_BAD_ACCESS_LOCATION) \
MOZILLA_PKIX_MAP(ERROR_CERT_NOT_IN_NAME_SPACE, 5, \ MOZILLA_PKIX_MAP(ERROR_CERT_NOT_IN_NAME_SPACE, 5, \
SEC_ERROR_CERT_NOT_IN_NAME_SPACE) \ SEC_ERROR_CERT_NOT_IN_NAME_SPACE) \
MOZILLA_PKIX_MAP(ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 6, \ MOZILLA_PKIX_MAP(ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 6, \
SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) \ SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) \
MOZILLA_PKIX_MAP(ERROR_CONNECT_REFUSED, 7, \ MOZILLA_PKIX_MAP(ERROR_CONNECT_REFUSED, 7, PR_CONNECT_REFUSED_ERROR) \
PR_CONNECT_REFUSED_ERROR) \
MOZILLA_PKIX_MAP(ERROR_EXPIRED_CERTIFICATE, 8, \ MOZILLA_PKIX_MAP(ERROR_EXPIRED_CERTIFICATE, 8, \
SEC_ERROR_EXPIRED_CERTIFICATE) \ SEC_ERROR_EXPIRED_CERTIFICATE) \
MOZILLA_PKIX_MAP(ERROR_EXTENSION_VALUE_INVALID, 9, \ MOZILLA_PKIX_MAP(ERROR_EXTENSION_VALUE_INVALID, 9, \
@ -106,10 +86,8 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
SEC_ERROR_INADEQUATE_CERT_TYPE) \ SEC_ERROR_INADEQUATE_CERT_TYPE) \
MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_USAGE, 11, \ MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_USAGE, 11, \
SEC_ERROR_INADEQUATE_KEY_USAGE) \ SEC_ERROR_INADEQUATE_KEY_USAGE) \
MOZILLA_PKIX_MAP(ERROR_INVALID_ALGORITHM, 12, \ MOZILLA_PKIX_MAP(ERROR_INVALID_ALGORITHM, 12, SEC_ERROR_INVALID_ALGORITHM) \
SEC_ERROR_INVALID_ALGORITHM) \ MOZILLA_PKIX_MAP(ERROR_INVALID_DER_TIME, 13, SEC_ERROR_INVALID_TIME) \
MOZILLA_PKIX_MAP(ERROR_INVALID_DER_TIME, 13, \
SEC_ERROR_INVALID_TIME) \
MOZILLA_PKIX_MAP(ERROR_KEY_PINNING_FAILURE, 14, \ MOZILLA_PKIX_MAP(ERROR_KEY_PINNING_FAILURE, 14, \
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) \ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) \
MOZILLA_PKIX_MAP(ERROR_PATH_LEN_CONSTRAINT_INVALID, 15, \ MOZILLA_PKIX_MAP(ERROR_PATH_LEN_CONSTRAINT_INVALID, 15, \
@ -120,44 +98,34 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
SEC_ERROR_REVOKED_CERTIFICATE) \ SEC_ERROR_REVOKED_CERTIFICATE) \
MOZILLA_PKIX_MAP(ERROR_UNKNOWN_CRITICAL_EXTENSION, 18, \ MOZILLA_PKIX_MAP(ERROR_UNKNOWN_CRITICAL_EXTENSION, 18, \
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) \ SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) \
MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ERROR, 19, \ MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ERROR, 19, PR_UNKNOWN_ERROR) \
PR_UNKNOWN_ERROR) \ MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ISSUER, 20, SEC_ERROR_UNKNOWN_ISSUER) \
MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ISSUER, 20, \ MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_CERT, 21, SEC_ERROR_UNTRUSTED_CERT) \
SEC_ERROR_UNKNOWN_ISSUER) \ MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_ISSUER, 22, SEC_ERROR_UNTRUSTED_ISSUER) \
MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_CERT, 21, \ MOZILLA_PKIX_MAP(ERROR_OCSP_BAD_SIGNATURE, 23, SEC_ERROR_OCSP_BAD_SIGNATURE) \
SEC_ERROR_UNTRUSTED_CERT) \
MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_ISSUER, 22, \
SEC_ERROR_UNTRUSTED_ISSUER) \
MOZILLA_PKIX_MAP(ERROR_OCSP_BAD_SIGNATURE, 23, \
SEC_ERROR_OCSP_BAD_SIGNATURE) \
MOZILLA_PKIX_MAP(ERROR_OCSP_INVALID_SIGNING_CERT, 24, \ MOZILLA_PKIX_MAP(ERROR_OCSP_INVALID_SIGNING_CERT, 24, \
SEC_ERROR_OCSP_INVALID_SIGNING_CERT) \ SEC_ERROR_OCSP_INVALID_SIGNING_CERT) \
MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_REQUEST, 25, \ MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_REQUEST, 25, \
SEC_ERROR_OCSP_MALFORMED_REQUEST) \ SEC_ERROR_OCSP_MALFORMED_REQUEST) \
MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_RESPONSE, 26, \ MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_RESPONSE, 26, \
SEC_ERROR_OCSP_MALFORMED_RESPONSE) \ SEC_ERROR_OCSP_MALFORMED_RESPONSE) \
MOZILLA_PKIX_MAP(ERROR_OCSP_OLD_RESPONSE, 27, \ MOZILLA_PKIX_MAP(ERROR_OCSP_OLD_RESPONSE, 27, SEC_ERROR_OCSP_OLD_RESPONSE) \
SEC_ERROR_OCSP_OLD_RESPONSE) \
MOZILLA_PKIX_MAP(ERROR_OCSP_REQUEST_NEEDS_SIG, 28, \ MOZILLA_PKIX_MAP(ERROR_OCSP_REQUEST_NEEDS_SIG, 28, \
SEC_ERROR_OCSP_REQUEST_NEEDS_SIG) \ SEC_ERROR_OCSP_REQUEST_NEEDS_SIG) \
MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONDER_CERT_INVALID, 29, \ MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONDER_CERT_INVALID, 29, \
SEC_ERROR_OCSP_RESPONDER_CERT_INVALID) \ SEC_ERROR_OCSP_RESPONDER_CERT_INVALID) \
MOZILLA_PKIX_MAP(ERROR_OCSP_SERVER_ERROR, 30, \ MOZILLA_PKIX_MAP(ERROR_OCSP_SERVER_ERROR, 30, SEC_ERROR_OCSP_SERVER_ERROR) \
SEC_ERROR_OCSP_SERVER_ERROR) \
MOZILLA_PKIX_MAP(ERROR_OCSP_TRY_SERVER_LATER, 31, \ MOZILLA_PKIX_MAP(ERROR_OCSP_TRY_SERVER_LATER, 31, \
SEC_ERROR_OCSP_TRY_SERVER_LATER) \ SEC_ERROR_OCSP_TRY_SERVER_LATER) \
MOZILLA_PKIX_MAP(ERROR_OCSP_UNAUTHORIZED_REQUEST, 32, \ MOZILLA_PKIX_MAP(ERROR_OCSP_UNAUTHORIZED_REQUEST, 32, \
SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \ SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \
MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, 33, \ MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, 33, \
SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \ SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \
MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_CERT, 34, \ MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_CERT, 34, SEC_ERROR_OCSP_UNKNOWN_CERT) \
SEC_ERROR_OCSP_UNKNOWN_CERT) \
MOZILLA_PKIX_MAP(ERROR_OCSP_FUTURE_RESPONSE, 35, \ MOZILLA_PKIX_MAP(ERROR_OCSP_FUTURE_RESPONSE, 35, \
SEC_ERROR_OCSP_FUTURE_RESPONSE) \ SEC_ERROR_OCSP_FUTURE_RESPONSE) \
MOZILLA_PKIX_MAP(ERROR_INVALID_KEY, 36, \ MOZILLA_PKIX_MAP(ERROR_INVALID_KEY, 36, SEC_ERROR_INVALID_KEY) \
SEC_ERROR_INVALID_KEY) \ MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_KEYALG, 37, SEC_ERROR_UNSUPPORTED_KEYALG) \
MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_KEYALG, 37, \
SEC_ERROR_UNSUPPORTED_KEYALG) \
MOZILLA_PKIX_MAP(ERROR_EXPIRED_ISSUER_CERTIFICATE, 38, \ MOZILLA_PKIX_MAP(ERROR_EXPIRED_ISSUER_CERTIFICATE, 38, \
SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) \ SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) \
MOZILLA_PKIX_MAP(ERROR_CA_CERT_USED_AS_END_ENTITY, 39, \ MOZILLA_PKIX_MAP(ERROR_CA_CERT_USED_AS_END_ENTITY, 39, \
@ -166,8 +134,7 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE) \ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE) \
MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \ MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \ MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \
MOZILLA_PKIX_MAP(ERROR_BAD_CERT_DOMAIN, 42, \ MOZILLA_PKIX_MAP(ERROR_BAD_CERT_DOMAIN, 42, SSL_ERROR_BAD_CERT_DOMAIN) \
SSL_ERROR_BAD_CERT_DOMAIN) \
MOZILLA_PKIX_MAP(ERROR_NO_RFC822NAME_MATCH, 43, \ MOZILLA_PKIX_MAP(ERROR_NO_RFC822NAME_MATCH, 43, \
MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH) \ MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH) \
MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_ELLIPTIC_CURVE, 44, \ MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_ELLIPTIC_CURVE, 44, \
@ -190,6 +157,11 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING) \ MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING) \
MOZILLA_PKIX_MAP(ERROR_EMPTY_ISSUER_NAME, 53, \ MOZILLA_PKIX_MAP(ERROR_EMPTY_ISSUER_NAME, 53, \
MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME) \ MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME) \
MOZILLA_PKIX_MAP(ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, 54, \
MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED) \
MOZILLA_PKIX_MAP(ERROR_SELF_SIGNED_CERT, 55, \
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT) \
MOZILLA_PKIX_MAP(ERROR_MITM_DETECTED, 56, MOZILLA_PKIX_ERROR_MITM_DETECTED) \
MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \ MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \
SEC_ERROR_INVALID_ARGS) \ SEC_ERROR_INVALID_ARGS) \
MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \ MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \
@ -198,10 +170,9 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
SEC_ERROR_LIBRARY_FAILURE) \ SEC_ERROR_LIBRARY_FAILURE) \
MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \ MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \
SEC_ERROR_NO_MEMORY) \ SEC_ERROR_NO_MEMORY) \
/* nothing here */ /* nothing here */
enum class Result enum class Result {
{
#define MOZILLA_PKIX_MAP(name, value, nss_name) name = value, #define MOZILLA_PKIX_MAP(name, value, nss_name) name = value,
MOZILLA_PKIX_MAP_LIST MOZILLA_PKIX_MAP_LIST
#undef MOZILLA_PKIX_MAP #undef MOZILLA_PKIX_MAP
@ -216,19 +187,15 @@ const char* MapResultToName(Result result);
// results in less line wrapping. // results in less line wrapping.
static const Result Success = Result::Success; static const Result Success = Result::Success;
inline bool inline bool IsFatalError(Result rv) {
IsFatalError(Result rv)
{
return (static_cast<unsigned int>(rv) & FATAL_ERROR_FLAG) != 0; return (static_cast<unsigned int>(rv) & FATAL_ERROR_FLAG) != 0;
} }
inline Result inline Result NotReached(const char* /*explanation*/, Result result) {
NotReached(const char* /*explanation*/, Result result)
{
assert(false); assert(false);
return result; return result;
} }
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_Result_h #endif // mozilla_pkix_Result_h

View file

@ -1,45 +1,28 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
/* Copyright 2014 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_Time_h #ifndef mozilla_pkix_Time_h
#define mozilla_pkix_Time_h #define mozilla_pkix_Time_h
#include <stdint.h>
#include <ctime> #include <ctime>
#include <limits> #include <limits>
#include <stdint.h>
#include "pkix/Result.h" #include "pkix/Result.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
// Time with a range from the first second of year 0 (AD) through at least the // Time with a range from the first second of year 0 (AD) through at least the
// last second of year 9999, which is the range of legal times in X.509 and // last second of year 9999, which is the range of legal times in X.509 and
// OCSP. This type has second-level precision. The time zone is always UTC. // OCSP. This type has second-level precision. The time zone is always UTC.
// //
// Pass by value, not by reference. // Pass by value, not by reference.
class Time final class Time final {
{ public:
public:
// Construct an uninitialized instance. // Construct an uninitialized instance.
// //
// This will fail to compile because there is no default constructor: // This will fail to compile because there is no default constructor:
@ -48,41 +31,33 @@ public:
// This will succeed, leaving the time uninitialized: // This will succeed, leaving the time uninitialized:
// Time x(Time::uninitialized); // Time x(Time::uninitialized);
enum Uninitialized { uninitialized }; enum Uninitialized { uninitialized };
explicit Time(Uninitialized) { } explicit Time(Uninitialized) {}
bool operator==(const Time& other) const bool operator==(const Time& other) const {
{
return elapsedSecondsAD == other.elapsedSecondsAD; return elapsedSecondsAD == other.elapsedSecondsAD;
} }
bool operator>(const Time& other) const bool operator>(const Time& other) const {
{
return elapsedSecondsAD > other.elapsedSecondsAD; return elapsedSecondsAD > other.elapsedSecondsAD;
} }
bool operator>=(const Time& other) const bool operator>=(const Time& other) const {
{
return elapsedSecondsAD >= other.elapsedSecondsAD; return elapsedSecondsAD >= other.elapsedSecondsAD;
} }
bool operator<(const Time& other) const bool operator<(const Time& other) const {
{
return elapsedSecondsAD < other.elapsedSecondsAD; return elapsedSecondsAD < other.elapsedSecondsAD;
} }
bool operator<=(const Time& other) const bool operator<=(const Time& other) const {
{
return elapsedSecondsAD <= other.elapsedSecondsAD; return elapsedSecondsAD <= other.elapsedSecondsAD;
} }
Result AddSeconds(uint64_t seconds) Result AddSeconds(uint64_t seconds) {
{ if (std::numeric_limits<uint64_t>::max() - elapsedSecondsAD < seconds) {
if (std::numeric_limits<uint64_t>::max() - elapsedSecondsAD
< seconds) {
return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow
} }
elapsedSecondsAD += seconds; elapsedSecondsAD += seconds;
return Success; return Success;
} }
Result SubtractSeconds(uint64_t seconds) Result SubtractSeconds(uint64_t seconds) {
{
if (seconds > elapsedSecondsAD) { if (seconds > elapsedSecondsAD) {
return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow
} }
@ -90,10 +65,10 @@ public:
return Success; return Success;
} }
static const uint64_t ONE_DAY_IN_SECONDS static const uint64_t ONE_DAY_IN_SECONDS =
= UINT64_C(24) * UINT64_C(60) * UINT64_C(60); UINT64_C(24) * UINT64_C(60) * UINT64_C(60);
private: private:
// This constructor is hidden to prevent accidents like this: // This constructor is hidden to prevent accidents like this:
// //
// Time foo(time_t t) // Time foo(time_t t)
@ -101,19 +76,16 @@ private:
// // WRONG! 1970-01-01-00:00:00 == time_t(0), but not Time(0)! // // WRONG! 1970-01-01-00:00:00 == time_t(0), but not Time(0)!
// return Time(t); // return Time(t);
// } // }
explicit Time(uint64_t elapsedSecondsAD) explicit Time(uint64_t aElapsedSecondsAD)
: elapsedSecondsAD(elapsedSecondsAD) : elapsedSecondsAD(aElapsedSecondsAD) {}
{
}
friend Time TimeFromElapsedSecondsAD(uint64_t); friend Time TimeFromElapsedSecondsAD(uint64_t);
friend class Duration; friend class Duration;
uint64_t elapsedSecondsAD; uint64_t elapsedSecondsAD;
}; };
inline Time TimeFromElapsedSecondsAD(uint64_t elapsedSecondsAD) inline Time TimeFromElapsedSecondsAD(uint64_t aElapsedSecondsAD) {
{ return Time(aElapsedSecondsAD);
return Time(elapsedSecondsAD);
} }
Time Now(); Time Now();
@ -121,34 +93,27 @@ Time Now();
// Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970) // Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970)
Time TimeFromEpochInSeconds(uint64_t secondsSinceEpoch); Time TimeFromEpochInSeconds(uint64_t secondsSinceEpoch);
class Duration final class Duration final {
{ public:
public:
Duration(Time timeA, Time timeB) Duration(Time timeA, Time timeB)
: durationInSeconds(timeA < timeB : durationInSeconds(
? timeB.elapsedSecondsAD - timeA.elapsedSecondsAD timeA < timeB ? timeB.elapsedSecondsAD - timeA.elapsedSecondsAD
: timeA.elapsedSecondsAD - timeB.elapsedSecondsAD) : timeA.elapsedSecondsAD - timeB.elapsedSecondsAD) {}
{
}
explicit Duration(uint64_t durationInSeconds) explicit Duration(uint64_t aDurationInSeconds)
: durationInSeconds(durationInSeconds) : durationInSeconds(aDurationInSeconds) {}
{
}
bool operator>(const Duration& other) const bool operator>(const Duration& other) const {
{
return durationInSeconds > other.durationInSeconds; return durationInSeconds > other.durationInSeconds;
} }
bool operator<(const Duration& other) const bool operator<(const Duration& other) const {
{
return durationInSeconds < other.durationInSeconds; return durationInSeconds < other.durationInSeconds;
} }
private: private:
uint64_t durationInSeconds; uint64_t durationInSeconds;
}; };
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_Time_h #endif // mozilla_pkix_Time_h

View file

@ -1,32 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_pkix_h #ifndef mozilla_pkix_pkix_h
#define mozilla_pkix_pkix_h #define mozilla_pkix_pkix_h
#include "pkixtypes.h" #include "pkix/pkixtypes.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// LIMITED SUPPORT FOR CERTIFICATE POLICIES // LIMITED SUPPORT FOR CERTIFICATE POLICIES
@ -102,8 +86,8 @@ namespace mozilla { namespace pkix {
// requiredPolicy: // requiredPolicy:
// This is the policy to apply; typically included in EV certificates. // This is the policy to apply; typically included in EV certificates.
// If there is no policy, pass in CertPolicyId::anyPolicy. // If there is no policy, pass in CertPolicyId::anyPolicy.
Result BuildCertChain(TrustDomain& trustDomain, Input cert, Result BuildCertChain(TrustDomain& trustDomain, Input cert, Time time,
Time time, EndEntityOrCA endEntityOrCA, EndEntityOrCA endEntityOrCA,
KeyUsage requiredKeyUsageIfPresent, KeyUsage requiredKeyUsageIfPresent,
KeyPurposeId requiredEKUIfPresent, KeyPurposeId requiredEKUIfPresent,
const CertPolicyId& requiredPolicy, const CertPolicyId& requiredPolicy,
@ -121,8 +105,7 @@ Result CheckCertHostname(Input cert, Input hostname,
// Construct an RFC-6960-encoded OCSP request, ready for submission to a // Construct an RFC-6960-encoded OCSP request, ready for submission to a
// responder, for the provided CertID. The request has no extensions. // responder, for the provided CertID. The request has no extensions.
static const size_t OCSP_REQUEST_MAX_LENGTH = 127; static const size_t OCSP_REQUEST_MAX_LENGTH = 127;
Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, const CertID& certID,
const CertID& certID,
/*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH], /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
/*out*/ size_t& outLen); /*out*/ size_t& outLen);
@ -139,10 +122,9 @@ Result CreateEncodedOCSPRequest(TrustDomain& trustDomain,
// which the encoded response is considered trustworthy (that is, as long as // which the encoded response is considered trustworthy (that is, as long as
// the given time at which to validate is less than or equal to validThrough, // the given time at which to validate is less than or equal to validThrough,
// the response will be considered trustworthy). // the response will be considered trustworthy).
Result VerifyEncodedOCSPResponse(TrustDomain& trustDomain, Result VerifyEncodedOCSPResponse(
const CertID& certID, Time time, TrustDomain& trustDomain, const CertID& certID, Time time,
uint16_t maxLifetimeInDays, uint16_t maxLifetimeInDays, Input encodedResponse,
Input encodedResponse,
/* out */ bool& expired, /* out */ bool& expired,
/* optional out */ Time* thisUpdate = nullptr, /* optional out */ Time* thisUpdate = nullptr,
/* optional out */ Time* validThrough = nullptr); /* optional out */ Time* validThrough = nullptr);
@ -154,7 +136,7 @@ Result VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
// requirement for another value. Empty extensions are also rejected. // requirement for another value. Empty extensions are also rejected.
Result CheckTLSFeaturesAreSatisfied(Input& cert, Result CheckTLSFeaturesAreSatisfied(Input& cert,
const Input* stapledOCSPResponse); const Input* stapledOCSPResponse);
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_pkix_h #endif // mozilla_pkix_pkix_h

View file

@ -1,39 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_pkixcheck_h #ifndef mozilla_pkix_pkixcheck_h
#define mozilla_pkix_pkixcheck_h #define mozilla_pkix_pkixcheck_h
#include "pkix/pkixtypes.h" #include "pkix/pkixtypes.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
class BackCert; class BackCert;
Result CheckIssuerIndependentProperties( Result CheckIssuerIndependentProperties(TrustDomain& trustDomain,
TrustDomain& trustDomain, const BackCert& cert, Time time,
const BackCert& cert,
Time time,
KeyUsage requiredKeyUsageIfPresent, KeyUsage requiredKeyUsageIfPresent,
KeyPurposeId requiredEKUIfPresent, KeyPurposeId requiredEKUIfPresent,
const CertPolicyId& requiredPolicy, const CertPolicyId& requiredPolicy,
@ -59,7 +41,7 @@ Result CheckValidity(Time time, Time notBefore, Time notAfter);
// Check that a subject has TLS Feature (rfc7633) requirements that match its // Check that a subject has TLS Feature (rfc7633) requirements that match its
// potential issuer // potential issuer
Result CheckTLSFeatures(const BackCert& subject, BackCert& potentialIssuer); Result CheckTLSFeatures(const BackCert& subject, BackCert& potentialIssuer);
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_pkixcheck_h #endif // mozilla_pkix_pkixcheck_h

View file

@ -1,25 +1,8 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_pkixder_h #ifndef mozilla_pkix_pkixder_h
#define mozilla_pkix_pkixder_h #define mozilla_pkix_pkixder_h
@ -39,23 +22,20 @@
#include "pkix/Input.h" #include "pkix/Input.h"
#include "pkix/pkixtypes.h" #include "pkix/pkixtypes.h"
namespace mozilla { namespace pkix { namespace der { namespace mozilla {
namespace pkix {
namespace der {
enum Class : uint8_t enum Class : uint8_t {
{
UNIVERSAL = 0 << 6, UNIVERSAL = 0 << 6,
// APPLICATION = 1 << 6, // unused // APPLICATION = 1 << 6, // unused
CONTEXT_SPECIFIC = 2 << 6, CONTEXT_SPECIFIC = 2 << 6,
// PRIVATE = 3 << 6 // unused // PRIVATE = 3 << 6 // unused
}; };
enum Constructed enum Constructed { CONSTRUCTED = 1 << 5 };
{
CONSTRUCTED = 1 << 5
};
enum Tag : uint8_t enum Tag : uint8_t {
{
BOOLEAN = UNIVERSAL | 0x01, BOOLEAN = UNIVERSAL | 0x01,
INTEGER = UNIVERSAL | 0x02, INTEGER = UNIVERSAL | 0x02,
BIT_STRING = UNIVERSAL | 0x03, BIT_STRING = UNIVERSAL | 0x03,
@ -79,9 +59,8 @@ Result ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag,
/*out*/ Input& value); /*out*/ Input& value);
Result End(Reader& input); Result End(Reader& input);
inline Result inline Result ExpectTagAndGetValue(Reader& input, uint8_t tag,
ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Input& value) /*out*/ Input& value) {
{
uint8_t actualTag; uint8_t actualTag;
Result rv = ReadTagAndGetValue(input, actualTag, value); Result rv = ReadTagAndGetValue(input, actualTag, value);
if (rv != Success) { if (rv != Success) {
@ -93,9 +72,8 @@ ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Input& value)
return Success; return Success;
} }
inline Result inline Result ExpectTagAndGetValue(Reader& input, uint8_t tag,
ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Reader& value) /*out*/ Reader& value) {
{
Input valueInput; Input valueInput;
Result rv = ExpectTagAndGetValue(input, tag, valueInput); Result rv = ExpectTagAndGetValue(input, tag, valueInput);
if (rv != Success) { if (rv != Success) {
@ -104,9 +82,7 @@ ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Reader& value)
return value.Init(valueInput); return value.Init(valueInput);
} }
inline Result inline Result ExpectTagAndEmptyValue(Reader& input, uint8_t tag) {
ExpectTagAndEmptyValue(Reader& input, uint8_t tag)
{
Reader value; Reader value;
Result rv = ExpectTagAndGetValue(input, tag, value); Result rv = ExpectTagAndGetValue(input, tag, value);
if (rv != Success) { if (rv != Success) {
@ -115,9 +91,7 @@ ExpectTagAndEmptyValue(Reader& input, uint8_t tag)
return End(value); return End(value);
} }
inline Result inline Result ExpectTagAndSkipValue(Reader& input, uint8_t tag) {
ExpectTagAndSkipValue(Reader& input, uint8_t tag)
{
Input ignoredValue; Input ignoredValue;
return ExpectTagAndGetValue(input, tag, ignoredValue); return ExpectTagAndGetValue(input, tag, ignoredValue);
} }
@ -135,9 +109,8 @@ inline Result SkipOptionalImplicitPrimitiveTag(Reader& input,
// Like ExpectTagAndGetValue, except the output Input will contain the // Like ExpectTagAndGetValue, except the output Input will contain the
// encoded tag and length along with the value. // encoded tag and length along with the value.
inline Result inline Result ExpectTagAndGetTLV(Reader& input, uint8_t tag,
ExpectTagAndGetTLV(Reader& input, uint8_t tag, /*out*/ Input& tlv) /*out*/ Input& tlv) {
{
Reader::Mark mark(input.GetMark()); Reader::Mark mark(input.GetMark());
Result rv = ExpectTagAndSkipValue(input, tag); Result rv = ExpectTagAndSkipValue(input, tag);
if (rv != Success) { if (rv != Success) {
@ -146,9 +119,7 @@ ExpectTagAndGetTLV(Reader& input, uint8_t tag, /*out*/ Input& tlv)
return input.GetInput(mark, tlv); return input.GetInput(mark, tlv);
} }
inline Result inline Result End(Reader& input) {
End(Reader& input)
{
if (!input.AtEnd()) { if (!input.AtEnd()) {
return Result::ERROR_BAD_DER; return Result::ERROR_BAD_DER;
} }
@ -157,9 +128,7 @@ End(Reader& input)
} }
template <typename Decoder> template <typename Decoder>
inline Result inline Result Nested(Reader& input, uint8_t tag, Decoder decoder) {
Nested(Reader& input, uint8_t tag, Decoder decoder)
{
Reader nested; Reader nested;
Result rv = ExpectTagAndGetValue(input, tag, nested); Result rv = ExpectTagAndGetValue(input, tag, nested);
if (rv != Success) { if (rv != Success) {
@ -173,9 +142,8 @@ Nested(Reader& input, uint8_t tag, Decoder decoder)
} }
template <typename Decoder> template <typename Decoder>
inline Result inline Result Nested(Reader& input, uint8_t outerTag, uint8_t innerTag,
Nested(Reader& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder) Decoder decoder) {
{
Reader nestedInput; Reader nestedInput;
Result rv = ExpectTagAndGetValue(input, outerTag, nestedInput); Result rv = ExpectTagAndGetValue(input, outerTag, nestedInput);
if (rv != Success) { if (rv != Success) {
@ -216,10 +184,8 @@ Nested(Reader& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder)
// foos. // foos.
// //
template <typename Decoder> template <typename Decoder>
inline Result inline Result NestedOf(Reader& input, uint8_t outerTag, uint8_t innerTag,
NestedOf(Reader& input, uint8_t outerTag, uint8_t innerTag, EmptyAllowed mayBeEmpty, Decoder decoder) {
EmptyAllowed mayBeEmpty, Decoder decoder)
{
Reader inner; Reader inner;
Result rv = ExpectTagAndGetValue(input, outerTag, inner); Result rv = ExpectTagAndGetValue(input, outerTag, inner);
if (rv != Success) { if (rv != Success) {
@ -247,10 +213,8 @@ NestedOf(Reader& input, uint8_t outerTag, uint8_t innerTag,
// DER-encoded data wrapped in a SEQUENCE (or similar) with nothing after it. // DER-encoded data wrapped in a SEQUENCE (or similar) with nothing after it.
// This function reduces the boilerplate necessary for stripping the outermost // This function reduces the boilerplate necessary for stripping the outermost
// SEQUENCE (or similar) and ensuring that nothing follows it. // SEQUENCE (or similar) and ensuring that nothing follows it.
inline Result inline Result ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag,
ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag, /*out*/ Reader& inner) {
/*out*/ Reader& inner)
{
Result rv = der::ExpectTagAndGetValue(outer, expectedTag, inner); Result rv = der::ExpectTagAndGetValue(outer, expectedTag, inner);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -259,10 +223,8 @@ ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag,
} }
// Similar to the above, but takes an Input instead of a Reader&. // Similar to the above, but takes an Input instead of a Reader&.
inline Result inline Result ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag,
ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag, /*out*/ Reader& inner) {
/*out*/ Reader& inner)
{
Reader outerReader(outer); Reader outerReader(outer);
return ExpectTagAndGetValueAtEnd(outerReader, expectedTag, inner); return ExpectTagAndGetValueAtEnd(outerReader, expectedTag, inner);
} }
@ -271,15 +233,14 @@ ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag,
namespace internal { namespace internal {
enum class IntegralValueRestriction enum class IntegralValueRestriction {
{
NoRestriction, NoRestriction,
MustBePositive, MustBePositive,
MustBe0To127, MustBe0To127,
}; };
Result IntegralBytes(Reader& input, uint8_t tag, Result IntegralBytes(
IntegralValueRestriction valueRestriction, Reader& input, uint8_t tag, IntegralValueRestriction valueRestriction,
/*out*/ Input& value, /*out*/ Input& value,
/*optional out*/ Input::size_type* significantBytes = nullptr); /*optional out*/ Input::size_type* significantBytes = nullptr);
@ -289,12 +250,9 @@ Result IntegralValue(Reader& input, uint8_t tag, /*out*/ uint8_t& value);
} // namespace internal } // namespace internal
Result Result BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value);
BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value);
inline Result inline Result Boolean(Reader& input, /*out*/ bool& value) {
Boolean(Reader& input, /*out*/ bool& value)
{
Reader valueReader; Reader valueReader;
Result rv = ExpectTagAndGetValue(input, BOOLEAN, valueReader); Result rv = ExpectTagAndGetValue(input, BOOLEAN, valueReader);
if (rv != Success) { if (rv != Success) {
@ -311,8 +269,12 @@ Boolean(Reader& input, /*out*/ bool& value)
return rv; return rv;
} }
switch (intValue) { switch (intValue) {
case 0: value = false; return Success; case 0:
case 0xFF: value = true; return Success; value = false;
return Success;
case 0xFF:
value = true;
return Success;
default: default:
return Result::ERROR_BAD_DER; return Result::ERROR_BAD_DER;
} }
@ -324,9 +286,7 @@ Boolean(Reader& input, /*out*/ bool& value)
// default value." However, it appears to be common that other libraries // default value." However, it appears to be common that other libraries
// incorrectly include the value of a BOOLEAN even when it's equal to the // incorrectly include the value of a BOOLEAN even when it's equal to the
// default value, so we allow invalid explicit encodings here. // default value, so we allow invalid explicit encodings here.
inline Result inline Result OptionalBoolean(Reader& input, /*out*/ bool& value) {
OptionalBoolean(Reader& input, /*out*/ bool& value)
{
value = false; value = false;
if (input.Peek(BOOLEAN)) { if (input.Peek(BOOLEAN)) {
Result rv = Boolean(input, value); Result rv = Boolean(input, value);
@ -339,9 +299,7 @@ OptionalBoolean(Reader& input, /*out*/ bool& value)
// This parser will only parse values between 0..127. If this range is // This parser will only parse values between 0..127. If this range is
// increased then callers will need to be changed. // increased then callers will need to be changed.
inline Result inline Result Enumerated(Reader& input, uint8_t& value) {
Enumerated(Reader& input, uint8_t& value)
{
return internal::IntegralValue(input, ENUMERATED | 0, value); return internal::IntegralValue(input, ENUMERATED | 0, value);
} }
@ -360,18 +318,14 @@ Result TimeChoice(Reader& input, uint8_t tag, /*out*/ Time& time);
// Only times from 1970-01-01-00:00:00 onward are accepted, in order to // Only times from 1970-01-01-00:00:00 onward are accepted, in order to
// eliminate the chance for complications in converting times to traditional // eliminate the chance for complications in converting times to traditional
// time formats that start at 1970. // time formats that start at 1970.
inline Result inline Result GeneralizedTime(Reader& input, /*out*/ Time& time) {
GeneralizedTime(Reader& input, /*out*/ Time& time)
{
return internal::TimeChoice(input, GENERALIZED_TIME, time); return internal::TimeChoice(input, GENERALIZED_TIME, time);
} }
// Only times from 1970-01-01-00:00:00 onward are accepted, in order to // Only times from 1970-01-01-00:00:00 onward are accepted, in order to
// eliminate the chance for complications in converting times to traditional // eliminate the chance for complications in converting times to traditional
// time formats that start at 1970. // time formats that start at 1970.
inline Result inline Result TimeChoice(Reader& input, /*out*/ Time& time) {
TimeChoice(Reader& input, /*out*/ Time& time)
{
uint8_t expectedTag = input.Peek(UTCTime) ? UTCTime : GENERALIZED_TIME; uint8_t expectedTag = input.Peek(UTCTime) ? UTCTime : GENERALIZED_TIME;
return internal::TimeChoice(input, expectedTag, time); return internal::TimeChoice(input, expectedTag, time);
} }
@ -380,20 +334,17 @@ TimeChoice(Reader& input, /*out*/ Time& time)
// zero are rejected. If significantBytes is not null, then it will be set to // zero are rejected. If significantBytes is not null, then it will be set to
// the number of significant bytes in the value (the length of the value, less // the number of significant bytes in the value (the length of the value, less
// the length of any leading padding), which is useful for key size checks. // the length of any leading padding), which is useful for key size checks.
inline Result inline Result PositiveInteger(
PositiveInteger(Reader& input, /*out*/ Input& value, Reader& input, /*out*/ Input& value,
/*optional out*/ Input::size_type* significantBytes = nullptr) /*optional out*/ Input::size_type* significantBytes = nullptr) {
{
return internal::IntegralBytes( return internal::IntegralBytes(
input, INTEGER, internal::IntegralValueRestriction::MustBePositive, input, INTEGER, internal::IntegralValueRestriction::MustBePositive, value,
value, significantBytes); significantBytes);
} }
// This parser will only parse values between 0..127. If this range is // This parser will only parse values between 0..127. If this range is
// increased then callers will need to be changed. // increased then callers will need to be changed.
inline Result inline Result Integer(Reader& input, /*out*/ uint8_t& value) {
Integer(Reader& input, /*out*/ uint8_t& value)
{
return internal::IntegralValue(input, INTEGER, value); return internal::IntegralValue(input, INTEGER, value);
} }
@ -401,9 +352,8 @@ Integer(Reader& input, /*out*/ uint8_t& value)
// increased then callers will need to be changed. The default value must be // increased then callers will need to be changed. The default value must be
// -1; defaultValue is only a parameter to make it clear in the calling code // -1; defaultValue is only a parameter to make it clear in the calling code
// what the default value is. // what the default value is.
inline Result inline Result OptionalInteger(Reader& input, long defaultValue,
OptionalInteger(Reader& input, long defaultValue, /*out*/ long& value) /*out*/ long& value) {
{
// If we need to support a different default value in the future, we need to // If we need to support a different default value in the future, we need to
// test that parsedValue != defaultValue. // test that parsedValue != defaultValue.
if (defaultValue != -1) { if (defaultValue != -1) {
@ -424,16 +374,12 @@ OptionalInteger(Reader& input, long defaultValue, /*out*/ long& value)
return Success; return Success;
} }
inline Result inline Result Null(Reader& input) {
Null(Reader& input)
{
return ExpectTagAndEmptyValue(input, NULLTag); return ExpectTagAndEmptyValue(input, NULLTag);
} }
template <uint8_t Len> template <uint8_t Len>
Result Result OID(Reader& input, const uint8_t (&expectedOid)[Len]) {
OID(Reader& input, const uint8_t (&expectedOid)[Len])
{
Reader value; Reader value;
Result rv = ExpectTagAndGetValue(input, OIDTag, value); Result rv = ExpectTagAndGetValue(input, OIDTag, value);
if (rv != Success) { if (rv != Success) {
@ -447,9 +393,7 @@ OID(Reader& input, const uint8_t (&expectedOid)[Len])
// PKI-specific types // PKI-specific types
inline Result inline Result CertificateSerialNumber(Reader& input, /*out*/ Input& value) {
CertificateSerialNumber(Reader& input, /*out*/ Input& value)
{
// http://tools.ietf.org/html/rfc5280#section-4.1.2.2: // http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
// //
// * "The serial number MUST be a positive integer assigned by the CA to // * "The serial number MUST be a positive integer assigned by the CA to
@ -461,13 +405,12 @@ CertificateSerialNumber(Reader& input, /*out*/ Input& value)
// that are negative or zero. Certificate users SHOULD be prepared to // that are negative or zero. Certificate users SHOULD be prepared to
// gracefully handle such certificates." // gracefully handle such certificates."
return internal::IntegralBytes( return internal::IntegralBytes(
input, INTEGER, internal::IntegralValueRestriction::NoRestriction, input, INTEGER, internal::IntegralValueRestriction::NoRestriction, value);
value);
} }
// x.509 and OCSP both use this same version numbering scheme, though OCSP // x.509 and OCSP both use this same version numbering scheme, though OCSP
// only supports v1. // only supports v1.
enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3 }; enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3, Uninitialized = 255 };
// X.509 Certificate and OCSP ResponseData both use // X.509 Certificate and OCSP ResponseData both use
// "[0] EXPLICIT Version DEFAULT v1". Although an explicit encoding of v1 is // "[0] EXPLICIT Version DEFAULT v1". Although an explicit encoding of v1 is
@ -476,10 +419,8 @@ enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3 };
Result OptionalVersion(Reader& input, /*out*/ Version& version); Result OptionalVersion(Reader& input, /*out*/ Version& version);
template <typename ExtensionHandler> template <typename ExtensionHandler>
inline Result inline Result OptionalExtensions(Reader& input, uint8_t tag,
OptionalExtensions(Reader& input, uint8_t tag, ExtensionHandler extensionHandler) {
ExtensionHandler extensionHandler)
{
if (!input.Peek(tag)) { if (!input.Peek(tag)) {
return Success; return Success;
} }
@ -490,7 +431,8 @@ OptionalExtensions(Reader& input, uint8_t tag,
// TODO(bug 997994): According to the specification, there should never be // TODO(bug 997994): According to the specification, there should never be
// an empty sequence of extensions but we've found OCSP responses that have // an empty sequence of extensions but we've found OCSP responses that have
// that (see bug 991898). // that (see bug 991898).
return NestedOf(tagged, SEQUENCE, SEQUENCE, EmptyAllowed::Yes, return NestedOf(
tagged, SEQUENCE, SEQUENCE, EmptyAllowed::Yes,
[extensionHandler](Reader& extension) -> Result { [extensionHandler](Reader& extension) -> Result {
// Extension ::= SEQUENCE { // Extension ::= SEQUENCE {
// extnID OBJECT IDENTIFIER, // extnID OBJECT IDENTIFIER,
@ -528,20 +470,15 @@ OptionalExtensions(Reader& input, uint8_t tag,
Result DigestAlgorithmIdentifier(Reader& input, Result DigestAlgorithmIdentifier(Reader& input,
/*out*/ DigestAlgorithm& algorithm); /*out*/ DigestAlgorithm& algorithm);
enum class PublicKeyAlgorithm enum class PublicKeyAlgorithm { RSA_PKCS1, ECDSA, Uninitialized };
{
RSA_PKCS1,
ECDSA,
};
Result SignatureAlgorithmIdentifierValue( Result SignatureAlgorithmIdentifierValue(
Reader& input, Reader& input,
/*out*/ PublicKeyAlgorithm& publicKeyAlgorithm, /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
/*out*/ DigestAlgorithm& digestAlgorithm); /*out*/ DigestAlgorithm& digestAlgorithm);
struct SignedDataWithSignature final struct SignedDataWithSignature final {
{ public:
public:
Input data; Input data;
Input algorithm; Input algorithm;
Input signature; Input signature;
@ -569,7 +506,8 @@ public:
// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
Result SignedData(Reader& input, /*out*/ Reader& tbs, Result SignedData(Reader& input, /*out*/ Reader& tbs,
/*out*/ SignedDataWithSignature& signedDataWithSignature); /*out*/ SignedDataWithSignature& signedDataWithSignature);
}
} } } // namespace mozilla::pkix::der }
} // namespace mozilla::pkix::der
#endif // mozilla_pkix_pkixder_h #endif // mozilla_pkix_pkixder_h

View file

@ -1,34 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_pkixnss_h #ifndef mozilla_pkix_pkixnss_h
#define mozilla_pkix_pkixnss_h #define mozilla_pkix_pkixnss_h
#include "pkixtypes.h" #include <seccomon.h>
#include "pkix/pkixtypes.h"
#include "prerror.h" #include "prerror.h"
#include "seccomon.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
// Verifies the PKCS#1.5 signature on the given data using the given RSA public // Verifies the PKCS#1.5 signature on the given data using the given RSA public
// key. // key.
@ -53,10 +37,8 @@ Result VerifyECDSASignedDigestNSS(const SignedDigest& sd,
// TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our // TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
// other, extensive, memory safety efforts in mozilla::pkix, and we should find // other, extensive, memory safety efforts in mozilla::pkix, and we should find
// a way to provide a more-obviously-safe interface. // a way to provide a more-obviously-safe interface.
Result DigestBufNSS(Input item, Result DigestBufNSS(Input item, DigestAlgorithm digestAlg,
DigestAlgorithm digestAlg, /*out*/ uint8_t* digestBuf, size_t digestBufLen);
/*out*/ uint8_t* digestBuf,
size_t digestBufLen);
Result MapPRErrorCodeToResult(PRErrorCode errorCode); Result MapPRErrorCodeToResult(PRErrorCode errorCode);
PRErrorCode MapResultToPRErrorCode(Result result); PRErrorCode MapResultToPRErrorCode(Result result);
@ -71,8 +53,7 @@ PRErrorCode MapResultToPRErrorCode(Result result);
static const PRErrorCode ERROR_BASE = -0x4000; static const PRErrorCode ERROR_BASE = -0x4000;
static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000; static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000;
enum ErrorCode enum ErrorCode {
{
MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0, MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0,
MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1, MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1,
MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = ERROR_BASE + 2, MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = ERROR_BASE + 2,
@ -86,23 +67,22 @@ enum ErrorCode
MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING = ERROR_BASE + 10, MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING = ERROR_BASE + 10,
MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING = ERROR_BASE + 11, MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING = ERROR_BASE + 11,
MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = ERROR_BASE + 12, MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME = ERROR_BASE + 12,
MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED = ERROR_BASE + 13,
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = ERROR_BASE + 14,
MOZILLA_PKIX_ERROR_MITM_DETECTED = ERROR_BASE + 15,
END_OF_LIST END_OF_LIST
}; };
void RegisterErrorTable(); void RegisterErrorTable();
inline SECItem UnsafeMapInputToSECItem(Input input) inline SECItem UnsafeMapInputToSECItem(Input input) {
{ SECItem result = {siBuffer, const_cast<uint8_t*>(input.UnsafeGetData()),
SECItem result = { input.GetLength()};
siBuffer,
const_cast<uint8_t*>(input.UnsafeGetData()),
input.GetLength()
};
static_assert(sizeof(decltype(input.GetLength())) <= sizeof(result.len), static_assert(sizeof(decltype(input.GetLength())) <= sizeof(result.len),
"input.GetLength() must fit in a SECItem"); "input.GetLength() must fit in a SECItem");
return result; return result;
} }
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_pkixnss_h #endif // mozilla_pkix_pkixnss_h

View file

@ -1,45 +1,29 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_pkixtypes_h #ifndef mozilla_pkix_pkixtypes_h
#define mozilla_pkix_pkixtypes_h #define mozilla_pkix_pkixtypes_h
#include <memory>
#include "pkix/Input.h" #include "pkix/Input.h"
#include "pkix/Time.h" #include "pkix/Time.h"
#include "stdint.h" #include "stdint.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
enum class DigestAlgorithm enum class DigestAlgorithm {
{
sha512 = 1, sha512 = 1,
sha384 = 2, sha384 = 2,
sha256 = 3, sha256 = 3,
sha1 = 4, sha1 = 4,
}; };
enum class NamedCurve enum class NamedCurve {
{
// secp521r1 (OID 1.3.132.0.35, RFC 5480) // secp521r1 (OID 1.3.132.0.35, RFC 5480)
secp521r1 = 1, secp521r1 = 1,
@ -50,8 +34,7 @@ enum class NamedCurve
secp256r1 = 3, secp256r1 = 3,
}; };
struct SignedDigest final struct SignedDigest final {
{
Input digest; Input digest;
DigestAlgorithm digestAlgorithm; DigestAlgorithm digestAlgorithm;
Input signature; Input signature;
@ -61,8 +44,7 @@ struct SignedDigest final
enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 }; enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
enum class KeyUsage : uint8_t enum class KeyUsage : uint8_t {
{
digitalSignature = 0, digitalSignature = 0,
nonRepudiation = 1, nonRepudiation = 1,
keyEncipherment = 2, keyEncipherment = 2,
@ -75,8 +57,7 @@ enum class KeyUsage : uint8_t
noParticularKeyUsageRequired = 0xff, noParticularKeyUsageRequired = 0xff,
}; };
enum class KeyPurposeId enum class KeyPurposeId {
{
anyExtendedKeyUsage = 0, anyExtendedKeyUsage = 0,
id_kp_serverAuth = 1, // id-kp-serverAuth id_kp_serverAuth = 1, // id-kp-serverAuth
id_kp_clientAuth = 2, // id-kp-clientAuth id_kp_clientAuth = 2, // id-kp-clientAuth
@ -85,19 +66,18 @@ enum class KeyPurposeId
id_kp_OCSPSigning = 9, // id-kp-OCSPSigning id_kp_OCSPSigning = 9, // id-kp-OCSPSigning
}; };
struct CertPolicyId final struct CertPolicyId final {
{
uint16_t numBytes; uint16_t numBytes;
static const uint16_t MAX_BYTES = 24; static const uint16_t MAX_BYTES = 24;
uint8_t bytes[MAX_BYTES]; uint8_t bytes[MAX_BYTES];
bool IsAnyPolicy() const; bool IsAnyPolicy() const;
bool operator==(const CertPolicyId& other) const;
static const CertPolicyId anyPolicy; static const CertPolicyId anyPolicy;
}; };
enum class TrustLevel enum class TrustLevel {
{
TrustAnchor = 1, // certificate is a trusted root CA certificate or TrustAnchor = 1, // certificate is a trusted root CA certificate or
// equivalent *for the given policy*. // equivalent *for the given policy*.
ActivelyDistrusted = 2, // certificate is known to be bad ActivelyDistrusted = 2, // certificate is known to be bad
@ -106,8 +86,7 @@ enum class TrustLevel
// Extensions extracted during the verification flow. // Extensions extracted during the verification flow.
// See TrustDomain::NoteAuxiliaryExtension. // See TrustDomain::NoteAuxiliaryExtension.
enum class AuxiliaryExtension enum class AuxiliaryExtension {
{
// Certificate Transparency data, specifically Signed Certificate // Certificate Transparency data, specifically Signed Certificate
// Timestamps (SCTs). See RFC 6962. // Timestamps (SCTs). See RFC 6962.
@ -130,25 +109,22 @@ enum class AuxiliaryExtension
// field from the issuer's certificate. serialNumber is the entire DER-encoded // field from the issuer's certificate. serialNumber is the entire DER-encoded
// serial number from the subject certificate (the certificate for which we are // serial number from the subject certificate (the certificate for which we are
// checking the revocation status). // checking the revocation status).
struct CertID final struct CertID final {
{ public:
public: CertID(Input aIssuer, Input aIssuerSubjectPublicKeyInfo, Input aSerialNumber)
CertID(Input issuer, Input issuerSubjectPublicKeyInfo, Input serialNumber) : issuer(aIssuer),
: issuer(issuer) issuerSubjectPublicKeyInfo(aIssuerSubjectPublicKeyInfo),
, issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo) serialNumber(aSerialNumber) {}
, serialNumber(serialNumber)
{
}
const Input issuer; const Input issuer;
const Input issuerSubjectPublicKeyInfo; const Input issuerSubjectPublicKeyInfo;
const Input serialNumber; const Input serialNumber;
void operator=(const CertID&) = delete; void operator=(const CertID&) = delete;
}; };
typedef std::unique_ptr<CertID> ScopedCertID;
class DERArray class DERArray {
{ public:
public:
// Returns the number of DER-encoded items in the array. // Returns the number of DER-encoded items in the array.
virtual size_t GetLength() const = 0; virtual size_t GetLength() const = 0;
@ -156,19 +132,19 @@ public:
// (0-indexed). The result is guaranteed to be non-null if i < GetLength(), // (0-indexed). The result is guaranteed to be non-null if i < GetLength(),
// and the result is guaranteed to be nullptr if i >= GetLength(). // and the result is guaranteed to be nullptr if i >= GetLength().
virtual const Input* GetDER(size_t i) const = 0; virtual const Input* GetDER(size_t i) const = 0;
protected:
DERArray() { } protected:
virtual ~DERArray() { } DERArray() {}
virtual ~DERArray() {}
}; };
// Applications control the behavior of path building and verification by // Applications control the behavior of path building and verification by
// implementing the TrustDomain interface. The TrustDomain is used for all // implementing the TrustDomain interface. The TrustDomain is used for all
// cryptography and for determining which certificates are trusted or // cryptography and for determining which certificates are trusted or
// distrusted. // distrusted.
class TrustDomain class TrustDomain {
{ public:
public: virtual ~TrustDomain() {}
virtual ~TrustDomain() { }
// Determine the level of trust in the given certificate for the given role. // Determine the level of trust in the given certificate for the given role.
// This will be called for every certificate encountered during path // This will be called for every certificate encountered during path
@ -187,8 +163,7 @@ public:
Input candidateCertDER, Input candidateCertDER,
/*out*/ TrustLevel& trustLevel) = 0; /*out*/ TrustLevel& trustLevel) = 0;
class IssuerChecker class IssuerChecker {
{
public: public:
// potentialIssuerDER is the complete DER encoding of the certificate to // potentialIssuerDER is the complete DER encoding of the certificate to
// be checked as a potential issuer. // be checked as a potential issuer.
@ -200,6 +175,7 @@ public:
virtual Result Check(Input potentialIssuerDER, virtual Result Check(Input potentialIssuerDER,
/*optional*/ const Input* additionalNameConstraints, /*optional*/ const Input* additionalNameConstraints,
/*out*/ bool& keepGoing) = 0; /*out*/ bool& keepGoing) = 0;
protected: protected:
IssuerChecker(); IssuerChecker();
virtual ~IssuerChecker(); virtual ~IssuerChecker();
@ -254,8 +230,8 @@ public:
// implementation has an efficient way of filtering potential issuers by name // implementation has an efficient way of filtering potential issuers by name
// and/or validity period itself, then it is probably better for performance // and/or validity period itself, then it is probably better for performance
// for it to do so. // for it to do so.
virtual Result FindIssuer(Input encodedIssuerName, virtual Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
IssuerChecker& checker, Time time) = 0; Time time) = 0;
// Called as soon as we think we have a valid chain but before revocation // Called as soon as we think we have a valid chain but before revocation
// checks are done. This function can be used to compute additional checks, // checks are done. This function can be used to compute additional checks,
@ -265,7 +241,8 @@ public:
// //
// This function may be called multiple times, regardless of whether it // This function may be called multiple times, regardless of whether it
// returns success or failure. It is guaranteed that BuildCertChain will not // returns success or failure. It is guaranteed that BuildCertChain will not
// return Success unless the last call to IsChainValid returns Success. Further, // return Success unless the last call to IsChainValid returns Success.
// Further,
// it is guaranteed that when BuildCertChain returns Success the last chain // it is guaranteed that when BuildCertChain returns Success the last chain
// passed to IsChainValid is the valid chain that should be used for further // passed to IsChainValid is the valid chain that should be used for further
// operations that require the whole chain. // operations that require the whole chain.
@ -278,13 +255,15 @@ public:
// wrong to assume that the certificate chain is valid. // wrong to assume that the certificate chain is valid.
// //
// certChain.GetDER(0) is the trust anchor. // certChain.GetDER(0) is the trust anchor.
virtual Result IsChainValid(const DERArray& certChain, Time time) = 0; virtual Result IsChainValid(const DERArray& certChain, Time time,
const CertPolicyId& requiredPolicy) = 0;
virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA, virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA,
const CertID& certID, Time time, const CertID& certID, Time time,
Duration validityDuration, Duration validityDuration,
/*optional*/ const Input* stapledOCSPresponse, /*optional*/ const Input* stapledOCSPresponse,
/*optional*/ const Input* aiaExtension) = 0; /*optional*/ const Input* aiaExtension,
/*optional*/ const Input* sctExtension) = 0;
// Check that the given digest algorithm is acceptable for use in signatures. // Check that the given digest algorithm is acceptable for use in signatures.
// //
@ -301,8 +280,7 @@ public:
// Result::ERROR_INADEQUATE_KEY_SIZE if the key size is not acceptable, // Result::ERROR_INADEQUATE_KEY_SIZE if the key size is not acceptable,
// or another error code if another error occurred. // or another error code if another error occurred.
virtual Result CheckRSAPublicKeyModulusSizeInBits( virtual Result CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA endEntityOrCA, EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) = 0;
unsigned int modulusSizeInBits) = 0;
// Verify the given RSA PKCS#1.5 signature on the given digest using the // Verify the given RSA PKCS#1.5 signature on the given digest using the
// given RSA public key. // given RSA public key.
@ -311,8 +289,7 @@ public:
// function, so it is not necessary to repeat those checks here. However, // function, so it is not necessary to repeat those checks here. However,
// VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical // VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical
// verification of the public key validity as specified in NIST SP 800-56A. // verification of the public key validity as specified in NIST SP 800-56A.
virtual Result VerifyRSAPKCS1SignedDigest( virtual Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) = 0; Input subjectPublicKeyInfo) = 0;
// Check that the given named ECC curve is acceptable for ECDSA signatures. // Check that the given named ECC curve is acceptable for ECDSA signatures.
@ -368,12 +345,11 @@ public:
// TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our // TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
// other, extensive, memory safety efforts in mozilla::pkix, and we should // other, extensive, memory safety efforts in mozilla::pkix, and we should
// find a way to provide a more-obviously-safe interface. // find a way to provide a more-obviously-safe interface.
virtual Result DigestBuf(Input item, virtual Result DigestBuf(Input item, DigestAlgorithm digestAlg,
DigestAlgorithm digestAlg, /*out*/ uint8_t* digestBuf, size_t digestBufLen) = 0;
/*out*/ uint8_t* digestBuf,
size_t digestBufLen) = 0; protected:
protected: TrustDomain() {}
TrustDomain() { }
TrustDomain(const TrustDomain&) = delete; TrustDomain(const TrustDomain&) = delete;
void operator=(const TrustDomain&) = delete; void operator=(const TrustDomain&) = delete;
@ -384,10 +360,9 @@ enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 };
// Applications control the behavior of matching presented name information from // Applications control the behavior of matching presented name information from
// a certificate against a reference hostname by implementing the // a certificate against a reference hostname by implementing the
// NameMatchingPolicy interface. Used in concert with CheckCertHostname. // NameMatchingPolicy interface. Used in concert with CheckCertHostname.
class NameMatchingPolicy class NameMatchingPolicy {
{ public:
public: virtual ~NameMatchingPolicy() {}
virtual ~NameMatchingPolicy() { }
// Given that the certificate in question has a notBefore field with the given // Given that the certificate in question has a notBefore field with the given
// value, should name matching fall back to searching within the subject // value, should name matching fall back to searching within the subject
@ -396,13 +371,13 @@ public:
Time notBefore, Time notBefore,
/*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0; /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0;
protected: protected:
NameMatchingPolicy() { } NameMatchingPolicy() {}
NameMatchingPolicy(const NameMatchingPolicy&) = delete; NameMatchingPolicy(const NameMatchingPolicy&) = delete;
void operator=(const NameMatchingPolicy&) = delete; void operator=(const NameMatchingPolicy&) = delete;
}; };
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_pkixtypes_h #endif // mozilla_pkix_pkixtypes_h

View file

@ -1,32 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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_pkixutil_h #ifndef mozilla_pkix_pkixutil_h
#define mozilla_pkix_pkixutil_h #define mozilla_pkix_pkixutil_h
#include "pkixder.h" #include "pkix/pkixder.h"
namespace mozilla { namespace pkix { namespace mozilla {
namespace pkix {
// During path building and verification, we build a linked list of BackCerts // During path building and verification, we build a linked list of BackCerts
// from the current cert toward the end-entity certificate. The linked list // from the current cert toward the end-entity certificate. The linked list
@ -37,17 +21,15 @@ namespace mozilla { namespace pkix {
// Each BackCert contains pointers to all the given certificate's extensions // Each BackCert contains pointers to all the given certificate's extensions
// so that we can parse the extension block once and then process the // so that we can parse the extension block once and then process the
// extensions in an order that may be different than they appear in the cert. // extensions in an order that may be different than they appear in the cert.
class BackCert final class BackCert final {
{ public:
public:
// certDER and childCert must be valid for the lifetime of BackCert. // certDER and childCert must be valid for the lifetime of BackCert.
BackCert(Input certDER, EndEntityOrCA endEntityOrCA, BackCert(Input aCertDER, EndEntityOrCA aEndEntityOrCA,
const BackCert* childCert) const BackCert* aChildCert)
: der(certDER) : der(aCertDER),
, endEntityOrCA(endEntityOrCA) endEntityOrCA(aEndEntityOrCA),
, childCert(childCert) childCert(aChildCert),
{ version(der::Version::Uninitialized) {}
}
Result Init(); Result Init();
@ -65,67 +47,47 @@ public:
// RFC 5280 names for everything. // RFC 5280 names for everything.
const Input GetValidity() const { return validity; } const Input GetValidity() const { return validity; }
const Input GetSubject() const { return subject; } const Input GetSubject() const { return subject; }
const Input GetSubjectPublicKeyInfo() const const Input GetSubjectPublicKeyInfo() const { return subjectPublicKeyInfo; }
{ const Input* GetAuthorityInfoAccess() const {
return subjectPublicKeyInfo;
}
const Input* GetAuthorityInfoAccess() const
{
return MaybeInput(authorityInfoAccess); return MaybeInput(authorityInfoAccess);
} }
const Input* GetBasicConstraints() const const Input* GetBasicConstraints() const {
{
return MaybeInput(basicConstraints); return MaybeInput(basicConstraints);
} }
const Input* GetCertificatePolicies() const const Input* GetCertificatePolicies() const {
{
return MaybeInput(certificatePolicies); return MaybeInput(certificatePolicies);
} }
const Input* GetExtKeyUsage() const const Input* GetExtKeyUsage() const { return MaybeInput(extKeyUsage); }
{ const Input* GetKeyUsage() const { return MaybeInput(keyUsage); }
return MaybeInput(extKeyUsage); const Input* GetInhibitAnyPolicy() const {
}
const Input* GetKeyUsage() const
{
return MaybeInput(keyUsage);
}
const Input* GetInhibitAnyPolicy() const
{
return MaybeInput(inhibitAnyPolicy); return MaybeInput(inhibitAnyPolicy);
} }
const Input* GetNameConstraints() const const Input* GetNameConstraints() const {
{
return MaybeInput(nameConstraints); return MaybeInput(nameConstraints);
} }
const Input* GetSubjectAltName() const const Input* GetSubjectAltName() const { return MaybeInput(subjectAltName); }
{ const Input* GetRequiredTLSFeatures() const {
return MaybeInput(subjectAltName);
}
const Input* GetRequiredTLSFeatures() const
{
return MaybeInput(requiredTLSFeatures); return MaybeInput(requiredTLSFeatures);
} }
const Input* GetSignedCertificateTimestamps() const const Input* GetSignedCertificateTimestamps() const {
{
return MaybeInput(signedCertificateTimestamps); return MaybeInput(signedCertificateTimestamps);
} }
private: private:
const Input der; const Input der;
public: public:
const EndEntityOrCA endEntityOrCA; const EndEntityOrCA endEntityOrCA;
BackCert const* const childCert; BackCert const* const childCert;
private: private:
// When parsing certificates in BackCert::Init, we don't accept empty // When parsing certificates in BackCert::Init, we don't accept empty
// extensions. Consequently, we don't have to store a distinction between // extensions. Consequently, we don't have to store a distinction between
// empty extensions and extensions that weren't included. However, when // empty extensions and extensions that weren't included. However, when
// *processing* extensions, we distinguish between whether an extension was // *processing* extensions, we distinguish between whether an extension was
// included or not based on whetehr the GetXXX function for the extension // included or not based on whetehr the GetXXX function for the extension
// returns nullptr. // returns nullptr.
static inline const Input* MaybeInput(const Input& item) static inline const Input* MaybeInput(const Input& item) {
{
return item.GetLength() > 0 ? &item : nullptr; return item.GetLength() > 0 ? &item : nullptr;
} }
@ -161,25 +123,20 @@ private:
void operator=(const BackCert&) = delete; void operator=(const BackCert&) = delete;
}; };
class NonOwningDERArray final : public DERArray class NonOwningDERArray final : public DERArray {
{ public:
public: NonOwningDERArray() : numItems(0) {
NonOwningDERArray()
: numItems(0)
{
// we don't need to initialize the items array because we always check // we don't need to initialize the items array because we always check
// numItems before accessing i. // numItems before accessing i.
} }
size_t GetLength() const override { return numItems; } size_t GetLength() const override { return numItems; }
const Input* GetDER(size_t i) const override const Input* GetDER(size_t i) const override {
{
return i < numItems ? &items[i] : nullptr; return i < numItems ? &items[i] : nullptr;
} }
Result Append(Input der) Result Append(Input der) {
{
if (numItems >= MAX_LENGTH) { if (numItems >= MAX_LENGTH) {
return Result::FATAL_ERROR_INVALID_ARGS; return Result::FATAL_ERROR_INVALID_ARGS;
} }
@ -193,7 +150,8 @@ public:
// Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT. // Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT.
static const size_t MAX_LENGTH = 8; static const size_t MAX_LENGTH = 8;
private:
private:
Input items[MAX_LENGTH]; // avoids any heap allocations Input items[MAX_LENGTH]; // avoids any heap allocations
size_t numItems; size_t numItems;
@ -203,16 +161,13 @@ private:
// Extracts the SignedCertificateTimestampList structure which is encoded as an // Extracts the SignedCertificateTimestampList structure which is encoded as an
// OCTET STRING within the X.509v3 / OCSP extensions (see RFC 6962 section 3.3). // OCTET STRING within the X.509v3 / OCSP extensions (see RFC 6962 section 3.3).
Result Result ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
Input& sctList); Input& sctList);
inline unsigned int inline unsigned int DaysBeforeYear(unsigned int year) {
DaysBeforeYear(unsigned int year)
{
assert(year <= 9999); assert(year <= 9999);
return ((year - 1u) * 365u) return ((year - 1u) * 365u) +
+ ((year - 1u) / 4u) // leap years are every 4 years, ((year - 1u) / 4u) // leap years are every 4 years,
- ((year - 1u) / 100u) // except years divisible by 100, - ((year - 1u) / 100u) // except years divisible by 100,
+ ((year - 1u) / 400u); // except years divisible by 400. + ((year - 1u) / 400u); // except years divisible by 400.
} }
@ -221,7 +176,7 @@ static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8; // sha-512
Result DigestSignedData(TrustDomain& trustDomain, Result DigestSignedData(TrustDomain& trustDomain,
const der::SignedDataWithSignature& signedData, const der::SignedDataWithSignature& signedData,
/*out*/ uint8_t(&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES], /*out*/ uint8_t (&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES],
/*out*/ der::PublicKeyAlgorithm& publicKeyAlg, /*out*/ der::PublicKeyAlgorithm& publicKeyAlg,
/*out*/ SignedDigest& signedDigest); /*out*/ SignedDigest& signedDigest);
@ -237,8 +192,8 @@ Result VerifySignedData(TrustDomain& trustDomain,
// Extracts the key parameters from |subjectPublicKeyInfo|, invoking // Extracts the key parameters from |subjectPublicKeyInfo|, invoking
// the relevant methods of |trustDomain|. // the relevant methods of |trustDomain|.
Result Result CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo,
CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, TrustDomain& trustDomain, TrustDomain& trustDomain,
EndEntityOrCA endEntityOrCA); EndEntityOrCA endEntityOrCA);
// In a switch over an enum, sometimes some compilers are not satisfied that // In a switch over an enum, sometimes some compilers are not satisfied that
@ -273,16 +228,20 @@ CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, TrustDomain& trustDomain,
// GCC will warn if not all cases are covered (-Wswitch-enum). It does not // GCC will warn if not all cases are covered (-Wswitch-enum). It does not
// assume that the default case is unreachable. // assume that the default case is unreachable.
#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \ #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \
default: assert(false); __builtin_unreachable(); default: \
assert(false); \
__builtin_unreachable();
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
// MSVC will warn if not all cases are covered (C4061, level 4). It does not // MSVC will warn if not all cases are covered (C4061, level 4). It does not
// assume that the default case is unreachable. // assume that the default case is unreachable.
#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \ #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \
default: assert(false); __assume(0); default: \
assert(false); \
__assume(0);
#else #else
#error Unsupported compiler for MOZILLA_PKIX_UNREACHABLE_DEFAULT. #error Unsupported compiler for MOZILLA_PKIX_UNREACHABLE_DEFAULT.
#endif #endif
}
} } // namespace mozilla::pkix } // namespace mozilla::pkix
#endif // mozilla_pkix_pkixutil_h #endif // mozilla_pkix_pkixutil_h

View file

@ -1,82 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_ScopedPtr_h
#define mozilla_pkix_ScopedPtr_h
namespace mozilla { namespace pkix {
// A subset polyfill of std::unique_ptr that does not support move construction
// or move assignment. This is used instead of std::unique_ptr because some
// important toolchains still don't provide std::unique_ptr, including in
// particular Android NDK projects with APP_STL=stlport_static or
// ALL_STL=stlport_shared.
template <typename T, void (&Destroyer)(T*)>
class ScopedPtr final
{
public:
explicit ScopedPtr(T* value = nullptr) : mValue(value) { }
ScopedPtr(const ScopedPtr&) = delete;
~ScopedPtr()
{
if (mValue) {
Destroyer(mValue);
}
}
void operator=(const ScopedPtr&) = delete;
T& operator*() const { return *mValue; }
T* operator->() const { return mValue; }
explicit operator bool() const { return mValue; }
T* get() const { return mValue; }
T* release()
{
T* result = mValue;
mValue = nullptr;
return result;
}
void reset(T* newValue = nullptr)
{
// The C++ standard requires std::unique_ptr to destroy the old value
// pointed to by mValue, if any, *after* assigning the new value to mValue.
T* oldValue = mValue;
mValue = newValue;
if (oldValue) {
Destroyer(oldValue);
}
}
private:
T* mValue;
};
} } // namespace mozilla::pkix
#endif // mozilla_pkix_ScopedPtr_h

View file

@ -1,30 +1,13 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkix/pkix.h" #include "pkix/pkix.h"
#include "pkixcheck.h" #include "pkix/pkixcheck.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace pkix { namespace mozilla { namespace pkix {
@ -35,7 +18,8 @@ static Result BuildForward(TrustDomain& trustDomain,
KeyPurposeId requiredEKUIfPresent, KeyPurposeId requiredEKUIfPresent,
const CertPolicyId& requiredPolicy, const CertPolicyId& requiredPolicy,
/*optional*/ const Input* stapledOCSPResponse, /*optional*/ const Input* stapledOCSPResponse,
unsigned int subCACount); unsigned int subCACount,
unsigned int& buildForwardCallBudget);
TrustDomain::IssuerChecker::IssuerChecker() { } TrustDomain::IssuerChecker::IssuerChecker() { }
TrustDomain::IssuerChecker::~IssuerChecker() { } TrustDomain::IssuerChecker::~IssuerChecker() { }
@ -45,21 +29,24 @@ TrustDomain::IssuerChecker::~IssuerChecker() { }
class PathBuildingStep final : public TrustDomain::IssuerChecker class PathBuildingStep final : public TrustDomain::IssuerChecker
{ {
public: public:
PathBuildingStep(TrustDomain& trustDomain, const BackCert& subject, PathBuildingStep(TrustDomain& aTrustDomain, const BackCert& aSubject,
Time time, KeyPurposeId requiredEKUIfPresent, Time aTime, KeyPurposeId aRequiredEKUIfPresent,
const CertPolicyId& requiredPolicy, const CertPolicyId& aRequiredPolicy,
/*optional*/ const Input* stapledOCSPResponse, /*optional*/ const Input* aStapledOCSPResponse,
unsigned int subCACount, Result deferredSubjectError) unsigned int aSubCACount, Result aDeferredSubjectError,
: trustDomain(trustDomain) unsigned int& aBuildForwardCallBudget)
, subject(subject) : trustDomain(aTrustDomain)
, time(time) , subject(aSubject)
, requiredEKUIfPresent(requiredEKUIfPresent) , time(aTime)
, requiredPolicy(requiredPolicy) , requiredEKUIfPresent(aRequiredEKUIfPresent)
, stapledOCSPResponse(stapledOCSPResponse) , requiredPolicy(aRequiredPolicy)
, subCACount(subCACount) , stapledOCSPResponse(aStapledOCSPResponse)
, deferredSubjectError(deferredSubjectError) , subCACount(aSubCACount)
, deferredSubjectError(aDeferredSubjectError)
, subjectSignaturePublicKeyAlg(der::PublicKeyAlgorithm::Uninitialized)
, result(Result::FATAL_ERROR_LIBRARY_FAILURE) , result(Result::FATAL_ERROR_LIBRARY_FAILURE)
, resultWasSet(false) , resultWasSet(false)
, buildForwardCallBudget(aBuildForwardCallBudget)
{ {
} }
@ -87,6 +74,7 @@ private:
Result RecordResult(Result currentResult, /*out*/ bool& keepGoing); Result RecordResult(Result currentResult, /*out*/ bool& keepGoing);
Result result; Result result;
bool resultWasSet; bool resultWasSet;
unsigned int& buildForwardCallBudget;
PathBuildingStep(const PathBuildingStep&) = delete; PathBuildingStep(const PathBuildingStep&) = delete;
void operator=(const PathBuildingStep&) = delete; void operator=(const PathBuildingStep&) = delete;
@ -160,9 +148,8 @@ PathBuildingStep::Check(Input potentialIssuerDER,
// Loop prevention, done as recommended by RFC4158 Section 5.2 // Loop prevention, done as recommended by RFC4158 Section 5.2
// TODO: this doesn't account for subjectAltNames! // TODO: this doesn't account for subjectAltNames!
// TODO(perf): This probably can and should be optimized in some way. // TODO(perf): This probably can and should be optimized in some way.
bool loopDetected = false; for (const BackCert* prev = potentialIssuer.childCert; prev;
for (const BackCert* prev = potentialIssuer.childCert; prev = prev->childCert) {
!loopDetected && prev != nullptr; prev = prev->childCert) {
if (InputsAreEqual(potentialIssuer.GetSubjectPublicKeyInfo(), if (InputsAreEqual(potentialIssuer.GetSubjectPublicKeyInfo(),
prev->GetSubjectPublicKeyInfo()) && prev->GetSubjectPublicKeyInfo()) &&
InputsAreEqual(potentialIssuer.GetSubject(), prev->GetSubject())) { InputsAreEqual(potentialIssuer.GetSubject(), prev->GetSubject())) {
@ -192,11 +179,20 @@ PathBuildingStep::Check(Input potentialIssuerDER,
return RecordResult(rv, keepGoing); return RecordResult(rv, keepGoing);
} }
// If we've ran out of budget, stop searching.
if (buildForwardCallBudget == 0) {
Result savedRv = RecordResult(Result::ERROR_UNKNOWN_ISSUER, keepGoing);
keepGoing = false;
return savedRv;
}
buildForwardCallBudget--;
// RFC 5280, Section 4.2.1.3: "If the keyUsage extension is present, then the // RFC 5280, Section 4.2.1.3: "If the keyUsage extension is present, then the
// subject public key MUST NOT be used to verify signatures on certificates // subject public key MUST NOT be used to verify signatures on certificates
// or CRLs unless the corresponding keyCertSign or cRLSign bit is set." // or CRLs unless the corresponding keyCertSign or cRLSign bit is set."
rv = BuildForward(trustDomain, potentialIssuer, time, KeyUsage::keyCertSign, rv = BuildForward(trustDomain, potentialIssuer, time, KeyUsage::keyCertSign,
requiredEKUIfPresent, requiredPolicy, nullptr, subCACount); requiredEKUIfPresent, requiredPolicy, nullptr, subCACount,
buildForwardCallBudget);
if (rv != Success) { if (rv != Success) {
return RecordResult(rv, keepGoing); return RecordResult(rv, keepGoing);
} }
@ -239,9 +235,15 @@ PathBuildingStep::Check(Input potentialIssuerDER,
Duration validityDuration(notAfter, notBefore); Duration validityDuration(notAfter, notBefore);
rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time, rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time,
validityDuration, stapledOCSPResponse, validityDuration, stapledOCSPResponse,
subject.GetAuthorityInfoAccess()); subject.GetAuthorityInfoAccess(),
subject.GetSignedCertificateTimestamps());
if (rv != Success) { if (rv != Success) {
return RecordResult(rv, keepGoing); // Since this is actually a problem with the current subject certificate
// (rather than the issuer), it doesn't make sense to keep going; all
// paths through this certificate will fail.
Result savedRv = RecordResult(rv, keepGoing);
keepGoing = false;
return savedRv;
} }
if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity) { if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
@ -251,7 +253,11 @@ PathBuildingStep::Check(Input potentialIssuerDER,
rv = ExtractSignedCertificateTimestampListFromExtension(*sctExtension, rv = ExtractSignedCertificateTimestampListFromExtension(*sctExtension,
sctList); sctList);
if (rv != Success) { if (rv != Success) {
return RecordResult(rv, keepGoing); // Again, the problem is with this certificate, and all paths through
// it will fail.
Result savedRv = RecordResult(rv, keepGoing);
keepGoing = false;
return savedRv;
} }
trustDomain.NoteAuxiliaryExtension(AuxiliaryExtension::EmbeddedSCTList, trustDomain.NoteAuxiliaryExtension(AuxiliaryExtension::EmbeddedSCTList,
sctList); sctList);
@ -276,7 +282,8 @@ BuildForward(TrustDomain& trustDomain,
KeyPurposeId requiredEKUIfPresent, KeyPurposeId requiredEKUIfPresent,
const CertPolicyId& requiredPolicy, const CertPolicyId& requiredPolicy,
/*optional*/ const Input* stapledOCSPResponse, /*optional*/ const Input* stapledOCSPResponse,
unsigned int subCACount) unsigned int subCACount,
unsigned int& buildForwardCallBudget)
{ {
Result rv; Result rv;
@ -311,7 +318,7 @@ BuildForward(TrustDomain& trustDomain,
// This must be done here, after the chain is built but before any // This must be done here, after the chain is built but before any
// revocation checks have been done. // revocation checks have been done.
return trustDomain.IsChainValid(chain, time); return trustDomain.IsChainValid(chain, time, requiredPolicy);
} }
if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) { if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) {
@ -334,7 +341,7 @@ BuildForward(TrustDomain& trustDomain,
PathBuildingStep pathBuilder(trustDomain, subject, time, PathBuildingStep pathBuilder(trustDomain, subject, time,
requiredEKUIfPresent, requiredPolicy, requiredEKUIfPresent, requiredPolicy,
stapledOCSPResponse, subCACount, stapledOCSPResponse, subCACount,
deferredEndEntityError); deferredEndEntityError, buildForwardCallBudget);
// TODO(bug 965136): Add SKI/AKI matching optimizations // TODO(bug 965136): Add SKI/AKI matching optimizations
rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time); rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time);
@ -373,9 +380,22 @@ BuildCertChain(TrustDomain& trustDomain, Input certDER,
return rv; return rv;
} }
// See bug 1056341 for context. If mozilla::pkix is being used in an
// environment where there are many certificates that all have the same
// distinguished name as their subject and issuer (but different SPKIs - see
// the loop prevention as per RFC4158 Section 5.2 in PathBuildingStep::Check),
// the space to search becomes exponential. Because it would be prohibitively
// expensive to explore the entire space, we introduce a budget here that,
// when exhausted, terminates the search with the result
// Result::ERROR_UNKNOWN_ISSUER. Essentially, we limit the total number of
// times `BuildForward` can be called. The current value appears to be a good
// balance between finding a path when one exists (when the space isn't too
// large) and timing out quickly enough when the space is too large or there
// is no valid path to a trust anchor.
unsigned int buildForwardCallBudget = 200000;
return BuildForward(trustDomain, cert, time, requiredKeyUsageIfPresent, return BuildForward(trustDomain, cert, time, requiredKeyUsageIfPresent,
requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse, requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse,
0/*subCACount*/); 0/*subCACount*/, buildForwardCallBudget);
} }
} } // namespace mozilla::pkix } } // namespace mozilla::pkix

View file

@ -1,27 +1,10 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
/* Copyright 2014 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.
*/
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace pkix { namespace mozilla { namespace pkix {
@ -151,7 +134,7 @@ BackCert::Init()
// SSL Client | false | id_kp_clientAuth // SSL Client | false | id_kp_clientAuth
// S/MIME Client | false | id_kp_emailProtection // S/MIME Client | false | id_kp_emailProtection
// Object Signing | false | id_kp_codeSigning // Object Signing | false | id_kp_codeSigning
// SSL Server CA | true | id_pk_serverAuth // SSL Server CA | true | id_kp_serverAuth
// SSL Client CA | true | id_kp_clientAuth // SSL Client CA | true | id_kp_clientAuth
// S/MIME CA | true | id_kp_emailProtection // S/MIME CA | true | id_kp_emailProtection
// Object Signing CA | true | id_kp_codeSigning // Object Signing CA | true | id_kp_codeSigning

View file

@ -1,30 +1,13 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkixcheck.h" #include "pkix/pkixcheck.h"
#include "pkixder.h" #include "pkix/pkixder.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace pkix { namespace mozilla { namespace pkix {
@ -116,7 +99,11 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain,
// for any curve that we support, the chances of us encountering a curve // for any curve that we support, the chances of us encountering a curve
// during path building is too low to be worth bothering with. // during path building is too low to be worth bothering with.
break; break;
case der::PublicKeyAlgorithm::Uninitialized:
{
assert(false);
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
} }
@ -338,15 +325,16 @@ CheckSubjectPublicKeyInfoContents(Reader& input, TrustDomain& trustDomain,
[&trustDomain, endEntityOrCA](Reader& r) { [&trustDomain, endEntityOrCA](Reader& r) {
Input modulus; Input modulus;
Input::size_type modulusSignificantBytes; Input::size_type modulusSignificantBytes;
Result rv = der::PositiveInteger(r, modulus, &modulusSignificantBytes); Result nestedRv =
if (rv != Success) { der::PositiveInteger(r, modulus, &modulusSignificantBytes);
return rv; if (nestedRv != Success) {
return nestedRv;
} }
// XXX: Should we do additional checks of the modulus? // XXX: Should we do additional checks of the modulus?
rv = trustDomain.CheckRSAPublicKeyModulusSizeInBits( nestedRv = trustDomain.CheckRSAPublicKeyModulusSizeInBits(
endEntityOrCA, modulusSignificantBytes * 8u); endEntityOrCA, modulusSignificantBytes * 8u);
if (rv != Success) { if (nestedRv != Success) {
return rv; return nestedRv;
} }
// XXX: We don't allow the TrustDomain to validate the exponent. // XXX: We don't allow the TrustDomain to validate the exponent.
@ -531,6 +519,13 @@ CertPolicyId::IsAnyPolicy() const {
std::equal(bytes, bytes + numBytes, ::mozilla::pkix::anyPolicy); std::equal(bytes, bytes + numBytes, ::mozilla::pkix::anyPolicy);
} }
bool
CertPolicyId::operator==(const CertPolicyId& other) const
{
return numBytes == other.numBytes &&
std::equal(bytes, bytes + numBytes, other.bytes);
}
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation // certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
Result Result
CheckCertificatePolicies(EndEntityOrCA endEntityOrCA, CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
@ -644,9 +639,9 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
Reader input(*encodedBasicConstraints); Reader input(*encodedBasicConstraints);
Result rv = der::Nested(input, der::SEQUENCE, Result rv = der::Nested(input, der::SEQUENCE,
[&isCA, &pathLenConstraint](Reader& r) { [&isCA, &pathLenConstraint](Reader& r) {
Result rv = der::OptionalBoolean(r, isCA); Result nestedRv = der::OptionalBoolean(r, isCA);
if (rv != Success) { if (nestedRv != Success) {
return rv; return nestedRv;
} }
// TODO(bug 985025): If isCA is false, pathLenConstraint // TODO(bug 985025): If isCA is false, pathLenConstraint
// MUST NOT be included (as per RFC 5280 section // MUST NOT be included (as per RFC 5280 section

View file

@ -1,29 +1,11 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkixder.h" #include "pkix/pkixder.h"
#include "pkix/pkixutil.h"
#include "pkixutil.h"
namespace mozilla { namespace pkix { namespace der { namespace mozilla { namespace pkix { namespace der {
@ -212,7 +194,6 @@ SignatureAlgorithmIdentifierValue(Reader& input,
Result Result
DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm) DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm)
{ {
Reader r;
return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result { return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result {
Reader algorithmID; Reader algorithmID;
Result rv = AlgorithmIdentifierValue(r, algorithmID); Result rv = AlgorithmIdentifierValue(r, algorithmID);

View file

@ -1,25 +1,8 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
/* Copyright 2014 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.
*/
// This code implements RFC6125-ish name matching, RFC5280-ish name constraint // This code implements RFC6125-ish name matching, RFC5280-ish name constraint
// checking, and related things. // checking, and related things.
@ -33,8 +16,10 @@
// constraints, the reference identifier is the entire encoded name constraint // constraints, the reference identifier is the entire encoded name constraint
// extension value. // extension value.
#include "pkixcheck.h" #include <algorithm>
#include "pkixutil.h"
#include "pkix/pkixcheck.h"
#include "pkix/pkixutil.h"
namespace mozilla { namespace pkix { namespace mozilla { namespace pkix {
@ -1607,12 +1592,12 @@ StartsWithIDNALabel(Input id)
{ {
static const uint8_t IDN_ALABEL_PREFIX[4] = { 'x', 'n', '-', '-' }; static const uint8_t IDN_ALABEL_PREFIX[4] = { 'x', 'n', '-', '-' };
Reader input(id); Reader input(id);
for (size_t i = 0; i < sizeof(IDN_ALABEL_PREFIX); ++i) { for (const uint8_t prefixByte : IDN_ALABEL_PREFIX) {
uint8_t b; uint8_t b;
if (input.Read(b) != Success) { if (input.Read(b) != Success) {
return false; return false;
} }
if (b != IDN_ALABEL_PREFIX[i]) { if (b != prefixByte) {
return false; return false;
} }
} }
@ -1704,11 +1689,9 @@ FinishIPv6Address(/*in/out*/ uint8_t (&address)[16], int numComponents,
} }
// Shift components that occur after the contraction over. // Shift components that occur after the contraction over.
size_t componentsToMove = static_cast<size_t>(numComponents - std::copy_backward(address + (2u * static_cast<size_t>(contractionIndex)),
contractionIndex); address + (2u * static_cast<size_t>(numComponents)),
memmove(address + (2u * static_cast<size_t>(8 - componentsToMove)), address + (2u * 8u));
address + (2u * static_cast<size_t>(contractionIndex)),
componentsToMove * 2u);
// Fill in the contracted area with zeros. // Fill in the contracted area with zeros.
std::fill_n(address + 2u * static_cast<size_t>(contractionIndex), std::fill_n(address + 2u * static_cast<size_t>(contractionIndex),
(8u - static_cast<size_t>(numComponents)) * 2u, static_cast<uint8_t>(0u)); (8u - static_cast<size_t>(numComponents)) * 2u, static_cast<uint8_t>(0u));

View file

@ -1,25 +1,8 @@
/*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkix/pkixnss.h" #include "pkix/pkixnss.h"
@ -28,9 +11,9 @@
#include "cryptohi.h" #include "cryptohi.h"
#include "keyhi.h" #include "keyhi.h"
#include "pk11pub.h" #include "pk11pub.h"
#include "nss_scoped_ptrs.h"
#include "pkix/pkix.h" #include "pkix/pkix.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
#include "ScopedPtr.h"
#include "secerr.h" #include "secerr.h"
#include "sslerr.h" #include "sslerr.h"
@ -55,12 +38,12 @@ VerifySignedDigest(const SignedDigest& sd,
SECItem subjectPublicKeyInfoSECItem = SECItem subjectPublicKeyInfoSECItem =
UnsafeMapInputToSECItem(subjectPublicKeyInfo); UnsafeMapInputToSECItem(subjectPublicKeyInfo);
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo> ScopedCERTSubjectPublicKeyInfo
spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem)); spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem));
if (!spki) { if (!spki) {
return MapPRErrorCodeToResult(PR_GetError()); return MapPRErrorCodeToResult(PR_GetError());
} }
ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> ScopedSECKEYPublicKey
pubKey(SECKEY_ExtractPublicKey(spki.get())); pubKey(SECKEY_ExtractPublicKey(spki.get()));
if (!pubKey) { if (!pubKey) {
return MapPRErrorCodeToResult(PR_GetError()); return MapPRErrorCodeToResult(PR_GetError());
@ -210,6 +193,14 @@ RegisterErrorTable()
{ "MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME", { "MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME",
"The server presented a certificate with an empty issuer distinguished " "The server presented a certificate with an empty issuer distinguished "
"name." }, "name." },
{ "MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED",
"An additional policy constraint failed when validating this "
"certificate." },
{ "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT",
"The certificate is not trusted because it is self-signed." },
{ "MOZILLA_PKIX_ERROR_MITM_DETECTED",
"Your connection is being intercepted by a TLS proxy. Uninstall it if "
"possible or configure your device to trust its root certificate." },
}; };
// Note that these error strings are not localizable. // Note that these error strings are not localizable.
// When these strings change, update the localization information too. // When these strings change, update the localization information too.

View file

@ -1,31 +1,14 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include <limits> #include <limits>
#include "pkix/pkix.h" #include "pkix/pkix.h"
#include "pkixcheck.h" #include "pkix/pkixcheck.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace { namespace {
@ -45,16 +28,16 @@ enum class CertStatus : uint8_t {
class Context final class Context final
{ {
public: public:
Context(TrustDomain& trustDomain, const CertID& certID, Time time, Context(TrustDomain& aTrustDomain, const CertID& aCertID, Time aTime,
uint16_t maxLifetimeInDays, /*optional out*/ Time* thisUpdate, uint16_t aMaxLifetimeInDays, /*optional out*/ Time* aThisUpdate,
/*optional out*/ Time* validThrough) /*optional out*/ Time* aValidThrough)
: trustDomain(trustDomain) : trustDomain(aTrustDomain)
, certID(certID) , certID(aCertID)
, time(time) , time(aTime)
, maxLifetimeInDays(maxLifetimeInDays) , maxLifetimeInDays(aMaxLifetimeInDays)
, certStatus(CertStatus::Unknown) , certStatus(CertStatus::Unknown)
, thisUpdate(thisUpdate) , thisUpdate(aThisUpdate)
, validThrough(validThrough) , validThrough(aValidThrough)
, expired(false) , expired(false)
, matchFound(false) , matchFound(false)
{ {
@ -172,7 +155,11 @@ static Result ExtensionNotUnderstood(Reader& extnID, Input extnValue,
static Result RememberSingleExtension(Context& context, Reader& extnID, static Result RememberSingleExtension(Context& context, Reader& extnID,
Input extnValue, bool critical, Input extnValue, bool critical,
/*out*/ bool& understood); /*out*/ bool& understood);
static inline Result CertID(Reader& input, // It is convention to name the function after the part of the data structure
// we're parsing from the RFC (e.g. OCSPResponse, ResponseBytes).
// But since we also have a C++ type called CertID, this function doesn't
// follow the convention to prevent shadowing.
static inline Result MatchCertID(Reader& input,
const Context& context, const Context& context,
/*out*/ bool& match); /*out*/ bool& match);
static Result MatchKeyHash(TrustDomain& trustDomain, static Result MatchKeyHash(TrustDomain& trustDomain,
@ -437,12 +424,13 @@ BasicResponse(Reader& input, Context& context)
der::SEQUENCE, [&certs](Reader& certsDER) -> Result { der::SEQUENCE, [&certs](Reader& certsDER) -> Result {
while (!certsDER.AtEnd()) { while (!certsDER.AtEnd()) {
Input cert; Input cert;
Result rv = der::ExpectTagAndGetTLV(certsDER, der::SEQUENCE, cert); Result nestedRv =
if (rv != Success) { der::ExpectTagAndGetTLV(certsDER, der::SEQUENCE, cert);
return rv; if (nestedRv != Success) {
return nestedRv;
} }
rv = certs.Append(cert); nestedRv = certs.Append(cert);
if (rv != Success) { if (nestedRv != Success) {
return Result::ERROR_BAD_DER; // Too many certs return Result::ERROR_BAD_DER; // Too many certs
} }
} }
@ -537,7 +525,7 @@ SingleResponse(Reader& input, Context& context)
{ {
bool match = false; bool match = false;
Result rv = der::Nested(input, der::SEQUENCE, [&context, &match](Reader& r) { Result rv = der::Nested(input, der::SEQUENCE, [&context, &match](Reader& r) {
return CertID(r, context, match); return MatchCertID(r, context, match);
}); });
if (rv != Success) { if (rv != Success) {
return rv; return rv;
@ -694,7 +682,7 @@ SingleResponse(Reader& input, Context& context)
// issuerKeyHash OCTET STRING, -- Hash of issuer's public key // issuerKeyHash OCTET STRING, -- Hash of issuer's public key
// serialNumber CertificateSerialNumber } // serialNumber CertificateSerialNumber }
static inline Result static inline Result
CertID(Reader& input, const Context& context, /*out*/ bool& match) MatchCertID(Reader& input, const Context& context, /*out*/ bool& match)
{ {
match = false; match = false;
@ -963,8 +951,8 @@ CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID,
*d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE) *d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE)
// reqCert.hashAlgorithm // reqCert.hashAlgorithm
for (size_t i = 0; i < sizeof(hashAlgorithm); ++i) { for (const uint8_t hashAlgorithmByte : hashAlgorithm) {
*d++ = hashAlgorithm[i]; *d++ = hashAlgorithmByte;
} }
// reqCert.issuerNameHash (OCTET STRING) // reqCert.issuerNameHash (OCTET STRING)

View file

@ -1,28 +1,11 @@
/*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkix/Result.h" #include "pkix/Result.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace pkix { namespace mozilla { namespace pkix {

View file

@ -1,30 +1,13 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
/* Copyright 2014 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.
*/
#include "pkix/Time.h" #include "pkix/Time.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
#ifdef WIN32 #ifdef _WINDOWS
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push, 3) #pragma warning(push, 3)
#endif #endif
@ -43,7 +26,7 @@ Now()
{ {
uint64_t seconds; uint64_t seconds;
#ifdef WIN32 #ifdef _WINDOWS
// "Contains a 64-bit value representing the number of 100-nanosecond // "Contains a 64-bit value representing the number of 100-nanosecond
// intervals since January 1, 1601 (UTC)." // intervals since January 1, 1601 (UTC)."
// - http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx // - http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx

View file

@ -1,27 +1,10 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
/* Copyright 2015 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.
*/
#include "pkixutil.h" #include "pkix/pkixutil.h"
namespace mozilla { namespace pkix { namespace mozilla { namespace pkix {
@ -78,6 +61,9 @@ VerifySignedDigest(TrustDomain& trustDomain,
case der::PublicKeyAlgorithm::RSA_PKCS1: case der::PublicKeyAlgorithm::RSA_PKCS1:
return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest, return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest,
signerSubjectPublicKeyInfo); signerSubjectPublicKeyInfo);
case der::PublicKeyAlgorithm::Uninitialized:
assert(false);
return Result::FATAL_ERROR_LIBRARY_FAILURE;
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
} }
} }

View file

@ -17,6 +17,7 @@ SOURCES += [
] ]
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'../nss/cpputil',
'include', 'include',
] ]

View file

@ -1,29 +1,13 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
/* Copyright 2015 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.
*/
#include "pkixtestutil.h" #include "pkix/test/pkixtestutil.h"
#include "pkixder.h" #include "pkix/pkixder.h"
#include "nss_scoped_ptrs.h"
// python DottedOIDToCode.py --prefixdefine PREFIX_1_2_840_10040 1.2.840.10040 // python DottedOIDToCode.py --prefixdefine PREFIX_1_2_840_10040 1.2.840.10040
#define PREFIX_1_2_840_10040 0x2a, 0x86, 0x48, 0xce, 0x38 #define PREFIX_1_2_840_10040 0x2a, 0x86, 0x48, 0xce, 0x38
@ -136,14 +120,14 @@ static const uint8_t DSS_G_RAW[] =
} // namespace } // namespace
TestSignatureAlgorithm::TestSignatureAlgorithm( TestSignatureAlgorithm::TestSignatureAlgorithm(
const TestPublicKeyAlgorithm& publicKeyAlg, const TestPublicKeyAlgorithm& aPublicKeyAlg,
TestDigestAlgorithmID digestAlg, TestDigestAlgorithmID aDigestAlg,
const ByteString& algorithmIdentifier, const ByteString& aAlgorithmIdentifier,
bool accepted) bool aAccepted)
: publicKeyAlg(publicKeyAlg) : publicKeyAlg(aPublicKeyAlg)
, digestAlg(digestAlg) , digestAlg(aDigestAlg)
, algorithmIdentifier(algorithmIdentifier) , algorithmIdentifier(aAlgorithmIdentifier)
, accepted(accepted) , accepted(aAccepted)
{ {
} }

View file

@ -1,27 +1,11 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkixtestutil.h" #include "pkix/test/pkixtestutil.h"
#include "pkix/test/pkixtestnss.h"
#include <limits> #include <limits>
@ -30,9 +14,10 @@
#include "nss.h" #include "nss.h"
#include "pk11pqg.h" #include "pk11pqg.h"
#include "pk11pub.h" #include "pk11pub.h"
#include "nss_scoped_ptrs.h"
#include "pkix/pkixnss.h" #include "pkix/pkixnss.h"
#include "pkixder.h" #include "pkix/pkixder.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
#include "prinit.h" #include "prinit.h"
#include "secerr.h" #include "secerr.h"
#include "secitem.h" #include "secitem.h"
@ -41,19 +26,6 @@ namespace mozilla { namespace pkix { namespace test {
namespace { namespace {
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
ScopedSECKEYPublicKey;
typedef ScopedPtr<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>
ScopedSECKEYPrivateKey;
inline void
SECITEM_FreeItem_true(SECItem* item)
{
SECITEM_FreeItem(item, true);
}
typedef mozilla::pkix::ScopedPtr<SECItem, SECITEM_FreeItem_true> ScopedSECItem;
TestKeyPair* GenerateKeyPairInner(); TestKeyPair* GenerateKeyPairInner();
void void
@ -77,12 +49,15 @@ InitReusedKeyPair()
class NSSTestKeyPair final : public TestKeyPair class NSSTestKeyPair final : public TestKeyPair
{ {
public: public:
// NSSTestKeyPair takes ownership of privateKey. NSSTestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
NSSTestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg,
const ByteString& spk, const ByteString& spk,
SECKEYPrivateKey* privateKey) const ByteString& aEncryptedPrivateKey,
: TestKeyPair(publicKeyAlg, spk) const ByteString& aEncryptionAlgorithm,
, privateKey(privateKey) const ByteString& aEncryptionParams)
: TestKeyPair(aPublicKeyAlg, spk)
, encryptedPrivateKey(aEncryptedPrivateKey)
, encryptionAlgorithm(aEncryptionAlgorithm)
, encryptionParams(aEncryptionParams)
{ {
} }
@ -120,10 +95,50 @@ public:
abort(); abort();
} }
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return MapPRErrorCodeToResult(PR_GetError());
}
SECItem encryptedPrivateKeyInfoItem = {
siBuffer,
const_cast<uint8_t*>(encryptedPrivateKey.data()),
static_cast<unsigned int>(encryptedPrivateKey.length())
};
SECItem encryptionAlgorithmItem = {
siBuffer,
const_cast<uint8_t*>(encryptionAlgorithm.data()),
static_cast<unsigned int>(encryptionAlgorithm.length())
};
SECItem encryptionParamsItem = {
siBuffer,
const_cast<uint8_t*>(encryptionParams.data()),
static_cast<unsigned int>(encryptionParams.length())
};
SECKEYEncryptedPrivateKeyInfo encryptedPrivateKeyInfo = {
nullptr,
{ encryptionAlgorithmItem, encryptionParamsItem },
encryptedPrivateKeyInfoItem
};
SECItem passwordItem = { siBuffer, nullptr, 0 };
SECItem publicValueItem = {
siBuffer,
const_cast<uint8_t*>(subjectPublicKey.data()),
static_cast<unsigned int>(subjectPublicKey.length())
};
SECKEYPrivateKey* privateKey;
// This should always be an RSA key (we'll have aborted above if we're not
// doing an RSA signature).
if (PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
slot.get(), &encryptedPrivateKeyInfo, &passwordItem, nullptr,
&publicValueItem, false, false, rsaKey, KU_ALL, &privateKey,
nullptr) != SECSuccess) {
return MapPRErrorCodeToResult(PR_GetError());
}
ScopedSECKEYPrivateKey scopedPrivateKey(privateKey);
SECItem signatureItem; SECItem signatureItem;
if (SEC_SignData(&signatureItem, tbs.data(), if (SEC_SignData(&signatureItem, tbs.data(),
static_cast<int>(tbs.length()), static_cast<int>(tbs.length()),
privateKey.get(), oidTag) != SECSuccess) { scopedPrivateKey.get(), oidTag) != SECSuccess) {
return MapPRErrorCodeToResult(PR_GetError()); return MapPRErrorCodeToResult(PR_GetError());
} }
signature.assign(signatureItem.data, signatureItem.len); signature.assign(signatureItem.data, signatureItem.len);
@ -133,40 +148,63 @@ public:
TestKeyPair* Clone() const override TestKeyPair* Clone() const override
{ {
ScopedSECKEYPrivateKey
privateKeyCopy(SECKEY_CopyPrivateKey(privateKey.get()));
if (!privateKeyCopy) {
return nullptr;
}
return new (std::nothrow) NSSTestKeyPair(publicKeyAlg, return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
subjectPublicKey, subjectPublicKey,
privateKeyCopy.release()); encryptedPrivateKey,
encryptionAlgorithm,
encryptionParams);
} }
private: private:
ScopedSECKEYPrivateKey privateKey; const ByteString encryptedPrivateKey;
const ByteString encryptionAlgorithm;
const ByteString encryptionParams;
}; };
} // namespace } // namespace
// This private function is also used by Gecko's PSM test framework // This private function is also used by Gecko's PSM test framework
// (OCSPCommon.cpp). // (OCSPCommon.cpp).
//
// Ownership of privateKey is transfered.
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg, TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
const SECKEYPublicKey& publicKey, const ScopedSECKEYPublicKey& publicKey,
SECKEYPrivateKey* privateKey) const ScopedSECKEYPrivateKey& privateKey)
{ {
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo> ScopedCERTSubjectPublicKeyInfo
spki(SECKEY_CreateSubjectPublicKeyInfo(&publicKey)); spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
if (!spki) { if (!spki) {
return nullptr; return nullptr;
} }
SECItem spkDER = spki->subjectPublicKey; SECItem spkDER = spki->subjectPublicKey;
DER_ConvertBitString(&spkDER); // bits to bytes DER_ConvertBitString(&spkDER); // bits to bytes
return new (std::nothrow) NSSTestKeyPair(publicKeyAlg, ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return nullptr;
}
// Because NSSTestKeyPair isn't tracked by XPCOM and won't otherwise be aware
// of shutdown, we don't have a way to release NSS resources at the
// appropriate time. To work around this, NSSTestKeyPair doesn't hold on to
// NSS resources. Instead, we export the generated private key part as an
// encrypted blob (with an empty password and fairly lame encryption). When we
// need to use it (e.g. to sign something), we decrypt it and create a
// temporary key object.
SECItem passwordItem = { siBuffer, nullptr, 0 };
ScopedSECKEYEncryptedPrivateKeyInfo encryptedPrivateKey(
PK11_ExportEncryptedPrivKeyInfo(
slot.get(), SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
&passwordItem, privateKey.get(), 1, nullptr));
if (!encryptedPrivateKey) {
return nullptr;
}
return new (std::nothrow) NSSTestKeyPair(
publicKeyAlg,
ByteString(spkDER.data, spkDER.len), ByteString(spkDER.data, spkDER.len),
privateKey); ByteString(encryptedPrivateKey->encryptedData.data,
encryptedPrivateKey->encryptedData.len),
ByteString(encryptedPrivateKey->algorithm.algorithm.data,
encryptedPrivateKey->algorithm.algorithm.len),
ByteString(encryptedPrivateKey->algorithm.parameters.data,
encryptedPrivateKey->algorithm.parameters.len));
} }
namespace { namespace {
@ -174,18 +212,18 @@ namespace {
TestKeyPair* TestKeyPair*
GenerateKeyPairInner() GenerateKeyPairInner()
{ {
ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot()); ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) { if (!slot) {
abort(); abort();
} }
PK11RSAGenParams params;
params.keySizeInBits = 2048;
params.pe = 65537;
// Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient // Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
// entropy to generate a random key. Attempting to add some entropy and // entropy to generate a random key. Attempting to add some entropy and
// retrying appears to solve this issue. // retrying appears to solve this issue.
for (uint32_t retries = 0; retries < 10; retries++) { for (uint32_t retries = 0; retries < 10; retries++) {
PK11RSAGenParams params;
params.keySizeInBits = 2048;
params.pe = 3;
SECKEYPublicKey* publicKeyTemp = nullptr; SECKEYPublicKey* publicKeyTemp = nullptr;
ScopedSECKEYPrivateKey ScopedSECKEYPrivateKey
privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
@ -193,7 +231,7 @@ GenerateKeyPairInner()
nullptr)); nullptr));
ScopedSECKEYPublicKey publicKey(publicKeyTemp); ScopedSECKEYPublicKey publicKey(publicKeyTemp);
if (privateKey) { if (privateKey) {
return CreateTestKeyPair(RSA_PKCS1(), *publicKey, privateKey.release()); return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
} }
assert(!publicKeyTemp); assert(!publicKeyTemp);
@ -206,7 +244,8 @@ GenerateKeyPairInner()
// random keys. // random keys.
// https://xkcd.com/221/ // https://xkcd.com/221/
static const uint8_t RANDOM_NUMBER[] = { 4, 4, 4, 4, 4, 4, 4, 4 }; static const uint8_t RANDOM_NUMBER[] = { 4, 4, 4, 4, 4, 4, 4, 4 };
if (PK11_RandomUpdate((void*) &RANDOM_NUMBER, if (PK11_RandomUpdate(
const_cast<void*>(reinterpret_cast<const void*>(RANDOM_NUMBER)),
sizeof(RANDOM_NUMBER)) != SECSuccess) { sizeof(RANDOM_NUMBER)) != SECSuccess) {
break; break;
} }
@ -240,7 +279,7 @@ GenerateDSSKeyPair()
{ {
InitNSSIfNeeded(); InitNSSIfNeeded();
ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot()); ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) { if (!slot) {
return nullptr; return nullptr;
} }
@ -274,7 +313,7 @@ GenerateDSSKeyPair()
return nullptr; return nullptr;
} }
ScopedSECKEYPublicKey publicKey(publicKeyTemp); ScopedSECKEYPublicKey publicKey(publicKeyTemp);
return CreateTestKeyPair(DSS(), *publicKey, privateKey.release()); return CreateTestKeyPair(DSS(), publicKey, privateKey);
} }
Result Result

View file

@ -1,27 +1,10 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 /* 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 * 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/. * 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.
*/
#include "pkixtestutil.h" #include "pkix/test/pkixtestutil.h"
#include <cerrno> #include <cerrno>
#include <cstdio> #include <cstdio>
@ -30,8 +13,8 @@
#include <sstream> #include <sstream>
#include <cstdlib> #include <cstdlib>
#include "pkixder.h" #include "pkix/pkixder.h"
#include "pkixutil.h" #include "pkix/pkixutil.h"
using namespace std; using namespace std;
@ -39,12 +22,14 @@ namespace mozilla { namespace pkix { namespace test {
namespace { namespace {
inline void struct ScopedMaybeDeleteFile {
fclose_void(FILE* file) { void operator()(FILE* f) {
(void) fclose(file); if (f) {
} (void)fclose(f);
}
typedef mozilla::pkix::ScopedPtr<FILE, fclose_void> ScopedFILE; }
};
typedef std::unique_ptr<FILE, ScopedMaybeDeleteFile> ScopedFILE;
FILE* FILE*
OpenFile(const string& dir, const string& filename, const string& mode) OpenFile(const string& dir, const string& filename, const string& mode)
@ -151,8 +136,8 @@ OCSPResponseExtension::OCSPResponseExtension()
{ {
} }
OCSPResponseContext::OCSPResponseContext(const CertID& certID, time_t time) OCSPResponseContext::OCSPResponseContext(const CertID& aCertID, time_t time)
: certID(certID) : certID(aCertID)
, responseStatus(successful) , responseStatus(successful)
, skipResponseBytes(false) , skipResponseBytes(false)
, producedAt(time) , producedAt(time)
@ -248,7 +233,7 @@ Integer(long value)
enum TimeEncoding { UTCTime = 0, GeneralizedTime = 1 }; enum TimeEncoding { UTCTime = 0, GeneralizedTime = 1 };
// Windows doesn't provide gmtime_r, but it provides something very similar. // Windows doesn't provide gmtime_r, but it provides something very similar.
#if defined(WIN32) && !defined(_POSIX_THREAD_SAFE_FUNCTIONS) #if defined(_WINDOWS) && (!defined(_POSIX_C_SOURCE) || !defined(_POSIX_THREAD_SAFE_FUNCTIONS))
static tm* static tm*
gmtime_r(const time_t* t, /*out*/ tm* exploded) gmtime_r(const time_t* t, /*out*/ tm* exploded)
{ {
@ -738,7 +723,7 @@ CreateEncodedSerialNumber(long serialNumberValue)
// pathLenConstraint INTEGER (0..MAX) OPTIONAL } // pathLenConstraint INTEGER (0..MAX) OPTIONAL }
ByteString ByteString
CreateEncodedBasicConstraints(bool isCA, CreateEncodedBasicConstraints(bool isCA,
/*optional*/ long* pathLenConstraintValue, /*optional in*/ const long* pathLenConstraintValue,
Critical critical) Critical critical)
{ {
ByteString value; ByteString value;
@ -1139,11 +1124,11 @@ CertStatus(OCSPResponseContext& context)
static const ByteString NO_UNUSED_BITS(1, 0x00); static const ByteString NO_UNUSED_BITS(1, 0x00);
// The SubjectPublicKeyInfo syntax is specified in RFC 5280 Section 4.1. // The SubjectPublicKeyInfo syntax is specified in RFC 5280 Section 4.1.
TestKeyPair::TestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg, TestKeyPair::TestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
const ByteString& spk) const ByteString& spk)
: publicKeyAlg(publicKeyAlg) : publicKeyAlg(aPublicKeyAlg)
, subjectPublicKeyInfo(TLV(der::SEQUENCE, , subjectPublicKeyInfo(TLV(der::SEQUENCE,
publicKeyAlg.algorithmIdentifier + aPublicKeyAlg.algorithmIdentifier +
TLV(der::BIT_STRING, NO_UNUSED_BITS + spk))) TLV(der::BIT_STRING, NO_UNUSED_BITS + spk)))
, subjectPublicKey(spk) , subjectPublicKey(spk)
{ {

View file

@ -24,6 +24,7 @@ import argparse
import itertools import itertools
import sys import sys
def base128(value): def base128(value):
""" """
Given an integral value, returns an array of the base-128 representation Given an integral value, returns an array of the base-128 representation
@ -50,6 +51,7 @@ def base128(value):
return result return result
def dottedOIDToEncodedArray(dottedOID): def dottedOIDToEncodedArray(dottedOID):
""" """
Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and
@ -68,6 +70,7 @@ def dottedOIDToEncodedArray(dottedOID):
restBase128 = [base128(x) for x in nodes[2:]] restBase128 = [base128(x) for x in nodes[2:]]
return [firstByte] + list(itertools.chain.from_iterable(restBase128)) return [firstByte] + list(itertools.chain.from_iterable(restBase128))
def dottedOIDToCArray(dottedOID, mode): def dottedOIDToCArray(dottedOID, mode):
""" """
Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and Takes a dotted OID string (e.g. '1.2.840.10045.4.3.4') as input, and
@ -86,6 +89,7 @@ def dottedOIDToCArray(dottedOID, mode):
return ", ".join(["0x%.2x" % b for b in bytes]) return ", ".join(["0x%.2x" % b for b in bytes])
def specNameToCName(specName): def specNameToCName(specName):
""" """
Given an string containing an ASN.1 name, returns a string that is a valid Given an string containing an ASN.1 name, returns a string that is a valid
@ -97,6 +101,7 @@ def specNameToCName(specName):
""" """
return specName.replace("-", "_") return specName.replace("-", "_")
def toCode(programName, specName, dottedOID, mode): def toCode(programName, specName, dottedOID, mode):
""" """
Given an ASN.1 name and a string containing the dotted representation of an Given an ASN.1 name and a string containing the dotted representation of an
@ -180,6 +185,7 @@ def toCode(programName, specName, dottedOID, mode):
" };\n") % (programNameWithOptions, specName, dottedOID, varName, " };\n") % (programNameWithOptions, specName, dottedOID, varName,
dottedOIDToCArray(dottedOID, mode)) dottedOIDToCArray(dottedOID, mode))
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Generate code snippets to handle OIDs in C++", description="Generate code snippets to handle OIDs in C++",