1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "CTPolicyEnforcer.h"
13 #include "CTLogVerifier.h"
14 #include "CTVerifyResult.h"
15 #include "SignedCertificateTimestamp.h"
16 #include "mozpkix/Time.h"
17 #include "gtest/gtest.h"
24 using namespace mozilla::pkix
;
26 class CTPolicyEnforcerTest
: public ::testing::Test
{
28 void GetLogId(Buffer
& logId
, size_t logNo
) {
29 logId
.resize(SHA256_LENGTH
);
30 std::fill(logId
.begin(), logId
.end(), 0);
31 // Just raw-copy |logId| into the output buffer.
32 assert(sizeof(logNo
) <= logId
.size());
33 memcpy(logId
.data(), &logNo
, sizeof(logNo
));
36 void AddSct(VerifiedSCTList
& verifiedScts
, size_t logNo
,
37 CTLogOperatorId operatorId
, SCTOrigin origin
, uint64_t timestamp
,
38 CTLogState logState
= CTLogState::Admissible
) {
39 SignedCertificateTimestamp sct
;
40 sct
.version
= SignedCertificateTimestamp::Version::V1
;
41 sct
.timestamp
= timestamp
;
43 GetLogId(logId
, logNo
);
44 sct
.logId
= std::move(logId
);
45 VerifiedSCT
verifiedSct(std::move(sct
), origin
, operatorId
, logState
,
47 verifiedScts
.push_back(std::move(verifiedSct
));
50 void AddMultipleScts(VerifiedSCTList
& verifiedScts
, size_t logsCount
,
51 uint8_t operatorsCount
, SCTOrigin origin
,
53 CTLogState logState
= CTLogState::Admissible
) {
54 for (size_t logNo
= 0; logNo
< logsCount
; logNo
++) {
55 CTLogOperatorId operatorId
= logNo
% operatorsCount
;
56 AddSct(verifiedScts
, logNo
, operatorId
, origin
, timestamp
, logState
);
60 void CheckCompliance(const VerifiedSCTList
& verifiedSct
,
61 Duration certLifetime
,
62 CTPolicyCompliance expectedCompliance
) {
63 CTPolicyCompliance compliance
=
64 CheckCTPolicyCompliance(verifiedSct
, certLifetime
);
65 EXPECT_EQ(expectedCompliance
, compliance
);
69 const size_t LOG_1
= 1;
70 const size_t LOG_2
= 2;
71 const size_t LOG_3
= 3;
73 const CTLogOperatorId OPERATOR_1
= 1;
74 const CTLogOperatorId OPERATOR_2
= 2;
75 const CTLogOperatorId OPERATOR_3
= 3;
77 const SCTOrigin ORIGIN_EMBEDDED
= SCTOrigin::Embedded
;
78 const SCTOrigin ORIGIN_TLS
= SCTOrigin::TLSExtension
;
79 const SCTOrigin ORIGIN_OCSP
= SCTOrigin::OCSPResponse
;
81 // 1 year of cert lifetime requires 3 SCTs for the embedded case.
82 const Duration DEFAULT_LIFETIME
= Duration(365 * Time::ONE_DAY_IN_SECONDS
);
84 // Date.parse("2015-08-15T00:00:00Z")
85 const uint64_t TIMESTAMP_1
= 1439596800000L;
87 // Date.parse("2016-04-15T00:00:00Z")
88 const uint64_t LOG_TIMESTAMP
= 1460678400000L;
90 // Date.parse("2016-04-01T00:00:00Z")
91 const uint64_t BEFORE_RETIREMENT
= 1459468800000L;
93 // Date.parse("2016-04-16T00:00:00Z")
94 const uint64_t AFTER_RETIREMENT
= 1460764800000L;
97 TEST_F(CTPolicyEnforcerTest
, ConformsToCTPolicyWithNonEmbeddedSCTs
) {
100 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
101 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_TLS
, TIMESTAMP_1
);
103 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::Compliant
);
106 TEST_F(CTPolicyEnforcerTest
, DoesNotConformNotEnoughDiverseNonEmbeddedSCTs
) {
107 VerifiedSCTList scts
;
109 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
110 AddSct(scts
, LOG_2
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
112 // The implementation attempts to fulfill the non-embedded compliance case
113 // first. Because the non-embedded SCTs do not have enough log diversity, the
114 // implementation then attempts to fulfill the embedded compliance case.
115 // Because there are no embedded SCTs, it returns a "not enough SCTs" error.
116 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
119 TEST_F(CTPolicyEnforcerTest
, ConformsToCTPolicyWithEmbeddedSCTs
) {
120 VerifiedSCTList scts
;
122 // 3 embedded SCTs required for DEFAULT_LIFETIME.
123 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
124 AddSct(scts
, LOG_2
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
125 AddSct(scts
, LOG_3
, OPERATOR_2
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
127 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::Compliant
);
130 TEST_F(CTPolicyEnforcerTest
, DoesNotConformNotEnoughDiverseEmbeddedSCTs
) {
131 VerifiedSCTList scts
;
133 // 3 embedded SCTs required for DEFAULT_LIFETIME.
134 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
135 AddSct(scts
, LOG_2
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
136 AddSct(scts
, LOG_3
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
138 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotDiverseScts
);
141 TEST_F(CTPolicyEnforcerTest
, ConformsToCTPolicyWithPooledNonEmbeddedSCTs
) {
142 VerifiedSCTList scts
;
144 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_OCSP
, TIMESTAMP_1
);
145 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_TLS
, TIMESTAMP_1
);
147 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::Compliant
);
150 TEST_F(CTPolicyEnforcerTest
, DoesNotConformToCTPolicyWithPooledEmbeddedSCTs
) {
151 VerifiedSCTList scts
;
153 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
154 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_OCSP
, TIMESTAMP_1
);
156 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
159 TEST_F(CTPolicyEnforcerTest
, DoesNotConformToCTPolicyNotEnoughSCTs
) {
160 VerifiedSCTList scts
;
162 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
163 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
165 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
168 TEST_F(CTPolicyEnforcerTest
, DoesNotConformToCTPolicyNotEnoughFreshSCTs
) {
169 VerifiedSCTList scts
;
171 // The results should be the same before and after disqualification,
172 // regardless of the delivery method.
174 // SCT from before disqualification.
176 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
177 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_TLS
, BEFORE_RETIREMENT
,
178 CTLogState::Retired
);
179 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
180 // SCT from after disqualification.
182 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
183 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_TLS
, AFTER_RETIREMENT
,
184 CTLogState::Retired
);
185 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
187 // Embedded SCT from before disqualification.
189 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
190 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_EMBEDDED
, BEFORE_RETIREMENT
,
191 CTLogState::Retired
);
192 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
194 // Embedded SCT from after disqualification.
196 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_TLS
, TIMESTAMP_1
);
197 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_EMBEDDED
, AFTER_RETIREMENT
,
198 CTLogState::Retired
);
199 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
202 TEST_F(CTPolicyEnforcerTest
, ConformsWithRetiredLogBeforeDisqualificationDate
) {
203 VerifiedSCTList scts
;
205 // 3 embedded SCTs required for DEFAULT_LIFETIME.
206 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
207 AddSct(scts
, LOG_2
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
208 AddSct(scts
, LOG_3
, OPERATOR_2
, ORIGIN_EMBEDDED
, BEFORE_RETIREMENT
,
209 CTLogState::Retired
);
211 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::Compliant
);
214 TEST_F(CTPolicyEnforcerTest
,
215 DoesNotConformWithRetiredLogAfterDisqualificationDate
) {
216 VerifiedSCTList scts
;
218 // 3 embedded SCTs required for DEFAULT_LIFETIME.
219 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
220 AddSct(scts
, LOG_2
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
221 AddSct(scts
, LOG_3
, OPERATOR_2
, ORIGIN_EMBEDDED
, AFTER_RETIREMENT
,
222 CTLogState::Retired
);
224 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
227 TEST_F(CTPolicyEnforcerTest
,
228 DoesNotConformWithIssuanceDateAfterDisqualificationDate
) {
229 VerifiedSCTList scts
;
231 // 3 embedded SCTs required for DEFAULT_LIFETIME.
232 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, AFTER_RETIREMENT
,
233 CTLogState::Retired
);
234 AddSct(scts
, LOG_2
, OPERATOR_1
, ORIGIN_EMBEDDED
, AFTER_RETIREMENT
);
235 AddSct(scts
, LOG_3
, OPERATOR_2
, ORIGIN_EMBEDDED
, AFTER_RETIREMENT
);
237 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotEnoughScts
);
240 TEST_F(CTPolicyEnforcerTest
,
241 DoesNotConformToCTPolicyNotEnoughUniqueEmbeddedRetiredLogs
) {
242 VerifiedSCTList scts
;
245 AddSct(scts
, LOG_1
, OPERATOR_1
, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
246 // Operator #2, same retired logs
247 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_EMBEDDED
, BEFORE_RETIREMENT
,
248 CTLogState::Retired
);
249 AddSct(scts
, LOG_2
, OPERATOR_2
, ORIGIN_EMBEDDED
, BEFORE_RETIREMENT
,
250 CTLogState::Retired
);
252 // 3 embedded SCTs required. However, only 2 are from distinct logs.
253 CheckCompliance(scts
, DEFAULT_LIFETIME
, CTPolicyCompliance::NotDiverseScts
);
256 TEST_F(CTPolicyEnforcerTest
,
257 ConformsToPolicyExactNumberOfSCTsForValidityPeriod
) {
258 // Test multiple validity periods.
259 const struct TestData
{
260 Duration certLifetime
;
262 } kTestData
[] = {{Duration(90 * Time::ONE_DAY_IN_SECONDS
), 2},
263 {Duration(180 * Time::ONE_DAY_IN_SECONDS
), 2},
264 {Duration(181 * Time::ONE_DAY_IN_SECONDS
), 3},
265 {Duration(365 * Time::ONE_DAY_IN_SECONDS
), 3}};
267 for (size_t i
= 0; i
< MOZILLA_CT_ARRAY_LENGTH(kTestData
); ++i
) {
270 Duration certLifetime
= kTestData
[i
].certLifetime
;
271 size_t sctsRequired
= kTestData
[i
].sctsRequired
;
273 // Less SCTs than required is not enough.
274 for (size_t sctsAvailable
= 0; sctsAvailable
< sctsRequired
;
276 VerifiedSCTList scts
;
277 AddMultipleScts(scts
, sctsAvailable
, 1, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
279 CTPolicyCompliance compliance
=
280 CheckCTPolicyCompliance(scts
, certLifetime
);
281 EXPECT_EQ(CTPolicyCompliance::NotEnoughScts
, compliance
)
282 << "i=" << i
<< " sctsRequired=" << sctsRequired
283 << " sctsAvailable=" << sctsAvailable
;
286 // Add exactly the required number of SCTs (from 2 operators).
287 VerifiedSCTList scts
;
288 AddMultipleScts(scts
, sctsRequired
, 2, ORIGIN_EMBEDDED
, TIMESTAMP_1
);
290 CTPolicyCompliance compliance
= CheckCTPolicyCompliance(scts
, certLifetime
);
291 EXPECT_EQ(CTPolicyCompliance::Compliant
, compliance
) << "i=" << i
;
296 } // namespace mozilla