mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-27 02:47:31 +09:00
Update NSS to 3.41
This commit is contained in:
parent
d5f6e64f43
commit
5f0986e66f
540 changed files with 49568 additions and 10631 deletions
61
security/nss/gtests/mozpkix_gtest/README.txt
Normal file
61
security/nss/gtests/mozpkix_gtest/README.txt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
-------------
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
Because of the rules below, you can run all the unit tests in this directory,
|
||||
and only these tests, with:
|
||||
|
||||
mach gtest "pkix*"
|
||||
|
||||
You can run just the tests for functions defined in filename pkixfoo.cpp with:
|
||||
|
||||
mach gtest "pkixfoo*"
|
||||
|
||||
If you run "mach gtest" then you'll end up running every gtest in Gecko.
|
||||
|
||||
|
||||
|
||||
------------
|
||||
Naming Files
|
||||
------------
|
||||
|
||||
Name files containing tests according to one of the following patterns:
|
||||
|
||||
* <filename>_tests.cpp
|
||||
* <filename>_<Function>_tests.cpp
|
||||
* <filename>_<category>_tests.cpp
|
||||
|
||||
<filename> is the name of the file containing the definitions of the
|
||||
function(s) being tested by every test.
|
||||
<Function> is the name of the function that is being tested by every
|
||||
test.
|
||||
<category> describes the group of related functions that are being
|
||||
tested by every test.
|
||||
|
||||
|
||||
|
||||
------------------------------------------------
|
||||
Always Use a Fixture Class: TEST_F(), not TEST()
|
||||
------------------------------------------------
|
||||
|
||||
Many tests don't technically need a fixture, and so TEST() could technically
|
||||
be used to define the test. However, when you use TEST_F() instead of TEST(),
|
||||
the compiler will not allow you to make any typos in the test case name, but
|
||||
if you use TEST() then the name of the test case is not checked.
|
||||
|
||||
See https://code.google.com/p/googletest/wiki/Primer#Test_Fixtures:_Using_the_Same_Data_Configuration_for_Multiple_Te
|
||||
to learn more about test fixtures.
|
||||
|
||||
---------------
|
||||
Naming Fixtures
|
||||
---------------
|
||||
|
||||
When all tests in a file use the same fixture, use the base name of the file
|
||||
without the "_tests" suffix as the name of the fixture class; e.g. tests in
|
||||
"pkixocsp.cpp" should use a fixture "class pkixocsp" by default.
|
||||
|
||||
Sometimes tests in a file need separate fixtures. In this case, name the
|
||||
fixture class according to the pattern <fixture_base>_<fixture_suffix>, where
|
||||
<fixture_base> is the base name of the file without the "_tests" suffix, and
|
||||
<fixture_suffix> is a descriptive name for the fixture class, e.g.
|
||||
"class pkixocsp_DelegatedResponder".
|
||||
71
security/nss/gtests/mozpkix_gtest/mozpkix_gtest.gyp
Normal file
71
security/nss/gtests/mozpkix_gtest/mozpkix_gtest.gyp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# 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/.
|
||||
{
|
||||
'includes': [
|
||||
'../../coreconf/config.gypi',
|
||||
'../common/gtest.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'mozpkix_gtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'<(DEPTH)/gtests/common/gtests.cc',
|
||||
'pkixbuild_tests.cpp',
|
||||
'pkixcert_extension_tests.cpp',
|
||||
'pkixcert_signature_algorithm_tests.cpp',
|
||||
'pkixcheck_CheckExtendedKeyUsage_tests.cpp',
|
||||
'pkixcheck_CheckIssuer_tests.cpp',
|
||||
'pkixcheck_CheckKeyUsage_tests.cpp',
|
||||
'pkixcheck_CheckSignatureAlgorithm_tests.cpp',
|
||||
'pkixcheck_CheckValidity_tests.cpp',
|
||||
'pkixcheck_ParseValidity_tests.cpp',
|
||||
'pkixcheck_TLSFeaturesSatisfiedInternal_tests.cpp',
|
||||
'pkixder_input_tests.cpp',
|
||||
'pkixder_pki_types_tests.cpp',
|
||||
'pkixder_universal_types_tests.cpp',
|
||||
'pkixgtest.cpp',
|
||||
'pkixnames_tests.cpp',
|
||||
'pkixocsp_CreateEncodedOCSPRequest_tests.cpp',
|
||||
'pkixocsp_VerifyEncodedOCSPResponse.cpp',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
|
||||
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
|
||||
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
|
||||
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
|
||||
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
|
||||
'<(DEPTH)/lib/base/base.gyp:nssb',
|
||||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
|
||||
'<(DEPTH)/lib/mozpkix/mozpkix.gyp:mozpkix',
|
||||
'<(DEPTH)/lib/mozpkix/mozpkix.gyp:mozpkix-testlib',
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(DEPTH)/lib/mozpkix/',
|
||||
'<(DEPTH)/lib/mozpkix/lib',
|
||||
'<(DEPTH)/lib/mozpkix/include/',
|
||||
'<(DEPTH)/lib/mozpkix/include/pkix-test/',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'OS=="win"', {
|
||||
'libraries': [
|
||||
'advapi32.lib',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'defines': [
|
||||
'NSS_USE_STATIC_LIBS'
|
||||
],
|
||||
}
|
||||
],
|
||||
'variables': {
|
||||
'module': 'nss',
|
||||
'use_static_libs': 1,
|
||||
}
|
||||
}
|
||||
894
security/nss/gtests/mozpkix_gtest/pkixbuild_tests.cpp
Normal file
894
security/nss/gtests/mozpkix_gtest/pkixbuild_tests.cpp
Normal file
|
|
@ -0,0 +1,894 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
// When building with -D_HAS_EXCEPTIONS=0, MSVC's <xtree> header triggers
|
||||
// warning C4702: unreachable code.
|
||||
// https://connect.microsoft.com/VisualStudio/feedback/details/809962
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4702)
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
static ByteString
|
||||
CreateCert(const char* issuerCN, // null means "empty name"
|
||||
const char* subjectCN, // null means "empty name"
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
/*optional modified*/ std::map<ByteString, ByteString>*
|
||||
subjectDERToCertDER = nullptr,
|
||||
/*optional*/ const ByteString* extension = nullptr,
|
||||
/*optional*/ const TestKeyPair* issuerKeyPair = nullptr,
|
||||
/*optional*/ const TestKeyPair* subjectKeyPair = nullptr)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
|
||||
EXPECT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
|
||||
ByteString issuerDER(issuerCN ? CNToDERName(issuerCN) : Name(ByteString()));
|
||||
ByteString subjectDER(subjectCN ? CNToDERName(subjectCN) : Name(ByteString()));
|
||||
|
||||
std::vector<ByteString> extensions;
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
|
||||
ByteString basicConstraints =
|
||||
CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
|
||||
EXPECT_FALSE(ENCODING_FAILED(basicConstraints));
|
||||
extensions.push_back(basicConstraints);
|
||||
}
|
||||
if (extension) {
|
||||
extensions.push_back(*extension);
|
||||
}
|
||||
extensions.push_back(ByteString()); // marks the end of the list
|
||||
|
||||
ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
|
||||
ByteString certDER(CreateEncodedCertificate(
|
||||
v3, sha256WithRSAEncryption(), serialNumber, issuerDER,
|
||||
oneDayBeforeNow, oneDayAfterNow, subjectDER,
|
||||
subjectKeyPair ? *subjectKeyPair : *reusedKey,
|
||||
extensions.data(),
|
||||
issuerKeyPair ? *issuerKeyPair : *reusedKey,
|
||||
sha256WithRSAEncryption()));
|
||||
EXPECT_FALSE(ENCODING_FAILED(certDER));
|
||||
|
||||
if (subjectDERToCertDER) {
|
||||
(*subjectDERToCertDER)[subjectDER] = certDER;
|
||||
}
|
||||
|
||||
return certDER;
|
||||
}
|
||||
|
||||
class TestTrustDomain final : public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
// The "cert chain tail" is a longish chain of certificates that is used by
|
||||
// all of the tests here. We share this chain across all the tests in order
|
||||
// to speed up the tests (generating keypairs for the certs is very slow).
|
||||
bool SetUpCertChainTail()
|
||||
{
|
||||
static char const* const names[] = {
|
||||
"CA1 (Root)", "CA2", "CA3", "CA4", "CA5", "CA6", "CA7"
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < MOZILLA_PKIX_ARRAY_LENGTH(names); ++i) {
|
||||
const char* issuerName = i == 0 ? names[0] : names[i-1];
|
||||
CreateCACert(issuerName, names[i]);
|
||||
if (i == 0) {
|
||||
rootCACertDER = leafCACertDER;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CreateCACert(const char* issuerName, const char* subjectName)
|
||||
{
|
||||
leafCACertDER = CreateCert(issuerName, subjectName,
|
||||
EndEntityOrCA::MustBeCA, &subjectDERToCertDER);
|
||||
assert(!ENCODING_FAILED(leafCACertDER));
|
||||
}
|
||||
|
||||
ByteString GetLeafCACertDER() const { return leafCACertDER; }
|
||||
|
||||
private:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
|
||||
? TrustLevel::TrustAnchor
|
||||
: TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
|
||||
override
|
||||
{
|
||||
ByteString subjectDER(InputToByteString(encodedIssuerName));
|
||||
ByteString certDER(subjectDERToCertDER[subjectDER]);
|
||||
Input derCert;
|
||||
Result rv = derCert.Init(certDER.data(), certDER.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
bool keepGoing;
|
||||
rv = checker.Check(derCert, nullptr/*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
std::map<ByteString, ByteString> subjectDERToCertDER;
|
||||
ByteString leafCACertDER;
|
||||
ByteString rootCACertDER;
|
||||
};
|
||||
|
||||
class pkixbuild : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
if (!trustDomain.SetUpCertChainTail()) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static TestTrustDomain trustDomain;
|
||||
};
|
||||
|
||||
/*static*/ TestTrustDomain pkixbuild::trustDomain;
|
||||
|
||||
TEST_F(pkixbuild, MaxAcceptableCertChainLength)
|
||||
{
|
||||
{
|
||||
ByteString leafCACert(trustDomain.GetLeafCACertDER());
|
||||
Input certDER;
|
||||
ASSERT_EQ(Success, certDER.Init(leafCACert.data(), leafCACert.length()));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, certDER, Now(),
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
{
|
||||
ByteString certDER(CreateCert("CA7", "Direct End-Entity",
|
||||
EndEntityOrCA::MustBeEndEntity));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
|
||||
{
|
||||
static char const* const caCertName = "CA Too Far";
|
||||
|
||||
trustDomain.CreateCACert("CA7", caCertName);
|
||||
|
||||
{
|
||||
ByteString certDER(trustDomain.GetLeafCACertDER());
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
{
|
||||
ByteString certDER(CreateCert(caCertName, "End-Entity Too Far",
|
||||
EndEntityOrCA::MustBeEndEntity));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
}
|
||||
|
||||
// A TrustDomain that checks certificates against a given root certificate.
|
||||
// It is initialized with the DER encoding of a root certificate that
|
||||
// is treated as a trust anchor and is assumed to have issued all certificates
|
||||
// (i.e. FindIssuer always attempts to build the next step in the chain with
|
||||
// it).
|
||||
class SingleRootTrustDomain : public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
explicit SingleRootTrustDomain(ByteString aRootDER)
|
||||
: rootDER(aRootDER)
|
||||
{
|
||||
}
|
||||
|
||||
// The CertPolicyId argument is unused because we don't care about EV.
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
Input rootCert;
|
||||
Result rv = rootCert.Init(rootDER.data(), rootDER.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (InputsAreEqual(candidateCert, rootCert)) {
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
} else {
|
||||
trustLevel = TrustLevel::InheritsTrust;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input, IssuerChecker& checker, Time) override
|
||||
{
|
||||
// keepGoing is an out parameter from IssuerChecker.Check. It would tell us
|
||||
// whether or not to continue attempting other potential issuers. We only
|
||||
// know of one potential issuer, however, so we ignore it.
|
||||
bool keepGoing;
|
||||
Input rootCert;
|
||||
Result rv = rootCert.Init(rootDER.data(), rootDER.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
return checker.Check(rootCert, nullptr, keepGoing);
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
private:
|
||||
ByteString rootDER;
|
||||
};
|
||||
|
||||
// A TrustDomain that explicitly fails if CheckRevocation is called.
|
||||
class ExpiredCertTrustDomain final : public SingleRootTrustDomain
|
||||
{
|
||||
public:
|
||||
explicit ExpiredCertTrustDomain(ByteString aRootDER)
|
||||
: SingleRootTrustDomain(aRootDER)
|
||||
{
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return NotReached("CheckRevocation should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(pkixbuild, NoRevocationCheckingForExpiredCert)
|
||||
{
|
||||
const char* rootCN = "Root CA";
|
||||
ByteString rootDER(CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
|
||||
nullptr));
|
||||
EXPECT_FALSE(ENCODING_FAILED(rootDER));
|
||||
ExpiredCertTrustDomain expiredCertTrustDomain(rootDER);
|
||||
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(100));
|
||||
EXPECT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
ByteString issuerDER(CNToDERName(rootCN));
|
||||
ByteString subjectDER(CNToDERName("Expired End-Entity Cert"));
|
||||
ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
|
||||
ByteString certDER(CreateEncodedCertificate(
|
||||
v3, sha256WithRSAEncryption(),
|
||||
serialNumber, issuerDER,
|
||||
twoDaysBeforeNow,
|
||||
oneDayBeforeNow,
|
||||
subjectDER, *reusedKey, nullptr, *reusedKey,
|
||||
sha256WithRSAEncryption()));
|
||||
EXPECT_FALSE(ENCODING_FAILED(certDER));
|
||||
|
||||
Input cert;
|
||||
ASSERT_EQ(Success, cert.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE,
|
||||
BuildCertChain(expiredCertTrustDomain, cert, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
class DSSTrustDomain final : public EverythingFailsByDefaultTrustDomain
|
||||
{
|
||||
public:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
|
||||
Input, /*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
|
||||
class pkixbuild_DSS : public ::testing::Test { };
|
||||
|
||||
TEST_F(pkixbuild_DSS, DSSEndEntityKeyNotAccepted)
|
||||
{
|
||||
DSSTrustDomain trustDomain;
|
||||
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(1));
|
||||
ASSERT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
|
||||
ByteString subjectDER(CNToDERName("DSS"));
|
||||
ASSERT_FALSE(ENCODING_FAILED(subjectDER));
|
||||
ScopedTestKeyPair subjectKey(GenerateDSSKeyPair());
|
||||
ASSERT_TRUE(subjectKey.get());
|
||||
|
||||
ByteString issuerDER(CNToDERName("RSA"));
|
||||
ASSERT_FALSE(ENCODING_FAILED(issuerDER));
|
||||
ScopedTestKeyPair issuerKey(CloneReusedKeyPair());
|
||||
ASSERT_TRUE(issuerKey.get());
|
||||
|
||||
ByteString cert(CreateEncodedCertificate(v3, sha256WithRSAEncryption(),
|
||||
serialNumber, issuerDER,
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
subjectDER, *subjectKey, nullptr,
|
||||
*issuerKey, sha256WithRSAEncryption()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(cert));
|
||||
Input certDER;
|
||||
ASSERT_EQ(Success, certDER.Init(cert.data(), cert.length()));
|
||||
|
||||
ASSERT_EQ(Result::ERROR_UNSUPPORTED_KEYALG,
|
||||
BuildCertChain(trustDomain, certDER, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
class IssuerNameCheckTrustDomain final : public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
IssuerNameCheckTrustDomain(const ByteString& aIssuer, bool aExpectedKeepGoing)
|
||||
: issuer(aIssuer)
|
||||
, expectedKeepGoing(aExpectedKeepGoing)
|
||||
{
|
||||
}
|
||||
|
||||
Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&, Input,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = endEntityOrCA == EndEntityOrCA::MustBeCA
|
||||
? TrustLevel::TrustAnchor
|
||||
: TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input, IssuerChecker& checker, Time) override
|
||||
{
|
||||
Input issuerInput;
|
||||
EXPECT_EQ(Success, issuerInput.Init(issuer.data(), issuer.length()));
|
||||
bool keepGoing;
|
||||
EXPECT_EQ(Success,
|
||||
checker.Check(issuerInput, nullptr /*additionalNameConstraints*/,
|
||||
keepGoing));
|
||||
EXPECT_EQ(expectedKeepGoing, keepGoing);
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
private:
|
||||
const ByteString issuer;
|
||||
const bool expectedKeepGoing;
|
||||
};
|
||||
|
||||
struct IssuerNameCheckParams
|
||||
{
|
||||
const char* subjectIssuerCN; // null means "empty name"
|
||||
const char* issuerSubjectCN; // null means "empty name"
|
||||
bool matches;
|
||||
Result expectedError;
|
||||
};
|
||||
|
||||
static const IssuerNameCheckParams ISSUER_NAME_CHECK_PARAMS[] =
|
||||
{
|
||||
{ "foo", "foo", true, Success },
|
||||
{ "foo", "bar", false, Result::ERROR_UNKNOWN_ISSUER },
|
||||
{ "f", "foo", false, Result::ERROR_UNKNOWN_ISSUER }, // prefix
|
||||
{ "foo", "f", false, Result::ERROR_UNKNOWN_ISSUER }, // prefix
|
||||
{ "foo", "Foo", false, Result::ERROR_UNKNOWN_ISSUER }, // case sensitive
|
||||
{ "", "", true, Success },
|
||||
{ nullptr, nullptr, false, Result::ERROR_EMPTY_ISSUER_NAME }, // empty issuer
|
||||
|
||||
// check that certificate-related errors are deferred and superseded by
|
||||
// ERROR_UNKNOWN_ISSUER when a chain can't be built due to name mismatches
|
||||
{ "foo", nullptr, false, Result::ERROR_UNKNOWN_ISSUER },
|
||||
{ nullptr, "foo", false, Result::ERROR_UNKNOWN_ISSUER }
|
||||
};
|
||||
|
||||
class pkixbuild_IssuerNameCheck
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<IssuerNameCheckParams>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(pkixbuild_IssuerNameCheck, MatchingName)
|
||||
{
|
||||
const IssuerNameCheckParams& params(GetParam());
|
||||
|
||||
ByteString issuerCertDER(CreateCert(params.issuerSubjectCN,
|
||||
params.issuerSubjectCN,
|
||||
EndEntityOrCA::MustBeCA, nullptr));
|
||||
ASSERT_FALSE(ENCODING_FAILED(issuerCertDER));
|
||||
|
||||
ByteString subjectCertDER(CreateCert(params.subjectIssuerCN, "end-entity",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr));
|
||||
ASSERT_FALSE(ENCODING_FAILED(subjectCertDER));
|
||||
|
||||
Input subjectCertDERInput;
|
||||
ASSERT_EQ(Success, subjectCertDERInput.Init(subjectCertDER.data(),
|
||||
subjectCertDER.length()));
|
||||
|
||||
IssuerNameCheckTrustDomain trustDomain(issuerCertDER, !params.matches);
|
||||
ASSERT_EQ(params.expectedError,
|
||||
BuildCertChain(trustDomain, subjectCertDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixbuild_IssuerNameCheck, pkixbuild_IssuerNameCheck,
|
||||
testing::ValuesIn(ISSUER_NAME_CHECK_PARAMS));
|
||||
|
||||
|
||||
// Records the embedded SCT list extension for later examination.
|
||||
class EmbeddedSCTListTestTrustDomain final : public SingleRootTrustDomain
|
||||
{
|
||||
public:
|
||||
explicit EmbeddedSCTListTestTrustDomain(ByteString aRootDER)
|
||||
: SingleRootTrustDomain(aRootDER)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension,
|
||||
Input extensionData) override
|
||||
{
|
||||
if (extension == AuxiliaryExtension::EmbeddedSCTList) {
|
||||
signedCertificateTimestamps = InputToByteString(extensionData);
|
||||
} else {
|
||||
ADD_FAILURE();
|
||||
}
|
||||
}
|
||||
|
||||
ByteString signedCertificateTimestamps;
|
||||
};
|
||||
|
||||
TEST_F(pkixbuild, CertificateTransparencyExtension)
|
||||
{
|
||||
// python security/pkix/tools/DottedOIDToCode.py --tlv
|
||||
// id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
|
||||
static const uint8_t tlv_id_embeddedSctList[] = {
|
||||
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
|
||||
};
|
||||
static const uint8_t dummySctList[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05
|
||||
};
|
||||
|
||||
ByteString ctExtension = TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_embeddedSctList) +
|
||||
Boolean(false) +
|
||||
TLV(der::OCTET_STRING,
|
||||
// SignedCertificateTimestampList structure is encoded as an OCTET STRING
|
||||
// within the X.509v3 extension (see RFC 6962 section 3.3).
|
||||
// pkix decodes it internally and returns the actual structure.
|
||||
TLV(der::OCTET_STRING, BytesToByteString(dummySctList))));
|
||||
|
||||
const char* rootCN = "Root CA";
|
||||
ByteString rootDER(CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA));
|
||||
ASSERT_FALSE(ENCODING_FAILED(rootDER));
|
||||
|
||||
ByteString certDER(CreateCert(rootCN, "Cert with SCT list",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr, /*subjectDERToCertDER*/
|
||||
&ctExtension));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
|
||||
Input certInput;
|
||||
ASSERT_EQ(Success, certInput.Init(certDER.data(), certDER.length()));
|
||||
|
||||
EmbeddedSCTListTestTrustDomain extTrustDomain(rootDER);
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(extTrustDomain, certInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr /*stapledOCSPResponse*/));
|
||||
ASSERT_EQ(BytesToByteString(dummySctList),
|
||||
extTrustDomain.signedCertificateTimestamps);
|
||||
}
|
||||
|
||||
// This TrustDomain implements a hierarchy like so:
|
||||
//
|
||||
// A B
|
||||
// | |
|
||||
// C D
|
||||
// \ /
|
||||
// E
|
||||
//
|
||||
// where A is a trust anchor, B is not a trust anchor and has no known issuer, C
|
||||
// and D are intermediates with the same subject and subject public key, and E
|
||||
// is an end-entity (in practice, the end-entity will be generated by the test
|
||||
// functions using this trust domain).
|
||||
class MultiplePathTrustDomain: public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
void SetUpCerts()
|
||||
{
|
||||
ASSERT_FALSE(ENCODING_FAILED(CreateCert("UntrustedRoot", "UntrustedRoot",
|
||||
EndEntityOrCA::MustBeCA,
|
||||
&subjectDERToCertDER)));
|
||||
// The subject DER -> cert DER mapping would be overwritten for subject
|
||||
// "Intermediate" when we create the second "Intermediate" certificate, so
|
||||
// we keep a copy of this "Intermediate".
|
||||
intermediateSignedByUntrustedRootCertDER =
|
||||
CreateCert("UntrustedRoot", "Intermediate", EndEntityOrCA::MustBeCA);
|
||||
ASSERT_FALSE(ENCODING_FAILED(intermediateSignedByUntrustedRootCertDER));
|
||||
rootCACertDER = CreateCert("TrustedRoot", "TrustedRoot",
|
||||
EndEntityOrCA::MustBeCA, &subjectDERToCertDER);
|
||||
ASSERT_FALSE(ENCODING_FAILED(rootCACertDER));
|
||||
ASSERT_FALSE(ENCODING_FAILED(CreateCert("TrustedRoot", "Intermediate",
|
||||
EndEntityOrCA::MustBeCA,
|
||||
&subjectDERToCertDER)));
|
||||
}
|
||||
|
||||
private:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
|
||||
? TrustLevel::TrustAnchor
|
||||
: TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckCert(ByteString& certDER, IssuerChecker& checker, bool& keepGoing)
|
||||
{
|
||||
Input derCert;
|
||||
Result rv = derCert.Init(certDER.data(), certDER.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
return checker.Check(derCert, nullptr/*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
}
|
||||
|
||||
Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
|
||||
override
|
||||
{
|
||||
ByteString subjectDER(InputToByteString(encodedIssuerName));
|
||||
ByteString certDER(subjectDERToCertDER[subjectDER]);
|
||||
assert(!ENCODING_FAILED(certDER));
|
||||
bool keepGoing;
|
||||
Result rv = CheckCert(certDER, checker, keepGoing);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
// Also try the other intermediate.
|
||||
if (keepGoing) {
|
||||
rv = CheckCert(intermediateSignedByUntrustedRootCertDER, checker,
|
||||
keepGoing);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
std::map<ByteString, ByteString> subjectDERToCertDER;
|
||||
ByteString rootCACertDER;
|
||||
ByteString intermediateSignedByUntrustedRootCertDER;
|
||||
};
|
||||
|
||||
TEST_F(pkixbuild, BadEmbeddedSCTWithMultiplePaths)
|
||||
{
|
||||
MultiplePathTrustDomain localTrustDomain;
|
||||
localTrustDomain.SetUpCerts();
|
||||
|
||||
// python security/pkix/tools/DottedOIDToCode.py --tlv
|
||||
// id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
|
||||
static const uint8_t tlv_id_embeddedSctList[] = {
|
||||
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
|
||||
};
|
||||
static const uint8_t dummySctList[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05
|
||||
};
|
||||
ByteString ctExtension = TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_embeddedSctList) +
|
||||
Boolean(false) +
|
||||
// The contents of the OCTET STRING are supposed to consist of an OCTET
|
||||
// STRING of useful data. We're testing what happens if it isn't, so shove
|
||||
// some bogus (non-OCTET STRING) data in there.
|
||||
TLV(der::OCTET_STRING, BytesToByteString(dummySctList)));
|
||||
ByteString certDER(CreateCert("Intermediate", "Cert with bogus SCT list",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr, /*subjectDERToCertDER*/
|
||||
&ctExtension));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
BuildCertChain(localTrustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
// Same as a MultiplePathTrustDomain, but the end-entity is revoked.
|
||||
class RevokedEndEntityTrustDomain final : public MultiplePathTrustDomain
|
||||
{
|
||||
public:
|
||||
Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&, Time,
|
||||
Duration, /*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override
|
||||
{
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
|
||||
return Result::ERROR_REVOKED_CERTIFICATE;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(pkixbuild, RevokedEndEntityWithMultiplePaths)
|
||||
{
|
||||
RevokedEndEntityTrustDomain localTrustDomain;
|
||||
localTrustDomain.SetUpCerts();
|
||||
ByteString certDER(CreateCert("Intermediate", "RevokedEndEntity",
|
||||
EndEntityOrCA::MustBeEndEntity));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE,
|
||||
BuildCertChain(localTrustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
// This represents a collection of different certificates that all have the same
|
||||
// subject and issuer distinguished name.
|
||||
class SelfIssuedCertificatesTrustDomain final : public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
void SetUpCerts(size_t totalCerts)
|
||||
{
|
||||
ASSERT_TRUE(totalCerts > 0);
|
||||
// First we generate a trust anchor.
|
||||
ScopedTestKeyPair rootKeyPair(GenerateKeyPair());
|
||||
rootCACertDER = CreateCert("DN", "DN", EndEntityOrCA::MustBeCA, nullptr,
|
||||
nullptr, rootKeyPair.get(), rootKeyPair.get());
|
||||
ASSERT_FALSE(ENCODING_FAILED(rootCACertDER));
|
||||
certs.push_back(rootCACertDER);
|
||||
ScopedTestKeyPair issuerKeyPair(rootKeyPair.release());
|
||||
size_t subCAsGenerated;
|
||||
// Then we generate 6 sub-CAs (given that we were requested to generate at
|
||||
// least that many).
|
||||
for (subCAsGenerated = 0;
|
||||
subCAsGenerated < totalCerts - 1 && subCAsGenerated < 6;
|
||||
subCAsGenerated++) {
|
||||
// Each certificate has to have a unique SPKI (mozilla::pkix does loop
|
||||
// detection and stops searching if it encounters two certificates in a
|
||||
// path with the same subject and SPKI).
|
||||
ScopedTestKeyPair keyPair(GenerateKeyPair());
|
||||
ByteString cert(CreateCert("DN", "DN", EndEntityOrCA::MustBeCA, nullptr,
|
||||
nullptr, issuerKeyPair.get(), keyPair.get()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(cert));
|
||||
certs.push_back(cert);
|
||||
issuerKeyPair.reset(keyPair.release());
|
||||
}
|
||||
// We set firstIssuerKey here because we can't end up with a path that has
|
||||
// more than 7 CAs in it (because mozilla::pkix limits the path length).
|
||||
firstIssuerKey.reset(issuerKeyPair.release());
|
||||
// For any more sub CAs we generate, it doesn't matter what their keys are
|
||||
// as long as they're different.
|
||||
for (; subCAsGenerated < totalCerts - 1; subCAsGenerated++) {
|
||||
ScopedTestKeyPair keyPair(GenerateKeyPair());
|
||||
ByteString cert(CreateCert("DN", "DN", EndEntityOrCA::MustBeCA, nullptr,
|
||||
nullptr, keyPair.get(), keyPair.get()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(cert));
|
||||
certs.insert(certs.begin(), cert);
|
||||
}
|
||||
}
|
||||
|
||||
const TestKeyPair* GetFirstIssuerKey()
|
||||
{
|
||||
return firstIssuerKey.get();
|
||||
}
|
||||
|
||||
private:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = InputEqualsByteString(candidateCert, rootCACertDER)
|
||||
? TrustLevel::TrustAnchor
|
||||
: TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input, IssuerChecker& checker, Time) override
|
||||
{
|
||||
bool keepGoing;
|
||||
for (auto& cert: certs) {
|
||||
Input certInput;
|
||||
Result rv = certInput.Init(cert.data(), cert.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
rv = checker.Check(certInput, nullptr, keepGoing);
|
||||
if (rv != Success || !keepGoing) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
std::vector<ByteString> certs;
|
||||
ByteString rootCACertDER;
|
||||
ScopedTestKeyPair firstIssuerKey;
|
||||
};
|
||||
|
||||
TEST_F(pkixbuild, AvoidUnboundedPathSearchingFailure)
|
||||
{
|
||||
SelfIssuedCertificatesTrustDomain localTrustDomain;
|
||||
// This creates a few hundred million potential paths of length 8 (end entity
|
||||
// + 6 sub-CAs + root). It would be prohibitively expensive to enumerate all
|
||||
// of these, so we give mozilla::pkix a budget that is spent when searching
|
||||
// paths. If the budget is exhausted, it simply returns an unknown issuer
|
||||
// error. In the future it might be nice to return a specific error that would
|
||||
// give the front-end a hint that maybe it shouldn't have so many certificates
|
||||
// that all have the same subject and issuer DN but different SPKIs.
|
||||
localTrustDomain.SetUpCerts(18);
|
||||
ByteString certDER(CreateCert("DN", "DN", EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr, nullptr,
|
||||
localTrustDomain.GetFirstIssuerKey()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(localTrustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
TEST_F(pkixbuild, AvoidUnboundedPathSearchingSuccess)
|
||||
{
|
||||
SelfIssuedCertificatesTrustDomain localTrustDomain;
|
||||
// This creates a few hundred thousand possible potential paths of length 8
|
||||
// (end entity + 6 sub-CAs + root). This will nearly exhaust mozilla::pkix's
|
||||
// search budget, so this should succeed.
|
||||
localTrustDomain.SetUpCerts(10);
|
||||
ByteString certDER(CreateCert("DN", "DN", EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr, nullptr,
|
||||
localTrustDomain.GetFirstIssuerKey()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(certDER));
|
||||
Input certDERInput;
|
||||
ASSERT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(localTrustDomain, certDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
276
security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp
Normal file
276
security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
#include "mozpkix/test/pkixtestutil.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
// Creates a self-signed certificate with the given extension.
|
||||
static ByteString
|
||||
CreateCertWithExtensions(const char* subjectCN,
|
||||
const ByteString* extensions)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
|
||||
EXPECT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
ByteString issuerDER(CNToDERName(subjectCN));
|
||||
EXPECT_FALSE(ENCODING_FAILED(issuerDER));
|
||||
ByteString subjectDER(CNToDERName(subjectCN));
|
||||
EXPECT_FALSE(ENCODING_FAILED(subjectDER));
|
||||
ScopedTestKeyPair subjectKey(CloneReusedKeyPair());
|
||||
return CreateEncodedCertificate(v3, sha256WithRSAEncryption(),
|
||||
serialNumber, issuerDER,
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
subjectDER, *subjectKey, extensions,
|
||||
*subjectKey,
|
||||
sha256WithRSAEncryption());
|
||||
}
|
||||
|
||||
// Creates a self-signed certificate with the given extension.
|
||||
static ByteString
|
||||
CreateCertWithOneExtension(const char* subjectStr, const ByteString& extension)
|
||||
{
|
||||
const ByteString extensions[] = { extension, ByteString() };
|
||||
return CreateCertWithExtensions(subjectStr, extensions);
|
||||
}
|
||||
|
||||
class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain
|
||||
{
|
||||
private:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
|
||||
static const uint8_t tlv_unknownExtensionOID[] = {
|
||||
0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a,
|
||||
0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-pe-authorityInformationAccess 1.3.6.1.5.5.7.1.1
|
||||
static const uint8_t tlv_id_pe_authorityInformationAccess[] = {
|
||||
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv wrongExtensionOID 1.3.6.6.1.5.5.7.1.1
|
||||
// (there is an extra "6" that shouldn't be in this OID)
|
||||
static const uint8_t tlv_wrongExtensionOID[] = {
|
||||
0x06, 0x09, 0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-ce-unknown 2.5.29.55
|
||||
// (this is a made-up OID for testing "id-ce"-prefixed OIDs that mozilla::pkix
|
||||
// doesn't handle)
|
||||
static const uint8_t tlv_id_ce_unknown[] = {
|
||||
0x06, 0x03, 0x55, 0x1d, 0x37
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-ce-inhibitAnyPolicy 2.5.29.54
|
||||
static const uint8_t tlv_id_ce_inhibitAnyPolicy[] = {
|
||||
0x06, 0x03, 0x55, 0x1d, 0x36
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
|
||||
static const uint8_t tlv_id_pkix_ocsp_nocheck[] = {
|
||||
0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
|
||||
};
|
||||
|
||||
struct ExtensionTestcase
|
||||
{
|
||||
ByteString extension;
|
||||
Result expectedResult;
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os, const ExtensionTestcase&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
static const ExtensionTestcase EXTENSION_TESTCASES[] =
|
||||
{
|
||||
// Tests that a non-critical extension not in the id-ce or id-pe arcs (which
|
||||
// is thus unknown to us) verifies successfully even if empty (extensions we
|
||||
// know about aren't normally allowed to be empty).
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_unknownExtensionOID) +
|
||||
TLV(der::OCTET_STRING, ByteString())),
|
||||
Success
|
||||
},
|
||||
|
||||
// Tests that a critical extension not in the id-ce or id-pe arcs (which is
|
||||
// thus unknown to us) is detected and that verification fails with the
|
||||
// appropriate error.
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_unknownExtensionOID) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, ByteString())),
|
||||
Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
|
||||
},
|
||||
|
||||
// Tests that a id-pe-authorityInformationAccess critical extension
|
||||
// is detected and that verification succeeds.
|
||||
// XXX: According to RFC 5280 an AIA that consists of an empty sequence is
|
||||
// not legal, but we accept it and that is not what we're testing here.
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_pe_authorityInformationAccess) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ByteString()))),
|
||||
Success
|
||||
},
|
||||
|
||||
// Tests that an incorrect OID for id-pe-authorityInformationAccess
|
||||
// (when marked critical) is detected and that verification fails.
|
||||
// (Until bug 1020993 was fixed, this wrong value was used for
|
||||
// id-pe-authorityInformationAccess.)
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_wrongExtensionOID) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, ByteString())),
|
||||
Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
|
||||
},
|
||||
|
||||
// We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
|
||||
// Tests that an unknown id-ce extension is detected and that verification
|
||||
// fails.
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_ce_unknown) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, ByteString())),
|
||||
Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
|
||||
},
|
||||
|
||||
// Tests that a certificate with a known critical id-ce extension (in this
|
||||
// case, OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies
|
||||
// successfully.
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_ce_inhibitAnyPolicy) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, Integer(0))),
|
||||
Success
|
||||
},
|
||||
|
||||
// Tests that a certificate with the id-pkix-ocsp-nocheck extension (marked
|
||||
// critical) verifies successfully.
|
||||
// RFC 6960:
|
||||
// ext-ocsp-nocheck EXTENSION ::= { SYNTAX NULL IDENTIFIED
|
||||
// BY id-pkix-ocsp-nocheck }
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, TLV(der::NULLTag, ByteString()))),
|
||||
Success
|
||||
},
|
||||
|
||||
// Tests that a certificate with another representation of the
|
||||
// id-pkix-ocsp-nocheck extension (marked critical) verifies successfully.
|
||||
// According to http://comments.gmane.org/gmane.ietf.x509/30947,
|
||||
// some code creates certificates where value of the extension is
|
||||
// an empty OCTET STRING.
|
||||
{ TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
|
||||
Boolean(true) +
|
||||
TLV(der::OCTET_STRING, ByteString())),
|
||||
Success
|
||||
},
|
||||
};
|
||||
|
||||
class pkixcert_extension
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<ExtensionTestcase>
|
||||
{
|
||||
protected:
|
||||
static TrustEverythingTrustDomain trustDomain;
|
||||
};
|
||||
|
||||
/*static*/ TrustEverythingTrustDomain pkixcert_extension::trustDomain;
|
||||
|
||||
TEST_P(pkixcert_extension, ExtensionHandledProperly)
|
||||
{
|
||||
const ExtensionTestcase& testcase(GetParam());
|
||||
const char* cn = "Cert Extension Test";
|
||||
ByteString cert(CreateCertWithOneExtension(cn, testcase.extension));
|
||||
ASSERT_FALSE(ENCODING_FAILED(cert));
|
||||
Input certInput;
|
||||
ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
|
||||
ASSERT_EQ(testcase.expectedResult,
|
||||
BuildCertChain(trustDomain, certInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixcert_extension,
|
||||
pkixcert_extension,
|
||||
testing::ValuesIn(EXTENSION_TESTCASES));
|
||||
|
||||
// Two subjectAltNames must result in an error.
|
||||
TEST_F(pkixcert_extension, DuplicateSubjectAltName)
|
||||
{
|
||||
// python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
|
||||
static const uint8_t tlv_id_ce_subjectAltName[] = {
|
||||
0x06, 0x03, 0x55, 0x1d, 0x11
|
||||
};
|
||||
|
||||
ByteString subjectAltName(
|
||||
TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_ce_subjectAltName) +
|
||||
TLV(der::OCTET_STRING, TLV(der::SEQUENCE, DNSName("example.com")))));
|
||||
static const ByteString extensions[] = { subjectAltName, subjectAltName,
|
||||
ByteString() };
|
||||
static const char* certCN = "Cert With Duplicate subjectAltName";
|
||||
ByteString cert(CreateCertWithExtensions(certCN, extensions));
|
||||
ASSERT_FALSE(ENCODING_FAILED(cert));
|
||||
Input certInput;
|
||||
ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
|
||||
ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
|
||||
BuildCertChain(trustDomain, certInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
static ByteString
|
||||
CreateCert(const char* issuerCN,
|
||||
const char* subjectCN,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
const TestSignatureAlgorithm& signatureAlgorithm,
|
||||
/*out*/ ByteString& subjectDER)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
|
||||
EXPECT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
|
||||
ByteString issuerDER(CNToDERName(issuerCN));
|
||||
EXPECT_FALSE(ENCODING_FAILED(issuerDER));
|
||||
subjectDER = CNToDERName(subjectCN);
|
||||
EXPECT_FALSE(ENCODING_FAILED(subjectDER));
|
||||
|
||||
ByteString extensions[2];
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
|
||||
extensions[0] =
|
||||
CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
|
||||
EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
|
||||
}
|
||||
|
||||
ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
|
||||
ByteString certDER(CreateEncodedCertificate(v3, signatureAlgorithm,
|
||||
serialNumber, issuerDER,
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
subjectDER, *reusedKey,
|
||||
extensions, *reusedKey,
|
||||
signatureAlgorithm));
|
||||
EXPECT_FALSE(ENCODING_FAILED(certDER));
|
||||
return certDER;
|
||||
}
|
||||
|
||||
class AlgorithmTestsTrustDomain final : public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
AlgorithmTestsTrustDomain(const ByteString& aRootDER,
|
||||
const ByteString& aRootSubjectDER,
|
||||
/*optional*/ const ByteString& aIntDER,
|
||||
/*optional*/ const ByteString& aIntSubjectDER)
|
||||
: rootDER(aRootDER)
|
||||
, rootSubjectDER(aRootSubjectDER)
|
||||
, intDER(aIntDER)
|
||||
, intSubjectDER(aIntSubjectDER)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
if (InputEqualsByteString(candidateCert, rootDER)) {
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
} else {
|
||||
trustLevel = TrustLevel::InheritsTrust;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
|
||||
override
|
||||
{
|
||||
ByteString* issuerDER = nullptr;
|
||||
if (InputEqualsByteString(encodedIssuerName, rootSubjectDER)) {
|
||||
issuerDER = &rootDER;
|
||||
} else if (InputEqualsByteString(encodedIssuerName, intSubjectDER)) {
|
||||
issuerDER = &intDER;
|
||||
} else {
|
||||
// FindIssuer just returns success if it can't find a potential issuer.
|
||||
return Success;
|
||||
}
|
||||
Input issuerCert;
|
||||
Result rv = issuerCert.Init(issuerDER->data(), issuerDER->length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
bool keepGoing;
|
||||
return checker.Check(issuerCert, nullptr, keepGoing);
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
const Input*, const Input*) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
ByteString rootDER;
|
||||
ByteString rootSubjectDER;
|
||||
ByteString intDER;
|
||||
ByteString intSubjectDER;
|
||||
};
|
||||
|
||||
static const TestSignatureAlgorithm NO_INTERMEDIATE
|
||||
{
|
||||
TestPublicKeyAlgorithm(ByteString()),
|
||||
TestDigestAlgorithmID::MD2,
|
||||
ByteString(),
|
||||
false
|
||||
};
|
||||
|
||||
struct ChainValidity final
|
||||
{
|
||||
ChainValidity(const TestSignatureAlgorithm& aEndEntitySignatureAlgorithm,
|
||||
const TestSignatureAlgorithm& aOptionalIntSignatureAlgorithm,
|
||||
const TestSignatureAlgorithm& aRootSignatureAlgorithm,
|
||||
bool aIsValid)
|
||||
: endEntitySignatureAlgorithm(aEndEntitySignatureAlgorithm)
|
||||
, optionalIntermediateSignatureAlgorithm(aOptionalIntSignatureAlgorithm)
|
||||
, rootSignatureAlgorithm(aRootSignatureAlgorithm)
|
||||
, isValid(aIsValid)
|
||||
{ }
|
||||
|
||||
// In general, a certificate is generated for each of these. However, if
|
||||
// optionalIntermediateSignatureAlgorithm is NO_INTERMEDIATE, then only 2
|
||||
// certificates are generated.
|
||||
// The certificate generated for the given rootSignatureAlgorithm is the
|
||||
// trust anchor.
|
||||
TestSignatureAlgorithm endEntitySignatureAlgorithm;
|
||||
TestSignatureAlgorithm optionalIntermediateSignatureAlgorithm;
|
||||
TestSignatureAlgorithm rootSignatureAlgorithm;
|
||||
bool isValid;
|
||||
};
|
||||
|
||||
static const ChainValidity CHAIN_VALIDITY[] =
|
||||
{
|
||||
// The trust anchor may have a signature with an unsupported signature
|
||||
// algorithm.
|
||||
ChainValidity(sha256WithRSAEncryption(),
|
||||
NO_INTERMEDIATE,
|
||||
md5WithRSAEncryption(),
|
||||
true),
|
||||
ChainValidity(sha256WithRSAEncryption(),
|
||||
NO_INTERMEDIATE,
|
||||
md2WithRSAEncryption(),
|
||||
true),
|
||||
|
||||
// Certificates that are not trust anchors must not have a signature with an
|
||||
// unsupported signature algorithm.
|
||||
ChainValidity(md5WithRSAEncryption(),
|
||||
NO_INTERMEDIATE,
|
||||
sha256WithRSAEncryption(),
|
||||
false),
|
||||
ChainValidity(md2WithRSAEncryption(),
|
||||
NO_INTERMEDIATE,
|
||||
sha256WithRSAEncryption(),
|
||||
false),
|
||||
ChainValidity(md2WithRSAEncryption(),
|
||||
NO_INTERMEDIATE,
|
||||
md5WithRSAEncryption(),
|
||||
false),
|
||||
ChainValidity(sha256WithRSAEncryption(),
|
||||
md5WithRSAEncryption(),
|
||||
sha256WithRSAEncryption(),
|
||||
false),
|
||||
ChainValidity(sha256WithRSAEncryption(),
|
||||
md2WithRSAEncryption(),
|
||||
sha256WithRSAEncryption(),
|
||||
false),
|
||||
ChainValidity(sha256WithRSAEncryption(),
|
||||
md2WithRSAEncryption(),
|
||||
md5WithRSAEncryption(),
|
||||
false),
|
||||
};
|
||||
|
||||
class pkixcert_IsValidChainForAlgorithm
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<ChainValidity>
|
||||
{
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os,
|
||||
const pkixcert_IsValidChainForAlgorithm&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os, const ChainValidity&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
TEST_P(pkixcert_IsValidChainForAlgorithm, IsValidChainForAlgorithm)
|
||||
{
|
||||
const ChainValidity& chainValidity(GetParam());
|
||||
const char* rootCN = "CN=Root";
|
||||
ByteString rootSubjectDER;
|
||||
ByteString rootEncoded(
|
||||
CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
|
||||
chainValidity.rootSignatureAlgorithm, rootSubjectDER));
|
||||
EXPECT_FALSE(ENCODING_FAILED(rootEncoded));
|
||||
EXPECT_FALSE(ENCODING_FAILED(rootSubjectDER));
|
||||
|
||||
const char* issuerCN = rootCN;
|
||||
|
||||
const char* intermediateCN = "CN=Intermediate";
|
||||
ByteString intermediateSubjectDER;
|
||||
ByteString intermediateEncoded;
|
||||
|
||||
// If the the algorithmIdentifier is empty, then it's NO_INTERMEDIATE.
|
||||
if (!chainValidity.optionalIntermediateSignatureAlgorithm
|
||||
.algorithmIdentifier.empty()) {
|
||||
intermediateEncoded =
|
||||
CreateCert(rootCN, intermediateCN, EndEntityOrCA::MustBeCA,
|
||||
chainValidity.optionalIntermediateSignatureAlgorithm,
|
||||
intermediateSubjectDER);
|
||||
EXPECT_FALSE(ENCODING_FAILED(intermediateEncoded));
|
||||
EXPECT_FALSE(ENCODING_FAILED(intermediateSubjectDER));
|
||||
issuerCN = intermediateCN;
|
||||
}
|
||||
|
||||
AlgorithmTestsTrustDomain trustDomain(rootEncoded, rootSubjectDER,
|
||||
intermediateEncoded,
|
||||
intermediateSubjectDER);
|
||||
|
||||
const char* endEntityCN = "CN=End Entity";
|
||||
ByteString endEntitySubjectDER;
|
||||
ByteString endEntityEncoded(
|
||||
CreateCert(issuerCN, endEntityCN, EndEntityOrCA::MustBeEndEntity,
|
||||
chainValidity.endEntitySignatureAlgorithm,
|
||||
endEntitySubjectDER));
|
||||
EXPECT_FALSE(ENCODING_FAILED(endEntityEncoded));
|
||||
EXPECT_FALSE(ENCODING_FAILED(endEntitySubjectDER));
|
||||
|
||||
Input endEntity;
|
||||
ASSERT_EQ(Success, endEntity.Init(endEntityEncoded.data(),
|
||||
endEntityEncoded.length()));
|
||||
Result expectedResult = chainValidity.isValid
|
||||
? Success
|
||||
: Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
ASSERT_EQ(expectedResult,
|
||||
BuildCertChain(trustDomain, endEntity, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy, nullptr));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixcert_IsValidChainForAlgorithm,
|
||||
pkixcert_IsValidChainForAlgorithm,
|
||||
testing::ValuesIn(CHAIN_VALIDITY));
|
||||
|
|
@ -0,0 +1,722 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2016 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 "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
#include "mozpkix/pkixutil.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
extern Result CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
const Input* encodedExtendedKeyUsage,
|
||||
KeyPurposeId requiredEKU,
|
||||
TrustDomain& trustDomain, Time notBefore);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
class pkixcheck_CheckExtendedKeyUsage : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
DefaultCryptoTrustDomain mTrustDomain;
|
||||
};
|
||||
|
||||
#define ASSERT_BAD(x) ASSERT_EQ(Result::ERROR_INADEQUATE_CERT_TYPE, x)
|
||||
|
||||
// tlv_id_kp_OCSPSigning and tlv_id_kp_serverAuth are defined in pkixtestutil.h
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-kp-clientAuth 1.3.6.1.5.5.7.3.2
|
||||
static const uint8_t tlv_id_kp_clientAuth[] = {
|
||||
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-kp-codeSigning 1.3.6.1.5.5.7.3.3
|
||||
static const uint8_t tlv_id_kp_codeSigning[] = {
|
||||
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id_kp_emailProtection 1.3.6.1.5.5.7.3.4
|
||||
static const uint8_t tlv_id_kp_emailProtection[] = {
|
||||
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-Netscape-stepUp 2.16.840.1.113730.4.1
|
||||
static const uint8_t tlv_id_Netscape_stepUp[] = {
|
||||
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv unknownOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
|
||||
static const uint8_t tlv_unknownOID[] = {
|
||||
0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a,
|
||||
0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv anyExtendedKeyUsage 2.5.29.37.0
|
||||
static const uint8_t tlv_anyExtendedKeyUsage[] = {
|
||||
0x06, 0x04, 0x55, 0x1d, 0x25, 0x00
|
||||
};
|
||||
|
||||
TEST_F(pkixcheck_CheckExtendedKeyUsage, none)
|
||||
{
|
||||
// The input Input is nullptr. This means the cert had no extended key usage
|
||||
// extension. This is always valid except for when the certificate is an
|
||||
// end-entity and the required usage is id-kp-OCSPSigning.
|
||||
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr,
|
||||
KeyPurposeId::id_kp_clientAuth,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyPurposeId::id_kp_clientAuth,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
nullptr,
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_BAD(CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyPurposeId::id_kp_OCSPSigning,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(Success, CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyPurposeId::id_kp_OCSPSigning,
|
||||
mTrustDomain, Now()));
|
||||
}
|
||||
|
||||
static const Input empty_null;
|
||||
|
||||
TEST_F(pkixcheck_CheckExtendedKeyUsage, empty)
|
||||
{
|
||||
// The input Input is empty. The cert has an empty extended key usage
|
||||
// extension, which is syntactically invalid.
|
||||
ASSERT_BAD(CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_null,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_BAD(CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, &empty_null,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
mTrustDomain, Now()));
|
||||
|
||||
static const uint8_t dummy = 0x00;
|
||||
Input empty_nonnull;
|
||||
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
||||
ASSERT_BAD(CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_nonnull,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_BAD(CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, &empty_nonnull,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
mTrustDomain, Now()));
|
||||
}
|
||||
|
||||
struct EKUTestcase
|
||||
{
|
||||
ByteString ekuSEQUENCE;
|
||||
KeyPurposeId keyPurposeId;
|
||||
Result expectedResultEndEntity;
|
||||
Result expectedResultCA;
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os, const EKUTestcase&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
class CheckExtendedKeyUsageTest
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<EKUTestcase>
|
||||
{
|
||||
protected:
|
||||
DefaultCryptoTrustDomain mTrustDomain;
|
||||
};
|
||||
|
||||
TEST_P(CheckExtendedKeyUsageTest, EKUTestcase)
|
||||
{
|
||||
const EKUTestcase& param(GetParam());
|
||||
Input encodedEKU;
|
||||
ASSERT_EQ(Success, encodedEKU.Init(param.ekuSEQUENCE.data(),
|
||||
param.ekuSEQUENCE.length()));
|
||||
ASSERT_EQ(param.expectedResultEndEntity,
|
||||
CheckExtendedKeyUsage(EndEntityOrCA::MustBeEndEntity, &encodedEKU,
|
||||
param.keyPurposeId,
|
||||
mTrustDomain, Now()));
|
||||
ASSERT_EQ(param.expectedResultCA,
|
||||
CheckExtendedKeyUsage(EndEntityOrCA::MustBeCA, &encodedEKU,
|
||||
param.keyPurposeId,
|
||||
mTrustDomain, Now()));
|
||||
}
|
||||
|
||||
#define SINGLE_EKU_SUCCESS(oidBytes, keyPurposeId) \
|
||||
{ TLV(der::SEQUENCE, BytesToByteString(oidBytes)), keyPurposeId, \
|
||||
Success, Success }
|
||||
#define SINGLE_EKU_SUCCESS_CA(oidBytes, keyPurposeId) \
|
||||
{ TLV(der::SEQUENCE, BytesToByteString(oidBytes)), keyPurposeId, \
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE, Success }
|
||||
#define SINGLE_EKU_FAILURE(oidBytes, keyPurposeId) \
|
||||
{ TLV(der::SEQUENCE, BytesToByteString(oidBytes)), keyPurposeId, \
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE, Result::ERROR_INADEQUATE_CERT_TYPE }
|
||||
#define DOUBLE_EKU_SUCCESS(oidBytes1, oidBytes2, keyPurposeId) \
|
||||
{ TLV(der::SEQUENCE, \
|
||||
BytesToByteString(oidBytes1) + BytesToByteString(oidBytes2)), \
|
||||
keyPurposeId, \
|
||||
Success, Success }
|
||||
#define DOUBLE_EKU_SUCCESS_CA(oidBytes1, oidBytes2, keyPurposeId) \
|
||||
{ TLV(der::SEQUENCE, \
|
||||
BytesToByteString(oidBytes1) + BytesToByteString(oidBytes2)), \
|
||||
keyPurposeId, \
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE, Success }
|
||||
#define DOUBLE_EKU_FAILURE(oidBytes1, oidBytes2, keyPurposeId) \
|
||||
{ TLV(der::SEQUENCE, \
|
||||
BytesToByteString(oidBytes1) + BytesToByteString(oidBytes2)), \
|
||||
keyPurposeId, \
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE, Result::ERROR_INADEQUATE_CERT_TYPE }
|
||||
|
||||
static const EKUTestcase EKU_TESTCASES[] =
|
||||
{
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_serverAuth, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_serverAuth, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_serverAuth, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_serverAuth, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_serverAuth, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_serverAuth, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_clientAuth, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_clientAuth, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_clientAuth, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_clientAuth, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_clientAuth, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_clientAuth, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_codeSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_codeSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_codeSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_codeSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_codeSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_codeSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_emailProtection, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_emailProtection, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_emailProtection, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_emailProtection, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_emailProtection, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_emailProtection, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
// For end-entities, if id-kp-OCSPSigning is present, no usage is allowed
|
||||
// except OCSPSigning.
|
||||
SINGLE_EKU_SUCCESS_CA(tlv_id_kp_OCSPSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_SUCCESS(tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
SINGLE_EKU_SUCCESS(tlv_id_Netscape_stepUp, KeyPurposeId::anyExtendedKeyUsage),
|
||||
// For compatibility, id-Netscape-stepUp is treated as equivalent to
|
||||
// id-kp-serverAuth for CAs.
|
||||
SINGLE_EKU_SUCCESS_CA(tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
SINGLE_EKU_SUCCESS(tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_FAILURE(tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
SINGLE_EKU_SUCCESS(tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
SINGLE_EKU_FAILURE(tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
SINGLE_EKU_FAILURE(tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
SINGLE_EKU_FAILURE(tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
SINGLE_EKU_FAILURE(tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_clientAuth, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_clientAuth, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_clientAuth, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_clientAuth, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_clientAuth, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_clientAuth, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_codeSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_emailProtection, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_serverAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_serverAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_Netscape_stepUp, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_serverAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_serverAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_codeSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_codeSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_emailProtection, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_clientAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_clientAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_Netscape_stepUp, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_clientAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_clientAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_clientAuth, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_id_kp_emailProtection, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_kp_emailProtection, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_codeSigning, tlv_id_kp_OCSPSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_codeSigning, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_id_Netscape_stepUp, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_codeSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_codeSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_codeSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_emailProtection, tlv_id_kp_OCSPSigning, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_emailProtection, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_id_kp_OCSPSigning, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_id_Netscape_stepUp, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_emailProtection, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_emailProtection, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_emailProtection, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_OCSPSigning, tlv_id_Netscape_stepUp, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_OCSPSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_OCSPSigning, tlv_id_Netscape_stepUp, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_OCSPSigning, tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_OCSPSigning, tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_kp_OCSPSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_kp_OCSPSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_kp_OCSPSigning, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_Netscape_stepUp, tlv_unknownOID, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_Netscape_stepUp, tlv_unknownOID, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_unknownOID, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_unknownOID, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_unknownOID, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_unknownOID, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_id_Netscape_stepUp, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_SUCCESS_CA(tlv_id_Netscape_stepUp, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_id_Netscape_stepUp, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
|
||||
DOUBLE_EKU_SUCCESS(tlv_unknownOID, tlv_anyExtendedKeyUsage, KeyPurposeId::anyExtendedKeyUsage),
|
||||
DOUBLE_EKU_FAILURE(tlv_unknownOID, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_serverAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_unknownOID, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_clientAuth),
|
||||
DOUBLE_EKU_FAILURE(tlv_unknownOID, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_codeSigning),
|
||||
DOUBLE_EKU_FAILURE(tlv_unknownOID, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_emailProtection),
|
||||
DOUBLE_EKU_FAILURE(tlv_unknownOID, tlv_anyExtendedKeyUsage, KeyPurposeId::id_kp_OCSPSigning),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixcheck_CheckExtendedKeyUsage,
|
||||
CheckExtendedKeyUsageTest,
|
||||
::testing::ValuesIn(EKU_TESTCASES));
|
||||
|
||||
struct EKUChainTestcase
|
||||
{
|
||||
ByteString ekuExtensionEE;
|
||||
ByteString ekuExtensionCA;
|
||||
KeyPurposeId keyPurposeId;
|
||||
Result expectedResult;
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os, const EKUChainTestcase&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
class CheckExtendedKeyUsageChainTest
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<EKUChainTestcase>
|
||||
{
|
||||
};
|
||||
|
||||
static ByteString
|
||||
CreateCert(const char* issuerCN, const char* subjectCN,
|
||||
EndEntityOrCA endEntityOrCA, ByteString encodedEKU)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
|
||||
EXPECT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
|
||||
ByteString issuerDER(CNToDERName(issuerCN));
|
||||
ByteString subjectDER(CNToDERName(subjectCN));
|
||||
|
||||
ByteString extensions[3];
|
||||
extensions[0] =
|
||||
CreateEncodedBasicConstraints(endEntityOrCA == EndEntityOrCA::MustBeCA,
|
||||
nullptr, Critical::Yes);
|
||||
EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
|
||||
if (encodedEKU.length() > 0) {
|
||||
extensions[1] = encodedEKU;
|
||||
}
|
||||
|
||||
ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
|
||||
ByteString certDER(CreateEncodedCertificate(
|
||||
v3, sha256WithRSAEncryption(), serialNumber, issuerDER,
|
||||
oneDayBeforeNow, oneDayAfterNow, subjectDER,
|
||||
*reusedKey, extensions, *reusedKey,
|
||||
sha256WithRSAEncryption()));
|
||||
EXPECT_FALSE(ENCODING_FAILED(certDER));
|
||||
|
||||
return certDER;
|
||||
}
|
||||
|
||||
class EKUTrustDomain final : public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
explicit EKUTrustDomain(ByteString issuerCertDER)
|
||||
: mIssuerCertDER(issuerCertDER)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
|
||||
TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = InputEqualsByteString(candidateCert, mIssuerCertDER)
|
||||
? TrustLevel::TrustAnchor
|
||||
: TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input, IssuerChecker& checker, Time) override
|
||||
{
|
||||
Input derCert;
|
||||
Result rv = derCert.Init(mIssuerCertDER.data(), mIssuerCertDER.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
bool keepGoing;
|
||||
return checker.Check(derCert, nullptr, keepGoing);
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
const Input*, const Input*) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
ByteString mIssuerCertDER;
|
||||
};
|
||||
|
||||
TEST_P(CheckExtendedKeyUsageChainTest, EKUChainTestcase)
|
||||
{
|
||||
const EKUChainTestcase& param(GetParam());
|
||||
ByteString issuerCertDER(CreateCert("CA", "CA", EndEntityOrCA::MustBeCA,
|
||||
param.ekuExtensionCA));
|
||||
ByteString subjectCertDER(CreateCert("CA", "EE",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
param.ekuExtensionEE));
|
||||
|
||||
EKUTrustDomain trustDomain(issuerCertDER);
|
||||
|
||||
Input subjectCertDERInput;
|
||||
ASSERT_EQ(Success, subjectCertDERInput.Init(subjectCertDER.data(),
|
||||
subjectCertDER.length()));
|
||||
ASSERT_EQ(param.expectedResult,
|
||||
BuildCertChain(trustDomain, subjectCertDERInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
param.keyPurposeId,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
// python DottedOIDToCode.py --tlv id-ce-extKeyUsage 2.5.29.37
|
||||
static const uint8_t tlv_id_ce_extKeyUsage[] = {
|
||||
0x06, 0x03, 0x55, 0x1d, 0x25
|
||||
};
|
||||
|
||||
static inline ByteString
|
||||
CreateEKUExtension(ByteString ekuOIDs)
|
||||
{
|
||||
return TLV(der::SEQUENCE,
|
||||
BytesToByteString(tlv_id_ce_extKeyUsage) +
|
||||
TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ekuOIDs)));
|
||||
}
|
||||
|
||||
static const EKUChainTestcase EKU_CHAIN_TESTCASES[] =
|
||||
{
|
||||
{
|
||||
// Both end-entity and CA have id-kp-serverAuth => should succeed
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
{
|
||||
// CA has no EKU extension => should succeed
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
ByteString(),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
{
|
||||
// End-entity has no EKU extension => should succeed
|
||||
ByteString(),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
{
|
||||
// No EKU extensions at all => should succeed
|
||||
ByteString(),
|
||||
ByteString(),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
{
|
||||
// CA has EKU without id-kp-serverAuth => should fail
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// End-entity has EKU without id-kp-serverAuth => should fail
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// Both end-entity and CA have EKU without id-kp-serverAuth => should fail
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// End-entity has no EKU, CA doesn't have id-kp-serverAuth => should fail
|
||||
ByteString(),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// End-entity doesn't have id-kp-serverAuth, CA has no EKU => should fail
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
ByteString(),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// CA has id-Netscape-stepUp => should succeed
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_Netscape_stepUp)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
{
|
||||
// End-entity has id-Netscape-stepUp => should fail
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_Netscape_stepUp)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// End-entity and CA have id-kp-serverAuth and id-kp-clientAuth => should
|
||||
// succeed
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth) +
|
||||
BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth) +
|
||||
BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
{
|
||||
// End-entity has id-kp-serverAuth and id-kp-OCSPSigning => should fail
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth) +
|
||||
BytesToByteString(tlv_id_kp_OCSPSigning)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth) +
|
||||
BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Result::ERROR_INADEQUATE_CERT_TYPE
|
||||
},
|
||||
{
|
||||
// CA has id-kp-serverAuth and id-kp-OCSPSigning => should succeed
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth) +
|
||||
BytesToByteString(tlv_id_kp_clientAuth)),
|
||||
CreateEKUExtension(BytesToByteString(tlv_id_kp_serverAuth) +
|
||||
BytesToByteString(tlv_id_kp_OCSPSigning)),
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
Success
|
||||
},
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixcheck_CheckExtendedKeyUsage,
|
||||
CheckExtendedKeyUsageChainTest,
|
||||
::testing::ValuesIn(EKU_CHAIN_TESTCASES));
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2016 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 "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixcheck.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
class pkixcheck_CheckIssuer : public ::testing::Test { };
|
||||
|
||||
static const uint8_t EMPTY_NAME_DATA[] = {
|
||||
0x30, 0x00 /* tag, length */
|
||||
};
|
||||
static const Input EMPTY_NAME(EMPTY_NAME_DATA);
|
||||
|
||||
static const uint8_t VALID_NAME_DATA[] = {
|
||||
/* From https://www.example.com/: C=US, O=DigiCert Inc, OU=www.digicert.com,
|
||||
* CN=DigiCert SHA2 High Assurance Server CA */
|
||||
0x30, 0x70, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
||||
0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A,
|
||||
0x13, 0x0C, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
|
||||
0x6E, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13,
|
||||
0x10, 0x77, 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
|
||||
0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x2F, 0x30, 0x2D, 0x06, 0x03, 0x55,
|
||||
0x04, 0x03, 0x13, 0x26, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
|
||||
0x20, 0x53, 0x48, 0x41, 0x32, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41,
|
||||
0x73, 0x73, 0x75, 0x72, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x53, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x20, 0x43, 0x41
|
||||
};
|
||||
static const Input VALID_NAME(VALID_NAME_DATA);
|
||||
|
||||
TEST_F(pkixcheck_CheckIssuer, ValidIssuer)
|
||||
{
|
||||
ASSERT_EQ(Success, CheckIssuer(VALID_NAME));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckIssuer, EmptyIssuer)
|
||||
{
|
||||
ASSERT_EQ(Result::ERROR_EMPTY_ISSUER_NAME, CheckIssuer(EMPTY_NAME));
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
extern Result CheckKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
const Input* encodedKeyUsage,
|
||||
KeyUsage requiredKeyUsageIfPresent);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
class pkixcheck_CheckKeyUsage : public ::testing::Test { };
|
||||
|
||||
#define ASSERT_BAD(x) ASSERT_EQ(Result::ERROR_INADEQUATE_KEY_USAGE, x)
|
||||
|
||||
// Make it easy to define test data for the common, simplest cases.
|
||||
#define NAMED_SIMPLE_KU(name, unusedBits, bits) \
|
||||
const uint8_t name##_bytes[4] = { \
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, unusedBits, bits \
|
||||
}; \
|
||||
const Input name(name##_bytes);
|
||||
|
||||
static const Input empty_null;
|
||||
|
||||
// Note that keyCertSign is really the only interesting case for CA
|
||||
// certificates since we don't support cRLSign.
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, EE_none)
|
||||
{
|
||||
// The input Input is nullptr. This means the cert had no keyUsage
|
||||
// extension. This is always valid because no key usage in an end-entity
|
||||
// means that there are no key usage restrictions.
|
||||
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyUsage::noParticularKeyUsageRequired));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyUsage::nonRepudiation));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyUsage::keyEncipherment));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyUsage::dataEncipherment));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
||||
KeyUsage::keyAgreement));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, EE_empty)
|
||||
{
|
||||
// The input Input is empty. The cert had an empty keyUsage extension,
|
||||
// which is syntactically invalid.
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_null,
|
||||
KeyUsage::digitalSignature));
|
||||
static const uint8_t dummy = 0x00;
|
||||
Input empty_nonnull;
|
||||
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_nonnull,
|
||||
KeyUsage::digitalSignature));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, CA_none)
|
||||
{
|
||||
// A CA certificate does not have a KU extension.
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
||||
KeyUsage::keyCertSign));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, CA_empty)
|
||||
{
|
||||
// A CA certificate has an empty KU extension.
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_null,
|
||||
KeyUsage::keyCertSign));
|
||||
static const uint8_t dummy = 0x00;
|
||||
Input empty_nonnull;
|
||||
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_nonnull,
|
||||
KeyUsage::keyCertSign));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, maxUnusedBits)
|
||||
{
|
||||
NAMED_SIMPLE_KU(encoded, 7, 0x80);
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &encoded,
|
||||
KeyUsage::digitalSignature));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, tooManyUnusedBits)
|
||||
{
|
||||
static uint8_t oneValueByteData[] = {
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 8/*unused bits*/, 0x80
|
||||
};
|
||||
static const Input oneValueByte(oneValueByteData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &oneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
|
||||
static uint8_t twoValueBytesData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 8/*unused bits*/, 0x01, 0x00
|
||||
};
|
||||
static const Input twoValueBytes(twoValueBytesData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, NoValueBytes_NoPaddingBits)
|
||||
{
|
||||
static const uint8_t DER_BYTES[] = {
|
||||
0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 0/*unused bits*/
|
||||
};
|
||||
static const Input DER(DER_BYTES);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
|
||||
KeyUsage::keyCertSign));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, NoValueBytes_7PaddingBits)
|
||||
{
|
||||
static const uint8_t DER_BYTES[] = {
|
||||
0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 7/*unused bits*/
|
||||
};
|
||||
static const Input DER(DER_BYTES);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
|
||||
KeyUsage::keyCertSign));
|
||||
}
|
||||
|
||||
void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage)
|
||||
{
|
||||
// Test that only the right bit is accepted for the usage for both EE and CA
|
||||
// certs.
|
||||
NAMED_SIMPLE_KU(good, unusedBits, bits);
|
||||
ASSERT_EQ(Success,
|
||||
CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good, usage));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, &good, usage));
|
||||
|
||||
// We use (~bits >> unusedBits) << unusedBits) instead of using the same
|
||||
// calculation that is in CheckKeyUsage to validate that the calculation in
|
||||
// CheckKeyUsage is correct.
|
||||
|
||||
// Test that none of the other non-padding bits are mistaken for the given
|
||||
// key usage in the single-byte value case.
|
||||
NAMED_SIMPLE_KU(notGood, unusedBits,
|
||||
static_cast<uint8_t>((~bits >> unusedBits) << unusedBits));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, ¬Good, usage));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, ¬Good, usage));
|
||||
|
||||
// Test that none of the other non-padding bits are mistaken for the given
|
||||
// key usage in the two-byte value case.
|
||||
const uint8_t twoByteNotGoodData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, unusedBits,
|
||||
static_cast<uint8_t>(~bits),
|
||||
static_cast<uint8_t>((0xFFu >> unusedBits) << unusedBits)
|
||||
};
|
||||
Input twoByteNotGood(twoByteNotGoodData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoByteNotGood,
|
||||
usage));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoByteNotGood, usage));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, simpleCases)
|
||||
{
|
||||
ASSERT_SimpleCase(7, 0x80, KeyUsage::digitalSignature);
|
||||
ASSERT_SimpleCase(6, 0x40, KeyUsage::nonRepudiation);
|
||||
ASSERT_SimpleCase(5, 0x20, KeyUsage::keyEncipherment);
|
||||
ASSERT_SimpleCase(4, 0x10, KeyUsage::dataEncipherment);
|
||||
ASSERT_SimpleCase(3, 0x08, KeyUsage::keyAgreement);
|
||||
}
|
||||
|
||||
// Only CAs are allowed to assert keyCertSign.
|
||||
// End-entity certs may assert it along with other key usages if keyCertSign
|
||||
// isn't the required key usage. This is for compatibility.
|
||||
TEST_F(pkixcheck_CheckKeyUsage, keyCertSign)
|
||||
{
|
||||
NAMED_SIMPLE_KU(good, 2, 0x04);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good,
|
||||
KeyUsage::keyCertSign));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, &good,
|
||||
KeyUsage::keyCertSign));
|
||||
|
||||
// Test that none of the other non-padding bits are mistaken for the given
|
||||
// key usage in the one-byte value case.
|
||||
NAMED_SIMPLE_KU(notGood, 2, 0xFB);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, ¬Good,
|
||||
KeyUsage::keyCertSign));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, ¬Good,
|
||||
KeyUsage::keyCertSign));
|
||||
|
||||
// Test that none of the other non-padding bits are mistaken for the given
|
||||
// key usage in the two-byte value case.
|
||||
static uint8_t twoByteNotGoodData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 2/*unused bits*/, 0xFBu, 0xFCu
|
||||
};
|
||||
static const Input twoByteNotGood(twoByteNotGoodData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoByteNotGood,
|
||||
KeyUsage::keyCertSign));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoByteNotGood,
|
||||
KeyUsage::keyCertSign));
|
||||
|
||||
// If an end-entity certificate does assert keyCertSign, this is allowed
|
||||
// as long as that isn't the required key usage.
|
||||
NAMED_SIMPLE_KU(digitalSignatureAndKeyCertSign, 2, 0x84);
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
&digitalSignatureAndKeyCertSign,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
&digitalSignatureAndKeyCertSign,
|
||||
KeyUsage::keyCertSign));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, unusedBitNotZero)
|
||||
{
|
||||
// single byte control case
|
||||
static uint8_t controlOneValueByteData[] = {
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80
|
||||
};
|
||||
static const Input controlOneValueByte(controlOneValueByteData);
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
&controlOneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA,
|
||||
&controlOneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
|
||||
// single-byte test case
|
||||
static uint8_t oneValueByteData[] = {
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80 | 0x01
|
||||
};
|
||||
static const Input oneValueByte(oneValueByteData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &oneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &oneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
|
||||
// two-byte control case
|
||||
static uint8_t controlTwoValueBytesData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
|
||||
0x80 | 0x01, 0x80
|
||||
};
|
||||
static const Input controlTwoValueBytes(controlTwoValueBytesData);
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
&controlTwoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA,
|
||||
&controlTwoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
|
||||
// two-byte test case
|
||||
static uint8_t twoValueBytesData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
|
||||
0x80 | 0x01, 0x80 | 0x01
|
||||
};
|
||||
static const Input twoValueBytes(twoValueBytesData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
}
|
||||
|
|
@ -0,0 +1,367 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 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 "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
extern Result CheckSignatureAlgorithm(
|
||||
TrustDomain& trustDomain, EndEntityOrCA endEntityOrCA,
|
||||
Time notBefore,
|
||||
const der::SignedDataWithSignature& signedData,
|
||||
Input signatureValue);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
struct CheckSignatureAlgorithmTestParams
|
||||
{
|
||||
ByteString signatureAlgorithmValue;
|
||||
ByteString signatureValue;
|
||||
unsigned int signatureLengthInBytes;
|
||||
Result expectedResult;
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os,
|
||||
const CheckSignatureAlgorithmTestParams&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
#define BS(s) ByteString(s, MOZILLA_PKIX_ARRAY_LENGTH(s))
|
||||
|
||||
// python DottedOIDToCode.py --tlv sha256WithRSAEncryption 1.2.840.113549.1.1.11
|
||||
static const uint8_t tlv_sha256WithRSAEncryption[] = {
|
||||
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
|
||||
};
|
||||
|
||||
// Same as tlv_sha256WithRSAEncryption, except one without the "0x0b" and with
|
||||
// the DER length decreased accordingly.
|
||||
static const uint8_t tlv_sha256WithRSAEncryption_truncated[] = {
|
||||
0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv sha-1WithRSAEncryption 1.2.840.113549.1.1.5
|
||||
static const uint8_t tlv_sha_1WithRSAEncryption[] = {
|
||||
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv sha1WithRSASignature 1.3.14.3.2.29
|
||||
static const uint8_t tlv_sha1WithRSASignature[] = {
|
||||
0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py --tlv md5WithRSAEncryption 1.2.840.113549.1.1.4
|
||||
static const uint8_t tlv_md5WithRSAEncryption[] = {
|
||||
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04
|
||||
};
|
||||
|
||||
static const CheckSignatureAlgorithmTestParams
|
||||
CHECKSIGNATUREALGORITHM_TEST_PARAMS[] =
|
||||
{
|
||||
{ // Both algorithm IDs are empty
|
||||
ByteString(),
|
||||
ByteString(),
|
||||
2048 / 8,
|
||||
Result::ERROR_BAD_DER,
|
||||
},
|
||||
{ // signatureAlgorithm is empty, signature is supported.
|
||||
ByteString(),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_BAD_DER,
|
||||
},
|
||||
{ // signatureAlgorithm is supported, signature is empty.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
ByteString(),
|
||||
2048 / 8,
|
||||
Result::ERROR_BAD_DER,
|
||||
},
|
||||
{ // Algorithms match, both are supported.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Success
|
||||
},
|
||||
{ // Algorithms do not match because signatureAlgorithm is truncated.
|
||||
BS(tlv_sha256WithRSAEncryption_truncated),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
},
|
||||
{ // Algorithms do not match because signature is truncated.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
BS(tlv_sha256WithRSAEncryption_truncated),
|
||||
2048 / 8,
|
||||
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
},
|
||||
{ // Algorithms do not match, both are supported.
|
||||
BS(tlv_sha_1WithRSAEncryption),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
||||
},
|
||||
{ // Algorithms do not match, both are supported.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
BS(tlv_sha_1WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
||||
},
|
||||
{ // Algorithms match, both are unsupported.
|
||||
BS(tlv_md5WithRSAEncryption),
|
||||
BS(tlv_md5WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
},
|
||||
{ // signatureAlgorithm is unsupported, signature is supported.
|
||||
BS(tlv_md5WithRSAEncryption),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
},
|
||||
{ // signatureAlgorithm is supported, signature is unsupported.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
BS(tlv_md5WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
|
||||
},
|
||||
{ // Both have the optional NULL parameter.
|
||||
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
|
||||
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
|
||||
2048 / 8,
|
||||
Success
|
||||
},
|
||||
{ // signatureAlgorithm has the optional NULL parameter, signature doesn't.
|
||||
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Success
|
||||
},
|
||||
{ // signatureAlgorithm does not have the optional NULL parameter, signature
|
||||
// does.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
|
||||
2048 / 8,
|
||||
Success
|
||||
},
|
||||
{ // The different OIDs for RSA-with-SHA1 we support are semantically
|
||||
// equivalent.
|
||||
BS(tlv_sha1WithRSASignature),
|
||||
BS(tlv_sha_1WithRSAEncryption),
|
||||
2048 / 8,
|
||||
Success,
|
||||
},
|
||||
{ // The different OIDs for RSA-with-SHA1 we support are semantically
|
||||
// equivalent (opposite order).
|
||||
BS(tlv_sha_1WithRSAEncryption),
|
||||
BS(tlv_sha1WithRSASignature),
|
||||
2048 / 8,
|
||||
Success,
|
||||
},
|
||||
{ // Algorithms match, both are supported, key size is not a multile of 128
|
||||
// bits. This test verifies that we're not wrongly rounding up the
|
||||
// signature size like we did in the original patch for bug 1131767.
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
BS(tlv_sha256WithRSAEncryption),
|
||||
(2048 / 8) - 1,
|
||||
Success
|
||||
},
|
||||
};
|
||||
|
||||
class pkixcheck_CheckSignatureAlgorithm
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<CheckSignatureAlgorithmTestParams>
|
||||
{
|
||||
};
|
||||
|
||||
class pkixcheck_CheckSignatureAlgorithm_TrustDomain final
|
||||
: public EverythingFailsByDefaultTrustDomain
|
||||
{
|
||||
public:
|
||||
explicit pkixcheck_CheckSignatureAlgorithm_TrustDomain(
|
||||
unsigned int aPublicKeySizeInBits)
|
||||
: publicKeySizeInBits(aPublicKeySizeInBits)
|
||||
, checkedDigestAlgorithm(false)
|
||||
, checkedModulusSizeInBits(false)
|
||||
{
|
||||
}
|
||||
|
||||
Result CheckSignatureDigestAlgorithm(DigestAlgorithm, EndEntityOrCA, Time)
|
||||
override
|
||||
{
|
||||
checkedDigestAlgorithm = true;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA endEntityOrCA,
|
||||
unsigned int modulusSizeInBits)
|
||||
override
|
||||
{
|
||||
EXPECT_EQ(EndEntityOrCA::MustBeEndEntity, endEntityOrCA);
|
||||
EXPECT_EQ(publicKeySizeInBits, modulusSizeInBits);
|
||||
checkedModulusSizeInBits = true;
|
||||
return Success;
|
||||
}
|
||||
|
||||
const unsigned int publicKeySizeInBits;
|
||||
bool checkedDigestAlgorithm;
|
||||
bool checkedModulusSizeInBits;
|
||||
};
|
||||
|
||||
TEST_P(pkixcheck_CheckSignatureAlgorithm, CheckSignatureAlgorithm)
|
||||
{
|
||||
const Time now(Now());
|
||||
const CheckSignatureAlgorithmTestParams& params(GetParam());
|
||||
|
||||
Input signatureValueInput;
|
||||
ASSERT_EQ(Success,
|
||||
signatureValueInput.Init(params.signatureValue.data(),
|
||||
params.signatureValue.length()));
|
||||
|
||||
pkixcheck_CheckSignatureAlgorithm_TrustDomain
|
||||
trustDomain(params.signatureLengthInBytes * 8);
|
||||
|
||||
der::SignedDataWithSignature signedData;
|
||||
ASSERT_EQ(Success,
|
||||
signedData.algorithm.Init(params.signatureAlgorithmValue.data(),
|
||||
params.signatureAlgorithmValue.length()));
|
||||
|
||||
ByteString dummySignature(params.signatureLengthInBytes, 0xDE);
|
||||
ASSERT_EQ(Success,
|
||||
signedData.signature.Init(dummySignature.data(),
|
||||
dummySignature.length()));
|
||||
|
||||
ASSERT_EQ(params.expectedResult,
|
||||
CheckSignatureAlgorithm(trustDomain, EndEntityOrCA::MustBeEndEntity,
|
||||
now, signedData, signatureValueInput));
|
||||
ASSERT_EQ(params.expectedResult == Success,
|
||||
trustDomain.checkedDigestAlgorithm);
|
||||
ASSERT_EQ(params.expectedResult == Success,
|
||||
trustDomain.checkedModulusSizeInBits);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
pkixcheck_CheckSignatureAlgorithm, pkixcheck_CheckSignatureAlgorithm,
|
||||
testing::ValuesIn(CHECKSIGNATUREALGORITHM_TEST_PARAMS));
|
||||
|
||||
class pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain
|
||||
: public DefaultCryptoTrustDomain
|
||||
{
|
||||
public:
|
||||
explicit pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain(
|
||||
const ByteString& aIssuer)
|
||||
: issuer(aIssuer)
|
||||
{
|
||||
}
|
||||
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
|
||||
Input cert, /*out*/ TrustLevel& trustLevel) override
|
||||
{
|
||||
trustLevel = InputEqualsByteString(cert, issuer)
|
||||
? TrustLevel::TrustAnchor
|
||||
: TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result FindIssuer(Input, IssuerChecker& checker, Time) override
|
||||
{
|
||||
EXPECT_FALSE(ENCODING_FAILED(issuer));
|
||||
|
||||
Input issuerInput;
|
||||
EXPECT_EQ(Success, issuerInput.Init(issuer.data(), issuer.length()));
|
||||
|
||||
bool keepGoing;
|
||||
EXPECT_EQ(Success, checker.Check(issuerInput, nullptr, keepGoing));
|
||||
EXPECT_FALSE(keepGoing);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
ByteString issuer;
|
||||
};
|
||||
|
||||
// Test that CheckSignatureAlgorithm actually gets called at some point when
|
||||
// BuildCertChain is called.
|
||||
TEST_F(pkixcheck_CheckSignatureAlgorithm, BuildCertChain)
|
||||
{
|
||||
ScopedTestKeyPair keyPair(CloneReusedKeyPair());
|
||||
ASSERT_TRUE(keyPair.get());
|
||||
|
||||
ByteString issuerExtensions[2];
|
||||
issuerExtensions[0] = CreateEncodedBasicConstraints(true, nullptr,
|
||||
Critical::No);
|
||||
ASSERT_FALSE(ENCODING_FAILED(issuerExtensions[0]));
|
||||
|
||||
ByteString issuer(CreateEncodedCertificate(3,
|
||||
sha256WithRSAEncryption(),
|
||||
CreateEncodedSerialNumber(1),
|
||||
CNToDERName("issuer"),
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
CNToDERName("issuer"),
|
||||
*keyPair,
|
||||
issuerExtensions,
|
||||
*keyPair,
|
||||
sha256WithRSAEncryption()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(issuer));
|
||||
|
||||
ByteString subject(CreateEncodedCertificate(3,
|
||||
sha1WithRSAEncryption(),
|
||||
CreateEncodedSerialNumber(2),
|
||||
CNToDERName("issuer"),
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
CNToDERName("subject"),
|
||||
*keyPair,
|
||||
nullptr,
|
||||
*keyPair,
|
||||
sha256WithRSAEncryption()));
|
||||
ASSERT_FALSE(ENCODING_FAILED(subject));
|
||||
|
||||
Input subjectInput;
|
||||
ASSERT_EQ(Success, subjectInput.Init(subject.data(), subject.length()));
|
||||
pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain
|
||||
trustDomain(issuer);
|
||||
Result rv = BuildCertChain(trustDomain, subjectInput, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr);
|
||||
ASSERT_EQ(Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH, rv);
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 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 "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixcheck.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
static const Time PAST_TIME(YMDHMS(1998, 12, 31, 12, 23, 56));
|
||||
|
||||
#define OLDER_GENERALIZEDTIME \
|
||||
0x18, 15, /* tag, length */ \
|
||||
'1', '9', '9', '9', '0', '1', '0', '1', /* 1999-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
#define OLDER_UTCTIME \
|
||||
0x17, 13, /* tag, length */ \
|
||||
'9', '9', '0', '1', '0', '1', /* (19)99-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
static const Time NOW(YMDHMS(2016, 12, 31, 12, 23, 56));
|
||||
|
||||
#define NEWER_GENERALIZEDTIME \
|
||||
0x18, 15, /* tag, length */ \
|
||||
'2', '0', '2', '1', '0', '1', '0', '1', /* 2021-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
#define NEWER_UTCTIME \
|
||||
0x17, 13, /* tag, length */ \
|
||||
'2', '1', '0', '1', '0', '1', /* 2021-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
static const Time FUTURE_TIME(YMDHMS(2025, 12, 31, 12, 23, 56));
|
||||
|
||||
class pkixcheck_CheckValidity : public ::testing::Test { };
|
||||
|
||||
static const uint8_t OLDER_UTCTIME_NEWER_UTCTIME_DATA[] = {
|
||||
OLDER_UTCTIME,
|
||||
NEWER_UTCTIME,
|
||||
};
|
||||
static const Input
|
||||
OLDER_UTCTIME_NEWER_UTCTIME(OLDER_UTCTIME_NEWER_UTCTIME_DATA);
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, Valid_UTCTIME_UTCTIME)
|
||||
{
|
||||
static Time notBefore(Time::uninitialized);
|
||||
static Time notAfter(Time::uninitialized);
|
||||
ASSERT_EQ(Success, ParseValidity(OLDER_UTCTIME_NEWER_UTCTIME, ¬Before, ¬After));
|
||||
ASSERT_EQ(Success, CheckValidity(NOW, notBefore, notAfter));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, Valid_GENERALIZEDTIME_GENERALIZEDTIME)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
OLDER_GENERALIZEDTIME,
|
||||
NEWER_GENERALIZEDTIME,
|
||||
};
|
||||
static const Input validity(DER);
|
||||
static Time notBefore(Time::uninitialized);
|
||||
static Time notAfter(Time::uninitialized);
|
||||
ASSERT_EQ(Success, ParseValidity(validity, ¬Before, ¬After));
|
||||
ASSERT_EQ(Success, CheckValidity(NOW, notBefore, notAfter));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, Valid_GENERALIZEDTIME_UTCTIME)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
OLDER_GENERALIZEDTIME,
|
||||
NEWER_UTCTIME,
|
||||
};
|
||||
static const Input validity(DER);
|
||||
static Time notBefore(Time::uninitialized);
|
||||
static Time notAfter(Time::uninitialized);
|
||||
ASSERT_EQ(Success, ParseValidity(validity, ¬Before, ¬After));
|
||||
ASSERT_EQ(Success, CheckValidity(NOW, notBefore, notAfter));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, Valid_UTCTIME_GENERALIZEDTIME)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
OLDER_UTCTIME,
|
||||
NEWER_GENERALIZEDTIME,
|
||||
};
|
||||
static const Input validity(DER);
|
||||
static Time notBefore(Time::uninitialized);
|
||||
static Time notAfter(Time::uninitialized);
|
||||
ASSERT_EQ(Success, ParseValidity(validity, ¬Before, ¬After));
|
||||
ASSERT_EQ(Success, CheckValidity(NOW, notBefore, notAfter));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, InvalidBeforeNotBefore)
|
||||
{
|
||||
static Time notBefore(Time::uninitialized);
|
||||
static Time notAfter(Time::uninitialized);
|
||||
ASSERT_EQ(Success, ParseValidity(OLDER_UTCTIME_NEWER_UTCTIME, ¬Before, ¬After));
|
||||
ASSERT_EQ(Result::ERROR_NOT_YET_VALID_CERTIFICATE, CheckValidity(PAST_TIME, notBefore, notAfter));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, InvalidAfterNotAfter)
|
||||
{
|
||||
static Time notBefore(Time::uninitialized);
|
||||
static Time notAfter(Time::uninitialized);
|
||||
ASSERT_EQ(Success, ParseValidity(OLDER_UTCTIME_NEWER_UTCTIME, ¬Before, ¬After));
|
||||
ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(FUTURE_TIME, notBefore, notAfter));
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 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 "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixcheck.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
#define OLDER_UTCTIME \
|
||||
0x17, 13, /* tag, length */ \
|
||||
'9', '9', '0', '1', '0', '1', /* (19)99-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
#define NEWER_UTCTIME \
|
||||
0x17, 13, /* tag, length */ \
|
||||
'2', '1', '0', '1', '0', '1', /* 2021-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
static const Time FUTURE_TIME(YMDHMS(2025, 12, 31, 12, 23, 56));
|
||||
|
||||
class pkixcheck_ParseValidity : public ::testing::Test { };
|
||||
|
||||
TEST_F(pkixcheck_ParseValidity, BothEmptyNull)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
0x17/*UTCTime*/, 0/*length*/,
|
||||
0x17/*UTCTime*/, 0/*length*/,
|
||||
};
|
||||
static const Input validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, ParseValidity(validity));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_ParseValidity, NotBeforeEmptyNull)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
0x17/*UTCTime*/, 0x00/*length*/,
|
||||
NEWER_UTCTIME
|
||||
};
|
||||
static const Input validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, ParseValidity(validity));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_ParseValidity, NotAfterEmptyNull)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
NEWER_UTCTIME,
|
||||
0x17/*UTCTime*/, 0x00/*length*/,
|
||||
};
|
||||
static const Input validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, ParseValidity(validity));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_ParseValidity, InvalidNotAfterBeforeNotBefore)
|
||||
{
|
||||
static const uint8_t DER[] = {
|
||||
NEWER_UTCTIME,
|
||||
OLDER_UTCTIME,
|
||||
};
|
||||
static const Input validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, ParseValidity(validity));
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 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 "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
extern Result TLSFeaturesSatisfiedInternal(const Input* requiredTLSFeatures,
|
||||
const Input* stapledOCSPResponse);
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
struct TLSFeaturesTestParams
|
||||
{
|
||||
ByteString requiredTLSFeatures;
|
||||
Result expectedResultWithResponse;
|
||||
Result expectedResultWithoutResponse;
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os, const TLSFeaturesTestParams&)
|
||||
{
|
||||
return os << "TODO (bug 1318770)";
|
||||
}
|
||||
|
||||
#define BS(s) ByteString(s, MOZILLA_PKIX_ARRAY_LENGTH(s))
|
||||
static const uint8_t statusRequest[] = {
|
||||
0x30, 0x03, 0x02, 0x01, 0x05
|
||||
};
|
||||
|
||||
static const uint8_t unknown[] = {
|
||||
0x30, 0x03, 0x02, 0x01, 0x06
|
||||
};
|
||||
|
||||
static const uint8_t statusRequestAndUnknown[] = {
|
||||
0x30, 0x06, 0x02, 0x01, 0x05, 0x02, 0x01, 0x06
|
||||
};
|
||||
|
||||
static const uint8_t duplicateStatusRequest[] = {
|
||||
0x30, 0x06, 0x02, 0x01, 0x05, 0x02, 0x01, 0x05
|
||||
};
|
||||
|
||||
static const uint8_t twoByteUnknown[] = {
|
||||
0x30, 0x04, 0x02, 0x02, 0x05, 0x05
|
||||
};
|
||||
|
||||
static const uint8_t zeroByteInteger[] = {
|
||||
0x30, 0x02, 0x02, 0x00
|
||||
};
|
||||
|
||||
static const TLSFeaturesTestParams
|
||||
TLSFEATURESSATISFIED_TEST_PARAMS[] =
|
||||
{
|
||||
// some tests with checks enforced
|
||||
{ ByteString(), Result::ERROR_BAD_DER, Result::ERROR_BAD_DER },
|
||||
{ BS(statusRequest), Success, Result::ERROR_REQUIRED_TLS_FEATURE_MISSING },
|
||||
{ BS(unknown), Result::ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
Result::ERROR_REQUIRED_TLS_FEATURE_MISSING },
|
||||
{ BS(statusRequestAndUnknown), Result::ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
Result::ERROR_REQUIRED_TLS_FEATURE_MISSING },
|
||||
{ BS(duplicateStatusRequest), Success,
|
||||
Result::ERROR_REQUIRED_TLS_FEATURE_MISSING },
|
||||
{ BS(twoByteUnknown), Result::ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
Result::ERROR_REQUIRED_TLS_FEATURE_MISSING },
|
||||
{ BS(zeroByteInteger), Result::ERROR_REQUIRED_TLS_FEATURE_MISSING,
|
||||
Result::ERROR_REQUIRED_TLS_FEATURE_MISSING },
|
||||
};
|
||||
|
||||
class pkixcheck_TLSFeaturesSatisfiedInternal
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<TLSFeaturesTestParams>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(pkixcheck_TLSFeaturesSatisfiedInternal, TLSFeaturesSatisfiedInternal) {
|
||||
const TLSFeaturesTestParams& params(GetParam());
|
||||
|
||||
Input featuresInput;
|
||||
ASSERT_EQ(Success, featuresInput.Init(params.requiredTLSFeatures.data(),
|
||||
params.requiredTLSFeatures.length()));
|
||||
Input responseInput;
|
||||
// just create an input with any data in it
|
||||
ByteString stapledOCSPResponse = BS(statusRequest);
|
||||
ASSERT_EQ(Success, responseInput.Init(stapledOCSPResponse.data(),
|
||||
stapledOCSPResponse.length()));
|
||||
// first we omit the response
|
||||
ASSERT_EQ(params.expectedResultWithoutResponse,
|
||||
TLSFeaturesSatisfiedInternal(&featuresInput, nullptr));
|
||||
// then we try again with the response
|
||||
ASSERT_EQ(params.expectedResultWithResponse,
|
||||
TLSFeaturesSatisfiedInternal(&featuresInput, &responseInput));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
pkixcheck_TLSFeaturesSatisfiedInternal,
|
||||
pkixcheck_TLSFeaturesSatisfiedInternal,
|
||||
testing::ValuesIn(TLSFEATURESSATISFIED_TEST_PARAMS));
|
||||
920
security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp
Normal file
920
security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp
Normal file
|
|
@ -0,0 +1,920 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::der;
|
||||
|
||||
namespace {
|
||||
|
||||
class pkixder_input_tests : public ::testing::Test { };
|
||||
|
||||
static const uint8_t DER_SEQUENCE_EMPTY[] = {
|
||||
0x30, // SEQUENCE
|
||||
0x00, // length
|
||||
};
|
||||
|
||||
static const uint8_t DER_SEQUENCE_NOT_EMPTY[] = {
|
||||
0x30, // SEQUENCE
|
||||
0x01, // length
|
||||
'X', // value
|
||||
};
|
||||
|
||||
static const uint8_t DER_SEQUENCE_NOT_EMPTY_VALUE[] = {
|
||||
'X', // value
|
||||
};
|
||||
|
||||
static const uint8_t DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED[] = {
|
||||
0x30, // SEQUENCE
|
||||
0x01, // length
|
||||
};
|
||||
|
||||
const uint8_t DER_SEQUENCE_OF_INT8[] = {
|
||||
0x30, // SEQUENCE
|
||||
0x09, // length
|
||||
0x02, 0x01, 0x01, // INTEGER length 1 value 0x01
|
||||
0x02, 0x01, 0x02, // INTEGER length 1 value 0x02
|
||||
0x02, 0x01, 0x03 // INTEGER length 1 value 0x03
|
||||
};
|
||||
|
||||
const uint8_t DER_TRUNCATED_SEQUENCE_OF_INT8[] = {
|
||||
0x30, // SEQUENCE
|
||||
0x09, // length
|
||||
0x02, 0x01, 0x01, // INTEGER length 1 value 0x01
|
||||
0x02, 0x01, 0x02 // INTEGER length 1 value 0x02
|
||||
// MISSING DATA HERE ON PURPOSE
|
||||
};
|
||||
|
||||
const uint8_t DER_OVERRUN_SEQUENCE_OF_INT8[] = {
|
||||
0x30, // SEQUENCE
|
||||
0x09, // length
|
||||
0x02, 0x01, 0x01, // INTEGER length 1 value 0x01
|
||||
0x02, 0x01, 0x02, // INTEGER length 1 value 0x02
|
||||
0x02, 0x02, 0xFF, 0x03 // INTEGER length 2 value 0xFF03
|
||||
};
|
||||
|
||||
const uint8_t DER_INT16[] = {
|
||||
0x02, // INTEGER
|
||||
0x02, // length
|
||||
0x12, 0x34 // 0x1234
|
||||
};
|
||||
|
||||
static const Input EMPTY_INPUT;
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInit)
|
||||
{
|
||||
Input buf;
|
||||
ASSERT_EQ(Success,
|
||||
buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitWithNullPointerOrZeroLength)
|
||||
{
|
||||
Input buf;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init(nullptr, 0));
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init(nullptr, 100));
|
||||
|
||||
// Though it seems odd to initialize with zero-length and non-null ptr, this
|
||||
// is working as intended. The Reader class was intended to protect against
|
||||
// buffer overflows, and there's no risk with the current behavior. See bug
|
||||
// 1000354.
|
||||
ASSERT_EQ(Success, buf.Init((const uint8_t*) "hello", 0));
|
||||
ASSERT_TRUE(buf.GetLength() == 0);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitWithLargeData)
|
||||
{
|
||||
Input buf;
|
||||
// Data argument length does not matter, it is not touched, just
|
||||
// needs to be non-null
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init((const uint8_t*) "", 0xffff+1));
|
||||
|
||||
ASSERT_EQ(Success, buf.Init((const uint8_t*) "", 0xffff));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitMultipleTimes)
|
||||
{
|
||||
Input buf;
|
||||
|
||||
ASSERT_EQ(Success,
|
||||
buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
|
||||
ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS,
|
||||
buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, PeekWithinBounds)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x11 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
ASSERT_TRUE(input.Peek(0x11));
|
||||
ASSERT_FALSE(input.Peek(0x22));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, PeekPastBounds)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 1));
|
||||
Reader input(buf);
|
||||
|
||||
uint8_t readByte;
|
||||
ASSERT_EQ(Success, input.Read(readByte));
|
||||
ASSERT_EQ(0x11, readByte);
|
||||
ASSERT_FALSE(input.Peek(0x22));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadByte)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
uint8_t readByte1;
|
||||
ASSERT_EQ(Success, input.Read(readByte1));
|
||||
ASSERT_EQ(0x11, readByte1);
|
||||
|
||||
uint8_t readByte2;
|
||||
ASSERT_EQ(Success, input.Read(readByte2));
|
||||
ASSERT_EQ(0x22, readByte2);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadBytePastEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 1));
|
||||
Reader input(buf);
|
||||
|
||||
uint8_t readByte1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readByte1));
|
||||
ASSERT_EQ(0x11, readByte1);
|
||||
|
||||
uint8_t readByte2 = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readByte2));
|
||||
ASSERT_NE(0x22, readByte2);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadByteWrapAroundPointer)
|
||||
{
|
||||
// The original implementation of our buffer read overflow checks was
|
||||
// susceptible to integer overflows which could make the checks ineffective.
|
||||
// This attempts to verify that we've fixed that. Unfortunately, decrementing
|
||||
// a null pointer is undefined behavior according to the C++ language spec.,
|
||||
// but this should catch the problem on at least some compilers, if not all of
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Reader input(buf);
|
||||
|
||||
uint8_t b;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(b));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWord)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
uint16_t readWord1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readWord1));
|
||||
ASSERT_EQ(0x1122, readWord1);
|
||||
|
||||
uint16_t readWord2 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readWord2));
|
||||
ASSERT_EQ(0x3344, readWord2);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWordPastEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 2)); // Initialize with too-short length
|
||||
Reader input(buf);
|
||||
|
||||
uint16_t readWord1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readWord1));
|
||||
ASSERT_EQ(0x1122, readWord1);
|
||||
|
||||
uint16_t readWord2 = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord2));
|
||||
ASSERT_NE(0x3344, readWord2);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWordWithInsufficentData)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 1));
|
||||
Reader input(buf);
|
||||
|
||||
uint16_t readWord1 = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord1));
|
||||
ASSERT_NE(0x1122, readWord1);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWordWrapAroundPointer)
|
||||
{
|
||||
// The original implementation of our buffer read overflow checks was
|
||||
// susceptible to integer overflows which could make the checks ineffective.
|
||||
// This attempts to verify that we've fixed that. Unfortunately, decrementing
|
||||
// a null pointer is undefined behavior according to the C++ language spec.,
|
||||
// but this should catch the problem on at least some compilers, if not all of
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Reader input(buf);
|
||||
uint16_t b;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(b));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(1));
|
||||
|
||||
uint8_t readByte1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readByte1));
|
||||
ASSERT_EQ(0x22, readByte1);
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(1));
|
||||
|
||||
uint8_t readByte2 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readByte2));
|
||||
ASSERT_EQ(0x44, readByte2);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_ToEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(sizeof der));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_PastEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_ToNewInput)
|
||||
{
|
||||
const uint8_t der[] = { 0x01, 0x02, 0x03, 0x04 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
Reader skippedInput;
|
||||
ASSERT_EQ(Success, input.Skip(3, skippedInput));
|
||||
|
||||
uint8_t readByte1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readByte1));
|
||||
ASSERT_EQ(0x04, readByte1);
|
||||
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
|
||||
// Reader has no Remaining() or Length() so we simply read the bytes
|
||||
// and then expect to be at the end.
|
||||
|
||||
for (uint8_t i = 1; i <= 3; ++i) {
|
||||
uint8_t readByte = 0;
|
||||
ASSERT_EQ(Success, skippedInput.Read(readByte));
|
||||
ASSERT_EQ(i, readByte);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(skippedInput.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_ToNewInputPastEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
Reader skippedInput;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der * 2, skippedInput));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_ToInput)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 };
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Success, input.Skip(sizeof expectedItemData, item));
|
||||
|
||||
Input expected(expectedItemData);
|
||||
ASSERT_TRUE(InputsAreEqual(expected, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_WrapAroundPointer)
|
||||
{
|
||||
// The original implementation of our buffer read overflow checks was
|
||||
// susceptible to integer overflows which could make the checks ineffective.
|
||||
// This attempts to verify that we've fixed that. Unfortunately, decrementing
|
||||
// a null pointer is undefined behavior according to the C++ language spec.,
|
||||
// but this should catch the problem on at least some compilers, if not all of
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(1));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, Skip_ToInputPastEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
Input skipped;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1, skipped));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, SkipToEnd_ToInput)
|
||||
{
|
||||
static const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
Input skipped;
|
||||
ASSERT_EQ(Success, input.SkipToEnd(skipped));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, SkipToEnd_ToInput_InputAlreadyInited)
|
||||
{
|
||||
static const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
static const uint8_t initialValue[] = { 0x01, 0x02, 0x03 };
|
||||
Input x(initialValue);
|
||||
// Fails because skipped was already initialized once, and Inputs are not
|
||||
// allowed to be Init()d multiple times.
|
||||
ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, input.SkipToEnd(x));
|
||||
ASSERT_TRUE(InputsAreEqual(x, Input(initialValue)));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndSkipValue)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
|
||||
ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE));
|
||||
ASSERT_EQ(Success, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithTruncatedData)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndSkipValue(input, SEQUENCE));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithOverrunData)
|
||||
{
|
||||
Input buf(DER_OVERRUN_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, AtEndOnUnInitializedInput)
|
||||
{
|
||||
Reader input;
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, AtEndAtBeginning)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, AtEndAtEnd)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(sizeof der));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MarkAndGetInput)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
Reader::Mark mark = input.GetMark();
|
||||
|
||||
const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 };
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(sizeof expectedItemData));
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Success, input.GetInput(mark, item));
|
||||
Input expected(expectedItemData);
|
||||
ASSERT_TRUE(InputsAreEqual(expected, item));
|
||||
}
|
||||
|
||||
// Cannot run this test on debug builds because of the NotReached
|
||||
#ifdef NDEBUG
|
||||
TEST_F(pkixder_input_tests, MarkAndGetInputDifferentInput)
|
||||
{
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
|
||||
Reader another;
|
||||
Reader::Mark mark = another.GetMark();
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(3));
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, input.GetInput(mark, item));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_AtEnd)
|
||||
{
|
||||
Reader input(EMPTY_INPUT);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_TruncatedAfterTag)
|
||||
{
|
||||
static const uint8_t DER[] = { SEQUENCE };
|
||||
Input buf(DER);
|
||||
Reader input(buf);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_ValidEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_EMPTY);
|
||||
Reader input(buf);
|
||||
uint8_t tag = 0;
|
||||
Input value;
|
||||
ASSERT_EQ(Success, ReadTagAndGetValue(input, tag, value));
|
||||
ASSERT_EQ(SEQUENCE, tag);
|
||||
ASSERT_EQ(0u, value.GetLength());
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_ValidNotEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
uint8_t tag = 0;
|
||||
Input value;
|
||||
ASSERT_EQ(Success, ReadTagAndGetValue(input, tag, value));
|
||||
ASSERT_EQ(SEQUENCE, tag);
|
||||
Input expected(DER_SEQUENCE_NOT_EMPTY_VALUE);
|
||||
ASSERT_TRUE(InputsAreEqual(expected, value));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ReadTagAndGetValue_Input_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Reader input(buf);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidWrongLength)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidHighTagNumberForm1)
|
||||
{
|
||||
// High tag number form is not allowed (illegal 1 byte tag)
|
||||
//
|
||||
// If the decoder treats 0x1F as a valid low tag number tag, then it will
|
||||
// treat the actual tag (1) as a length, and then it will return Success
|
||||
// with value == { 0x00 } and tag == 0x1f.
|
||||
//
|
||||
// It is illegal to encode tag 1 in the high tag number form because it isn't
|
||||
// the shortest encoding (the low tag number form is).
|
||||
static const uint8_t DER[] = {
|
||||
0x1F, // high tag number form indicator
|
||||
1, // tag 1 (not legal!)
|
||||
0 // length zero
|
||||
};
|
||||
Input buf(DER);
|
||||
Reader input(buf);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidHighTagNumberForm2)
|
||||
{
|
||||
// High tag number form is not allowed (legal 1 byte tag).
|
||||
//
|
||||
// ReadTagAndGetValue's check to prohibit the high tag number form has no
|
||||
// effect on whether this test passes or fails, because ReadTagAndGetValue
|
||||
// will interpret the second byte (31) as a length, and the input doesn't
|
||||
// have 31 bytes following it. This test is here to guard against the case
|
||||
// where somebody actually implements high tag number form parsing, to remind
|
||||
// that person that they need to add tests here, including in particular
|
||||
// tests for overly-long encodings.
|
||||
static const uint8_t DER[] = {
|
||||
0x1F, // high tag number form indicator
|
||||
31, // tag 31
|
||||
0 // length zero
|
||||
};
|
||||
Input buf(DER);
|
||||
Reader input(buf);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidHighTagNumberForm3)
|
||||
{
|
||||
// High tag number form is not allowed (2 byte legal tag)
|
||||
//
|
||||
// ReadTagAndGetValue's check to prohibit the high tag number form has no
|
||||
// effect on whether this test passes or fails, because ReadTagAndGetValue
|
||||
// will interpret the second byte as a length, and the input doesn't have
|
||||
// that many bytes following it. This test is here to guard against the case
|
||||
// where somebody actually implements high tag number form parsing, to remind
|
||||
// that person that they need to add tests here, including in particular
|
||||
// tests for overly-long encodings.
|
||||
static const uint8_t DER[] = {
|
||||
0x1F, // high tag number form indicator
|
||||
0x80 | 0x01, 0x00, // tag 0x100 (256)
|
||||
0 // length zero
|
||||
};
|
||||
Input buf(DER);
|
||||
Reader input(buf);
|
||||
uint8_t tag;
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ReadTagAndGetValue(input, tag, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_ValidEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_EMPTY);
|
||||
Reader input(buf);
|
||||
Reader value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_TRUE(value.AtEnd());
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_ValidNotEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
Reader value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_TRUE(value.MatchRest(DER_SEQUENCE_NOT_EMPTY_VALUE));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndGetValue_Reader_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Reader input(buf);
|
||||
Reader value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_InvalidWrongLength)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
Reader value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_InvalidWrongTag)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
Reader value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, INTEGER, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_EMPTY);
|
||||
Reader input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_EQ(0u, value.GetLength());
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidNotEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
Input expected(DER_SEQUENCE_NOT_EMPTY_VALUE);
|
||||
ASSERT_TRUE(InputsAreEqual(expected, value));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndGetValue_Input_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Reader input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_InvalidWrongLength)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_InvalidWrongTag)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, INTEGER, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_ValidEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_EMPTY);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Success, ExpectTagAndEmptyValue(input, SEQUENCE));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_InValidNotEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, SEQUENCE));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndEmptyValue_Input_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, SEQUENCE));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_InvalidWrongLength)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, SEQUENCE));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_InvalidWrongTag)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, INTEGER));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_ValidEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_EMPTY);
|
||||
Reader input(buf);
|
||||
Input tlv;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
Input expected(DER_SEQUENCE_EMPTY);
|
||||
ASSERT_TRUE(InputsAreEqual(expected, tlv));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_ValidNotEmpty)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
Input tlv;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
Input expected(DER_SEQUENCE_NOT_EMPTY);
|
||||
ASSERT_TRUE(InputsAreEqual(expected, tlv));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndGetTLV_Input_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Reader input(buf);
|
||||
Input tlv;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_InvalidWrongLength)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
Input tlv;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_InvalidWrongTag)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Reader input(buf);
|
||||
Input tlv;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, INTEGER, tlv));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, EndAtEnd)
|
||||
{
|
||||
Input buf(DER_INT16);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(4));
|
||||
ASSERT_EQ(Success, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, EndBeforeEnd)
|
||||
{
|
||||
Input buf(DER_INT16);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(2));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, EndAtBeginning)
|
||||
{
|
||||
Input buf(DER_INT16);
|
||||
Reader input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
|
||||
}
|
||||
|
||||
// TODO: Need tests for Nested too?
|
||||
|
||||
Result NestedOfHelper(Reader& input, std::vector<uint8_t>& readValues)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
Result rv = input.Read(value);
|
||||
EXPECT_EQ(Success, rv);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
readValues.push_back(value);
|
||||
return Success;
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, NestedOf)
|
||||
{
|
||||
Input buf(DER_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
|
||||
std::vector<uint8_t> readValues;
|
||||
ASSERT_EQ(Success,
|
||||
NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
|
||||
[&readValues](Reader& r) {
|
||||
return NestedOfHelper(r, readValues);
|
||||
}));
|
||||
ASSERT_EQ(3u, readValues.size());
|
||||
ASSERT_EQ(0x01, readValues[0]);
|
||||
ASSERT_EQ(0x02, readValues[1]);
|
||||
ASSERT_EQ(0x03, readValues[2]);
|
||||
ASSERT_EQ(Success, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, NestedOfWithTruncatedData)
|
||||
{
|
||||
Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Reader input(buf);
|
||||
|
||||
std::vector<uint8_t> readValues;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
|
||||
[&readValues](Reader& r) {
|
||||
return NestedOfHelper(r, readValues);
|
||||
}));
|
||||
ASSERT_EQ(0u, readValues.size());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRestAtEnd)
|
||||
{
|
||||
static const uint8_t der[1] = { };
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Reader input(buf);
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
static const uint8_t toMatch[] = { 1 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatch));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest1Match)
|
||||
{
|
||||
static const uint8_t der[] = { 1 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
ASSERT_TRUE(input.MatchRest(der));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest1Mismatch)
|
||||
{
|
||||
static const uint8_t der[] = { 1 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
static const uint8_t toMatch[] = { 2 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatch));
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest2WithTrailingByte)
|
||||
{
|
||||
static const uint8_t der[] = { 1, 2, 3 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
static const uint8_t toMatch[] = { 1, 2 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatch));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest2Mismatch)
|
||||
{
|
||||
static const uint8_t der[] = { 1, 2, 3 };
|
||||
Input buf(der);
|
||||
Reader input(buf);
|
||||
static const uint8_t toMatchMismatch[] = { 1, 3 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatchMismatch));
|
||||
ASSERT_TRUE(input.MatchRest(der));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
480
security/nss/gtests/mozpkix_gtest/pkixder_pki_types_tests.cpp
Normal file
480
security/nss/gtests/mozpkix_gtest/pkixder_pki_types_tests.cpp
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixtypes.h"
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::der;
|
||||
|
||||
class pkixder_pki_types_tests : public ::testing::Test { };
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, CertificateSerialNumber)
|
||||
{
|
||||
const uint8_t DER_CERT_SERIAL[] = {
|
||||
0x02, // INTEGER
|
||||
8, // length
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
|
||||
};
|
||||
Input input(DER_CERT_SERIAL);
|
||||
Reader reader(input);
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Success, CertificateSerialNumber(reader, item));
|
||||
|
||||
Input expected;
|
||||
ASSERT_EQ(Success,
|
||||
expected.Init(DER_CERT_SERIAL + 2, sizeof DER_CERT_SERIAL - 2));
|
||||
ASSERT_TRUE(InputsAreEqual(expected, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, CertificateSerialNumberLongest)
|
||||
{
|
||||
const uint8_t DER_CERT_SERIAL_LONGEST[] = {
|
||||
0x02, // INTEGER
|
||||
20, // length
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
|
||||
};
|
||||
Input input(DER_CERT_SERIAL_LONGEST);
|
||||
Reader reader(input);
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Success, CertificateSerialNumber(reader, item));
|
||||
|
||||
Input expected;
|
||||
ASSERT_EQ(Success,
|
||||
expected.Init(DER_CERT_SERIAL_LONGEST + 2,
|
||||
sizeof DER_CERT_SERIAL_LONGEST - 2));
|
||||
ASSERT_TRUE(InputsAreEqual(expected, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, CertificateSerialNumberCrazyLong)
|
||||
{
|
||||
const uint8_t DER_CERT_SERIAL_CRAZY_LONG[] = {
|
||||
0x02, // INTEGER
|
||||
32, // length
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
|
||||
};
|
||||
Input input(DER_CERT_SERIAL_CRAZY_LONG);
|
||||
Reader reader(input);
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Success, CertificateSerialNumber(reader, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, CertificateSerialNumberZeroLength)
|
||||
{
|
||||
const uint8_t DER_CERT_SERIAL_ZERO_LENGTH[] = {
|
||||
0x02, // INTEGER
|
||||
0x00 // length
|
||||
};
|
||||
Input input(DER_CERT_SERIAL_ZERO_LENGTH);
|
||||
Reader reader(input);
|
||||
|
||||
Input item;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_INTEGER_ENCODING,
|
||||
CertificateSerialNumber(reader, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, OptionalVersionV1ExplicitEncodingAllowed)
|
||||
{
|
||||
const uint8_t DER_OPTIONAL_VERSION_V1[] = {
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x00 // INTEGER(0)
|
||||
};
|
||||
Input input(DER_OPTIONAL_VERSION_V1);
|
||||
Reader reader(input);
|
||||
|
||||
// XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we
|
||||
// do here for compatibility reasons.
|
||||
// Version version;
|
||||
// ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version));
|
||||
der::Version version = der::Version::v3;
|
||||
ASSERT_EQ(Success, OptionalVersion(reader, version));
|
||||
ASSERT_EQ(der::Version::v1, version);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, OptionalVersionV2)
|
||||
{
|
||||
const uint8_t DER_OPTIONAL_VERSION_V2[] = {
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x01 // INTEGER(1)
|
||||
};
|
||||
Input input(DER_OPTIONAL_VERSION_V2);
|
||||
Reader reader(input);
|
||||
|
||||
der::Version version = der::Version::v1;
|
||||
ASSERT_EQ(Success, OptionalVersion(reader, version));
|
||||
ASSERT_EQ(der::Version::v2, version);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, OptionalVersionV3)
|
||||
{
|
||||
const uint8_t DER_OPTIONAL_VERSION_V3[] = {
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x02 // INTEGER(2)
|
||||
};
|
||||
Input input(DER_OPTIONAL_VERSION_V3);
|
||||
Reader reader(input);
|
||||
|
||||
der::Version version = der::Version::v1;
|
||||
ASSERT_EQ(Success, OptionalVersion(reader, version));
|
||||
ASSERT_EQ(der::Version::v3, version);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, OptionalVersionUnknown)
|
||||
{
|
||||
const uint8_t DER_OPTIONAL_VERSION_INVALID[] = {
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x42 // INTEGER(0x42)
|
||||
};
|
||||
Input input(DER_OPTIONAL_VERSION_INVALID);
|
||||
Reader reader(input);
|
||||
|
||||
der::Version version = der::Version::v1;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, OptionalVersionInvalidTooLong)
|
||||
{
|
||||
const uint8_t DER_OPTIONAL_VERSION_INVALID_TOO_LONG[] = {
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x02, 0x12, 0x34 // INTEGER(0x1234)
|
||||
};
|
||||
Input input(DER_OPTIONAL_VERSION_INVALID_TOO_LONG);
|
||||
Reader reader(input);
|
||||
|
||||
der::Version version;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, OptionalVersionMissing)
|
||||
{
|
||||
const uint8_t DER_OPTIONAL_VERSION_MISSING[] = {
|
||||
0x02, 0x11, 0x22 // INTEGER
|
||||
};
|
||||
Input input(DER_OPTIONAL_VERSION_MISSING);
|
||||
Reader reader(input);
|
||||
|
||||
der::Version version = der::Version::v3;
|
||||
ASSERT_EQ(Success, OptionalVersion(reader, version));
|
||||
ASSERT_EQ(der::Version::v1, version);
|
||||
}
|
||||
|
||||
static const size_t MAX_ALGORITHM_OID_DER_LENGTH = 13;
|
||||
|
||||
struct InvalidAlgorithmIdentifierTestInfo
|
||||
{
|
||||
uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH];
|
||||
size_t derLength;
|
||||
};
|
||||
|
||||
struct ValidDigestAlgorithmIdentifierTestInfo
|
||||
{
|
||||
DigestAlgorithm algorithm;
|
||||
uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH];
|
||||
size_t derLength;
|
||||
};
|
||||
|
||||
class pkixder_DigestAlgorithmIdentifier_Valid
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<ValidDigestAlgorithmIdentifierTestInfo>
|
||||
{
|
||||
};
|
||||
|
||||
static const ValidDigestAlgorithmIdentifierTestInfo
|
||||
VALID_DIGEST_ALGORITHM_TEST_INFO[] =
|
||||
{
|
||||
{ DigestAlgorithm::sha512,
|
||||
{ 0x30, 0x0b, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 },
|
||||
13
|
||||
},
|
||||
{ DigestAlgorithm::sha384,
|
||||
{ 0x30, 0x0b, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 },
|
||||
13
|
||||
},
|
||||
{ DigestAlgorithm::sha256,
|
||||
{ 0x30, 0x0b, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 },
|
||||
13
|
||||
},
|
||||
{ DigestAlgorithm::sha1,
|
||||
{ 0x30, 0x07, 0x06, 0x05,
|
||||
0x2b, 0x0e, 0x03, 0x02, 0x1a },
|
||||
9
|
||||
},
|
||||
};
|
||||
|
||||
TEST_P(pkixder_DigestAlgorithmIdentifier_Valid, Valid)
|
||||
{
|
||||
const ValidDigestAlgorithmIdentifierTestInfo& param(GetParam());
|
||||
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(param.der, param.derLength));
|
||||
Reader reader(input);
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Success, DigestAlgorithmIdentifier(reader, alg));
|
||||
ASSERT_EQ(param.algorithm, alg);
|
||||
ASSERT_EQ(Success, End(reader));
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t derWithNullParam[MAX_ALGORITHM_OID_DER_LENGTH + 2];
|
||||
memcpy(derWithNullParam, param.der, param.derLength);
|
||||
derWithNullParam[1] += 2; // we're going to expand the value by 2 bytes
|
||||
derWithNullParam[param.derLength] = 0x05; // NULL tag
|
||||
derWithNullParam[param.derLength + 1] = 0x00; // length zero
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2));
|
||||
Reader reader(input);
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Success, DigestAlgorithmIdentifier(reader, alg));
|
||||
ASSERT_EQ(param.algorithm, alg);
|
||||
ASSERT_EQ(Success, End(reader));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixder_DigestAlgorithmIdentifier_Valid,
|
||||
pkixder_DigestAlgorithmIdentifier_Valid,
|
||||
testing::ValuesIn(VALID_DIGEST_ALGORITHM_TEST_INFO));
|
||||
|
||||
class pkixder_DigestAlgorithmIdentifier_Invalid
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<InvalidAlgorithmIdentifierTestInfo>
|
||||
{
|
||||
};
|
||||
|
||||
static const InvalidAlgorithmIdentifierTestInfo
|
||||
INVALID_DIGEST_ALGORITHM_TEST_INFO[] =
|
||||
{
|
||||
{ // MD5
|
||||
{ 0x30, 0x0a, 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05 },
|
||||
12,
|
||||
},
|
||||
{ // ecdsa-with-SHA256 (1.2.840.10045.4.3.2) (not a hash algorithm)
|
||||
{ 0x30, 0x0a, 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 },
|
||||
12,
|
||||
},
|
||||
};
|
||||
|
||||
TEST_P(pkixder_DigestAlgorithmIdentifier_Invalid, Invalid)
|
||||
{
|
||||
const InvalidAlgorithmIdentifierTestInfo& param(GetParam());
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(param.der, param.derLength));
|
||||
Reader reader(input);
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM,
|
||||
DigestAlgorithmIdentifier(reader, alg));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixder_DigestAlgorithmIdentifier_Invalid,
|
||||
pkixder_DigestAlgorithmIdentifier_Invalid,
|
||||
testing::ValuesIn(INVALID_DIGEST_ALGORITHM_TEST_INFO));
|
||||
|
||||
struct ValidSignatureAlgorithmIdentifierValueTestInfo
|
||||
{
|
||||
PublicKeyAlgorithm publicKeyAlg;
|
||||
DigestAlgorithm digestAlg;
|
||||
uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH];
|
||||
size_t derLength;
|
||||
};
|
||||
|
||||
static const ValidSignatureAlgorithmIdentifierValueTestInfo
|
||||
VALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO[] =
|
||||
{
|
||||
// ECDSA
|
||||
{ PublicKeyAlgorithm::ECDSA,
|
||||
DigestAlgorithm::sha512,
|
||||
{ 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04 },
|
||||
10,
|
||||
},
|
||||
{ PublicKeyAlgorithm::ECDSA,
|
||||
DigestAlgorithm::sha384,
|
||||
{ 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03 },
|
||||
10,
|
||||
},
|
||||
{ PublicKeyAlgorithm::ECDSA,
|
||||
DigestAlgorithm::sha256,
|
||||
{ 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 },
|
||||
10,
|
||||
},
|
||||
{ PublicKeyAlgorithm::ECDSA,
|
||||
DigestAlgorithm::sha1,
|
||||
{ 0x06, 0x07,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01 },
|
||||
9,
|
||||
},
|
||||
|
||||
// RSA
|
||||
{ PublicKeyAlgorithm::RSA_PKCS1,
|
||||
DigestAlgorithm::sha512,
|
||||
{ 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d },
|
||||
11,
|
||||
},
|
||||
{ PublicKeyAlgorithm::RSA_PKCS1,
|
||||
DigestAlgorithm::sha384,
|
||||
{ 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c },
|
||||
11,
|
||||
},
|
||||
{ PublicKeyAlgorithm::RSA_PKCS1,
|
||||
DigestAlgorithm::sha256,
|
||||
{ 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b },
|
||||
11,
|
||||
},
|
||||
{ PublicKeyAlgorithm::RSA_PKCS1,
|
||||
DigestAlgorithm::sha1,
|
||||
// IETF Standard OID
|
||||
{ 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05 },
|
||||
11,
|
||||
},
|
||||
{ PublicKeyAlgorithm::RSA_PKCS1,
|
||||
DigestAlgorithm::sha1,
|
||||
// Legacy OIW OID (bug 1042479)
|
||||
{ 0x06, 0x05,
|
||||
0x2b, 0x0e, 0x03, 0x02, 0x1d },
|
||||
7,
|
||||
},
|
||||
};
|
||||
|
||||
class pkixder_SignatureAlgorithmIdentifierValue_Valid
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<
|
||||
ValidSignatureAlgorithmIdentifierValueTestInfo>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(pkixder_SignatureAlgorithmIdentifierValue_Valid, Valid)
|
||||
{
|
||||
const ValidSignatureAlgorithmIdentifierValueTestInfo& param(GetParam());
|
||||
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(param.der, param.derLength));
|
||||
Reader reader(input);
|
||||
PublicKeyAlgorithm publicKeyAlg;
|
||||
DigestAlgorithm digestAlg;
|
||||
ASSERT_EQ(Success,
|
||||
SignatureAlgorithmIdentifierValue(reader, publicKeyAlg,
|
||||
digestAlg));
|
||||
ASSERT_EQ(param.publicKeyAlg, publicKeyAlg);
|
||||
ASSERT_EQ(param.digestAlg, digestAlg);
|
||||
ASSERT_EQ(Success, End(reader));
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t derWithNullParam[MAX_ALGORITHM_OID_DER_LENGTH + 2];
|
||||
memcpy(derWithNullParam, param.der, param.derLength);
|
||||
derWithNullParam[param.derLength] = 0x05; // NULL tag
|
||||
derWithNullParam[param.derLength + 1] = 0x00; // length zero
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2));
|
||||
Reader reader(input);
|
||||
PublicKeyAlgorithm publicKeyAlg;
|
||||
DigestAlgorithm digestAlg;
|
||||
ASSERT_EQ(Success,
|
||||
SignatureAlgorithmIdentifierValue(reader, publicKeyAlg,
|
||||
digestAlg));
|
||||
ASSERT_EQ(param.publicKeyAlg, publicKeyAlg);
|
||||
ASSERT_EQ(param.digestAlg, digestAlg);
|
||||
ASSERT_EQ(Success, End(reader));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
pkixder_SignatureAlgorithmIdentifierValue_Valid,
|
||||
pkixder_SignatureAlgorithmIdentifierValue_Valid,
|
||||
testing::ValuesIn(VALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO));
|
||||
|
||||
static const InvalidAlgorithmIdentifierTestInfo
|
||||
INVALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO[] =
|
||||
{
|
||||
// id-dsa-with-sha256 (2.16.840.1.101.3.4.3.2)
|
||||
{ { 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x02 },
|
||||
11,
|
||||
},
|
||||
|
||||
// id-dsa-with-sha1 (1.2.840.10040.4.3)
|
||||
{ { 0x06, 0x07,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x03 },
|
||||
9,
|
||||
},
|
||||
|
||||
// RSA-with-MD5 (1.2.840.113549.1.1.4)
|
||||
{ { 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04 },
|
||||
11,
|
||||
},
|
||||
|
||||
// id-sha256 (2.16.840.1.101.3.4.2.1). It is invalid because SHA-256 is not
|
||||
// a signature algorithm.
|
||||
{ { 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 },
|
||||
11,
|
||||
},
|
||||
};
|
||||
|
||||
class pkixder_SignatureAlgorithmIdentifier_Invalid
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<InvalidAlgorithmIdentifierTestInfo>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(pkixder_SignatureAlgorithmIdentifier_Invalid, Invalid)
|
||||
{
|
||||
const InvalidAlgorithmIdentifierTestInfo& param(GetParam());
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(param.der, param.derLength));
|
||||
Reader reader(input);
|
||||
der::PublicKeyAlgorithm publicKeyAlg;
|
||||
DigestAlgorithm digestAlg;
|
||||
ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
SignatureAlgorithmIdentifierValue(reader, publicKeyAlg, digestAlg));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
pkixder_SignatureAlgorithmIdentifier_Invalid,
|
||||
pkixder_SignatureAlgorithmIdentifier_Invalid,
|
||||
testing::ValuesIn(INVALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO));
|
||||
1226
security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp
Normal file
1226
security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp
Normal file
File diff suppressed because it is too large
Load diff
46
security/nss/gtests/mozpkix_gtest/pkixgtest.cpp
Normal file
46
security/nss/gtests/mozpkix_gtest/pkixgtest.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "mozpkix/Time.h"
|
||||
|
||||
namespace mozilla { namespace pkix { namespace test {
|
||||
|
||||
static const std::time_t ONE_DAY_IN_SECONDS_AS_TIME_T =
|
||||
static_cast<std::time_t>(Time::ONE_DAY_IN_SECONDS);
|
||||
|
||||
// This assumes that time/time_t are POSIX-compliant in that time() returns
|
||||
// the number of seconds since the Unix epoch.
|
||||
static const std::time_t now(time(nullptr));
|
||||
const std::time_t oneDayBeforeNow(now - ONE_DAY_IN_SECONDS_AS_TIME_T);
|
||||
const std::time_t oneDayAfterNow(now + ONE_DAY_IN_SECONDS_AS_TIME_T);
|
||||
const std::time_t twoDaysBeforeNow(now - (2 * ONE_DAY_IN_SECONDS_AS_TIME_T));
|
||||
const std::time_t twoDaysAfterNow(now + (2 * ONE_DAY_IN_SECONDS_AS_TIME_T));
|
||||
const std::time_t tenDaysBeforeNow(now - (10 * ONE_DAY_IN_SECONDS_AS_TIME_T));
|
||||
const std::time_t tenDaysAfterNow(now + (10 * ONE_DAY_IN_SECONDS_AS_TIME_T));
|
||||
|
||||
} } } // namespace mozilla::pkix::test
|
||||
229
security/nss/gtests/mozpkix_gtest/pkixgtest.h
Normal file
229
security/nss/gtests/mozpkix_gtest/pkixgtest.h
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 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_pkixgtest_h
|
||||
#define mozilla_pkix_pkixgtest_h
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
#pragma clang diagnostic ignored "-Wmissing-noreturn"
|
||||
#pragma clang diagnostic ignored "-Wshift-sign-overflow"
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
||||
#pragma clang diagnostic ignored "-Wundef"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(push, 3)
|
||||
// C4224: Nonstandard extension used: formal parameter 'X' was previously
|
||||
// defined as a type.
|
||||
#pragma warning(disable : 4224)
|
||||
// C4826: Conversion from 'type1 ' to 'type_2' is sign - extended. This may
|
||||
// cause unexpected runtime behavior.
|
||||
#pragma warning(disable : 4826)
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "mozpkix/pkix.h"
|
||||
#include "mozpkix/test/pkixtestutil.h"
|
||||
|
||||
// PrintTo must be in the same namespace as the type we're overloading it for.
|
||||
namespace mozilla {
|
||||
namespace pkix {
|
||||
|
||||
inline void PrintTo(const Result& result, ::std::ostream* os) {
|
||||
const char* stringified = MapResultToName(result);
|
||||
if (stringified) {
|
||||
*os << stringified;
|
||||
} else {
|
||||
*os << "mozilla::pkix::Result(" << static_cast<unsigned int>(result) << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix
|
||||
|
||||
namespace mozilla {
|
||||
namespace pkix {
|
||||
namespace test {
|
||||
|
||||
extern const std::time_t oneDayBeforeNow;
|
||||
extern const std::time_t oneDayAfterNow;
|
||||
extern const std::time_t twoDaysBeforeNow;
|
||||
extern const std::time_t twoDaysAfterNow;
|
||||
extern const std::time_t tenDaysBeforeNow;
|
||||
extern const std::time_t tenDaysAfterNow;
|
||||
|
||||
class EverythingFailsByDefaultTrustDomain : public TrustDomain {
|
||||
public:
|
||||
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
|
||||
/*out*/ TrustLevel&) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("GetCertTrust should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result FindIssuer(Input, IssuerChecker&, Time) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("FindIssuer should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
/*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("CheckRevocation should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("IsChainValid should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result DigestBuf(Input, DigestAlgorithm, /*out*/ uint8_t*, size_t) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("DigestBuf should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result CheckSignatureDigestAlgorithm(DigestAlgorithm, EndEntityOrCA,
|
||||
Time) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("CheckSignatureDigestAlgorithm should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("CheckECDSACurveIsAcceptable should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("VerifyECDSASignedDigest should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA,
|
||||
unsigned int) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("CheckRSAPublicKeyModulusSizeInBits should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("VerifyRSAPKCS1SignedDigest should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result CheckValidityIsAcceptable(Time, Time, EndEntityOrCA,
|
||||
KeyPurposeId) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("CheckValidityIsAcceptable should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result NetscapeStepUpMatchesServerAuth(Time, bool&) override {
|
||||
ADD_FAILURE();
|
||||
return NotReached("NetscapeStepUpMatchesServerAuth should not be called",
|
||||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
virtual void NoteAuxiliaryExtension(AuxiliaryExtension, Input) override {
|
||||
ADD_FAILURE();
|
||||
}
|
||||
};
|
||||
|
||||
class DefaultCryptoTrustDomain : public EverythingFailsByDefaultTrustDomain {
|
||||
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
|
||||
/*out*/ uint8_t* digestBuf, size_t digestBufLen) override {
|
||||
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
|
||||
}
|
||||
|
||||
Result CheckSignatureDigestAlgorithm(DigestAlgorithm, EndEntityOrCA,
|
||||
Time) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo) override {
|
||||
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
|
||||
}
|
||||
|
||||
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA,
|
||||
unsigned int) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo) override {
|
||||
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
|
||||
}
|
||||
|
||||
Result CheckValidityIsAcceptable(Time, Time, EndEntityOrCA,
|
||||
KeyPurposeId) override {
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result NetscapeStepUpMatchesServerAuth(Time, /*out*/ bool& matches) override {
|
||||
matches = true;
|
||||
return Success;
|
||||
}
|
||||
|
||||
void NoteAuxiliaryExtension(AuxiliaryExtension, Input) override {}
|
||||
};
|
||||
|
||||
class DefaultNameMatchingPolicy : public NameMatchingPolicy {
|
||||
public:
|
||||
virtual Result FallBackToCommonName(
|
||||
Time,
|
||||
/*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) override {
|
||||
fallBackToCommonName = FallBackToSearchWithinSubject::Yes;
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::pkix::test
|
||||
|
||||
#endif // mozilla_pkix_pkixgtest_h
|
||||
2838
security/nss/gtests/mozpkix_gtest/pkixnames_tests.cpp
Normal file
2838
security/nss/gtests/mozpkix_gtest/pkixnames_tests.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
/* Copyright 2013 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "pkixgtest.h"
|
||||
|
||||
#include "mozpkix/pkixder.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
class CreateEncodedOCSPRequestTrustDomain final
|
||||
: public EverythingFailsByDefaultTrustDomain
|
||||
{
|
||||
private:
|
||||
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
|
||||
/*out*/ uint8_t *digestBuf, size_t digestBufLen)
|
||||
override
|
||||
{
|
||||
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
|
||||
}
|
||||
|
||||
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
|
||||
override
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
|
||||
class pkixocsp_CreateEncodedOCSPRequest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void MakeIssuerCertIDComponents(const char* issuerASCII,
|
||||
/*out*/ ByteString& issuerDER,
|
||||
/*out*/ ByteString& issuerSPKI)
|
||||
{
|
||||
issuerDER = CNToDERName(issuerASCII);
|
||||
ASSERT_FALSE(ENCODING_FAILED(issuerDER));
|
||||
|
||||
ScopedTestKeyPair keyPair(GenerateKeyPair());
|
||||
ASSERT_TRUE(keyPair.get());
|
||||
issuerSPKI = keyPair->subjectPublicKeyInfo;
|
||||
}
|
||||
|
||||
CreateEncodedOCSPRequestTrustDomain trustDomain;
|
||||
};
|
||||
|
||||
// Test that the large length of the child serial number causes
|
||||
// CreateEncodedOCSPRequest to fail.
|
||||
TEST_F(pkixocsp_CreateEncodedOCSPRequest, ChildCertLongSerialNumberTest)
|
||||
{
|
||||
static const uint8_t UNSUPPORTED_LEN = 128; // must be larger than 127
|
||||
|
||||
ByteString serialNumberString;
|
||||
// tag + length + value is 1 + 2 + UNSUPPORTED_LEN
|
||||
// Encoding the length takes two bytes: one byte to indicate that a
|
||||
// second byte follows, and the second byte to indicate the length.
|
||||
serialNumberString.push_back(0x80 + 1);
|
||||
serialNumberString.push_back(UNSUPPORTED_LEN);
|
||||
// value is 0x010000...00
|
||||
serialNumberString.push_back(0x01);
|
||||
for (size_t i = 1; i < UNSUPPORTED_LEN; ++i) {
|
||||
serialNumberString.push_back(0x00);
|
||||
}
|
||||
|
||||
ByteString issuerDER;
|
||||
ByteString issuerSPKI;
|
||||
ASSERT_NO_FATAL_FAILURE(MakeIssuerCertIDComponents("CA", issuerDER,
|
||||
issuerSPKI));
|
||||
|
||||
Input issuer;
|
||||
ASSERT_EQ(Success, issuer.Init(issuerDER.data(), issuerDER.length()));
|
||||
|
||||
Input spki;
|
||||
ASSERT_EQ(Success, spki.Init(issuerSPKI.data(), issuerSPKI.length()));
|
||||
|
||||
Input serialNumber;
|
||||
ASSERT_EQ(Success, serialNumber.Init(serialNumberString.data(),
|
||||
serialNumberString.length()));
|
||||
|
||||
uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
|
||||
size_t ocspRequestLength;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
CreateEncodedOCSPRequest(trustDomain,
|
||||
CertID(issuer, spki, serialNumber),
|
||||
ocspRequest, ocspRequestLength));
|
||||
}
|
||||
|
||||
// Test that CreateEncodedOCSPRequest handles the longest serial number that
|
||||
// it's required to support (i.e. 20 octets).
|
||||
TEST_F(pkixocsp_CreateEncodedOCSPRequest, LongestSupportedSerialNumberTest)
|
||||
{
|
||||
static const uint8_t LONGEST_REQUIRED_LEN = 20;
|
||||
|
||||
ByteString serialNumberString;
|
||||
// tag + length + value is 1 + 1 + LONGEST_REQUIRED_LEN
|
||||
serialNumberString.push_back(der::INTEGER);
|
||||
serialNumberString.push_back(LONGEST_REQUIRED_LEN);
|
||||
serialNumberString.push_back(0x01);
|
||||
// value is 0x010000...00
|
||||
for (size_t i = 1; i < LONGEST_REQUIRED_LEN; ++i) {
|
||||
serialNumberString.push_back(0x00);
|
||||
}
|
||||
|
||||
ByteString issuerDER;
|
||||
ByteString issuerSPKI;
|
||||
ASSERT_NO_FATAL_FAILURE(MakeIssuerCertIDComponents("CA", issuerDER,
|
||||
issuerSPKI));
|
||||
|
||||
Input issuer;
|
||||
ASSERT_EQ(Success, issuer.Init(issuerDER.data(), issuerDER.length()));
|
||||
|
||||
Input spki;
|
||||
ASSERT_EQ(Success, spki.Init(issuerSPKI.data(), issuerSPKI.length()));
|
||||
|
||||
Input serialNumber;
|
||||
ASSERT_EQ(Success, serialNumber.Init(serialNumberString.data(),
|
||||
serialNumberString.length()));
|
||||
|
||||
uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
|
||||
size_t ocspRequestLength;
|
||||
ASSERT_EQ(Success,
|
||||
CreateEncodedOCSPRequest(trustDomain,
|
||||
CertID(issuer, spki, serialNumber),
|
||||
ocspRequest, ocspRequestLength));
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue