CTPolicyEnforcerTest.cpp (14320B)
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/. */ 6 7 #include "CTPolicyEnforcer.h" 8 9 #include <algorithm> 10 #include <stdint.h> 11 12 #include "CTLogVerifier.h" 13 #include "CTVerifyResult.h" 14 #include "SignedCertificateTimestamp.h" 15 #include "mozpkix/Time.h" 16 #include "gtest/gtest.h" 17 #include "hasht.h" 18 #include "prtime.h" 19 20 namespace mozilla { 21 namespace ct { 22 23 using namespace mozilla::pkix; 24 25 class CTPolicyEnforcerTest : public ::testing::Test { 26 public: 27 void GetLogId(Buffer& logId, size_t logNo) { 28 logId.resize(SHA256_LENGTH); 29 std::fill(logId.begin(), logId.end(), 0); 30 // Just raw-copy |logId| into the output buffer. 31 assert(sizeof(logNo) <= logId.size()); 32 memcpy(logId.data(), &logNo, sizeof(logNo)); 33 } 34 35 void AddSct(VerifiedSCTList& verifiedScts, size_t logNo, 36 CTLogOperatorId operatorId, SCTOrigin origin, uint64_t timestamp, 37 CTLogState logState = CTLogState::Admissible, 38 CTLogFormat logFormat = CTLogFormat::RFC6962, 39 Maybe<uint64_t> leafIndex = Nothing()) { 40 SignedCertificateTimestamp sct; 41 sct.version = SignedCertificateTimestamp::Version::V1; 42 sct.timestamp = timestamp; 43 sct.leafIndex = leafIndex; 44 Buffer logId; 45 GetLogId(logId, logNo); 46 sct.logId = std::move(logId); 47 VerifiedSCT verifiedSct(std::move(sct), origin, operatorId, logState, 48 logFormat, LOG_TIMESTAMP); 49 verifiedScts.push_back(std::move(verifiedSct)); 50 } 51 52 void AddMultipleScts(VerifiedSCTList& verifiedScts, size_t logsCount, 53 uint8_t operatorsCount, SCTOrigin origin, 54 uint64_t timestamp, 55 CTLogState logState = CTLogState::Admissible, 56 CTLogFormat logFormat = CTLogFormat::RFC6962) { 57 for (size_t logNo = 0; logNo < logsCount; logNo++) { 58 CTLogOperatorId operatorId = logNo % operatorsCount; 59 AddSct(verifiedScts, logNo, operatorId, origin, timestamp, logState, 60 logFormat); 61 } 62 } 63 64 void CheckCompliance(const VerifiedSCTList& verifiedSct, 65 Duration certLifetime, 66 CTPolicyCompliance expectedCompliance) { 67 CTPolicyCompliance compliance = 68 CheckCTPolicyCompliance(verifiedSct, certLifetime); 69 EXPECT_EQ(expectedCompliance, compliance); 70 } 71 72 protected: 73 const size_t LOG_1 = 1; 74 const size_t LOG_2 = 2; 75 const size_t LOG_3 = 3; 76 77 const CTLogOperatorId OPERATOR_1 = 1; 78 const CTLogOperatorId OPERATOR_2 = 2; 79 const CTLogOperatorId OPERATOR_3 = 3; 80 81 const SCTOrigin ORIGIN_EMBEDDED = SCTOrigin::Embedded; 82 const SCTOrigin ORIGIN_TLS = SCTOrigin::TLSExtension; 83 const SCTOrigin ORIGIN_OCSP = SCTOrigin::OCSPResponse; 84 85 // 1 year of cert lifetime requires 3 SCTs for the embedded case. 86 const Duration DEFAULT_LIFETIME = Duration(365 * Time::ONE_DAY_IN_SECONDS); 87 88 // Date.parse("2015-08-15T00:00:00Z") 89 const uint64_t TIMESTAMP_1 = 1439596800000L; 90 91 // Date.parse("2016-04-15T00:00:00Z") 92 const uint64_t LOG_TIMESTAMP = 1460678400000L; 93 94 // Date.parse("2016-04-01T00:00:00Z") 95 const uint64_t BEFORE_RETIREMENT = 1459468800000L; 96 97 // Date.parse("2016-04-16T00:00:00Z") 98 const uint64_t AFTER_RETIREMENT = 1460764800000L; 99 }; 100 101 TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithNonEmbeddedSCTs) { 102 VerifiedSCTList scts; 103 104 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 105 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1); 106 107 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 108 } 109 110 TEST_F(CTPolicyEnforcerTest, DoesNotConformNotEnoughDiverseNonEmbeddedSCTs) { 111 VerifiedSCTList scts; 112 113 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 114 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 115 116 // The implementation attempts to fulfill the non-embedded compliance case 117 // first. Because the non-embedded SCTs do not have enough log diversity, the 118 // implementation then attempts to fulfill the embedded compliance case. 119 // Because there are no embedded SCTs, it returns a "not enough SCTs" error. 120 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 121 } 122 123 TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithEmbeddedSCTs) { 124 VerifiedSCTList scts; 125 126 // 3 embedded SCTs required for DEFAULT_LIFETIME. 127 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 128 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 129 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1); 130 131 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 132 } 133 134 TEST_F(CTPolicyEnforcerTest, DoesNotConformNotEnoughDiverseEmbeddedSCTs) { 135 VerifiedSCTList scts; 136 137 // 3 embedded SCTs required for DEFAULT_LIFETIME. 138 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 139 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 140 AddSct(scts, LOG_3, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 141 142 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotDiverseScts); 143 } 144 145 TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithPooledNonEmbeddedSCTs) { 146 VerifiedSCTList scts; 147 148 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_OCSP, TIMESTAMP_1); 149 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1); 150 151 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 152 } 153 154 TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTPolicyWithPooledEmbeddedSCTs) { 155 VerifiedSCTList scts; 156 157 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 158 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_OCSP, TIMESTAMP_1); 159 160 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 161 } 162 163 TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughSCTs) { 164 VerifiedSCTList scts; 165 166 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 167 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1); 168 169 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 170 } 171 172 TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughFreshSCTs) { 173 VerifiedSCTList scts; 174 175 // The results should be the same before and after disqualification, 176 // regardless of the delivery method. 177 178 // SCT from before disqualification. 179 scts.clear(); 180 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 181 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, BEFORE_RETIREMENT, 182 CTLogState::Retired); 183 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 184 // SCT from after disqualification. 185 scts.clear(); 186 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 187 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, AFTER_RETIREMENT, 188 CTLogState::Retired); 189 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 190 191 // Embedded SCT from before disqualification. 192 scts.clear(); 193 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 194 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, BEFORE_RETIREMENT, 195 CTLogState::Retired); 196 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 197 198 // Embedded SCT from after disqualification. 199 scts.clear(); 200 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1); 201 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, AFTER_RETIREMENT, 202 CTLogState::Retired); 203 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 204 } 205 206 TEST_F(CTPolicyEnforcerTest, ConformsWithRetiredLogBeforeDisqualificationDate) { 207 VerifiedSCTList scts; 208 209 // 3 embedded SCTs required for DEFAULT_LIFETIME. 210 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 211 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 212 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, BEFORE_RETIREMENT, 213 CTLogState::Retired); 214 215 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 216 } 217 218 TEST_F(CTPolicyEnforcerTest, 219 DoesNotConformWithRetiredLogAfterDisqualificationDate) { 220 VerifiedSCTList scts; 221 222 // 3 embedded SCTs required for DEFAULT_LIFETIME. 223 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 224 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 225 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, AFTER_RETIREMENT, 226 CTLogState::Retired); 227 228 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 229 } 230 231 TEST_F(CTPolicyEnforcerTest, 232 DoesNotConformWithIssuanceDateAfterDisqualificationDate) { 233 VerifiedSCTList scts; 234 235 // 3 embedded SCTs required for DEFAULT_LIFETIME. 236 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, AFTER_RETIREMENT, 237 CTLogState::Retired); 238 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, AFTER_RETIREMENT); 239 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, AFTER_RETIREMENT); 240 241 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 242 } 243 244 TEST_F(CTPolicyEnforcerTest, 245 DoesNotConformToCTPolicyNotEnoughUniqueEmbeddedRetiredLogs) { 246 VerifiedSCTList scts; 247 248 // Operator #1 249 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1); 250 // Operator #2, same retired logs 251 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, BEFORE_RETIREMENT, 252 CTLogState::Retired); 253 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, BEFORE_RETIREMENT, 254 CTLogState::Retired); 255 256 // 3 embedded SCTs required. However, only 2 are from distinct logs. 257 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotDiverseScts); 258 } 259 260 TEST_F(CTPolicyEnforcerTest, 261 ConformsToPolicyExactNumberOfSCTsForValidityPeriod) { 262 // Test multiple validity periods. 263 const struct TestData { 264 Duration certLifetime; 265 size_t sctsRequired; 266 } kTestData[] = {{Duration(90 * Time::ONE_DAY_IN_SECONDS), 2}, 267 {Duration(180 * Time::ONE_DAY_IN_SECONDS), 2}, 268 {Duration(181 * Time::ONE_DAY_IN_SECONDS), 3}, 269 {Duration(365 * Time::ONE_DAY_IN_SECONDS), 3}}; 270 271 for (size_t i = 0; i < MOZILLA_CT_ARRAY_LENGTH(kTestData); ++i) { 272 SCOPED_TRACE(i); 273 274 Duration certLifetime = kTestData[i].certLifetime; 275 size_t sctsRequired = kTestData[i].sctsRequired; 276 277 // Less SCTs than required is not enough. 278 for (size_t sctsAvailable = 0; sctsAvailable < sctsRequired; 279 ++sctsAvailable) { 280 VerifiedSCTList scts; 281 AddMultipleScts(scts, sctsAvailable, 1, ORIGIN_EMBEDDED, TIMESTAMP_1); 282 283 CTPolicyCompliance compliance = 284 CheckCTPolicyCompliance(scts, certLifetime); 285 EXPECT_EQ(CTPolicyCompliance::NotEnoughScts, compliance) 286 << "i=" << i << " sctsRequired=" << sctsRequired 287 << " sctsAvailable=" << sctsAvailable; 288 } 289 290 // Add exactly the required number of SCTs (from 2 operators). 291 VerifiedSCTList scts; 292 AddMultipleScts(scts, sctsRequired, 2, ORIGIN_EMBEDDED, TIMESTAMP_1); 293 294 CTPolicyCompliance compliance = CheckCTPolicyCompliance(scts, certLifetime); 295 EXPECT_EQ(CTPolicyCompliance::Compliant, compliance) << "i=" << i; 296 } 297 } 298 299 TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithAtLeastOneRFC6962Log) { 300 VerifiedSCTList scts; 301 302 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1, 303 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 304 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1, 305 CTLogState::Admissible, CTLogFormat::RFC6962); 306 307 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 308 } 309 310 TEST_F(CTPolicyEnforcerTest, 311 ConformsToCTPolicyWithAtLeastOneRFC6962LogEmbedded) { 312 VerifiedSCTList scts; 313 314 // 3 embedded SCTs required for DEFAULT_LIFETIME. 315 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1, 316 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 317 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1, 318 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 319 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1, 320 CTLogState::Admissible, CTLogFormat::RFC6962); 321 322 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 323 } 324 325 TEST_F(CTPolicyEnforcerTest, DoesConformToCTPolicyWithNoRFC6962Logs) { 326 VerifiedSCTList scts; 327 328 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1, 329 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 330 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1, 331 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 332 333 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 334 } 335 336 TEST_F(CTPolicyEnforcerTest, DoesConformToCTPolicyWithNoRFC6962LogsEmbedded) { 337 VerifiedSCTList scts; 338 339 // 3 embedded SCTs required for DEFAULT_LIFETIME. 340 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1, 341 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 342 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1, 343 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 344 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1, 345 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 346 347 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::Compliant); 348 } 349 350 TEST_F(CTPolicyEnforcerTest, 351 DoesNotConformToCTPolicyWithSCTFromTiledLogWithNoLeafIndex) { 352 VerifiedSCTList scts; 353 354 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1, 355 CTLogState::Admissible, CTLogFormat::Tiled, Nothing()); 356 AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1, 357 CTLogState::Admissible, CTLogFormat::RFC6962); 358 359 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 360 } 361 362 TEST_F(CTPolicyEnforcerTest, 363 DoesNotConformToCTPolicyWithSCTFromTiledLogWithNoLeafIndexEmbedded) { 364 VerifiedSCTList scts; 365 366 // 3 embedded SCTs required for DEFAULT_LIFETIME. 367 AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1, 368 CTLogState::Admissible, CTLogFormat::Tiled, Some(23)); 369 AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1, 370 CTLogState::Admissible, CTLogFormat::Tiled, Nothing()); 371 AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1, 372 CTLogState::Admissible, CTLogFormat::RFC6962); 373 374 CheckCompliance(scts, DEFAULT_LIFETIME, CTPolicyCompliance::NotEnoughScts); 375 } 376 377 } // namespace ct 378 } // namespace mozilla