Bug 1943761 - Add class alignment to the mozsearch analysis file. r=asuth
[gecko.git] / security / ct / tests / gtest / CTPolicyEnforcerTest.cpp
blobc6cb165700c4754a39fd4df81381fe901d74392a
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"
9 #include <algorithm>
10 #include <stdint.h>
11 #include <stdio.h>
13 #include "CTLogVerifier.h"
14 #include "CTVerifyResult.h"
15 #include "SignedCertificateTimestamp.h"
16 #include "mozpkix/Time.h"
17 #include "gtest/gtest.h"
18 #include "hasht.h"
19 #include "prtime.h"
21 namespace mozilla {
22 namespace ct {
24 using namespace mozilla::pkix;
26 class CTPolicyEnforcerTest : public ::testing::Test {
27 public:
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;
42 Buffer logId;
43 GetLogId(logId, logNo);
44 sct.logId = std::move(logId);
45 VerifiedSCT verifiedSct(std::move(sct), origin, operatorId, logState,
46 LOG_TIMESTAMP);
47 verifiedScts.push_back(std::move(verifiedSct));
50 void AddMultipleScts(VerifiedSCTList& verifiedScts, size_t logsCount,
51 uint8_t operatorsCount, SCTOrigin origin,
52 uint64_t timestamp,
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);
68 protected:
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) {
98 VerifiedSCTList scts;
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.
175 scts.clear();
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.
181 scts.clear();
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.
188 scts.clear();
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.
195 scts.clear();
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;
244 // Operator #1
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;
261 size_t sctsRequired;
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) {
268 SCOPED_TRACE(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;
275 ++sctsAvailable) {
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;
295 } // namespace ct
296 } // namespace mozilla