diff options
author | Moonchild <moonchild@palemoon.org> | 2021-03-14 13:06:22 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2021-03-14 13:06:22 +0000 |
commit | 005d9c42d39a9e742c75cd19b26de8fad3a3339b (patch) | |
tree | e46cf0a62aacf3dd4e682ed5b0fa33253052bfef /security/pkix | |
parent | cc8a7e3f7b7d40967d2dd537b6343c87ba9138c7 (diff) | |
download | uxp-005d9c42d39a9e742c75cd19b26de8fad3a3339b.tar.gz |
Issue #1746 - Update pkix code with later NSS code.
Diffstat (limited to 'security/pkix')
27 files changed, 908 insertions, 1412 deletions
diff --git a/security/pkix/include/pkix-test/pkixtestnss.h b/security/pkix/include/pkix-test/pkixtestnss.h new file mode 100644 index 0000000000..596be63523 --- /dev/null +++ b/security/pkix/include/pkix-test/pkixtestnss.h @@ -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 diff --git a/security/pkix/test/lib/pkixtestutil.h b/security/pkix/include/pkix-test/pkixtestutil.h index 7e00ed4f3b..1841e9380c 100644 --- a/security/pkix/test/lib/pkixtestutil.h +++ b/security/pkix/include/pkix-test/pkixtestutil.h @@ -1,47 +1,29 @@ /* -*- 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_test_pkixtestutils_h -#define mozilla_pkix_test_pkixtestutils_h +#ifndef mozilla_pkix_test_pkixtestutil_h +#define mozilla_pkix_test_pkixtestutil_h +#include <cstdint> +#include <cstring> #include <ctime> -#include <stdint.h> // Some Mozilla-supported compilers lack <cstdint> #include <string> -#include <cstring> #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; inline bool ENCODING_FAILED(const ByteString& bs) { return bs.empty(); } template <size_t L> -inline ByteString -BytesToByteString(const uint8_t (&bytes)[L]) -{ +inline ByteString BytesToByteString(const uint8_t (&bytes)[L]) { return ByteString(bytes, L); } @@ -64,17 +46,14 @@ bool InputEqualsByteString(Input input, const ByteString& bs); ByteString InputToByteString(Input input); // python DottedOIDToCode.py --tlv id-kp-OCSPSigning 1.3.6.1.5.5.7.3.9 -static const uint8_t tlv_id_kp_OCSPSigning[] = { - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09 -}; +static const uint8_t tlv_id_kp_OCSPSigning[] = {0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x09}; // python DottedOIDToCode.py --tlv id-kp-serverAuth 1.3.6.1.5.5.7.3.1 -static const uint8_t tlv_id_kp_serverAuth[] = { - 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01 -}; +static const uint8_t tlv_id_kp_serverAuth[] = {0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x01}; -enum class TestDigestAlgorithmID -{ +enum class TestDigestAlgorithmID { MD2, MD5, SHA1, @@ -84,12 +63,10 @@ enum class TestDigestAlgorithmID SHA512, }; -struct TestPublicKeyAlgorithm -{ - explicit TestPublicKeyAlgorithm(const ByteString& algorithmIdentifier) - : algorithmIdentifier(algorithmIdentifier) { } - bool operator==(const TestPublicKeyAlgorithm& other) const - { +struct TestPublicKeyAlgorithm { + explicit TestPublicKeyAlgorithm(const ByteString& aAlgorithmIdentifier) + : algorithmIdentifier(aAlgorithmIdentifier) {} + bool operator==(const TestPublicKeyAlgorithm& other) const { return algorithmIdentifier == other.algorithmIdentifier; } ByteString algorithmIdentifier; @@ -102,12 +79,10 @@ ByteString DSS_G(); TestPublicKeyAlgorithm DSS(); TestPublicKeyAlgorithm RSA_PKCS1(); -struct TestSignatureAlgorithm -{ +struct TestSignatureAlgorithm { TestSignatureAlgorithm(const TestPublicKeyAlgorithm& publicKeyAlg, TestDigestAlgorithmID digestAlg, - const ByteString& algorithmIdentifier, - bool accepted); + const ByteString& algorithmIdentifier, bool accepted); TestPublicKeyAlgorithm publicKeyAlg; 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); -inline ByteString -TLV(uint8_t tag, const ByteString& value) -{ +inline ByteString TLV(uint8_t tag, const ByteString& 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. template <size_t N> -inline ByteString -TLV(uint8_t tag, const char(&value)[N]) -{ +inline ByteString TLV(uint8_t tag, const char (&value)[N]) { static_assert(N > 0, "cannot have string literal of size 0"); assert(value[N - 1] == 0); return TLV(tag, ByteString(reinterpret_cast<const uint8_t*>(&value), N - 1)); } template <size_t N> -inline ByteString -TLV(uint8_t tag, size_t length, const char(&value)[N]) -{ +inline ByteString TLV(uint8_t tag, size_t length, const char (&value)[N]) { static_assert(N > 0, "cannot have string literal of size 0"); assert(value[N - 1] == 0); return TLV(tag, length, @@ -160,29 +129,27 @@ ByteString Integer(long value); ByteString CN(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/); -inline ByteString -CN(const char* value, uint8_t encodingTag = 0x0c /*UTF8String*/) -{ - return CN(ByteString(reinterpret_cast<const uint8_t*>(value), - std::strlen(value)), encodingTag); +inline ByteString CN(const char* value, + uint8_t encodingTag = 0x0c /*UTF8String*/) { + return CN( + ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)), + encodingTag); } ByteString OU(const ByteString&, uint8_t encodingTag = 0x0c /*UTF8String*/); -inline ByteString -OU(const char* value, uint8_t encodingTag = 0x0c /*UTF8String*/) -{ - return OU(ByteString(reinterpret_cast<const uint8_t*>(value), - std::strlen(value)), encodingTag); +inline ByteString OU(const char* value, + uint8_t encodingTag = 0x0c /*UTF8String*/) { + return OU( + ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value)), + encodingTag); } ByteString emailAddress(const ByteString&); -inline ByteString -emailAddress(const char* value) -{ - return emailAddress(ByteString(reinterpret_cast<const uint8_t*>(value), - std::strlen(value))); +inline ByteString emailAddress(const char* value) { + return emailAddress( + ByteString(reinterpret_cast<const uint8_t*>(value), std::strlen(value))); } // RelativeDistinguishedName ::= @@ -197,17 +164,11 @@ ByteString RDN(const ByteString& avas); // ByteString Name(const ByteString& rdns); -inline ByteString -CNToDERName(const ByteString& cn) -{ +inline ByteString CNToDERName(const ByteString& cn) { return Name(RDN(CN(cn))); } -inline ByteString -CNToDERName(const char* cn) -{ - return Name(RDN(CN(cn))); -} +inline ByteString CNToDERName(const char* cn) { return Name(RDN(CN(cn))); } // GeneralName ::= CHOICE { // otherName [0] OtherName, @@ -220,55 +181,40 @@ CNToDERName(const char* cn) // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } -inline ByteString -RFC822Name(const ByteString& name) -{ +inline ByteString RFC822Name(const ByteString& name) { // (2 << 6) means "context-specific", 1 is the GeneralName tag. return TLV((2 << 6) | 1, name); } template <size_t L> -inline ByteString -RFC822Name(const char (&bytes)[L]) -{ - return RFC822Name(ByteString(reinterpret_cast<const uint8_t*>(&bytes), - L - 1)); +inline ByteString RFC822Name(const char (&bytes)[L]) { + return RFC822Name( + ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1)); } -inline ByteString -DNSName(const ByteString& name) -{ +inline ByteString DNSName(const ByteString& name) { // (2 << 6) means "context-specific", 2 is the GeneralName tag. return TLV((2 << 6) | 2, name); } template <size_t L> -inline ByteString -DNSName(const char (&bytes)[L]) -{ - return DNSName(ByteString(reinterpret_cast<const uint8_t*>(&bytes), - L - 1)); +inline ByteString DNSName(const char (&bytes)[L]) { + return DNSName(ByteString(reinterpret_cast<const uint8_t*>(&bytes), L - 1)); } -inline ByteString -DirectoryName(const ByteString& name) -{ +inline ByteString DirectoryName(const ByteString& name) { // (2 << 6) means "context-specific", (1 << 5) means "constructed", and 4 is // the DirectoryName tag. return TLV((2 << 6) | (1 << 5) | 4, name); } -inline ByteString -IPAddress() -{ +inline ByteString IPAddress() { // (2 << 6) means "context-specific", 7 is the GeneralName tag. return TLV((2 << 6) | 7, ByteString()); } template <size_t L> -inline ByteString -IPAddress(const uint8_t (&bytes)[L]) -{ +inline ByteString IPAddress(const uint8_t (&bytes)[L]) { // (2 << 6) means "context-specific", 7 is the GeneralName tag. return TLV((2 << 6) | 7, ByteString(bytes, L)); } @@ -282,10 +228,9 @@ IPAddress(const uint8_t (&bytes)[L]) ByteString CreateEncodedSubjectAltName(const ByteString& names); ByteString CreateEncodedEmptySubjectAltName(); -class TestKeyPair -{ -public: - virtual ~TestKeyPair() { } +class TestKeyPair { + public: + virtual ~TestKeyPair() {} const TestPublicKeyAlgorithm publicKeyAlg; @@ -302,8 +247,10 @@ public: /*out*/ ByteString& signature) 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; void operator=(const TestKeyPair&) = delete; }; @@ -312,7 +259,7 @@ TestKeyPair* CloneReusedKeyPair(); TestKeyPair* GenerateKeyPair(); TestKeyPair* GenerateDSSKeyPair(); inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; } -typedef ScopedPtr<TestKeyPair, DeleteTestKeyPair> ScopedTestKeyPair; +typedef std::unique_ptr<TestKeyPair> ScopedTestKeyPair; Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest, 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 // ByteString. (If the first item of the array is empty then an empty // Extensions sequence will be encoded.) -ByteString CreateEncodedCertificate(long version, - const TestSignatureAlgorithm& signature, - const ByteString& serialNumber, - const ByteString& issuerNameDER, - time_t notBefore, time_t notAfter, - const ByteString& subjectNameDER, - const TestKeyPair& subjectKeyPair, - /*optional*/ const ByteString* extensions, - const TestKeyPair& issuerKeyPair, - const TestSignatureAlgorithm& signatureAlgorithm); +ByteString CreateEncodedCertificate( + long version, const TestSignatureAlgorithm& signature, + const ByteString& serialNumber, const ByteString& issuerNameDER, + time_t notBefore, time_t notAfter, const ByteString& subjectNameDER, + const TestKeyPair& subjectKeyPair, + /*optional*/ const ByteString* extensions, const TestKeyPair& issuerKeyPair, + const TestSignatureAlgorithm& signatureAlgorithm); ByteString CreateEncodedSerialNumber(long value); enum class Critical { No = 0, Yes = 1 }; -ByteString CreateEncodedBasicConstraints(bool isCA, - /*optional*/ long* pathLenConstraint, - Critical critical); +ByteString CreateEncodedBasicConstraints( + bool isCA, + /*optional in*/ const long* pathLenConstraint, Critical critical); // Creates a DER-encoded extKeyUsage extension with one EKU OID. ByteString CreateEncodedEKUExtension(Input eku, Critical critical); @@ -372,9 +316,8 @@ ByteString CreateEncodedEKUExtension(Input eku, Critical critical); /////////////////////////////////////////////////////////////////////////////// // Encode OCSP responses -class OCSPResponseExtension final -{ -public: +class OCSPResponseExtension final { + public: OCSPResponseExtension(); ByteString id; @@ -383,9 +326,8 @@ public: OCSPResponseExtension* next; }; -class OCSPResponseContext final -{ -public: +class OCSPResponseContext final { + public: OCSPResponseContext(const CertID& certID, std::time_t time); const CertID& certID; @@ -393,8 +335,7 @@ public: // The fields below are in the order that they appear in an OCSP response. - enum OCSPResponseStatus - { + enum OCSPResponseStatus { successful = 0, malformedRequest = 1, internalError = 2, @@ -403,13 +344,13 @@ public: sigRequired = 5, unauthorized = 6, }; - uint8_t responseStatus; // an OCSPResponseStatus or an invalid value - bool skipResponseBytes; // If true, don't include responseBytes + uint8_t responseStatus; // an OCSPResponseStatus or an invalid value + bool skipResponseBytes; // If true, don't include responseBytes // responderID - ByteString signerNameDER; // If set, responderID will use the byName - // form; otherwise responderID will use the - // byKeyHash form. + ByteString signerNameDER; // If set, responderID will use the byName + // form; otherwise responderID will use the + // byKeyHash form. std::time_t producedAt; @@ -417,31 +358,31 @@ public: OCSPResponseExtension* singleExtensions; // ResponseData extensions. OCSPResponseExtension* responseExtensions; - bool includeEmptyExtensions; // If true, include the extension wrapper - // regardless of if there are any actual - // extensions. + bool includeEmptyExtensions; // If true, include the extension wrapper + // regardless of if there are any actual + // extensions. ScopedTestKeyPair signerKeyPair; TestSignatureAlgorithm signatureAlgorithm; - bool badSignature; // If true, alter the signature to fail verification - const ByteString* certs; // optional; array terminated by an empty string + bool badSignature; // If true, alter the signature to fail verification + const ByteString* certs; // optional; array terminated by an empty string // The following fields are on a per-SingleResponse basis. In the future we // may support including multiple SingleResponses per response. - enum CertStatus - { + enum CertStatus { good = 0, revoked = 1, unknown = 2, }; - uint8_t certStatus; // CertStatus or an invalid value - std::time_t revocationTime; // For certStatus == revoked + uint8_t certStatus; // CertStatus or an invalid value + std::time_t revocationTime; // For certStatus == revoked std::time_t thisUpdate; std::time_t nextUpdate; bool includeNextUpdate; }; ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context); +} +} +} // namespace mozilla::pkix::test -} } } // namespace mozilla::pkix::test - -#endif // mozilla_pkix_test_pkixtestutils_h +#endif // mozilla_pkix_test_pkixtestutil_h diff --git a/security/pkix/include/pkix/Input.h b/security/pkix/include/pkix/Input.h index 22f0780c96..4aa4157207 100644 --- a/security/pkix/include/pkix/Input.h +++ b/security/pkix/include/pkix/Input.h @@ -1,25 +1,8 @@ /* -*- 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_Input_h #define mozilla_pkix_Input_h @@ -29,7 +12,8 @@ #include "pkix/Result.h" #include "stdint.h" -namespace mozilla { namespace pkix { +namespace mozilla { +namespace pkix { class Reader; @@ -48,9 +32,8 @@ class Reader; // // Note that in the example, GoodExample has the same performance // characteristics as WorseExample, but with much better safety guarantees. -class Input final -{ -public: +class Input final { + public: typedef uint16_t size_type; // This constructor is useful for inputs that are statically known to be of a @@ -65,37 +48,28 @@ public: // Input expected; // Result rv = expected.Init(EXPECTED_BYTES, sizeof EXPECTED_BYTES); template <size_type N> - explicit Input(const uint8_t (&data)[N]) - : data(data) - , len(N) - { - } + explicit Input(const uint8_t (&aData)[N]) : data(aData), len(N) {} // Construct a valid, empty, Init-able Input. - Input() - : data(nullptr) - , len(0u) - { - } + Input() : data(nullptr), len(0u) {} // This is intentionally not explicit in order to allow value semantics. Input(const Input&) = default; // Initialize the input. data must be non-null and len must be less than // 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) { // already initialized return Result::FATAL_ERROR_INVALID_ARGS; } - if (!data || len > 0xffffu) { + if (!aData || aLen > 0xffffu) { // input too large return Result::ERROR_BAD_DER; } - this->data = data; - this->len = len; + this->data = aData; + this->len = aLen; return Success; } @@ -106,10 +80,7 @@ public: // This is basically operator=, but it wasn't given that name because // normally callers do not check the result of operator=, and normally // operator= can be used multiple times. - Result Init(Input other) - { - return Init(other.data, other.len); - } + Result Init(Input other) { return Init(other.data, other.len); } // Returns the length of the input. // @@ -121,18 +92,17 @@ public: // don't want to declare in this header file. const uint8_t* UnsafeGetData() const { return data; } -private: + private: const uint8_t* data; size_t len; - void operator=(const Input&) = delete; // Use Init instead. + void operator=(const Input&) = delete; // Use Init instead. }; -inline bool -InputsAreEqual(const Input& a, const Input& b) -{ +inline bool InputsAreEqual(const Input& a, const Input& b) { 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 @@ -143,38 +113,28 @@ InputsAreEqual(const Input& a, const Input& b) // // In general, Reader allows for one byte of lookahead and no backtracking. // However, the Match* functions internally may have more lookahead. -class Reader final -{ -public: - Reader() - : input(nullptr) - , end(nullptr) - { - } +class Reader final { + public: + Reader() : input(nullptr), end(nullptr) {} - explicit Reader(Input input) - : input(input.UnsafeGetData()) - , end(input.UnsafeGetData() + input.GetLength()) - { - } + explicit Reader(Input aInput) + : input(aInput.UnsafeGetData()), + end(aInput.UnsafeGetData() + aInput.GetLength()) {} - Result Init(Input input) - { + Result Init(Input aInput) { if (this->input) { return Result::FATAL_ERROR_INVALID_ARGS; } - this->input = input.UnsafeGetData(); - this->end = input.UnsafeGetData() + input.GetLength(); + this->input = aInput.UnsafeGetData(); + this->end = aInput.UnsafeGetData() + aInput.GetLength(); return Success; } - bool Peek(uint8_t expectedByte) const - { + bool Peek(uint8_t expectedByte) const { return input < end && *input == expectedByte; } - Result Read(uint8_t& out) - { + Result Read(uint8_t& out) { Result rv = EnsureLength(1); if (rv != Success) { return rv; @@ -183,8 +143,7 @@ public: return Success; } - Result Read(uint16_t& out) - { + Result Read(uint16_t& out) { Result rv = EnsureLength(2); if (rv != Success) { return rv; @@ -196,8 +155,7 @@ public: } 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 // here we want to be sure that there is nothing following the matched // bytes @@ -211,8 +169,7 @@ public: return true; } - bool MatchRest(Input toMatch) - { + bool MatchRest(Input toMatch) { // Normally we use EnsureLength which compares (input + len < end), but // here we want to be sure that there is nothing following the matched // bytes @@ -227,8 +184,7 @@ public: return true; } - Result Skip(Input::size_type len) - { + Result Skip(Input::size_type len) { Result rv = EnsureLength(len); if (rv != Success) { return rv; @@ -237,8 +193,7 @@ public: return Success; } - Result Skip(Input::size_type len, Reader& skipped) - { + Result Skip(Input::size_type len, Reader& skipped) { Result rv = EnsureLength(len); if (rv != Success) { return rv; @@ -251,8 +206,7 @@ public: return Success; } - Result Skip(Input::size_type len, /*out*/ Input& skipped) - { + Result Skip(Input::size_type len, /*out*/ Input& skipped) { Result rv = EnsureLength(len); if (rv != Success) { return rv; @@ -265,18 +219,13 @@ public: return Success; } - void SkipToEnd() - { - input = end; - } + void SkipToEnd() { input = end; } - Result SkipToEnd(/*out*/ Input& skipped) - { + Result SkipToEnd(/*out*/ 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) { return Result::ERROR_BAD_DER; } @@ -285,13 +234,13 @@ public: bool AtEnd() const { return input == end; } - class Mark final - { - public: - Mark(const Mark&) = default; // Intentionally not explicit. - private: + class Mark final { + public: + Mark(const Mark&) = default; // Intentionally not explicit. + private: 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 uint8_t* const mark; void operator=(const Mark&) = delete; @@ -299,8 +248,7 @@ public: 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) { return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS); } @@ -308,9 +256,8 @@ public: static_cast<Input::size_type>(input - mark.mark)); } -private: - Result Init(const uint8_t* data, Input::size_type len) - { + private: + Result Init(const uint8_t* data, Input::size_type len) { if (input) { // already initialized return Result::FATAL_ERROR_INVALID_ARGS; @@ -327,9 +274,7 @@ private: void operator=(const Reader&) = delete; }; -inline bool -InputContains(const Input& input, uint8_t toFind) -{ +inline bool InputContains(const Input& input, uint8_t toFind) { Reader reader(input); for (;;) { 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 diff --git a/security/pkix/include/pkix/Result.h b/security/pkix/include/pkix/Result.h index 076ec76fe3..0e0cfdf117 100644 --- a/security/pkix/include/pkix/Result.h +++ b/security/pkix/include/pkix/Result.h @@ -1,32 +1,16 @@ /* -*- 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_Result_h #define mozilla_pkix_Result_h #include <cassert> -namespace mozilla { namespace pkix { +namespace mozilla { +namespace pkix { static const unsigned int FATAL_ERROR_FLAG = 0x800; @@ -82,126 +66,113 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800; // The third argument to MOZILLA_PKIX_MAP() is used, along with the first // argument, for maintaining the mapping of mozilla::pkix error codes to // NSS/NSPR error codes in pkixnss.cpp. -#define MOZILLA_PKIX_MAP_LIST \ - MOZILLA_PKIX_MAP(Success, 0, 0) \ - MOZILLA_PKIX_MAP(ERROR_BAD_DER, 1, \ - SEC_ERROR_BAD_DER) \ - MOZILLA_PKIX_MAP(ERROR_CA_CERT_INVALID, 2, \ - 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, \ - SEC_ERROR_CERT_BAD_ACCESS_LOCATION) \ - MOZILLA_PKIX_MAP(ERROR_CERT_NOT_IN_NAME_SPACE, 5, \ - SEC_ERROR_CERT_NOT_IN_NAME_SPACE) \ - MOZILLA_PKIX_MAP(ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 6, \ - SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) \ - MOZILLA_PKIX_MAP(ERROR_CONNECT_REFUSED, 7, \ - PR_CONNECT_REFUSED_ERROR) \ - MOZILLA_PKIX_MAP(ERROR_EXPIRED_CERTIFICATE, 8, \ - SEC_ERROR_EXPIRED_CERTIFICATE) \ - MOZILLA_PKIX_MAP(ERROR_EXTENSION_VALUE_INVALID, 9, \ - SEC_ERROR_EXTENSION_VALUE_INVALID) \ - MOZILLA_PKIX_MAP(ERROR_INADEQUATE_CERT_TYPE, 10, \ - SEC_ERROR_INADEQUATE_CERT_TYPE) \ - MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_USAGE, 11, \ - SEC_ERROR_INADEQUATE_KEY_USAGE) \ - MOZILLA_PKIX_MAP(ERROR_INVALID_ALGORITHM, 12, \ - SEC_ERROR_INVALID_ALGORITHM) \ - MOZILLA_PKIX_MAP(ERROR_INVALID_DER_TIME, 13, \ - SEC_ERROR_INVALID_TIME) \ - MOZILLA_PKIX_MAP(ERROR_KEY_PINNING_FAILURE, 14, \ - MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) \ - MOZILLA_PKIX_MAP(ERROR_PATH_LEN_CONSTRAINT_INVALID, 15, \ - SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID) \ - MOZILLA_PKIX_MAP(ERROR_POLICY_VALIDATION_FAILED, 16, \ - SEC_ERROR_POLICY_VALIDATION_FAILED) \ - MOZILLA_PKIX_MAP(ERROR_REVOKED_CERTIFICATE, 17, \ - SEC_ERROR_REVOKED_CERTIFICATE) \ - MOZILLA_PKIX_MAP(ERROR_UNKNOWN_CRITICAL_EXTENSION, 18, \ - SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) \ - MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ERROR, 19, \ - PR_UNKNOWN_ERROR) \ - MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ISSUER, 20, \ - SEC_ERROR_UNKNOWN_ISSUER) \ - MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_CERT, 21, \ - 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, \ - SEC_ERROR_OCSP_INVALID_SIGNING_CERT) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_REQUEST, 25, \ - SEC_ERROR_OCSP_MALFORMED_REQUEST) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_RESPONSE, 26, \ - SEC_ERROR_OCSP_MALFORMED_RESPONSE) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_OLD_RESPONSE, 27, \ - SEC_ERROR_OCSP_OLD_RESPONSE) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_REQUEST_NEEDS_SIG, 28, \ - SEC_ERROR_OCSP_REQUEST_NEEDS_SIG) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONDER_CERT_INVALID, 29, \ - SEC_ERROR_OCSP_RESPONDER_CERT_INVALID) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_SERVER_ERROR, 30, \ - SEC_ERROR_OCSP_SERVER_ERROR) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_TRY_SERVER_LATER, 31, \ - SEC_ERROR_OCSP_TRY_SERVER_LATER) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_UNAUTHORIZED_REQUEST, 32, \ - SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, 33, \ - SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_CERT, 34, \ - SEC_ERROR_OCSP_UNKNOWN_CERT) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_FUTURE_RESPONSE, 35, \ - SEC_ERROR_OCSP_FUTURE_RESPONSE) \ - MOZILLA_PKIX_MAP(ERROR_INVALID_KEY, 36, \ - SEC_ERROR_INVALID_KEY) \ - MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_KEYALG, 37, \ - SEC_ERROR_UNSUPPORTED_KEYALG) \ - MOZILLA_PKIX_MAP(ERROR_EXPIRED_ISSUER_CERTIFICATE, 38, \ - SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) \ - MOZILLA_PKIX_MAP(ERROR_CA_CERT_USED_AS_END_ENTITY, 39, \ - MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY) \ - MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_SIZE, 40, \ - MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE) \ - MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \ - MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \ - MOZILLA_PKIX_MAP(ERROR_BAD_CERT_DOMAIN, 42, \ - SSL_ERROR_BAD_CERT_DOMAIN) \ - MOZILLA_PKIX_MAP(ERROR_NO_RFC822NAME_MATCH, 43, \ - MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH) \ - MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_ELLIPTIC_CURVE, 44, \ - SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE) \ - MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_CERTIFICATE, 45, \ - MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE) \ - MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE, 46, \ - MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE) \ - MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_EC_POINT_FORM, 47, \ - SEC_ERROR_UNSUPPORTED_EC_POINT_FORM) \ - MOZILLA_PKIX_MAP(ERROR_SIGNATURE_ALGORITHM_MISMATCH, 48, \ - MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH) \ - MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONSE_FOR_CERT_MISSING, 49, \ - MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING) \ - MOZILLA_PKIX_MAP(ERROR_VALIDITY_TOO_LONG, 50, \ - MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG) \ - MOZILLA_PKIX_MAP(ERROR_REQUIRED_TLS_FEATURE_MISSING, 51, \ - MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING) \ - MOZILLA_PKIX_MAP(ERROR_INVALID_INTEGER_ENCODING, 52, \ - MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING) \ - MOZILLA_PKIX_MAP(ERROR_EMPTY_ISSUER_NAME, 53, \ - MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME) \ - MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \ - SEC_ERROR_INVALID_ARGS) \ - MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \ - PR_INVALID_STATE_ERROR) \ - MOZILLA_PKIX_MAP(FATAL_ERROR_LIBRARY_FAILURE, FATAL_ERROR_FLAG | 3, \ - SEC_ERROR_LIBRARY_FAILURE) \ - MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \ - SEC_ERROR_NO_MEMORY) \ - /* nothing here */ +#define MOZILLA_PKIX_MAP_LIST \ + MOZILLA_PKIX_MAP(Success, 0, 0) \ + MOZILLA_PKIX_MAP(ERROR_BAD_DER, 1, SEC_ERROR_BAD_DER) \ + MOZILLA_PKIX_MAP(ERROR_CA_CERT_INVALID, 2, 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, \ + SEC_ERROR_CERT_BAD_ACCESS_LOCATION) \ + MOZILLA_PKIX_MAP(ERROR_CERT_NOT_IN_NAME_SPACE, 5, \ + SEC_ERROR_CERT_NOT_IN_NAME_SPACE) \ + MOZILLA_PKIX_MAP(ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 6, \ + SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) \ + MOZILLA_PKIX_MAP(ERROR_CONNECT_REFUSED, 7, PR_CONNECT_REFUSED_ERROR) \ + MOZILLA_PKIX_MAP(ERROR_EXPIRED_CERTIFICATE, 8, \ + SEC_ERROR_EXPIRED_CERTIFICATE) \ + MOZILLA_PKIX_MAP(ERROR_EXTENSION_VALUE_INVALID, 9, \ + SEC_ERROR_EXTENSION_VALUE_INVALID) \ + MOZILLA_PKIX_MAP(ERROR_INADEQUATE_CERT_TYPE, 10, \ + SEC_ERROR_INADEQUATE_CERT_TYPE) \ + MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_USAGE, 11, \ + SEC_ERROR_INADEQUATE_KEY_USAGE) \ + MOZILLA_PKIX_MAP(ERROR_INVALID_ALGORITHM, 12, SEC_ERROR_INVALID_ALGORITHM) \ + MOZILLA_PKIX_MAP(ERROR_INVALID_DER_TIME, 13, SEC_ERROR_INVALID_TIME) \ + MOZILLA_PKIX_MAP(ERROR_KEY_PINNING_FAILURE, 14, \ + MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) \ + MOZILLA_PKIX_MAP(ERROR_PATH_LEN_CONSTRAINT_INVALID, 15, \ + SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID) \ + MOZILLA_PKIX_MAP(ERROR_POLICY_VALIDATION_FAILED, 16, \ + SEC_ERROR_POLICY_VALIDATION_FAILED) \ + MOZILLA_PKIX_MAP(ERROR_REVOKED_CERTIFICATE, 17, \ + SEC_ERROR_REVOKED_CERTIFICATE) \ + MOZILLA_PKIX_MAP(ERROR_UNKNOWN_CRITICAL_EXTENSION, 18, \ + SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) \ + MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ERROR, 19, PR_UNKNOWN_ERROR) \ + MOZILLA_PKIX_MAP(ERROR_UNKNOWN_ISSUER, 20, SEC_ERROR_UNKNOWN_ISSUER) \ + MOZILLA_PKIX_MAP(ERROR_UNTRUSTED_CERT, 21, 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, \ + SEC_ERROR_OCSP_INVALID_SIGNING_CERT) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_REQUEST, 25, \ + SEC_ERROR_OCSP_MALFORMED_REQUEST) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_MALFORMED_RESPONSE, 26, \ + SEC_ERROR_OCSP_MALFORMED_RESPONSE) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_OLD_RESPONSE, 27, SEC_ERROR_OCSP_OLD_RESPONSE) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_REQUEST_NEEDS_SIG, 28, \ + SEC_ERROR_OCSP_REQUEST_NEEDS_SIG) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONDER_CERT_INVALID, 29, \ + SEC_ERROR_OCSP_RESPONDER_CERT_INVALID) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_SERVER_ERROR, 30, SEC_ERROR_OCSP_SERVER_ERROR) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_TRY_SERVER_LATER, 31, \ + SEC_ERROR_OCSP_TRY_SERVER_LATER) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_UNAUTHORIZED_REQUEST, 32, \ + SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, 33, \ + SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_UNKNOWN_CERT, 34, SEC_ERROR_OCSP_UNKNOWN_CERT) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_FUTURE_RESPONSE, 35, \ + SEC_ERROR_OCSP_FUTURE_RESPONSE) \ + MOZILLA_PKIX_MAP(ERROR_INVALID_KEY, 36, SEC_ERROR_INVALID_KEY) \ + MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_KEYALG, 37, SEC_ERROR_UNSUPPORTED_KEYALG) \ + MOZILLA_PKIX_MAP(ERROR_EXPIRED_ISSUER_CERTIFICATE, 38, \ + SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) \ + MOZILLA_PKIX_MAP(ERROR_CA_CERT_USED_AS_END_ENTITY, 39, \ + MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY) \ + MOZILLA_PKIX_MAP(ERROR_INADEQUATE_KEY_SIZE, 40, \ + MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE) \ + MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \ + MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \ + MOZILLA_PKIX_MAP(ERROR_BAD_CERT_DOMAIN, 42, SSL_ERROR_BAD_CERT_DOMAIN) \ + MOZILLA_PKIX_MAP(ERROR_NO_RFC822NAME_MATCH, 43, \ + MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH) \ + MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_ELLIPTIC_CURVE, 44, \ + SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE) \ + MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_CERTIFICATE, 45, \ + MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE) \ + MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE, 46, \ + MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE) \ + MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_EC_POINT_FORM, 47, \ + SEC_ERROR_UNSUPPORTED_EC_POINT_FORM) \ + MOZILLA_PKIX_MAP(ERROR_SIGNATURE_ALGORITHM_MISMATCH, 48, \ + MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH) \ + MOZILLA_PKIX_MAP(ERROR_OCSP_RESPONSE_FOR_CERT_MISSING, 49, \ + MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING) \ + MOZILLA_PKIX_MAP(ERROR_VALIDITY_TOO_LONG, 50, \ + MOZILLA_PKIX_ERROR_VALIDITY_TOO_LONG) \ + MOZILLA_PKIX_MAP(ERROR_REQUIRED_TLS_FEATURE_MISSING, 51, \ + MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING) \ + MOZILLA_PKIX_MAP(ERROR_INVALID_INTEGER_ENCODING, 52, \ + MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING) \ + MOZILLA_PKIX_MAP(ERROR_EMPTY_ISSUER_NAME, 53, \ + 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, \ + SEC_ERROR_INVALID_ARGS) \ + MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \ + PR_INVALID_STATE_ERROR) \ + MOZILLA_PKIX_MAP(FATAL_ERROR_LIBRARY_FAILURE, FATAL_ERROR_FLAG | 3, \ + SEC_ERROR_LIBRARY_FAILURE) \ + MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \ + SEC_ERROR_NO_MEMORY) \ +/* nothing here */ -enum class Result -{ +enum class Result { #define MOZILLA_PKIX_MAP(name, value, nss_name) name = value, MOZILLA_PKIX_MAP_LIST #undef MOZILLA_PKIX_MAP @@ -216,19 +187,15 @@ const char* MapResultToName(Result result); // results in less line wrapping. static const Result Success = Result::Success; -inline bool -IsFatalError(Result rv) -{ +inline bool IsFatalError(Result rv) { return (static_cast<unsigned int>(rv) & FATAL_ERROR_FLAG) != 0; } -inline Result -NotReached(const char* /*explanation*/, Result result) -{ +inline Result NotReached(const char* /*explanation*/, Result result) { assert(false); return result; } +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_Result_h +#endif // mozilla_pkix_Result_h diff --git a/security/pkix/include/pkix/Time.h b/security/pkix/include/pkix/Time.h index 3fbdf07f54..251533016f 100644 --- a/security/pkix/include/pkix/Time.h +++ b/security/pkix/include/pkix/Time.h @@ -1,45 +1,28 @@ /* -*- 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 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 #define mozilla_pkix_Time_h +#include <stdint.h> #include <ctime> #include <limits> -#include <stdint.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 // 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. // // Pass by value, not by reference. -class Time final -{ -public: +class Time final { + public: // Construct an uninitialized instance. // // This will fail to compile because there is no default constructor: @@ -48,52 +31,44 @@ public: // This will succeed, leaving the time uninitialized: // Time x(Time::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; } - bool operator>(const Time& other) const - { + bool operator>(const Time& other) const { return elapsedSecondsAD > other.elapsedSecondsAD; } - bool operator>=(const Time& other) const - { + bool operator>=(const Time& other) const { return elapsedSecondsAD >= other.elapsedSecondsAD; } - bool operator<(const Time& other) const - { + bool operator<(const Time& other) const { return elapsedSecondsAD < other.elapsedSecondsAD; } - bool operator<=(const Time& other) const - { + bool operator<=(const Time& other) const { return elapsedSecondsAD <= other.elapsedSecondsAD; } - Result AddSeconds(uint64_t seconds) - { - if (std::numeric_limits<uint64_t>::max() - elapsedSecondsAD - < seconds) { - return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow + Result AddSeconds(uint64_t seconds) { + if (std::numeric_limits<uint64_t>::max() - elapsedSecondsAD < seconds) { + return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow } elapsedSecondsAD += seconds; return Success; } - Result SubtractSeconds(uint64_t seconds) - { + Result SubtractSeconds(uint64_t seconds) { if (seconds > elapsedSecondsAD) { - return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow + return Result::FATAL_ERROR_INVALID_ARGS; // integer overflow } elapsedSecondsAD -= seconds; return Success; } - static const uint64_t ONE_DAY_IN_SECONDS - = UINT64_C(24) * UINT64_C(60) * UINT64_C(60); + static const uint64_t ONE_DAY_IN_SECONDS = + UINT64_C(24) * UINT64_C(60) * UINT64_C(60); -private: + private: // This constructor is hidden to prevent accidents like this: // // Time foo(time_t t) @@ -101,19 +76,16 @@ private: // // WRONG! 1970-01-01-00:00:00 == time_t(0), but not Time(0)! // return Time(t); // } - explicit Time(uint64_t elapsedSecondsAD) - : elapsedSecondsAD(elapsedSecondsAD) - { - } + explicit Time(uint64_t aElapsedSecondsAD) + : elapsedSecondsAD(aElapsedSecondsAD) {} friend Time TimeFromElapsedSecondsAD(uint64_t); friend class Duration; uint64_t elapsedSecondsAD; }; -inline Time TimeFromElapsedSecondsAD(uint64_t elapsedSecondsAD) -{ - return Time(elapsedSecondsAD); +inline Time TimeFromElapsedSecondsAD(uint64_t aElapsedSecondsAD) { + return Time(aElapsedSecondsAD); } Time Now(); @@ -121,34 +93,27 @@ Time Now(); // Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970) Time TimeFromEpochInSeconds(uint64_t secondsSinceEpoch); -class Duration final -{ -public: +class Duration final { + public: Duration(Time timeA, Time timeB) - : durationInSeconds(timeA < timeB - ? timeB.elapsedSecondsAD - timeA.elapsedSecondsAD - : timeA.elapsedSecondsAD - timeB.elapsedSecondsAD) - { - } + : durationInSeconds( + timeA < timeB ? timeB.elapsedSecondsAD - timeA.elapsedSecondsAD + : timeA.elapsedSecondsAD - timeB.elapsedSecondsAD) {} - explicit Duration(uint64_t durationInSeconds) - : durationInSeconds(durationInSeconds) - { - } + explicit Duration(uint64_t aDurationInSeconds) + : durationInSeconds(aDurationInSeconds) {} - bool operator>(const Duration& other) const - { + bool operator>(const Duration& other) const { return durationInSeconds > other.durationInSeconds; } - bool operator<(const Duration& other) const - { + bool operator<(const Duration& other) const { return durationInSeconds < other.durationInSeconds; } -private: + private: uint64_t durationInSeconds; }; +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_Time_h +#endif // mozilla_pkix_Time_h diff --git a/security/pkix/include/pkix/pkix.h b/security/pkix/include/pkix/pkix.h index 23ce32a3d0..2ceec06411 100644 --- a/security/pkix/include/pkix/pkix.h +++ b/security/pkix/include/pkix/pkix.h @@ -1,32 +1,16 @@ /* -*- 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_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 @@ -102,8 +86,8 @@ namespace mozilla { namespace pkix { // requiredPolicy: // This is the policy to apply; typically included in EV certificates. // If there is no policy, pass in CertPolicyId::anyPolicy. -Result BuildCertChain(TrustDomain& trustDomain, Input cert, - Time time, EndEntityOrCA endEntityOrCA, +Result BuildCertChain(TrustDomain& trustDomain, Input cert, Time time, + EndEntityOrCA endEntityOrCA, KeyUsage requiredKeyUsageIfPresent, KeyPurposeId requiredEKUIfPresent, 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 // responder, for the provided CertID. The request has no extensions. static const size_t OCSP_REQUEST_MAX_LENGTH = 127; -Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, - const CertID& certID, +Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, const CertID& certID, /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH], /*out*/ size_t& outLen); @@ -139,13 +122,12 @@ Result CreateEncodedOCSPRequest(TrustDomain& trustDomain, // 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 response will be considered trustworthy). -Result VerifyEncodedOCSPResponse(TrustDomain& trustDomain, - const CertID& certID, Time time, - uint16_t maxLifetimeInDays, - Input encodedResponse, - /* out */ bool& expired, - /* optional out */ Time* thisUpdate = nullptr, - /* optional out */ Time* validThrough = nullptr); +Result VerifyEncodedOCSPResponse( + TrustDomain& trustDomain, const CertID& certID, Time time, + uint16_t maxLifetimeInDays, Input encodedResponse, + /* out */ bool& expired, + /* optional out */ Time* thisUpdate = nullptr, + /* optional out */ Time* validThrough = nullptr); // Check that the TLSFeature extensions in a given end-entity cert (which is // assumed to have been already validated with BuildCertChain) are satisfied. @@ -154,7 +136,7 @@ Result VerifyEncodedOCSPResponse(TrustDomain& trustDomain, // requirement for another value. Empty extensions are also rejected. Result CheckTLSFeaturesAreSatisfied(Input& cert, const Input* stapledOCSPResponse); +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_pkix_h +#endif // mozilla_pkix_pkix_h diff --git a/security/pkix/lib/pkixcheck.h b/security/pkix/include/pkix/pkixcheck.h index ea71c425aa..385a04bcb4 100644 --- a/security/pkix/lib/pkixcheck.h +++ b/security/pkix/include/pkix/pkixcheck.h @@ -1,44 +1,26 @@ /* -*- 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_pkixcheck_h #define mozilla_pkix_pkixcheck_h #include "pkix/pkixtypes.h" -namespace mozilla { namespace pkix { +namespace mozilla { +namespace pkix { class BackCert; -Result CheckIssuerIndependentProperties( - TrustDomain& trustDomain, - const BackCert& cert, - Time time, - KeyUsage requiredKeyUsageIfPresent, - KeyPurposeId requiredEKUIfPresent, - const CertPolicyId& requiredPolicy, - unsigned int subCACount, - /*out*/ TrustLevel& trustLevel); +Result CheckIssuerIndependentProperties(TrustDomain& trustDomain, + const BackCert& cert, Time time, + KeyUsage requiredKeyUsageIfPresent, + KeyPurposeId requiredEKUIfPresent, + const CertPolicyId& requiredPolicy, + unsigned int subCACount, + /*out*/ TrustLevel& trustLevel); Result CheckNameConstraints(Input encodedNameConstraints, const BackCert& firstChild, @@ -59,7 +41,7 @@ Result CheckValidity(Time time, Time notBefore, Time notAfter); // Check that a subject has TLS Feature (rfc7633) requirements that match its // potential issuer Result CheckTLSFeatures(const BackCert& subject, BackCert& potentialIssuer); +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_pkixcheck_h +#endif // mozilla_pkix_pkixcheck_h diff --git a/security/pkix/lib/pkixder.h b/security/pkix/include/pkix/pkixder.h index a1cc7a25af..2d9fbb87cd 100644 --- a/security/pkix/lib/pkixder.h +++ b/security/pkix/include/pkix/pkixder.h @@ -1,25 +1,8 @@ /* -*- 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_pkixder_h #define mozilla_pkix_pkixder_h @@ -39,23 +22,20 @@ #include "pkix/Input.h" #include "pkix/pkixtypes.h" -namespace mozilla { namespace pkix { namespace der { +namespace mozilla { +namespace pkix { +namespace der { -enum Class : uint8_t -{ - UNIVERSAL = 0 << 6, -// APPLICATION = 1 << 6, // unused - CONTEXT_SPECIFIC = 2 << 6, -// PRIVATE = 3 << 6 // unused +enum Class : uint8_t { + UNIVERSAL = 0 << 6, + // APPLICATION = 1 << 6, // unused + CONTEXT_SPECIFIC = 2 << 6, + // PRIVATE = 3 << 6 // unused }; -enum Constructed -{ - CONSTRUCTED = 1 << 5 -}; +enum Constructed { CONSTRUCTED = 1 << 5 }; -enum Tag : uint8_t -{ +enum Tag : uint8_t { BOOLEAN = UNIVERSAL | 0x01, INTEGER = UNIVERSAL | 0x02, BIT_STRING = UNIVERSAL | 0x03, @@ -64,8 +44,8 @@ enum Tag : uint8_t OIDTag = UNIVERSAL | 0x06, ENUMERATED = UNIVERSAL | 0x0a, UTF8String = UNIVERSAL | 0x0c, - SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x10, // 0x30 - SET = UNIVERSAL | CONSTRUCTED | 0x11, // 0x31 + SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x10, // 0x30 + SET = UNIVERSAL | CONSTRUCTED | 0x11, // 0x31 PrintableString = UNIVERSAL | 0x13, TeletexString = UNIVERSAL | 0x14, IA5String = UNIVERSAL | 0x16, @@ -79,9 +59,8 @@ Result ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag, /*out*/ Input& value); Result End(Reader& input); -inline Result -ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Input& value) -{ +inline Result ExpectTagAndGetValue(Reader& input, uint8_t tag, + /*out*/ Input& value) { uint8_t actualTag; Result rv = ReadTagAndGetValue(input, actualTag, value); if (rv != Success) { @@ -93,9 +72,8 @@ ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Input& value) return Success; } -inline Result -ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Reader& value) -{ +inline Result ExpectTagAndGetValue(Reader& input, uint8_t tag, + /*out*/ Reader& value) { Input valueInput; Result rv = ExpectTagAndGetValue(input, tag, valueInput); if (rv != Success) { @@ -104,9 +82,7 @@ ExpectTagAndGetValue(Reader& input, uint8_t tag, /*out*/ Reader& value) return value.Init(valueInput); } -inline Result -ExpectTagAndEmptyValue(Reader& input, uint8_t tag) -{ +inline Result ExpectTagAndEmptyValue(Reader& input, uint8_t tag) { Reader value; Result rv = ExpectTagAndGetValue(input, tag, value); if (rv != Success) { @@ -115,18 +91,26 @@ ExpectTagAndEmptyValue(Reader& input, uint8_t tag) return End(value); } -inline Result -ExpectTagAndSkipValue(Reader& input, uint8_t tag) -{ +inline Result ExpectTagAndSkipValue(Reader& input, uint8_t tag) { Input ignoredValue; return ExpectTagAndGetValue(input, tag, ignoredValue); } +// This skips IMPLICIT OPTIONAL tags that are "primitive" (not constructed), +// given the number in the class of the tag (i.e. the number in the brackets in +// `issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL`). +inline Result SkipOptionalImplicitPrimitiveTag(Reader& input, + uint8_t numberInClass) { + if (input.Peek(CONTEXT_SPECIFIC | numberInClass)) { + return ExpectTagAndSkipValue(input, CONTEXT_SPECIFIC | numberInClass); + } + return Success; +} + // Like ExpectTagAndGetValue, except the output Input will contain the // encoded tag and length along with the value. -inline Result -ExpectTagAndGetTLV(Reader& input, uint8_t tag, /*out*/ Input& tlv) -{ +inline Result ExpectTagAndGetTLV(Reader& input, uint8_t tag, + /*out*/ Input& tlv) { Reader::Mark mark(input.GetMark()); Result rv = ExpectTagAndSkipValue(input, tag); if (rv != Success) { @@ -135,9 +119,7 @@ ExpectTagAndGetTLV(Reader& input, uint8_t tag, /*out*/ Input& tlv) return input.GetInput(mark, tlv); } -inline Result -End(Reader& input) -{ +inline Result End(Reader& input) { if (!input.AtEnd()) { return Result::ERROR_BAD_DER; } @@ -146,9 +128,7 @@ End(Reader& input) } template <typename Decoder> -inline Result -Nested(Reader& input, uint8_t tag, Decoder decoder) -{ +inline Result Nested(Reader& input, uint8_t tag, Decoder decoder) { Reader nested; Result rv = ExpectTagAndGetValue(input, tag, nested); if (rv != Success) { @@ -162,9 +142,8 @@ Nested(Reader& input, uint8_t tag, Decoder decoder) } template <typename Decoder> -inline Result -Nested(Reader& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder) -{ +inline Result Nested(Reader& input, uint8_t outerTag, uint8_t innerTag, + Decoder decoder) { Reader nestedInput; Result rv = ExpectTagAndGetValue(input, outerTag, nestedInput); if (rv != Success) { @@ -205,10 +184,8 @@ Nested(Reader& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder) // foos. // template <typename Decoder> -inline Result -NestedOf(Reader& input, uint8_t outerTag, uint8_t innerTag, - EmptyAllowed mayBeEmpty, Decoder decoder) -{ +inline Result NestedOf(Reader& input, uint8_t outerTag, uint8_t innerTag, + EmptyAllowed mayBeEmpty, Decoder decoder) { Reader inner; Result rv = ExpectTagAndGetValue(input, outerTag, inner); if (rv != Success) { @@ -236,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. // This function reduces the boilerplate necessary for stripping the outermost // SEQUENCE (or similar) and ensuring that nothing follows it. -inline Result -ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag, - /*out*/ Reader& inner) -{ +inline Result ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag, + /*out*/ Reader& inner) { Result rv = der::ExpectTagAndGetValue(outer, expectedTag, inner); if (rv != Success) { return rv; @@ -248,10 +223,8 @@ ExpectTagAndGetValueAtEnd(Reader& outer, uint8_t expectedTag, } // Similar to the above, but takes an Input instead of a Reader&. -inline Result -ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag, - /*out*/ Reader& inner) -{ +inline Result ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag, + /*out*/ Reader& inner) { Reader outerReader(outer); return ExpectTagAndGetValueAtEnd(outerReader, expectedTag, inner); } @@ -260,30 +233,26 @@ ExpectTagAndGetValueAtEnd(Input outer, uint8_t expectedTag, namespace internal { -enum class IntegralValueRestriction -{ +enum class IntegralValueRestriction { NoRestriction, MustBePositive, MustBe0To127, }; -Result IntegralBytes(Reader& input, uint8_t tag, - IntegralValueRestriction valueRestriction, - /*out*/ Input& value, +Result IntegralBytes( + Reader& input, uint8_t tag, IntegralValueRestriction valueRestriction, + /*out*/ Input& value, /*optional out*/ Input::size_type* significantBytes = nullptr); // This parser will only parse values between 0..127. If this range is // increased then callers will need to be changed. Result IntegralValue(Reader& input, uint8_t tag, /*out*/ uint8_t& value); -} // namespace internal +} // namespace internal -Result -BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value); +Result BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value); -inline Result -Boolean(Reader& input, /*out*/ bool& value) -{ +inline Result Boolean(Reader& input, /*out*/ bool& value) { Reader valueReader; Result rv = ExpectTagAndGetValue(input, BOOLEAN, valueReader); if (rv != Success) { @@ -300,8 +269,12 @@ Boolean(Reader& input, /*out*/ bool& value) return rv; } switch (intValue) { - case 0: value = false; return Success; - case 0xFF: value = true; return Success; + case 0: + value = false; + return Success; + case 0xFF: + value = true; + return Success; default: return Result::ERROR_BAD_DER; } @@ -313,9 +286,7 @@ Boolean(Reader& input, /*out*/ bool& value) // 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 // default value, so we allow invalid explicit encodings here. -inline Result -OptionalBoolean(Reader& input, /*out*/ bool& value) -{ +inline Result OptionalBoolean(Reader& input, /*out*/ bool& value) { value = false; if (input.Peek(BOOLEAN)) { Result rv = Boolean(input, value); @@ -328,9 +299,7 @@ OptionalBoolean(Reader& input, /*out*/ bool& value) // This parser will only parse values between 0..127. If this range is // increased then callers will need to be changed. -inline Result -Enumerated(Reader& input, uint8_t& value) -{ +inline Result Enumerated(Reader& input, uint8_t& value) { return internal::IntegralValue(input, ENUMERATED | 0, value); } @@ -344,23 +313,19 @@ namespace internal { // time formats that start at 1970. Result TimeChoice(Reader& input, uint8_t tag, /*out*/ Time& time); -} // namespace internal +} // namespace internal // 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 // time formats that start at 1970. -inline Result -GeneralizedTime(Reader& input, /*out*/ Time& time) -{ +inline Result GeneralizedTime(Reader& input, /*out*/ Time& time) { return internal::TimeChoice(input, GENERALIZED_TIME, time); } // 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 // time formats that start at 1970. -inline Result -TimeChoice(Reader& input, /*out*/ Time& time) -{ +inline Result TimeChoice(Reader& input, /*out*/ Time& time) { uint8_t expectedTag = input.Peek(UTCTime) ? UTCTime : GENERALIZED_TIME; return internal::TimeChoice(input, expectedTag, time); } @@ -369,20 +334,17 @@ TimeChoice(Reader& input, /*out*/ Time& time) // 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 length of any leading padding), which is useful for key size checks. -inline Result -PositiveInteger(Reader& input, /*out*/ Input& value, - /*optional out*/ Input::size_type* significantBytes = nullptr) -{ +inline Result PositiveInteger( + Reader& input, /*out*/ Input& value, + /*optional out*/ Input::size_type* significantBytes = nullptr) { return internal::IntegralBytes( - input, INTEGER, internal::IntegralValueRestriction::MustBePositive, - value, significantBytes); + input, INTEGER, internal::IntegralValueRestriction::MustBePositive, value, + significantBytes); } // This parser will only parse values between 0..127. If this range is // increased then callers will need to be changed. -inline Result -Integer(Reader& input, /*out*/ uint8_t& value) -{ +inline Result Integer(Reader& input, /*out*/ uint8_t& value) { return internal::IntegralValue(input, INTEGER, value); } @@ -390,9 +352,8 @@ Integer(Reader& input, /*out*/ uint8_t& value) // 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 // what the default value is. -inline Result -OptionalInteger(Reader& input, long defaultValue, /*out*/ long& value) -{ +inline Result OptionalInteger(Reader& input, long defaultValue, + /*out*/ long& value) { // If we need to support a different default value in the future, we need to // test that parsedValue != defaultValue. if (defaultValue != -1) { @@ -413,16 +374,12 @@ OptionalInteger(Reader& input, long defaultValue, /*out*/ long& value) return Success; } -inline Result -Null(Reader& input) -{ +inline Result Null(Reader& input) { return ExpectTagAndEmptyValue(input, NULLTag); } template <uint8_t Len> -Result -OID(Reader& input, const uint8_t (&expectedOid)[Len]) -{ +Result OID(Reader& input, const uint8_t (&expectedOid)[Len]) { Reader value; Result rv = ExpectTagAndGetValue(input, OIDTag, value); if (rv != Success) { @@ -436,9 +393,7 @@ OID(Reader& input, const uint8_t (&expectedOid)[Len]) // PKI-specific types -inline Result -CertificateSerialNumber(Reader& input, /*out*/ Input& value) -{ +inline Result CertificateSerialNumber(Reader& input, /*out*/ Input& value) { // http://tools.ietf.org/html/rfc5280#section-4.1.2.2: // // * "The serial number MUST be a positive integer assigned by the CA to @@ -450,13 +405,12 @@ CertificateSerialNumber(Reader& input, /*out*/ Input& value) // that are negative or zero. Certificate users SHOULD be prepared to // gracefully handle such certificates." return internal::IntegralBytes( - input, INTEGER, internal::IntegralValueRestriction::NoRestriction, - value); + input, INTEGER, internal::IntegralValueRestriction::NoRestriction, value); } // x.509 and OCSP both use this same version numbering scheme, though OCSP // 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 // "[0] EXPLICIT Version DEFAULT v1". Although an explicit encoding of v1 is @@ -465,10 +419,8 @@ enum class Version { v1 = 0, v2 = 1, v3 = 2, v4 = 3 }; Result OptionalVersion(Reader& input, /*out*/ Version& version); template <typename ExtensionHandler> -inline Result -OptionalExtensions(Reader& input, uint8_t tag, - ExtensionHandler extensionHandler) -{ +inline Result OptionalExtensions(Reader& input, uint8_t tag, + ExtensionHandler extensionHandler) { if (!input.Peek(tag)) { return Success; } @@ -479,58 +431,54 @@ OptionalExtensions(Reader& input, uint8_t tag, // TODO(bug 997994): According to the specification, there should never be // an empty sequence of extensions but we've found OCSP responses that have // that (see bug 991898). - return NestedOf(tagged, SEQUENCE, SEQUENCE, EmptyAllowed::Yes, - [extensionHandler](Reader& extension) -> Result { - // Extension ::= SEQUENCE { - // extnID OBJECT IDENTIFIER, - // critical BOOLEAN DEFAULT FALSE, - // extnValue OCTET STRING - // } - Reader extnID; - Result rv = ExpectTagAndGetValue(extension, OIDTag, extnID); - if (rv != Success) { - return rv; - } - bool critical; - rv = OptionalBoolean(extension, critical); - if (rv != Success) { - return rv; - } - Input extnValue; - rv = ExpectTagAndGetValue(extension, OCTET_STRING, extnValue); - if (rv != Success) { - return rv; - } - bool understood = false; - rv = extensionHandler(extnID, extnValue, critical, understood); - if (rv != Success) { - return rv; - } - if (critical && !understood) { - return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION; - } - return Success; - }); + return NestedOf( + tagged, SEQUENCE, SEQUENCE, EmptyAllowed::Yes, + [extensionHandler](Reader& extension) -> Result { + // Extension ::= SEQUENCE { + // extnID OBJECT IDENTIFIER, + // critical BOOLEAN DEFAULT FALSE, + // extnValue OCTET STRING + // } + Reader extnID; + Result rv = ExpectTagAndGetValue(extension, OIDTag, extnID); + if (rv != Success) { + return rv; + } + bool critical; + rv = OptionalBoolean(extension, critical); + if (rv != Success) { + return rv; + } + Input extnValue; + rv = ExpectTagAndGetValue(extension, OCTET_STRING, extnValue); + if (rv != Success) { + return rv; + } + bool understood = false; + rv = extensionHandler(extnID, extnValue, critical, understood); + if (rv != Success) { + return rv; + } + if (critical && !understood) { + return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION; + } + return Success; + }); }); } Result DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm); -enum class PublicKeyAlgorithm -{ - RSA_PKCS1, - ECDSA, -}; +enum class PublicKeyAlgorithm { RSA_PKCS1, ECDSA, Uninitialized }; Result SignatureAlgorithmIdentifierValue( - Reader& input, - /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm, - /*out*/ DigestAlgorithm& digestAlgorithm); + Reader& input, + /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm, + /*out*/ DigestAlgorithm& digestAlgorithm); -struct SignedDataWithSignature final -{ -public: +struct SignedDataWithSignature final { + public: Input data; Input algorithm; Input signature; @@ -558,7 +506,8 @@ public: // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } Result SignedData(Reader& input, /*out*/ Reader& tbs, /*out*/ SignedDataWithSignature& signedDataWithSignature); +} +} +} // namespace mozilla::pkix::der -} } } // namespace mozilla::pkix::der - -#endif // mozilla_pkix_pkixder_h +#endif // mozilla_pkix_pkixder_h diff --git a/security/pkix/include/pkix/pkixnss.h b/security/pkix/include/pkix/pkixnss.h index 2c0bbf703b..43b198d515 100644 --- a/security/pkix/include/pkix/pkixnss.h +++ b/security/pkix/include/pkix/pkixnss.h @@ -1,34 +1,18 @@ /* -*- 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_pkixnss_h #define mozilla_pkix_pkixnss_h -#include "pkixtypes.h" +#include <seccomon.h> +#include "pkix/pkixtypes.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 // key. @@ -53,10 +37,8 @@ Result VerifyECDSASignedDigestNSS(const SignedDigest& sd, // 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 // a way to provide a more-obviously-safe interface. -Result DigestBufNSS(Input item, - DigestAlgorithm digestAlg, - /*out*/ uint8_t* digestBuf, - size_t digestBufLen); +Result DigestBufNSS(Input item, DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, size_t digestBufLen); Result MapPRErrorCodeToResult(PRErrorCode errorCode); PRErrorCode MapResultToPRErrorCode(Result result); @@ -71,8 +53,7 @@ PRErrorCode MapResultToPRErrorCode(Result result); static const PRErrorCode ERROR_BASE = -0x4000; static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000; -enum ErrorCode -{ +enum ErrorCode { MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0, MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1, 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_INVALID_INTEGER_ENCODING = ERROR_BASE + 11, 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 }; void RegisterErrorTable(); -inline SECItem UnsafeMapInputToSECItem(Input input) -{ - SECItem result = { - siBuffer, - const_cast<uint8_t*>(input.UnsafeGetData()), - input.GetLength() - }; +inline SECItem UnsafeMapInputToSECItem(Input input) { + SECItem result = {siBuffer, const_cast<uint8_t*>(input.UnsafeGetData()), + input.GetLength()}; static_assert(sizeof(decltype(input.GetLength())) <= sizeof(result.len), "input.GetLength() must fit in a SECItem"); return result; } +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_pkixnss_h +#endif // mozilla_pkix_pkixnss_h diff --git a/security/pkix/include/pkix/pkixtypes.h b/security/pkix/include/pkix/pkixtypes.h index b20dd2654a..7023faac44 100644 --- a/security/pkix/include/pkix/pkixtypes.h +++ b/security/pkix/include/pkix/pkixtypes.h @@ -1,45 +1,29 @@ /* -*- 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_pkixtypes_h #define mozilla_pkix_pkixtypes_h +#include <memory> + #include "pkix/Input.h" #include "pkix/Time.h" #include "stdint.h" -namespace mozilla { namespace pkix { +namespace mozilla { +namespace pkix { -enum class DigestAlgorithm -{ +enum class DigestAlgorithm { sha512 = 1, sha384 = 2, sha256 = 3, sha1 = 4, }; -enum class NamedCurve -{ +enum class NamedCurve { // secp521r1 (OID 1.3.132.0.35, RFC 5480) secp521r1 = 1, @@ -50,8 +34,7 @@ enum class NamedCurve secp256r1 = 3, }; -struct SignedDigest final -{ +struct SignedDigest final { Input digest; DigestAlgorithm digestAlgorithm; Input signature; @@ -61,53 +44,49 @@ struct SignedDigest final enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 }; -enum class KeyUsage : uint8_t -{ +enum class KeyUsage : uint8_t { digitalSignature = 0, - nonRepudiation = 1, - keyEncipherment = 2, + nonRepudiation = 1, + keyEncipherment = 2, dataEncipherment = 3, - keyAgreement = 4, - keyCertSign = 5, + keyAgreement = 4, + keyCertSign = 5, // cRLSign = 6, // encipherOnly = 7, // decipherOnly = 8, noParticularKeyUsageRequired = 0xff, }; -enum class KeyPurposeId -{ +enum class KeyPurposeId { anyExtendedKeyUsage = 0, - id_kp_serverAuth = 1, // id-kp-serverAuth - id_kp_clientAuth = 2, // id-kp-clientAuth - id_kp_codeSigning = 3, // id-kp-codeSigning - id_kp_emailProtection = 4, // id-kp-emailProtection - id_kp_OCSPSigning = 9, // id-kp-OCSPSigning + id_kp_serverAuth = 1, // id-kp-serverAuth + id_kp_clientAuth = 2, // id-kp-clientAuth + id_kp_codeSigning = 3, // id-kp-codeSigning + id_kp_emailProtection = 4, // id-kp-emailProtection + id_kp_OCSPSigning = 9, // id-kp-OCSPSigning }; -struct CertPolicyId final -{ +struct CertPolicyId final { uint16_t numBytes; static const uint16_t MAX_BYTES = 24; uint8_t bytes[MAX_BYTES]; bool IsAnyPolicy() const; + bool operator==(const CertPolicyId& other) const; static const CertPolicyId anyPolicy; }; -enum class TrustLevel -{ - TrustAnchor = 1, // certificate is a trusted root CA certificate or - // equivalent *for the given policy*. - ActivelyDistrusted = 2, // certificate is known to be bad - InheritsTrust = 3 // certificate must chain to a trust anchor +enum class TrustLevel { + TrustAnchor = 1, // certificate is a trusted root CA certificate or + // equivalent *for the given policy*. + ActivelyDistrusted = 2, // certificate is known to be bad + InheritsTrust = 3 // certificate must chain to a trust anchor }; // Extensions extracted during the verification flow. // See TrustDomain::NoteAuxiliaryExtension. -enum class AuxiliaryExtension -{ +enum class AuxiliaryExtension { // Certificate Transparency data, specifically Signed Certificate // Timestamps (SCTs). See RFC 6962. @@ -130,25 +109,22 @@ enum class AuxiliaryExtension // field from the issuer's certificate. serialNumber is the entire DER-encoded // serial number from the subject certificate (the certificate for which we are // checking the revocation status). -struct CertID final -{ -public: - CertID(Input issuer, Input issuerSubjectPublicKeyInfo, Input serialNumber) - : issuer(issuer) - , issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo) - , serialNumber(serialNumber) - { - } +struct CertID final { + public: + CertID(Input aIssuer, Input aIssuerSubjectPublicKeyInfo, Input aSerialNumber) + : issuer(aIssuer), + issuerSubjectPublicKeyInfo(aIssuerSubjectPublicKeyInfo), + serialNumber(aSerialNumber) {} const Input issuer; const Input issuerSubjectPublicKeyInfo; const Input serialNumber; void operator=(const CertID&) = delete; }; +typedef std::unique_ptr<CertID> ScopedCertID; -class DERArray -{ -public: +class DERArray { + public: // Returns the number of DER-encoded items in the array. virtual size_t GetLength() const = 0; @@ -156,19 +132,19 @@ public: // (0-indexed). The result is guaranteed to be non-null if i < GetLength(), // and the result is guaranteed to be nullptr if i >= GetLength(). virtual const Input* GetDER(size_t i) const = 0; -protected: - DERArray() { } - virtual ~DERArray() { } + + protected: + DERArray() {} + virtual ~DERArray() {} }; // Applications control the behavior of path building and verification by // implementing the TrustDomain interface. The TrustDomain is used for all // cryptography and for determining which certificates are trusted or // distrusted. -class TrustDomain -{ -public: - virtual ~TrustDomain() { } +class TrustDomain { + public: + virtual ~TrustDomain() {} // Determine the level of trust in the given certificate for the given role. // This will be called for every certificate encountered during path @@ -187,9 +163,8 @@ public: Input candidateCertDER, /*out*/ TrustLevel& trustLevel) = 0; - class IssuerChecker - { - public: + class IssuerChecker { + public: // potentialIssuerDER is the complete DER encoding of the certificate to // be checked as a potential issuer. // @@ -198,9 +173,10 @@ public: // constraints will be checked in addition to any any name constraints // contained in potentialIssuerDER. virtual Result Check(Input potentialIssuerDER, - /*optional*/ const Input* additionalNameConstraints, - /*out*/ bool& keepGoing) = 0; - protected: + /*optional*/ const Input* additionalNameConstraints, + /*out*/ bool& keepGoing) = 0; + + protected: IssuerChecker(); virtual ~IssuerChecker(); @@ -254,8 +230,8 @@ public: // implementation has an efficient way of filtering potential issuers by name // and/or validity period itself, then it is probably better for performance // for it to do so. - virtual Result FindIssuer(Input encodedIssuerName, - IssuerChecker& checker, Time time) = 0; + virtual Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, + Time time) = 0; // 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, @@ -265,7 +241,8 @@ public: // // This function may be called multiple times, regardless of whether it // 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 // passed to IsChainValid is the valid chain that should be used for further // operations that require the whole chain. @@ -278,13 +255,15 @@ public: // wrong to assume that the certificate chain is valid. // // 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, const CertID& certID, Time time, Duration validityDuration, - /*optional*/ const Input* stapledOCSPresponse, - /*optional*/ const Input* aiaExtension) = 0; + /*optional*/ const Input* stapledOCSPresponse, + /*optional*/ const Input* aiaExtension, + /*optional*/ const Input* sctExtension) = 0; // 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, // or another error code if another error occurred. virtual Result CheckRSAPublicKeyModulusSizeInBits( - EndEntityOrCA endEntityOrCA, - unsigned int modulusSizeInBits) = 0; + EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) = 0; // Verify the given RSA PKCS#1.5 signature on the given digest using the // given RSA public key. @@ -311,9 +289,8 @@ public: // function, so it is not necessary to repeat those checks here. However, // VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical // verification of the public key validity as specified in NIST SP 800-56A. - virtual Result VerifyRSAPKCS1SignedDigest( - const SignedDigest& signedDigest, - Input subjectPublicKeyInfo) = 0; + virtual Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest, + Input subjectPublicKeyInfo) = 0; // 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 // other, extensive, memory safety efforts in mozilla::pkix, and we should // find a way to provide a more-obviously-safe interface. - virtual Result DigestBuf(Input item, - DigestAlgorithm digestAlg, - /*out*/ uint8_t* digestBuf, - size_t digestBufLen) = 0; -protected: - TrustDomain() { } + virtual Result DigestBuf(Input item, DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, size_t digestBufLen) = 0; + + protected: + TrustDomain() {} TrustDomain(const TrustDomain&) = delete; void operator=(const TrustDomain&) = delete; @@ -384,25 +360,24 @@ enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 }; // Applications control the behavior of matching presented name information from // a certificate against a reference hostname by implementing the // NameMatchingPolicy interface. Used in concert with CheckCertHostname. -class NameMatchingPolicy -{ -public: - virtual ~NameMatchingPolicy() { } +class NameMatchingPolicy { + public: + virtual ~NameMatchingPolicy() {} // Given that the certificate in question has a notBefore field with the given // value, should name matching fall back to searching within the subject // common name field? virtual Result FallBackToCommonName( - Time notBefore, - /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0; + Time notBefore, + /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0; -protected: - NameMatchingPolicy() { } + protected: + NameMatchingPolicy() {} NameMatchingPolicy(const NameMatchingPolicy&) = delete; void operator=(const NameMatchingPolicy&) = delete; }; +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_pkixtypes_h +#endif // mozilla_pkix_pkixtypes_h diff --git a/security/pkix/lib/pkixutil.h b/security/pkix/include/pkix/pkixutil.h index 390e5fd4dc..8de36de0a7 100644 --- a/security/pkix/lib/pkixutil.h +++ b/security/pkix/include/pkix/pkixutil.h @@ -1,32 +1,16 @@ /* -*- 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_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 // 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 // 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. -class BackCert final -{ -public: +class BackCert final { + public: // certDER and childCert must be valid for the lifetime of BackCert. - BackCert(Input certDER, EndEntityOrCA endEntityOrCA, - const BackCert* childCert) - : der(certDER) - , endEntityOrCA(endEntityOrCA) - , childCert(childCert) - { - } + BackCert(Input aCertDER, EndEntityOrCA aEndEntityOrCA, + const BackCert* aChildCert) + : der(aCertDER), + endEntityOrCA(aEndEntityOrCA), + childCert(aChildCert), + version(der::Version::Uninitialized) {} Result Init(); @@ -65,67 +47,47 @@ public: // RFC 5280 names for everything. const Input GetValidity() const { return validity; } const Input GetSubject() const { return subject; } - const Input GetSubjectPublicKeyInfo() const - { - return subjectPublicKeyInfo; - } - const Input* GetAuthorityInfoAccess() const - { + const Input GetSubjectPublicKeyInfo() const { return subjectPublicKeyInfo; } + const Input* GetAuthorityInfoAccess() const { return MaybeInput(authorityInfoAccess); } - const Input* GetBasicConstraints() const - { + const Input* GetBasicConstraints() const { return MaybeInput(basicConstraints); } - const Input* GetCertificatePolicies() const - { + const Input* GetCertificatePolicies() const { return MaybeInput(certificatePolicies); } - const Input* GetExtKeyUsage() const - { - return MaybeInput(extKeyUsage); - } - const Input* GetKeyUsage() const - { - return MaybeInput(keyUsage); - } - const Input* GetInhibitAnyPolicy() const - { + const Input* GetExtKeyUsage() const { return MaybeInput(extKeyUsage); } + const Input* GetKeyUsage() const { return MaybeInput(keyUsage); } + const Input* GetInhibitAnyPolicy() const { return MaybeInput(inhibitAnyPolicy); } - const Input* GetNameConstraints() const - { + const Input* GetNameConstraints() const { return MaybeInput(nameConstraints); } - const Input* GetSubjectAltName() const - { - return MaybeInput(subjectAltName); - } - const Input* GetRequiredTLSFeatures() const - { + const Input* GetSubjectAltName() const { return MaybeInput(subjectAltName); } + const Input* GetRequiredTLSFeatures() const { return MaybeInput(requiredTLSFeatures); } - const Input* GetSignedCertificateTimestamps() const - { + const Input* GetSignedCertificateTimestamps() const { return MaybeInput(signedCertificateTimestamps); } -private: + private: const Input der; -public: + public: const EndEntityOrCA endEntityOrCA; BackCert const* const childCert; -private: + private: // When parsing certificates in BackCert::Init, we don't accept empty // extensions. Consequently, we don't have to store a distinction between // empty extensions and extensions that weren't included. However, when // *processing* extensions, we distinguish between whether an extension was // included or not based on whetehr the GetXXX function for the extension // returns nullptr. - static inline const Input* MaybeInput(const Input& item) - { + static inline const Input* MaybeInput(const Input& item) { return item.GetLength() > 0 ? &item : nullptr; } @@ -152,7 +114,7 @@ private: Input subjectAltName; Input criticalNetscapeCertificateType; Input requiredTLSFeatures; - Input signedCertificateTimestamps; // RFC 6962 (Certificate Transparency) + Input signedCertificateTimestamps; // RFC 6962 (Certificate Transparency) Result RememberExtension(Reader& extnID, Input extnValue, bool critical, /*out*/ bool& understood); @@ -161,29 +123,24 @@ private: void operator=(const BackCert&) = delete; }; -class NonOwningDERArray final : public DERArray -{ -public: - NonOwningDERArray() - : numItems(0) - { +class NonOwningDERArray final : public DERArray { + public: + NonOwningDERArray() : numItems(0) { // we don't need to initialize the items array because we always check // numItems before accessing i. } 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; } - Result Append(Input der) - { + Result Append(Input der) { if (numItems >= MAX_LENGTH) { return Result::FATAL_ERROR_INVALID_ARGS; } - Result rv = items[numItems].Init(der); // structure assignment + Result rv = items[numItems].Init(der); // structure assignment if (rv != Success) { return rv; } @@ -193,8 +150,9 @@ public: // Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT. static const size_t MAX_LENGTH = 8; -private: - Input items[MAX_LENGTH]; // avoids any heap allocations + + private: + Input items[MAX_LENGTH]; // avoids any heap allocations size_t numItems; NonOwningDERArray(const NonOwningDERArray&) = delete; @@ -203,25 +161,22 @@ private: // Extracts the SignedCertificateTimestampList structure which is encoded as an // OCTET STRING within the X.509v3 / OCSP extensions (see RFC 6962 section 3.3). -Result -ExtractSignedCertificateTimestampListFromExtension(Input extnValue, - Input& sctList); +Result ExtractSignedCertificateTimestampListFromExtension(Input extnValue, + Input& sctList); -inline unsigned int -DaysBeforeYear(unsigned int year) -{ +inline unsigned int DaysBeforeYear(unsigned int year) { assert(year <= 9999); - return ((year - 1u) * 365u) - + ((year - 1u) / 4u) // leap years are every 4 years, - - ((year - 1u) / 100u) // except years divisible by 100, - + ((year - 1u) / 400u); // except years divisible by 400. + return ((year - 1u) * 365u) + + ((year - 1u) / 4u) // leap years are every 4 years, + - ((year - 1u) / 100u) // except years divisible by 100, + + ((year - 1u) / 400u); // except years divisible by 400. } -static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8; // sha-512 +static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8; // sha-512 Result DigestSignedData(TrustDomain& trustDomain, 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*/ SignedDigest& signedDigest); @@ -237,9 +192,9 @@ Result VerifySignedData(TrustDomain& trustDomain, // Extracts the key parameters from |subjectPublicKeyInfo|, invoking // the relevant methods of |trustDomain|. -Result -CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, TrustDomain& trustDomain, - EndEntityOrCA endEntityOrCA); +Result CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, + TrustDomain& trustDomain, + EndEntityOrCA endEntityOrCA); // In a switch over an enum, sometimes some compilers are not satisfied that // all control flow paths have been considered unless there is a default case. @@ -268,21 +223,25 @@ CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo, TrustDomain& trustDomain, // (-W-covered-switch-default). Versions prior to 3.5 warned about unreachable // code in such default cases (-Wunreachable-code) even when // -W-covered-switch-default was disabled, but that changed in Clang 3.5. -#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM // empty +#define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM // empty #elif defined(__GNUC__) // GCC will warn if not all cases are covered (-Wswitch-enum). It does not // assume that the default case is unreachable. #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \ - default: assert(false); __builtin_unreachable(); + default: \ + assert(false); \ + __builtin_unreachable(); #elif defined(_MSC_VER) // MSVC will warn if not all cases are covered (C4061, level 4). It does not // assume that the default case is unreachable. #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \ - default: assert(false); __assume(0); + default: \ + assert(false); \ + __assume(0); #else #error Unsupported compiler for MOZILLA_PKIX_UNREACHABLE_DEFAULT. #endif +} +} // namespace mozilla::pkix -} } // namespace mozilla::pkix - -#endif // mozilla_pkix_pkixutil_h +#endif // mozilla_pkix_pkixutil_h diff --git a/security/pkix/lib/ScopedPtr.h b/security/pkix/lib/ScopedPtr.h deleted file mode 100644 index 0b24364827..0000000000 --- a/security/pkix/lib/ScopedPtr.h +++ /dev/null @@ -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 diff --git a/security/pkix/lib/pkixbuild.cpp b/security/pkix/lib/pkixbuild.cpp index d6754554ce..02de1ff705 100644 --- a/security/pkix/lib/pkixbuild.cpp +++ b/security/pkix/lib/pkixbuild.cpp @@ -1,30 +1,13 @@ /* -*- 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. - */ #include "pkix/pkix.h" -#include "pkixcheck.h" -#include "pkixutil.h" +#include "pkix/pkixcheck.h" +#include "pkix/pkixutil.h" namespace mozilla { namespace pkix { @@ -35,7 +18,8 @@ static Result BuildForward(TrustDomain& trustDomain, KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, /*optional*/ const Input* stapledOCSPResponse, - unsigned int subCACount); + unsigned int subCACount, + unsigned int& buildForwardCallBudget); TrustDomain::IssuerChecker::IssuerChecker() { } TrustDomain::IssuerChecker::~IssuerChecker() { } @@ -45,21 +29,24 @@ TrustDomain::IssuerChecker::~IssuerChecker() { } class PathBuildingStep final : public TrustDomain::IssuerChecker { public: - PathBuildingStep(TrustDomain& trustDomain, const BackCert& subject, - Time time, KeyPurposeId requiredEKUIfPresent, - const CertPolicyId& requiredPolicy, - /*optional*/ const Input* stapledOCSPResponse, - unsigned int subCACount, Result deferredSubjectError) - : trustDomain(trustDomain) - , subject(subject) - , time(time) - , requiredEKUIfPresent(requiredEKUIfPresent) - , requiredPolicy(requiredPolicy) - , stapledOCSPResponse(stapledOCSPResponse) - , subCACount(subCACount) - , deferredSubjectError(deferredSubjectError) + PathBuildingStep(TrustDomain& aTrustDomain, const BackCert& aSubject, + Time aTime, KeyPurposeId aRequiredEKUIfPresent, + const CertPolicyId& aRequiredPolicy, + /*optional*/ const Input* aStapledOCSPResponse, + unsigned int aSubCACount, Result aDeferredSubjectError, + unsigned int& aBuildForwardCallBudget) + : trustDomain(aTrustDomain) + , subject(aSubject) + , time(aTime) + , requiredEKUIfPresent(aRequiredEKUIfPresent) + , requiredPolicy(aRequiredPolicy) + , stapledOCSPResponse(aStapledOCSPResponse) + , subCACount(aSubCACount) + , deferredSubjectError(aDeferredSubjectError) + , subjectSignaturePublicKeyAlg(der::PublicKeyAlgorithm::Uninitialized) , result(Result::FATAL_ERROR_LIBRARY_FAILURE) , resultWasSet(false) + , buildForwardCallBudget(aBuildForwardCallBudget) { } @@ -87,6 +74,7 @@ private: Result RecordResult(Result currentResult, /*out*/ bool& keepGoing); Result result; bool resultWasSet; + unsigned int& buildForwardCallBudget; PathBuildingStep(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 // TODO: this doesn't account for subjectAltNames! // TODO(perf): This probably can and should be optimized in some way. - bool loopDetected = false; - for (const BackCert* prev = potentialIssuer.childCert; - !loopDetected && prev != nullptr; prev = prev->childCert) { + for (const BackCert* prev = potentialIssuer.childCert; prev; + prev = prev->childCert) { if (InputsAreEqual(potentialIssuer.GetSubjectPublicKeyInfo(), prev->GetSubjectPublicKeyInfo()) && InputsAreEqual(potentialIssuer.GetSubject(), prev->GetSubject())) { @@ -192,11 +179,20 @@ PathBuildingStep::Check(Input potentialIssuerDER, 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 // subject public key MUST NOT be used to verify signatures on certificates // or CRLs unless the corresponding keyCertSign or cRLSign bit is set." rv = BuildForward(trustDomain, potentialIssuer, time, KeyUsage::keyCertSign, - requiredEKUIfPresent, requiredPolicy, nullptr, subCACount); + requiredEKUIfPresent, requiredPolicy, nullptr, subCACount, + buildForwardCallBudget); if (rv != Success) { return RecordResult(rv, keepGoing); } @@ -239,9 +235,15 @@ PathBuildingStep::Check(Input potentialIssuerDER, Duration validityDuration(notAfter, notBefore); rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time, validityDuration, stapledOCSPResponse, - subject.GetAuthorityInfoAccess()); + subject.GetAuthorityInfoAccess(), + subject.GetSignedCertificateTimestamps()); 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) { @@ -251,7 +253,11 @@ PathBuildingStep::Check(Input potentialIssuerDER, rv = ExtractSignedCertificateTimestampListFromExtension(*sctExtension, sctList); 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, sctList); @@ -276,7 +282,8 @@ BuildForward(TrustDomain& trustDomain, KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, /*optional*/ const Input* stapledOCSPResponse, - unsigned int subCACount) + unsigned int subCACount, + unsigned int& buildForwardCallBudget) { Result rv; @@ -311,7 +318,7 @@ BuildForward(TrustDomain& trustDomain, // This must be done here, after the chain is built but before any // revocation checks have been done. - return trustDomain.IsChainValid(chain, time); + return trustDomain.IsChainValid(chain, time, requiredPolicy); } if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) { @@ -334,7 +341,7 @@ BuildForward(TrustDomain& trustDomain, PathBuildingStep pathBuilder(trustDomain, subject, time, requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse, subCACount, - deferredEndEntityError); + deferredEndEntityError, buildForwardCallBudget); // TODO(bug 965136): Add SKI/AKI matching optimizations rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time); @@ -373,9 +380,22 @@ BuildCertChain(TrustDomain& trustDomain, Input certDER, 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, requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse, - 0/*subCACount*/); + 0/*subCACount*/, buildForwardCallBudget); } } } // namespace mozilla::pkix diff --git a/security/pkix/lib/pkixcert.cpp b/security/pkix/lib/pkixcert.cpp index fddf018cfa..bdac0482c3 100644 --- a/security/pkix/lib/pkixcert.cpp +++ b/security/pkix/lib/pkixcert.cpp @@ -1,27 +1,10 @@ /* -*- 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 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 { @@ -104,29 +87,24 @@ BackCert::Init() return rv; } - static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED; - // According to RFC 5280, all fields below this line are forbidden for // certificate versions less than v3. However, for compatibility reasons, // we parse v1/v2 certificates in the same way as v3 certificates. So if // these fields appear in a v1 certificate, they will be used. // Ignore issuerUniqueID if present. - if (tbsCertificate.Peek(CSC | 1)) { - rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1); - if (rv != Success) { - return rv; - } + rv = der::SkipOptionalImplicitPrimitiveTag(tbsCertificate, 1); + if (rv != Success) { + return rv; } // Ignore subjectUniqueID if present. - if (tbsCertificate.Peek(CSC | 2)) { - rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2); - if (rv != Success) { - return rv; - } + rv = der::SkipOptionalImplicitPrimitiveTag(tbsCertificate, 2); + if (rv != Success) { + return rv; } + static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED; rv = der::OptionalExtensions( tbsCertificate, CSC | 3, [this](Reader& extnID, const Input& extnValue, bool critical, @@ -156,7 +134,7 @@ BackCert::Init() // SSL Client | false | id_kp_clientAuth // S/MIME Client | false | id_kp_emailProtection // 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 // S/MIME CA | true | id_kp_emailProtection // Object Signing CA | true | id_kp_codeSigning diff --git a/security/pkix/lib/pkixcheck.cpp b/security/pkix/lib/pkixcheck.cpp index 583e3133f0..3828283c87 100644 --- a/security/pkix/lib/pkixcheck.cpp +++ b/security/pkix/lib/pkixcheck.cpp @@ -1,30 +1,13 @@ /* -*- 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. - */ -#include "pkixcheck.h" +#include "pkix/pkixcheck.h" -#include "pkixder.h" -#include "pkixutil.h" +#include "pkix/pkixder.h" +#include "pkix/pkixutil.h" namespace mozilla { namespace pkix { @@ -116,7 +99,11 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain, // for any curve that we support, the chances of us encountering a curve // during path building is too low to be worth bothering with. break; - + case der::PublicKeyAlgorithm::Uninitialized: + { + assert(false); + return Result::FATAL_ERROR_LIBRARY_FAILURE; + } MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM } @@ -338,15 +325,16 @@ CheckSubjectPublicKeyInfoContents(Reader& input, TrustDomain& trustDomain, [&trustDomain, endEntityOrCA](Reader& r) { Input modulus; Input::size_type modulusSignificantBytes; - Result rv = der::PositiveInteger(r, modulus, &modulusSignificantBytes); - if (rv != Success) { - return rv; + Result nestedRv = + der::PositiveInteger(r, modulus, &modulusSignificantBytes); + if (nestedRv != Success) { + return nestedRv; } // XXX: Should we do additional checks of the modulus? - rv = trustDomain.CheckRSAPublicKeyModulusSizeInBits( - endEntityOrCA, modulusSignificantBytes * 8u); - if (rv != Success) { - return rv; + nestedRv = trustDomain.CheckRSAPublicKeyModulusSizeInBits( + endEntityOrCA, modulusSignificantBytes * 8u); + if (nestedRv != Success) { + return nestedRv; } // 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); } +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 Result CheckCertificatePolicies(EndEntityOrCA endEntityOrCA, @@ -644,9 +639,9 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA, Reader input(*encodedBasicConstraints); Result rv = der::Nested(input, der::SEQUENCE, [&isCA, &pathLenConstraint](Reader& r) { - Result rv = der::OptionalBoolean(r, isCA); - if (rv != Success) { - return rv; + Result nestedRv = der::OptionalBoolean(r, isCA); + if (nestedRv != Success) { + return nestedRv; } // TODO(bug 985025): If isCA is false, pathLenConstraint // MUST NOT be included (as per RFC 5280 section diff --git a/security/pkix/lib/pkixder.cpp b/security/pkix/lib/pkixder.cpp index 7aa4f77f95..f1fc849732 100644 --- a/security/pkix/lib/pkixder.cpp +++ b/security/pkix/lib/pkixder.cpp @@ -1,29 +1,11 @@ /* -*- 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. - */ - -#include "pkixder.h" -#include "pkixutil.h" +#include "pkix/pkixder.h" +#include "pkix/pkixutil.h" namespace mozilla { namespace pkix { namespace der { @@ -212,7 +194,6 @@ SignatureAlgorithmIdentifierValue(Reader& input, Result DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm) { - Reader r; return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result { Reader algorithmID; Result rv = AlgorithmIdentifierValue(r, algorithmID); diff --git a/security/pkix/lib/pkixnames.cpp b/security/pkix/lib/pkixnames.cpp index 8b2867693b..f4349d7992 100644 --- a/security/pkix/lib/pkixnames.cpp +++ b/security/pkix/lib/pkixnames.cpp @@ -1,25 +1,8 @@ /* -*- 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 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 // checking, and related things. @@ -33,8 +16,10 @@ // constraints, the reference identifier is the entire encoded name constraint // extension value. -#include "pkixcheck.h" -#include "pkixutil.h" +#include <algorithm> + +#include "pkix/pkixcheck.h" +#include "pkix/pkixutil.h" namespace mozilla { namespace pkix { @@ -1607,12 +1592,12 @@ StartsWithIDNALabel(Input id) { static const uint8_t IDN_ALABEL_PREFIX[4] = { 'x', 'n', '-', '-' }; 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; if (input.Read(b) != Success) { return false; } - if (b != IDN_ALABEL_PREFIX[i]) { + if (b != prefixByte) { return false; } } @@ -1704,11 +1689,9 @@ FinishIPv6Address(/*in/out*/ uint8_t (&address)[16], int numComponents, } // Shift components that occur after the contraction over. - size_t componentsToMove = static_cast<size_t>(numComponents - - contractionIndex); - memmove(address + (2u * static_cast<size_t>(8 - componentsToMove)), - address + (2u * static_cast<size_t>(contractionIndex)), - componentsToMove * 2u); + std::copy_backward(address + (2u * static_cast<size_t>(contractionIndex)), + address + (2u * static_cast<size_t>(numComponents)), + address + (2u * 8u)); // Fill in the contracted area with zeros. std::fill_n(address + 2u * static_cast<size_t>(contractionIndex), (8u - static_cast<size_t>(numComponents)) * 2u, static_cast<uint8_t>(0u)); diff --git a/security/pkix/lib/pkixnss.cpp b/security/pkix/lib/pkixnss.cpp index 196b74fe7f..c4928ed538 100644 --- a/security/pkix/lib/pkixnss.cpp +++ b/security/pkix/lib/pkixnss.cpp @@ -1,25 +1,8 @@ /*- *- 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. - */ #include "pkix/pkixnss.h" @@ -28,9 +11,9 @@ #include "cryptohi.h" #include "keyhi.h" #include "pk11pub.h" +#include "nss_scoped_ptrs.h" #include "pkix/pkix.h" -#include "pkixutil.h" -#include "ScopedPtr.h" +#include "pkix/pkixutil.h" #include "secerr.h" #include "sslerr.h" @@ -55,12 +38,12 @@ VerifySignedDigest(const SignedDigest& sd, SECItem subjectPublicKeyInfoSECItem = UnsafeMapInputToSECItem(subjectPublicKeyInfo); - ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo> + ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem)); if (!spki) { return MapPRErrorCodeToResult(PR_GetError()); } - ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> + ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(spki.get())); if (!pubKey) { return MapPRErrorCodeToResult(PR_GetError()); @@ -210,6 +193,14 @@ RegisterErrorTable() { "MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME", "The server presented a certificate with an empty issuer distinguished " "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. // When these strings change, update the localization information too. diff --git a/security/pkix/lib/pkixocsp.cpp b/security/pkix/lib/pkixocsp.cpp index 215020f676..03f88bafcc 100644 --- a/security/pkix/lib/pkixocsp.cpp +++ b/security/pkix/lib/pkixocsp.cpp @@ -1,31 +1,14 @@ /* -*- 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. - */ #include <limits> #include "pkix/pkix.h" -#include "pkixcheck.h" -#include "pkixutil.h" +#include "pkix/pkixcheck.h" +#include "pkix/pkixutil.h" namespace { @@ -45,16 +28,16 @@ enum class CertStatus : uint8_t { class Context final { public: - Context(TrustDomain& trustDomain, const CertID& certID, Time time, - uint16_t maxLifetimeInDays, /*optional out*/ Time* thisUpdate, - /*optional out*/ Time* validThrough) - : trustDomain(trustDomain) - , certID(certID) - , time(time) - , maxLifetimeInDays(maxLifetimeInDays) + Context(TrustDomain& aTrustDomain, const CertID& aCertID, Time aTime, + uint16_t aMaxLifetimeInDays, /*optional out*/ Time* aThisUpdate, + /*optional out*/ Time* aValidThrough) + : trustDomain(aTrustDomain) + , certID(aCertID) + , time(aTime) + , maxLifetimeInDays(aMaxLifetimeInDays) , certStatus(CertStatus::Unknown) - , thisUpdate(thisUpdate) - , validThrough(validThrough) + , thisUpdate(aThisUpdate) + , validThrough(aValidThrough) , expired(false) , matchFound(false) { @@ -172,9 +155,13 @@ static Result ExtensionNotUnderstood(Reader& extnID, Input extnValue, static Result RememberSingleExtension(Context& context, Reader& extnID, Input extnValue, bool critical, /*out*/ bool& understood); -static inline Result CertID(Reader& input, - const Context& context, - /*out*/ bool& match); +// 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, + /*out*/ bool& match); static Result MatchKeyHash(TrustDomain& trustDomain, Input issuerKeyHash, Input issuerSubjectPublicKeyInfo, @@ -437,12 +424,13 @@ BasicResponse(Reader& input, Context& context) der::SEQUENCE, [&certs](Reader& certsDER) -> Result { while (!certsDER.AtEnd()) { Input cert; - Result rv = der::ExpectTagAndGetTLV(certsDER, der::SEQUENCE, cert); - if (rv != Success) { - return rv; + Result nestedRv = + der::ExpectTagAndGetTLV(certsDER, der::SEQUENCE, cert); + if (nestedRv != Success) { + return nestedRv; } - rv = certs.Append(cert); - if (rv != Success) { + nestedRv = certs.Append(cert); + if (nestedRv != Success) { return Result::ERROR_BAD_DER; // Too many certs } } @@ -537,7 +525,7 @@ SingleResponse(Reader& input, Context& context) { bool match = false; Result rv = der::Nested(input, der::SEQUENCE, [&context, &match](Reader& r) { - return CertID(r, context, match); + return MatchCertID(r, context, match); }); if (rv != Success) { return rv; @@ -694,7 +682,7 @@ SingleResponse(Reader& input, Context& context) // issuerKeyHash OCTET STRING, -- Hash of issuer's public key // serialNumber CertificateSerialNumber } static inline Result -CertID(Reader& input, const Context& context, /*out*/ bool& match) +MatchCertID(Reader& input, const Context& context, /*out*/ bool& match) { match = false; @@ -963,8 +951,8 @@ CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID, *d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE) // reqCert.hashAlgorithm - for (size_t i = 0; i < sizeof(hashAlgorithm); ++i) { - *d++ = hashAlgorithm[i]; + for (const uint8_t hashAlgorithmByte : hashAlgorithm) { + *d++ = hashAlgorithmByte; } // reqCert.issuerNameHash (OCTET STRING) diff --git a/security/pkix/lib/pkixresult.cpp b/security/pkix/lib/pkixresult.cpp index 7e3803e094..9aa2139ca9 100644 --- a/security/pkix/lib/pkixresult.cpp +++ b/security/pkix/lib/pkixresult.cpp @@ -1,28 +1,11 @@ /*- *- 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. - */ #include "pkix/Result.h" -#include "pkixutil.h" +#include "pkix/pkixutil.h" namespace mozilla { namespace pkix { diff --git a/security/pkix/lib/pkixtime.cpp b/security/pkix/lib/pkixtime.cpp index 4e2f9b269f..1d7388584b 100644 --- a/security/pkix/lib/pkixtime.cpp +++ b/security/pkix/lib/pkixtime.cpp @@ -1,30 +1,13 @@ /* -*- 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 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 "pkixutil.h" +#include "pkix/pkixutil.h" -#ifdef WIN32 +#ifdef _WINDOWS #ifdef _MSC_VER #pragma warning(push, 3) #endif @@ -43,7 +26,7 @@ Now() { uint64_t seconds; -#ifdef WIN32 +#ifdef _WINDOWS // "Contains a 64-bit value representing the number of 100-nanosecond // intervals since January 1, 1601 (UTC)." // - http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx diff --git a/security/pkix/lib/pkixverify.cpp b/security/pkix/lib/pkixverify.cpp index 44a9efc9a0..935ca11d91 100644 --- a/security/pkix/lib/pkixverify.cpp +++ b/security/pkix/lib/pkixverify.cpp @@ -1,27 +1,10 @@ /* -*- 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 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 { @@ -78,6 +61,9 @@ VerifySignedDigest(TrustDomain& trustDomain, case der::PublicKeyAlgorithm::RSA_PKCS1: return trustDomain.VerifyRSAPKCS1SignedDigest(signedDigest, signerSubjectPublicKeyInfo); + case der::PublicKeyAlgorithm::Uninitialized: + assert(false); + return Result::FATAL_ERROR_LIBRARY_FAILURE; MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM } } diff --git a/security/pkix/moz.build b/security/pkix/moz.build index 78c72bb30a..eae307dea8 100644 --- a/security/pkix/moz.build +++ b/security/pkix/moz.build @@ -17,6 +17,7 @@ SOURCES += [ ] LOCAL_INCLUDES += [ + '../nss/cpputil', 'include', ] diff --git a/security/pkix/test/lib/pkixtestalg.cpp b/security/pkix/test/lib/pkixtestalg.cpp index 9a2fcd69ae..d698154d04 100644 --- a/security/pkix/test/lib/pkixtestalg.cpp +++ b/security/pkix/test/lib/pkixtestalg.cpp @@ -1,29 +1,13 @@ /* -*- 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 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 #define PREFIX_1_2_840_10040 0x2a, 0x86, 0x48, 0xce, 0x38 @@ -136,14 +120,14 @@ static const uint8_t DSS_G_RAW[] = } // namespace TestSignatureAlgorithm::TestSignatureAlgorithm( - const TestPublicKeyAlgorithm& publicKeyAlg, - TestDigestAlgorithmID digestAlg, - const ByteString& algorithmIdentifier, - bool accepted) - : publicKeyAlg(publicKeyAlg) - , digestAlg(digestAlg) - , algorithmIdentifier(algorithmIdentifier) - , accepted(accepted) + const TestPublicKeyAlgorithm& aPublicKeyAlg, + TestDigestAlgorithmID aDigestAlg, + const ByteString& aAlgorithmIdentifier, + bool aAccepted) + : publicKeyAlg(aPublicKeyAlg) + , digestAlg(aDigestAlg) + , algorithmIdentifier(aAlgorithmIdentifier) + , accepted(aAccepted) { } diff --git a/security/pkix/test/lib/pkixtestnss.cpp b/security/pkix/test/lib/pkixtestnss.cpp index ce9dfbb12e..001fdfbc46 100644 --- a/security/pkix/test/lib/pkixtestnss.cpp +++ b/security/pkix/test/lib/pkixtestnss.cpp @@ -1,27 +1,11 @@ /* -*- 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. - */ -#include "pkixtestutil.h" +#include "pkix/test/pkixtestutil.h" +#include "pkix/test/pkixtestnss.h" #include <limits> @@ -30,9 +14,10 @@ #include "nss.h" #include "pk11pqg.h" #include "pk11pub.h" +#include "nss_scoped_ptrs.h" #include "pkix/pkixnss.h" -#include "pkixder.h" -#include "pkixutil.h" +#include "pkix/pkixder.h" +#include "pkix/pkixutil.h" #include "prinit.h" #include "secerr.h" #include "secitem.h" @@ -41,19 +26,6 @@ namespace mozilla { namespace pkix { namespace test { 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(); void @@ -77,12 +49,15 @@ InitReusedKeyPair() class NSSTestKeyPair final : public TestKeyPair { public: - // NSSTestKeyPair takes ownership of privateKey. - NSSTestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg, + NSSTestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg, const ByteString& spk, - SECKEYPrivateKey* privateKey) - : TestKeyPair(publicKeyAlg, spk) - , privateKey(privateKey) + const ByteString& aEncryptedPrivateKey, + const ByteString& aEncryptionAlgorithm, + const ByteString& aEncryptionParams) + : TestKeyPair(aPublicKeyAlg, spk) + , encryptedPrivateKey(aEncryptedPrivateKey) + , encryptionAlgorithm(aEncryptionAlgorithm) + , encryptionParams(aEncryptionParams) { } @@ -120,10 +95,50 @@ public: 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; if (SEC_SignData(&signatureItem, tbs.data(), static_cast<int>(tbs.length()), - privateKey.get(), oidTag) != SECSuccess) { + scopedPrivateKey.get(), oidTag) != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } signature.assign(signatureItem.data, signatureItem.len); @@ -133,40 +148,63 @@ public: TestKeyPair* Clone() const override { - ScopedSECKEYPrivateKey - privateKeyCopy(SECKEY_CopyPrivateKey(privateKey.get())); - if (!privateKeyCopy) { - return nullptr; - } return new (std::nothrow) NSSTestKeyPair(publicKeyAlg, subjectPublicKey, - privateKeyCopy.release()); + encryptedPrivateKey, + encryptionAlgorithm, + encryptionParams); } private: - ScopedSECKEYPrivateKey privateKey; + const ByteString encryptedPrivateKey; + const ByteString encryptionAlgorithm; + const ByteString encryptionParams; }; } // namespace // This private function is also used by Gecko's PSM test framework // (OCSPCommon.cpp). -// -// Ownership of privateKey is transfered. TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg, - const SECKEYPublicKey& publicKey, - SECKEYPrivateKey* privateKey) + const ScopedSECKEYPublicKey& publicKey, + const ScopedSECKEYPrivateKey& privateKey) { - ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo> - spki(SECKEY_CreateSubjectPublicKeyInfo(&publicKey)); + ScopedCERTSubjectPublicKeyInfo + spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get())); if (!spki) { return nullptr; } SECItem spkDER = spki->subjectPublicKey; DER_ConvertBitString(&spkDER); // bits to bytes - return new (std::nothrow) NSSTestKeyPair(publicKeyAlg, - ByteString(spkDER.data, spkDER.len), - privateKey); + 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(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 { @@ -174,18 +212,18 @@ namespace { TestKeyPair* GenerateKeyPairInner() { - ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot()); + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { abort(); } + PK11RSAGenParams params; + params.keySizeInBits = 2048; + params.pe = 65537; // Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient // entropy to generate a random key. Attempting to add some entropy and // retrying appears to solve this issue. for (uint32_t retries = 0; retries < 10; retries++) { - PK11RSAGenParams params; - params.keySizeInBits = 2048; - params.pe = 3; SECKEYPublicKey* publicKeyTemp = nullptr; ScopedSECKEYPrivateKey privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, @@ -193,7 +231,7 @@ GenerateKeyPairInner() nullptr)); ScopedSECKEYPublicKey publicKey(publicKeyTemp); if (privateKey) { - return CreateTestKeyPair(RSA_PKCS1(), *publicKey, privateKey.release()); + return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey); } assert(!publicKeyTemp); @@ -206,8 +244,9 @@ GenerateKeyPairInner() // random keys. // https://xkcd.com/221/ static const uint8_t RANDOM_NUMBER[] = { 4, 4, 4, 4, 4, 4, 4, 4 }; - if (PK11_RandomUpdate((void*) &RANDOM_NUMBER, - sizeof(RANDOM_NUMBER)) != SECSuccess) { + if (PK11_RandomUpdate( + const_cast<void*>(reinterpret_cast<const void*>(RANDOM_NUMBER)), + sizeof(RANDOM_NUMBER)) != SECSuccess) { break; } } @@ -240,7 +279,7 @@ GenerateDSSKeyPair() { InitNSSIfNeeded(); - ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot()); + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { return nullptr; } @@ -274,7 +313,7 @@ GenerateDSSKeyPair() return nullptr; } ScopedSECKEYPublicKey publicKey(publicKeyTemp); - return CreateTestKeyPair(DSS(), *publicKey, privateKey.release()); + return CreateTestKeyPair(DSS(), publicKey, privateKey); } Result diff --git a/security/pkix/test/lib/pkixtestutil.cpp b/security/pkix/test/lib/pkixtestutil.cpp index fa4d7eeee0..32401af81b 100644 --- a/security/pkix/test/lib/pkixtestutil.cpp +++ b/security/pkix/test/lib/pkixtestutil.cpp @@ -1,27 +1,10 @@ /* -*- 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. - */ -#include "pkixtestutil.h" +#include "pkix/test/pkixtestutil.h" #include <cerrno> #include <cstdio> @@ -30,8 +13,8 @@ #include <sstream> #include <cstdlib> -#include "pkixder.h" -#include "pkixutil.h" +#include "pkix/pkixder.h" +#include "pkix/pkixutil.h" using namespace std; @@ -39,12 +22,14 @@ namespace mozilla { namespace pkix { namespace test { namespace { -inline void -fclose_void(FILE* file) { - (void) fclose(file); -} - -typedef mozilla::pkix::ScopedPtr<FILE, fclose_void> ScopedFILE; +struct ScopedMaybeDeleteFile { + void operator()(FILE* f) { + if (f) { + (void)fclose(f); + } + } +}; +typedef std::unique_ptr<FILE, ScopedMaybeDeleteFile> ScopedFILE; FILE* OpenFile(const string& dir, const string& filename, const string& mode) @@ -151,8 +136,8 @@ OCSPResponseExtension::OCSPResponseExtension() { } -OCSPResponseContext::OCSPResponseContext(const CertID& certID, time_t time) - : certID(certID) +OCSPResponseContext::OCSPResponseContext(const CertID& aCertID, time_t time) + : certID(aCertID) , responseStatus(successful) , skipResponseBytes(false) , producedAt(time) @@ -248,7 +233,7 @@ Integer(long value) enum TimeEncoding { UTCTime = 0, GeneralizedTime = 1 }; // 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* gmtime_r(const time_t* t, /*out*/ tm* exploded) { @@ -738,7 +723,7 @@ CreateEncodedSerialNumber(long serialNumberValue) // pathLenConstraint INTEGER (0..MAX) OPTIONAL } ByteString CreateEncodedBasicConstraints(bool isCA, - /*optional*/ long* pathLenConstraintValue, + /*optional in*/ const long* pathLenConstraintValue, Critical critical) { ByteString value; @@ -1139,11 +1124,11 @@ CertStatus(OCSPResponseContext& context) static const ByteString NO_UNUSED_BITS(1, 0x00); // The SubjectPublicKeyInfo syntax is specified in RFC 5280 Section 4.1. -TestKeyPair::TestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg, +TestKeyPair::TestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg, const ByteString& spk) - : publicKeyAlg(publicKeyAlg) + : publicKeyAlg(aPublicKeyAlg) , subjectPublicKeyInfo(TLV(der::SEQUENCE, - publicKeyAlg.algorithmIdentifier + + aPublicKeyAlg.algorithmIdentifier + TLV(der::BIT_STRING, NO_UNUSED_BITS + spk))) , subjectPublicKey(spk) { diff --git a/security/pkix/tools/DottedOIDToCode.py b/security/pkix/tools/DottedOIDToCode.py index b8eb88d832..dfd4ade074 100644 --- a/security/pkix/tools/DottedOIDToCode.py +++ b/security/pkix/tools/DottedOIDToCode.py @@ -24,6 +24,7 @@ import argparse import itertools import sys + def base128(value): """ Given an integral value, returns an array of the base-128 representation @@ -50,6 +51,7 @@ def base128(value): return result + def dottedOIDToEncodedArray(dottedOID): """ 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:]] return [firstByte] + list(itertools.chain.from_iterable(restBase128)) + def dottedOIDToCArray(dottedOID, mode): """ 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]) + def specNameToCName(specName): """ 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("-", "_") + def toCode(programName, specName, dottedOID, mode): """ Given an ASN.1 name and a string containing the dotted representation of an @@ -180,11 +185,12 @@ def toCode(programName, specName, dottedOID, mode): " };\n") % (programNameWithOptions, specName, dottedOID, varName, dottedOIDToCArray(dottedOID, mode)) + if __name__ == "__main__": parser = argparse.ArgumentParser( - description="Generate code snippets to handle OIDs in C++", - epilog="example: python %s ecdsa-with-SHA1 1.2.840.10045.4.1" - % sys.argv[0]) + description="Generate code snippets to handle OIDs in C++", + epilog="example: python %s ecdsa-with-SHA1 1.2.840.10045.4.1" + % sys.argv[0]) group = parser.add_mutually_exclusive_group() group.add_argument("--tlv", action='store_true', help="Wrap the encoded OID value with the tag and length") |