Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/certverifier/tests/gtest/CTPolicyEnforcerTest.cpp
Line
Count
Source (jump to first uncovered line)
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
#include <stdio.h>
12
13
#include "CTVerifyResult.h"
14
#include "gtest/gtest.h"
15
#include "hasht.h"
16
#include "mozilla/ArrayUtils.h"
17
#include "mozilla/Assertions.h"
18
#include "prtime.h"
19
#include "SignedCertificateTimestamp.h"
20
21
// Implemented in CertVerifier.cpp.
22
extern mozilla::pkix::Result
23
GetCertLifetimeInFullMonths(PRTime certNotBefore,
24
                            PRTime certNotAfter,
25
                            size_t& months);
26
27
namespace mozilla { namespace ct {
28
29
using namespace mozilla::pkix;
30
31
class CTPolicyEnforcerTest : public ::testing::Test
32
{
33
public:
34
  void SetUp() override
35
0
  {
36
0
    MOZ_ALWAYS_TRUE(OPERATORS_1_AND_2.append(OPERATOR_1));
37
0
    MOZ_ALWAYS_TRUE(OPERATORS_1_AND_2.append(OPERATOR_2));
38
0
  }
39
40
  void GetLogId(Buffer& logId, size_t logNo)
41
0
  {
42
0
    ASSERT_TRUE(logId.resize(SHA256_LENGTH));
43
0
    std::fill(logId.begin(), logId.end(), 0);
44
0
    // Just raw-copy |logId| into the output buffer.
45
0
    MOZ_ASSERT(sizeof(logNo) <= logId.length());
46
0
    memcpy(logId.begin(), &logNo, sizeof(logNo));
47
0
  }
48
49
  void AddSct(VerifiedSCTList& verifiedScts,
50
              size_t logNo,
51
              CTLogOperatorId operatorId,
52
              VerifiedSCT::Origin origin,
53
              uint64_t timestamp,
54
              VerifiedSCT::Status status = VerifiedSCT::Status::Valid)
55
0
  {
56
0
    VerifiedSCT verifiedSct;
57
0
    verifiedSct.status = status;
58
0
    verifiedSct.origin = origin;
59
0
    verifiedSct.logOperatorId = operatorId;
60
0
    verifiedSct.logDisqualificationTime =
61
0
      status == VerifiedSCT::Status::ValidFromDisqualifiedLog ?
62
0
      DISQUALIFIED_AT : UINT64_MAX;
63
0
    verifiedSct.sct.version = SignedCertificateTimestamp::Version::V1;
64
0
    verifiedSct.sct.timestamp = timestamp;
65
0
    Buffer logId;
66
0
    GetLogId(logId, logNo);
67
0
    verifiedSct.sct.logId = std::move(logId);
68
0
    ASSERT_TRUE(verifiedScts.append(std::move(verifiedSct)));
69
0
  }
70
71
  void AddMultipleScts(VerifiedSCTList& verifiedScts,
72
                       size_t logsCount,
73
                       uint8_t operatorsCount,
74
                       VerifiedSCT::Origin origin,
75
                       uint64_t timestamp,
76
                       VerifiedSCT::Status status = VerifiedSCT::Status::Valid)
77
0
  {
78
0
    for (size_t logNo = 0; logNo < logsCount; logNo++) {
79
0
      CTLogOperatorId operatorId = logNo % operatorsCount;
80
0
      AddSct(verifiedScts, logNo, operatorId, origin, timestamp, status);
81
0
    }
82
0
  }
83
84
  void CheckCompliance(const VerifiedSCTList& verifiedSct,
85
                       size_t certLifetimeInCalendarMonths,
86
                       const CTLogOperatorList& dependentLogOperators,
87
                       CTPolicyCompliance expectedCompliance)
88
0
  {
89
0
    CTPolicyCompliance compliance;
90
0
    ASSERT_EQ(Success,
91
0
              mPolicyEnforcer.CheckCompliance(verifiedSct,
92
0
                                              certLifetimeInCalendarMonths,
93
0
                                              dependentLogOperators,
94
0
                                              compliance));
95
0
    EXPECT_EQ(expectedCompliance, compliance);
96
0
  }
97
98
protected:
99
  CTPolicyEnforcer mPolicyEnforcer;
100
101
  const size_t LOG_1 = 1;
102
  const size_t LOG_2 = 2;
103
  const size_t LOG_3 = 3;
104
  const size_t LOG_4 = 4;
105
  const size_t LOG_5 = 5;
106
107
  const CTLogOperatorId OPERATOR_1 = 1;
108
  const CTLogOperatorId OPERATOR_2 = 2;
109
  const CTLogOperatorId OPERATOR_3 = 3;
110
111
  CTLogOperatorList NO_OPERATORS;
112
  CTLogOperatorList OPERATORS_1_AND_2;
113
114
  const VerifiedSCT::Origin ORIGIN_EMBEDDED = VerifiedSCT::Origin::Embedded;
115
  const VerifiedSCT::Origin ORIGIN_TLS = VerifiedSCT::Origin::TLSExtension;
116
  const VerifiedSCT::Origin ORIGIN_OCSP = VerifiedSCT::Origin::OCSPResponse;
117
118
  // 4 years of cert lifetime requires 5 SCTs for the embedded case.
119
  const size_t DEFAULT_MONTHS = 4 * 12L;
120
121
  // Date.parse("2015-08-15T00:00:00Z")
122
  const uint64_t TIMESTAMP_1 = 1439596800000L;
123
124
  // Date.parse("2016-04-15T00:00:00Z")
125
  const uint64_t DISQUALIFIED_AT = 1460678400000L;
126
127
  // Date.parse("2016-04-01T00:00:00Z")
128
  const uint64_t BEFORE_DISQUALIFIED = 1459468800000L;
129
130
  // Date.parse("2016-04-16T00:00:00Z")
131
  const uint64_t AFTER_DISQUALIFIED = 1460764800000L;
132
};
133
134
TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithNonEmbeddedSCTs)
135
0
{
136
0
  VerifiedSCTList scts;
137
0
138
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1);
139
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1);
140
0
141
0
  CheckCompliance(scts,  DEFAULT_MONTHS, NO_OPERATORS,
142
0
                  CTPolicyCompliance::Compliant);
143
0
}
144
145
TEST_F(CTPolicyEnforcerTest, DoesNotConformNotEnoughDiverseNonEmbeddedSCTs)
146
0
{
147
0
  VerifiedSCTList scts;
148
0
149
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1);
150
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1);
151
0
152
0
  CheckCompliance(scts, DEFAULT_MONTHS, OPERATORS_1_AND_2,
153
0
                  CTPolicyCompliance::NotDiverseScts);
154
0
}
155
156
TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithEmbeddedSCTs)
157
0
{
158
0
  VerifiedSCTList scts;
159
0
160
0
  // 5 embedded SCTs required for DEFAULT_MONTHS.
161
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
162
0
  AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
163
0
  AddSct(scts, LOG_3, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
164
0
  AddSct(scts, LOG_4, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
165
0
  AddSct(scts, LOG_5, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1);
166
0
167
0
  CheckCompliance(scts,  DEFAULT_MONTHS, NO_OPERATORS,
168
0
                  CTPolicyCompliance::Compliant);
169
0
}
170
171
TEST_F(CTPolicyEnforcerTest, DoesNotConformNotEnoughDiverseEmbeddedSCTs)
172
0
{
173
0
  VerifiedSCTList scts;
174
0
175
0
  // 5 embedded SCTs required for DEFAULT_MONTHS.
176
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
177
0
  AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
178
0
  AddSct(scts, LOG_3, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
179
0
  AddSct(scts, LOG_4, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
180
0
  AddSct(scts, LOG_5, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1);
181
0
182
0
  CheckCompliance(scts,  DEFAULT_MONTHS, OPERATORS_1_AND_2,
183
0
                  CTPolicyCompliance::NotDiverseScts);
184
0
}
185
186
TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithPooledNonEmbeddedSCTs)
187
0
{
188
0
  VerifiedSCTList scts;
189
0
190
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_OCSP, TIMESTAMP_1);
191
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, TIMESTAMP_1);
192
0
193
0
  CheckCompliance(scts,  DEFAULT_MONTHS, NO_OPERATORS,
194
0
                  CTPolicyCompliance::Compliant);
195
0
}
196
197
TEST_F(CTPolicyEnforcerTest, ConformsToCTPolicyWithPooledEmbeddedSCTs)
198
0
{
199
0
  VerifiedSCTList scts;
200
0
201
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
202
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_OCSP, TIMESTAMP_1);
203
0
204
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
205
0
                  CTPolicyCompliance::Compliant);
206
0
}
207
208
TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughSCTs)
209
0
{
210
0
  VerifiedSCTList scts;
211
0
212
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
213
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1);
214
0
215
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
216
0
                  CTPolicyCompliance::NotEnoughScts);
217
0
}
218
219
TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughFreshSCTs)
220
0
{
221
0
  VerifiedSCTList scts;
222
0
223
0
  // The results should be the same before and after disqualification,
224
0
  // regardless of the delivery method.
225
0
226
0
  // SCT from before disqualification.
227
0
  scts.clear();
228
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1);
229
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, BEFORE_DISQUALIFIED,
230
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
231
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
232
0
                  CTPolicyCompliance::NotEnoughScts);
233
0
  // SCT from after disqualification.
234
0
  scts.clear();
235
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1);
236
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_TLS, AFTER_DISQUALIFIED,
237
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
238
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
239
0
                  CTPolicyCompliance::NotEnoughScts);
240
0
241
0
  // Embedded SCT from before disqualification.
242
0
  scts.clear();
243
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1);
244
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, BEFORE_DISQUALIFIED,
245
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
246
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
247
0
                  CTPolicyCompliance::NotEnoughScts);
248
0
249
0
  // Embedded SCT from after disqualification.
250
0
  scts.clear();
251
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_TLS, TIMESTAMP_1);
252
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED,
253
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
254
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
255
0
                  CTPolicyCompliance::NotEnoughScts);
256
0
}
257
258
TEST_F(CTPolicyEnforcerTest,
259
       ConformsWithDisqualifiedLogBeforeDisqualificationDate)
260
0
{
261
0
  VerifiedSCTList scts;
262
0
263
0
  // 5 embedded SCTs required for DEFAULT_MONTHS.
264
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
265
0
  AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
266
0
  AddSct(scts, LOG_3, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
267
0
  AddSct(scts, LOG_4, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
268
0
  AddSct(scts, LOG_5, OPERATOR_2, ORIGIN_EMBEDDED, BEFORE_DISQUALIFIED,
269
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
270
0
271
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
272
0
                  CTPolicyCompliance::Compliant);
273
0
}
274
275
TEST_F(CTPolicyEnforcerTest,
276
       DoesNotConformWithDisqualifiedLogAfterDisqualificationDate)
277
0
{
278
0
  VerifiedSCTList scts;
279
0
280
0
  // 5 embedded SCTs required for DEFAULT_MONTHS.
281
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
282
0
  AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
283
0
  AddSct(scts, LOG_3, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
284
0
  AddSct(scts, LOG_4, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
285
0
  AddSct(scts, LOG_5, OPERATOR_2, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED,
286
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
287
0
288
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
289
0
                  CTPolicyCompliance::NotEnoughScts);
290
0
}
291
292
TEST_F(CTPolicyEnforcerTest,
293
       DoesNotConformWithIssuanceDateAfterDisqualificationDate)
294
0
{
295
0
  VerifiedSCTList scts;
296
0
297
0
  // 5 embedded SCTs required for DEFAULT_MONTHS.
298
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED,
299
0
         VerifiedSCT::Status::ValidFromDisqualifiedLog);
300
0
  AddSct(scts, LOG_2, OPERATOR_1, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED);
301
0
  AddSct(scts, LOG_3, OPERATOR_1, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED);
302
0
  AddSct(scts, LOG_4, OPERATOR_1, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED);
303
0
  AddSct(scts, LOG_5, OPERATOR_2, ORIGIN_EMBEDDED, AFTER_DISQUALIFIED);
304
0
305
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
306
0
                  CTPolicyCompliance::NotEnoughScts);
307
0
}
308
309
TEST_F(CTPolicyEnforcerTest,
310
       DoesNotConformToCTPolicyNotEnoughUniqueEmbeddedLogs)
311
0
{
312
0
  VerifiedSCTList scts;
313
0
314
0
  // Operator #1
315
0
  AddSct(scts, LOG_1, OPERATOR_1, ORIGIN_EMBEDDED, TIMESTAMP_1);
316
0
  // Operator #2, different logs
317
0
  AddSct(scts, LOG_2, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1);
318
0
  AddSct(scts, LOG_3, OPERATOR_2, ORIGIN_EMBEDDED, TIMESTAMP_1);
319
0
  // Operator #3, same log
320
0
  AddSct(scts, LOG_4, OPERATOR_3, ORIGIN_EMBEDDED, TIMESTAMP_1);
321
0
  AddSct(scts, LOG_4, OPERATOR_3, ORIGIN_EMBEDDED, TIMESTAMP_1);
322
0
323
0
  // 5 embedded SCTs required. However, only 4 are from distinct logs.
324
0
  CheckCompliance(scts, DEFAULT_MONTHS, NO_OPERATORS,
325
0
                  CTPolicyCompliance::NotEnoughScts);
326
0
}
327
328
TEST_F(CTPolicyEnforcerTest,
329
       ConformsToPolicyExactNumberOfSCTsForValidityPeriod)
330
0
{
331
0
  // Test multiple validity periods.
332
0
  const struct TestData {
333
0
    size_t certLifetimeInCalendarMonths;
334
0
    size_t sctsRequired;
335
0
  } kTestData[] = {
336
0
    { 3, 2 },
337
0
    { 12 + 2, 2 },
338
0
    { 12 + 3, 3 },
339
0
    { 2*12 + 2, 3 },
340
0
    { 2*12 + 3, 4 },
341
0
    { 3*12 + 2, 4 },
342
0
    { 3*12 + 4, 5 }
343
0
  };
344
0
345
0
  for (size_t i = 0; i < ArrayLength(kTestData); ++i) {
346
0
    SCOPED_TRACE(i);
347
0
348
0
    size_t months = kTestData[i].certLifetimeInCalendarMonths;
349
0
    size_t sctsRequired = kTestData[i].sctsRequired;
350
0
351
0
    // Less SCTs than required is not enough.
352
0
    for (size_t sctsAvailable = 0; sctsAvailable < sctsRequired;
353
0
         ++sctsAvailable) {
354
0
      VerifiedSCTList scts;
355
0
      AddMultipleScts(scts, sctsAvailable, 1, ORIGIN_EMBEDDED, TIMESTAMP_1);
356
0
357
0
      CTPolicyCompliance compliance;
358
0
      ASSERT_EQ(Success,
359
0
                mPolicyEnforcer.CheckCompliance(scts, months, NO_OPERATORS,
360
0
                                                compliance))
361
0
        << "i=" << i
362
0
        << " sctsRequired=" << sctsRequired
363
0
        << " sctsAvailable=" << sctsAvailable;
364
0
      EXPECT_EQ(CTPolicyCompliance::NotEnoughScts, compliance)
365
0
        << "i=" << i
366
0
        << " sctsRequired=" << sctsRequired
367
0
        << " sctsAvailable=" << sctsAvailable;
368
0
    }
369
0
370
0
    // Add exactly the required number of SCTs (from 2 operators).
371
0
    VerifiedSCTList scts;
372
0
    AddMultipleScts(scts, sctsRequired, 2, ORIGIN_EMBEDDED, TIMESTAMP_1);
373
0
374
0
    CTPolicyCompliance compliance;
375
0
    ASSERT_EQ(Success,
376
0
              mPolicyEnforcer.CheckCompliance(scts, months, NO_OPERATORS,
377
0
                                              compliance))
378
0
      << "i=" << i;
379
0
    EXPECT_EQ(CTPolicyCompliance::Compliant, compliance)
380
0
      << "i=" << i;
381
0
  }
382
0
}
383
384
TEST_F(CTPolicyEnforcerTest, TestEdgeCasesOfGetCertLifetimeInFullMonths)
385
0
{
386
0
  const struct TestData {
387
0
    PRTime notBefore;
388
0
    PRTime notAfter;
389
0
    size_t expectedMonths;
390
0
  } kTestData[] = {
391
0
    { // 1 second less than 1 month
392
0
      1424863500000000, // Date.parse("2015-02-25T11:25:00Z") * 1000
393
0
      1427196299000000, // Date.parse("2015-03-24T11:24:59Z") * 1000
394
0
      0 },
395
0
    { // exactly 1 month
396
0
      1424863500000000, // Date.parse("2015-02-25T11:25:00Z") * 1000
397
0
      1427282700000000, // Date.parse("2015-03-25T11:25:00Z") * 1000
398
0
      1 },
399
0
    { // 1 year, 1 month
400
0
      1427282700000000, // Date.parse("2015-03-25T11:25:00Z") * 1000
401
0
      1461583500000000, // Date.parse("2016-04-25T11:25:00Z") * 1000
402
0
      13 },
403
0
    { // 1 year, 1 month, first day of notBefore month, last of notAfter
404
0
      1425209100000000, // Date.parse("2015-03-01T11:25:00Z") * 1000
405
0
      1462015500000000, // Date.parse("2016-04-30T11:25:00Z") * 1000
406
0
      13 },
407
0
    { // 1 year, adjacent months, last day of notBefore month, first of notAfter
408
0
      1427801100000000, // Date.parse("2015-03-31T11:25:00Z") * 1000
409
0
      1459509900000000, // Date.parse("2016-04-01T11:25:00Z") * 1000
410
0
      12 }
411
0
  };
412
0
413
0
  for (size_t i = 0; i < ArrayLength(kTestData); ++i) {
414
0
    SCOPED_TRACE(i);
415
0
416
0
    size_t months;
417
0
    ASSERT_EQ(Success,
418
0
              GetCertLifetimeInFullMonths(kTestData[i].notBefore,
419
0
                                          kTestData[i].notAfter,
420
0
                                          months))
421
0
              << "i=" << i;
422
0
    EXPECT_EQ(kTestData[i].expectedMonths, months)
423
0
              << "i=" << i;
424
0
  }
425
0
}
426
427
} } // namespace mozilla::ct