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 "MultiLogCTVerifier.h"
9 #include "CTObjectsExtractor.h"
10 #include "CTSerialization.h"
11 #include "mozilla/StaticPrefs_security.h"
16 using namespace mozilla::pkix
;
18 MultiLogCTVerifier::MultiLogCTVerifier()
19 : mSignatureCache(signature_cache_new(
20 StaticPrefs::security_pki_sct_signature_cache_size()),
21 signature_cache_free
) {}
23 void MultiLogCTVerifier::AddLog(CTLogVerifier
&& log
) {
24 mLogs
.push_back(std::move(log
));
27 pkix::Result
MultiLogCTVerifier::Verify(Input cert
,
28 Input issuerSubjectPublicKeyInfo
,
29 Input sctListFromCert
,
30 Input sctListFromOCSPResponse
,
31 Input sctListFromTLSExtension
,
32 Time time
, CTVerifyResult
& result
) {
33 assert(cert
.GetLength() > 0);
38 // Verify embedded SCTs
39 if (issuerSubjectPublicKeyInfo
.GetLength() > 0 &&
40 sctListFromCert
.GetLength() > 0) {
41 LogEntry precertEntry
;
42 rv
= GetPrecertLogEntry(cert
, issuerSubjectPublicKeyInfo
, precertEntry
);
46 rv
= VerifySCTs(sctListFromCert
, precertEntry
, SCTOrigin::Embedded
, time
,
54 GetX509LogEntry(cert
, x509Entry
);
56 // Verify SCTs from a stapled OCSP response
57 if (sctListFromOCSPResponse
.GetLength() > 0) {
58 rv
= VerifySCTs(sctListFromOCSPResponse
, x509Entry
, SCTOrigin::OCSPResponse
,
65 // Verify SCTs from a TLS extension
66 if (sctListFromTLSExtension
.GetLength() > 0) {
67 rv
= VerifySCTs(sctListFromTLSExtension
, x509Entry
, SCTOrigin::TLSExtension
,
76 void DecodeSCTs(Input encodedSctList
,
77 std::vector
<SignedCertificateTimestamp
>& decodedSCTs
,
78 size_t& decodingErrors
) {
82 pkix::Result rv
= DecodeSCTList(encodedSctList
, listReader
);
88 while (!listReader
.AtEnd()) {
90 rv
= ReadSCTListItem(listReader
, encodedSct
);
96 Reader
encodedSctReader(encodedSct
);
97 SignedCertificateTimestamp sct
;
98 rv
= DecodeSignedCertificateTimestamp(encodedSctReader
, sct
);
103 decodedSCTs
.push_back(std::move(sct
));
107 pkix::Result
MultiLogCTVerifier::VerifySCTs(Input encodedSctList
,
108 const LogEntry
& expectedEntry
,
109 SCTOrigin origin
, Time time
,
110 CTVerifyResult
& result
) {
111 std::vector
<SignedCertificateTimestamp
> decodedSCTs
;
112 DecodeSCTs(encodedSctList
, decodedSCTs
, result
.decodingErrors
);
113 for (auto sct
: decodedSCTs
) {
115 VerifySingleSCT(std::move(sct
), expectedEntry
, origin
, time
, result
);
123 pkix::Result
MultiLogCTVerifier::VerifySingleSCT(
124 SignedCertificateTimestamp
&& sct
, const LogEntry
& expectedEntry
,
125 SCTOrigin origin
, Time time
, CTVerifyResult
& result
) {
127 case SCTOrigin::Embedded
:
128 result
.embeddedSCTs
++;
130 case SCTOrigin::TLSExtension
:
131 result
.sctsFromTLSHandshake
++;
133 case SCTOrigin::OCSPResponse
:
134 result
.sctsFromOCSP
++;
138 CTLogVerifier
* matchingLog
= nullptr;
139 for (auto& log
: mLogs
) {
140 if (log
.keyId() == sct
.logId
) {
147 // SCT does not match any known log.
148 result
.sctsFromUnknownLogs
++;
152 if (!matchingLog
->SignatureParametersMatch(sct
.signature
)) {
153 // SCT signature parameters do not match the log's.
154 result
.sctsWithInvalidSignatures
++;
159 matchingLog
->Verify(expectedEntry
, sct
, mSignatureCache
.get());
161 if (rv
== pkix::Result::ERROR_BAD_SIGNATURE
) {
162 result
.sctsWithInvalidSignatures
++;
168 // Make sure the timestamp is legitimate (not in the future).
169 // SCT's |timestamp| is measured in milliseconds since the epoch,
170 // ignoring leap seconds. When converting it to a second-level precision
171 // pkix::Time, we need to round it either up or down. In our case, rounding up
172 // (towards the future) is more "secure", although practically
173 // it does not matter.
174 Time sctTime
= TimeFromEpochInSeconds((sct
.timestamp
+ 999u) / 1000u);
175 if (sctTime
> time
) {
176 result
.sctsWithInvalidTimestamps
++;
180 VerifiedSCT
verifiedSct(std::move(sct
), origin
, matchingLog
->operatorId(),
181 matchingLog
->state(), matchingLog
->timestamp());
182 result
.verifiedScts
.push_back(std::move(verifiedSct
));
187 } // namespace mozilla