Bug 1317951, part 1 - Certificate Transparency - extracted verification related fields from SCT to a separate struct. r=keeler draft
authorSergei Chernov <sergei.cv@ndivi.com>
Wed, 23 Nov 2016 15:37:31 +0200
changeset 445518 d5590733c87c3a8a525eb29dabfdb9be2822a0a6
parent 439707 2598a93e2e1a27f363af9fdd290cf4184cc51d48
child 445519 7d53a6d2cfa6ba9dae66f6e9809d2bd38236b155
child 445847 7de86fc1adce043b0d53fab14d977dfc212eef67
child 446293 3d6dbfa4d0a6a24dbd8907f42071943895ba068a
push id37533
push usersergei.cv@ndivi.com
push dateTue, 29 Nov 2016 21:08:28 +0000
reviewerskeeler
bugs1317951
milestone53.0a1
Bug 1317951, part 1 - Certificate Transparency - extracted verification related fields from SCT to a separate struct. r=keeler MozReview-Commit-ID: 3iHUdZrzyXB
security/certverifier/CTSerialization.cpp
security/certverifier/CTVerifyResult.cpp
security/certverifier/CTVerifyResult.h
security/certverifier/CertVerifier.cpp
security/certverifier/MultiLogCTVerifier.cpp
security/certverifier/MultiLogCTVerifier.h
security/certverifier/SignedCertificateTimestamp.cpp
security/certverifier/SignedCertificateTimestamp.h
security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
security/manager/ssl/SSLServerCertVerification.cpp
security/manager/ssl/nsSSLStatus.cpp
--- a/security/certverifier/CTSerialization.cpp
+++ b/security/certverifier/CTSerialization.cpp
@@ -506,20 +506,16 @@ DecodeSignedCertificateTimestamp(Reader&
     return rv;
   }
   rv = InputToBuffer(extensions, result.extensions);
   if (rv != Success) {
     return rv;
   }
   result.timestamp = timestamp;
 
-  result.origin = SignedCertificateTimestamp::Origin::Unknown;
-  result.verificationStatus =
-    SignedCertificateTimestamp::VerificationStatus::None;
-
   output = Move(result);
   return Success;
 }
 
 Result
 EncodeSCTList(const Vector<pkix::Input>& scts, Buffer& output)
 {
   // Find out the total size of the SCT list to be written so we can
--- a/security/certverifier/CTVerifyResult.cpp
+++ b/security/certverifier/CTVerifyResult.cpp
@@ -1,18 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CTVerifyResult.h"
 
+#include <stdint.h>
+
 namespace mozilla { namespace ct {
 
+VerifiedSCT::VerifiedSCT()
+  : status(Status::None)
+  , origin(Origin::Unknown)
+{
+}
+
 void
 CTVerifyResult::Reset()
 {
-  scts.clear();
+  verifiedScts.clear();
   decodingErrors = 0;
 }
 
 } } // namespace mozilla::ct
--- a/security/certverifier/CTVerifyResult.h
+++ b/security/certverifier/CTVerifyResult.h
@@ -7,25 +7,59 @@
 #ifndef CTVerifyResult_h
 #define CTVerifyResult_h
 
 #include "mozilla/Vector.h"
 #include "SignedCertificateTimestamp.h"
 
 namespace mozilla { namespace ct {
 
-typedef Vector<SignedCertificateTimestamp> SCTList;
+// Holds a verified Signed Certificate Timestamp along with the verification
+// status (e.g. valid/invalid) and additional information related to the
+// verification.
+struct VerifiedSCT
+{
+  VerifiedSCT();
+
+  // The original SCT.
+  SignedCertificateTimestamp sct;
+
+  enum class Status {
+    None,
+    // The SCT is from a known log, and the signature is valid.
+    Valid,
+    // The SCT is from an unknown log and can not be verified.
+    UnknownLog,
+    // The SCT is from a known log, but the signature is invalid.
+    InvalidSignature,
+    // The SCT signature is valid, but the timestamp is in the future.
+    // Such SCTs are considered invalid (see RFC 6962, Section 5.2).
+    InvalidTimestamp,
+  };
+
+  enum class Origin {
+    Unknown,
+    Embedded,
+    TLSExtension,
+    OCSPResponse,
+  };
+
+  Status status;
+  Origin origin;
+};
+
+typedef Vector<VerifiedSCT> VerifiedSCTList;
 
 // Holds Signed Certificate Timestamps verification results.
 class CTVerifyResult
 {
 public:
-  // SCTs that were processed during the verification. For each SCT,
-  // the verification result is stored in its |verificationStatus| field.
-  SCTList scts;
+  // SCTs that were processed during the verification along with their
+  // verification results.
+  VerifiedSCTList verifiedScts;
 
   // The verifier makes the best effort to extract the available SCTs
   // from the binary sources provided to it.
   // If some SCT cannot be extracted due to encoding errors, the verifier
   // proceeds to the next available one. In other words, decoding errors are
   // effectively ignored.
   // Note that a serialized SCT may fail to decode for a "legitimate" reason,
   // e.g. if the SCT is from a future version of the Certificate Transparency
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CertVerifier.h"
 
 #include <stdint.h>
 
 #include "CTKnownLogs.h"
+#include "CTLogVerifier.h"
 #include "ExtendedValidation.h"
 #include "MultiLogCTVerifier.h"
 #include "NSSCertDBTrustDomain.h"
 #include "NSSErrorsService.h"
 #include "cert.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Casting.h"
 #include "nsNSSComponent.h"
@@ -159,21 +160,29 @@ CertVerifier::LoadKnownCTLogs()
   for (const CTLogInfo& log : kCTLogList) {
     Input publicKey;
     Result rv = publicKey.Init(
       BitwiseCast<const uint8_t*, const char*>(log.logKey), log.logKeyLength);
     if (rv != Success) {
       MOZ_ASSERT_UNREACHABLE("Failed reading a log key for a known CT Log");
       continue;
     }
-    rv = mCTVerifier->AddLog(publicKey);
+
+    CTLogVerifier logVerifier;
+    rv = logVerifier.Init(publicKey);
     if (rv != Success) {
       MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
       continue;
     }
+
+    rv = mCTVerifier->AddLog(Move(logVerifier));
+    if (rv != Success) {
+      MOZ_ASSERT_UNREACHABLE("Failed activating a known CT Log");
+      continue;
+    }
   }
 }
 
 Result
 CertVerifier::VerifySignedCertificateTimestamps(
   NSSCertDBTrustDomain& trustDomain, const UniqueCERTCertList& builtChain,
   Input sctsFromTLS, Time time,
   /*optional out*/ CertificateTransparencyInfo* ctInfo)
@@ -253,45 +262,45 @@ CertVerifier::VerifySignedCertificateTim
                            result);
   if (rv != Success) {
     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
             ("SCT verification failed with fatal error %i\n", rv));
     return rv;
   }
 
   if (MOZ_LOG_TEST(gCertVerifierLog, LogLevel::Debug)) {
-    size_t verifiedCount = 0;
+    size_t validCount = 0;
     size_t unknownLogCount = 0;
     size_t invalidSignatureCount = 0;
     size_t invalidTimestampCount = 0;
-    for (const SignedCertificateTimestamp& sct : result.scts) {
-      switch (sct.verificationStatus) {
-        case SignedCertificateTimestamp::VerificationStatus::OK:
-          verifiedCount++;
+    for (const VerifiedSCT& verifiedSct : result.verifiedScts) {
+      switch (verifiedSct.status) {
+        case VerifiedSCT::Status::Valid:
+          validCount++;
           break;
-        case SignedCertificateTimestamp::VerificationStatus::UnknownLog:
+        case VerifiedSCT::Status::UnknownLog:
           unknownLogCount++;
           break;
-        case SignedCertificateTimestamp::VerificationStatus::InvalidSignature:
+        case VerifiedSCT::Status::InvalidSignature:
           invalidSignatureCount++;
           break;
-        case SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp:
+        case VerifiedSCT::Status::InvalidTimestamp:
           invalidTimestampCount++;
           break;
-        case SignedCertificateTimestamp::VerificationStatus::None:
+        case VerifiedSCT::Status::None:
         default:
-          MOZ_ASSERT_UNREACHABLE("Unexpected SCT verificationStatus");
+          MOZ_ASSERT_UNREACHABLE("Unexpected SCT verification status");
       }
     }
     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
             ("SCT verification result: "
-             "verified=%zu unknownLog=%zu "
+             "valid=%zu unknownLog=%zu "
              "invalidSignature=%zu invalidTimestamp=%zu "
              "decodingErrors=%zu\n",
-             verifiedCount, unknownLogCount,
+             validCount, unknownLogCount,
              invalidSignatureCount, invalidTimestampCount,
              result.decodingErrors));
   }
 
   if (ctInfo) {
     ctInfo->processedSCTs = true;
     ctInfo->verifyResult = Move(result);
   }
--- a/security/certverifier/MultiLogCTVerifier.cpp
+++ b/security/certverifier/MultiLogCTVerifier.cpp
@@ -10,37 +10,32 @@
 #include "CTSerialization.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Move.h"
 
 namespace mozilla { namespace ct {
 
 using namespace mozilla::pkix;
 
-// Note: this moves |sct| to the target list in |result|, invalidating |sct|.
+// Note: this moves |verifiedSct| to the target list in |result|.
 static Result
 StoreVerifiedSct(CTVerifyResult& result,
-                 SignedCertificateTimestamp&& sct,
-                 SignedCertificateTimestamp::VerificationStatus status)
+                 VerifiedSCT&& verifiedSct,
+                 VerifiedSCT::Status status)
 {
-  sct.verificationStatus = status;
-  if (!result.scts.append(Move(sct))) {
+  verifiedSct.status = status;
+  if (!result.verifiedScts.append(Move(verifiedSct))) {
     return Result::FATAL_ERROR_NO_MEMORY;
   }
   return Success;
 }
 
 Result
-MultiLogCTVerifier::AddLog(Input publicKey)
+MultiLogCTVerifier::AddLog(CTLogVerifier&& log)
 {
-  CTLogVerifier log;
-  Result rv = log.Init(publicKey);
-  if (rv != Success) {
-    return rv;
-  }
   if (!mLogs.append(Move(log))) {
     return Result::FATAL_ERROR_NO_MEMORY;
   }
   return Success;
 }
 
 Result
 MultiLogCTVerifier::Verify(Input cert,
@@ -60,55 +55,52 @@ MultiLogCTVerifier::Verify(Input cert,
   if (issuerSubjectPublicKeyInfo.GetLength() > 0 &&
       sctListFromCert.GetLength() > 0) {
     LogEntry precertEntry;
     rv = GetPrecertLogEntry(cert, issuerSubjectPublicKeyInfo, precertEntry);
     if (rv != Success) {
       return rv;
     }
     rv = VerifySCTs(sctListFromCert, precertEntry,
-                    SignedCertificateTimestamp::Origin::Embedded, time,
-                    result);
+                    VerifiedSCT::Origin::Embedded, time, result);
     if (rv != Success) {
       return rv;
     }
   }
 
   LogEntry x509Entry;
   rv = GetX509LogEntry(cert, x509Entry);
   if (rv != Success) {
     return rv;
   }
 
   // Verify SCTs from a stapled OCSP response
   if (sctListFromOCSPResponse.GetLength() > 0) {
     rv = VerifySCTs(sctListFromOCSPResponse, x509Entry,
-                    SignedCertificateTimestamp::Origin::OCSPResponse, time,
-                    result);
+                    VerifiedSCT::Origin::OCSPResponse, time, result);
     if (rv != Success) {
       return rv;
     }
   }
 
   // Verify SCTs from a TLS extension
   if (sctListFromTLSExtension.GetLength() > 0) {
     rv = VerifySCTs(sctListFromTLSExtension, x509Entry,
-                    SignedCertificateTimestamp::Origin::TLSExtension, time,
-                    result);
+                    VerifiedSCT::Origin::TLSExtension, time, result);
     if (rv != Success) {
       return rv;
     }
   }
   return Success;
 }
 
 Result
 MultiLogCTVerifier::VerifySCTs(Input encodedSctList,
                                const LogEntry& expectedEntry,
-                               SignedCertificateTimestamp::Origin origin,
+                               VerifiedSCT::Origin origin,
                                Time time,
                                CTVerifyResult& result)
 {
   Reader listReader;
   Result rv = DecodeSCTList(encodedSctList, listReader);
   if (rv != Success) {
     result.decodingErrors++;
     return Success;
@@ -124,70 +116,76 @@ MultiLogCTVerifier::VerifySCTs(Input enc
 
     Reader encodedSctReader(encodedSct);
     SignedCertificateTimestamp sct;
     rv = DecodeSignedCertificateTimestamp(encodedSctReader, sct);
     if (rv != Success) {
       result.decodingErrors++;
       continue;
     }
-    sct.origin = origin;
 
-    rv = VerifySingleSCT(Move(sct), expectedEntry, time, result);
+    rv = VerifySingleSCT(Move(sct), expectedEntry, origin, time, result);
     if (rv != Success) {
       return rv;
     }
   }
   return Success;
 }
 
 Result
 MultiLogCTVerifier::VerifySingleSCT(SignedCertificateTimestamp&& sct,
                                     const LogEntry& expectedEntry,
+                                    VerifiedSCT::Origin origin,
                                     Time time,
                                     CTVerifyResult& result)
 {
+  VerifiedSCT verifiedSct;
+  verifiedSct.origin = origin;
+  verifiedSct.sct = Move(sct);
+
   CTLogVerifier* matchingLog = nullptr;
   for (auto& log : mLogs) {
-    if (log.keyId() == sct.logId) {
+    if (log.keyId() == verifiedSct.sct.logId) {
       matchingLog = &log;
       break;
     }
   }
 
   if (!matchingLog) {
     // SCT does not match any known log.
-    return StoreVerifiedSct(result, Move(sct),
-      SignedCertificateTimestamp::VerificationStatus::UnknownLog);
+    return StoreVerifiedSct(result, Move(verifiedSct),
+                            VerifiedSCT::Status::UnknownLog);
   }
 
-  if (!matchingLog->SignatureParametersMatch(sct.signature)) {
+  if (!matchingLog->SignatureParametersMatch(verifiedSct.sct.signature)) {
     // SCT signature parameters do not match the log's.
-    return StoreVerifiedSct(result, Move(sct),
-      SignedCertificateTimestamp::VerificationStatus::InvalidSignature);
+    return StoreVerifiedSct(result, Move(verifiedSct),
+                            VerifiedSCT::Status::InvalidSignature);
   }
 
-  Result rv = matchingLog->Verify(expectedEntry, sct);
+  Result rv = matchingLog->Verify(expectedEntry, verifiedSct.sct);
   if (rv != Success) {
     if (rv == Result::ERROR_BAD_SIGNATURE) {
-      return StoreVerifiedSct(result, Move(sct),
-        SignedCertificateTimestamp::VerificationStatus::InvalidSignature);
+      return StoreVerifiedSct(result, Move(verifiedSct),
+                              VerifiedSCT::Status::InvalidSignature);
     }
     return rv;
   }
 
-  // |sct.timestamp| is measured in milliseconds since the epoch,
+  // Make sure the timestamp is legitimate (not in the future).
+  // SCT's |timestamp| is measured in milliseconds since the epoch,
   // ignoring leap seconds. When converting it to a second-level precision
   // pkix::Time, we need to round it either up or down. In our case, rounding up
-  // is more "secure", although practically it does not matter.
-  Time sctTime = TimeFromEpochInSeconds((sct.timestamp + 999u) / 1000u);
-
-  // SCT verified ok, just make sure the timestamp is legitimate.
+  // (towards the future) is more "secure", although practically
+  // it does not matter.
+  Time sctTime =
+    TimeFromEpochInSeconds((verifiedSct.sct.timestamp + 999u) / 1000u);
   if (sctTime > time) {
-    return StoreVerifiedSct(result, Move(sct),
-      SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp);
+    return StoreVerifiedSct(result, Move(verifiedSct),
+                            VerifiedSCT::Status::InvalidTimestamp);
   }
 
-  return StoreVerifiedSct(result, Move(sct),
-    SignedCertificateTimestamp::VerificationStatus::OK);
+  // SCT verified ok.
+  return StoreVerifiedSct(result, Move(verifiedSct),
+                          VerifiedSCT::Status::Valid);
 }
 
 } } // namespace mozilla::ct
--- a/security/certverifier/MultiLogCTVerifier.h
+++ b/security/certverifier/MultiLogCTVerifier.h
@@ -18,17 +18,17 @@
 namespace mozilla { namespace ct {
 
 // A Certificate Transparency verifier that can verify Signed Certificate
 // Timestamps from multiple logs.
 class MultiLogCTVerifier
 {
 public:
   // Adds a new log to the list of known logs to verify against.
-  pkix::Result AddLog(pkix::Input publicKey);
+  pkix::Result AddLog(CTLogVerifier&& log);
 
   // Verifies SCTs embedded in the certificate itself, SCTs embedded in a
   // stapled OCSP response, and SCTs obtained via the
   // signed_certificate_timestamp TLS extension on the given |cert|.
   //
   // A certificate is permitted but not required to use multiple sources for
   // SCTs. It is expected that most certificates will use only one source
   // (embedding, TLS extension or OCSP stapling).
@@ -61,24 +61,25 @@ public:
                       CTVerifyResult& result);
 
 private:
   // Verifies a list of SCTs from |encodedSctList| over |expectedEntry|,
   // placing the verification results in |result|. The SCTs in the list
   // come from |origin| (as will be reflected in the origin field of each SCT).
   pkix::Result VerifySCTs(pkix::Input encodedSctList,
                           const LogEntry& expectedEntry,
-                          SignedCertificateTimestamp::Origin origin,
+                          VerifiedSCT::Origin origin,
                           pkix::Time time,
                           CTVerifyResult& result);
 
   // Verifies a single, parsed SCT against all known logs.
   // Note: moves |sct| to the target list in |result|, invalidating |sct|.
   pkix::Result VerifySingleSCT(SignedCertificateTimestamp&& sct,
                                const ct::LogEntry& expectedEntry,
+                               VerifiedSCT::Origin origin,
                                pkix::Time time,
                                CTVerifyResult& result);
 
   // The list of known logs.
   Vector<CTLogVerifier> mLogs;
 };
 
 } } // namespace mozilla::ct
--- a/security/certverifier/SignedCertificateTimestamp.cpp
+++ b/security/certverifier/SignedCertificateTimestamp.cpp
@@ -33,13 +33,14 @@ namespace mozilla {
 bool
 operator==(const ct::Buffer& a, const ct::Buffer& b)
 {
   return (a.empty() && b.empty()) ||
     (a.length() == b.length() && memcmp(a.begin(), b.begin(), a.length()) == 0);
 }
 
 bool
-operator!=(const ct::Buffer& a, const ct::Buffer& b) {
+operator!=(const ct::Buffer& a, const ct::Buffer& b)
+{
   return !(a == b);
 }
 
 } // namespace mozilla
--- a/security/certverifier/SignedCertificateTimestamp.h
+++ b/security/certverifier/SignedCertificateTimestamp.h
@@ -80,42 +80,16 @@ struct SignedCertificateTimestamp
 
   Version version;
   Buffer logId;
   // "timestamp" is the current time in milliseconds, measured since the epoch,
   // ignoring leap seconds. See RFC 6962, Section 3.2.
   uint64_t timestamp;
   Buffer extensions;
   DigitallySigned signature;
-
-  // Supplementary fields, not defined in CT RFC. Set during the various
-  // stages of processing the received SCTs.
-
-  enum class Origin {
-    Unknown,
-    Embedded,
-    TLSExtension,
-    OCSPResponse
-  };
-
-  enum class VerificationStatus {
-    None,
-    // The SCT is from a known log, and the signature is valid.
-    OK,
-    // The SCT is from an unknown log and can not be verified.
-    UnknownLog,
-    // The SCT is from a known log, but the signature is invalid.
-    InvalidSignature,
-    // The SCT signature is valid, but the timestamp is in the future.
-    // Such SCT are considered invalid (see RFC 6962, Section 5.2).
-    InvalidTimestamp
-  };
-
-  Origin origin;
-  VerificationStatus verificationStatus;
 };
 
 
 inline pkix::Result BufferToInput(const Buffer& buffer, pkix::Input& input)
 {
   return input.Init(buffer.begin(), buffer.length());
 }
 
--- a/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
+++ b/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
@@ -28,37 +28,38 @@ public:
     : mNow(Time::uninitialized)
   {}
 
   void SetUp() override
   {
     // Does nothing if NSS is already initialized.
     MOZ_RELEASE_ASSERT(NSS_NoDB_Init(nullptr) == SECSuccess);
 
-    ASSERT_EQ(Success, mVerifier.AddLog(InputForBuffer(GetTestPublicKey())));
+    CTLogVerifier log;
+    ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey())));
+    ASSERT_EQ(Success, mVerifier.AddLog(Move(log)));
 
     mTestCert = GetDEREncodedX509Cert();
     mEmbeddedCert = GetDEREncodedTestEmbeddedCert();
     mCaCert = GetDEREncodedCACert();
     mCaCertSPKI = ExtractCertSPKI(mCaCert);
     mIntermediateCert = GetDEREncodedIntermediateCert();
     mIntermediateCertSPKI = ExtractCertSPKI(mIntermediateCert);
 
     // Set the current time making sure all test timestamps are in the past.
     mNow = TimeFromEpochInSeconds(1451606400u); // Date.parse("2016-01-01")/1000
   }
 
-  void CheckForSingleVerifiedSCTInResult(const CTVerifyResult& result,
-    SignedCertificateTimestamp::Origin origin)
+  void CheckForSingleValidSCTInResult(const CTVerifyResult& result,
+                                      VerifiedSCT::Origin origin)
   {
     EXPECT_EQ(0U, result.decodingErrors);
-    ASSERT_EQ(1U, result.scts.length());
-    EXPECT_EQ(SignedCertificateTimestamp::VerificationStatus::OK,
-              result.scts[0].verificationStatus);
-    EXPECT_EQ(origin, result.scts[0].origin);
+    ASSERT_EQ(1U, result.verifiedScts.length());
+    EXPECT_EQ(VerifiedSCT::Status::Valid, result.verifiedScts[0].status);
+    EXPECT_EQ(origin, result.verifiedScts[0].origin);
   }
 
   // Writes an SCTList containing a single |sct| into |output|.
   void EncodeSCTListForTesting(Input sct, Buffer& output)
   {
     Vector<Input> list;
     ASSERT_TRUE(list.append(Move(sct)));
     ASSERT_EQ(Success, EncodeSCTList(list, output));
@@ -80,18 +81,17 @@ public:
     ExtractEmbeddedSCTList(cert, sctList);
     ASSERT_FALSE(sctList.empty());
 
     CTVerifyResult result;
     ASSERT_EQ(Success,
               mVerifier.Verify(InputForBuffer(cert), InputForBuffer(issuerSPKI),
                                InputForBuffer(sctList), Input(), Input(),
                                mNow, result));
-    CheckForSingleVerifiedSCTInResult(result,
-      SignedCertificateTimestamp::Origin::Embedded);
+    CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::Embedded);
   }
 
 protected:
   MultiLogCTVerifier mVerifier;
   Buffer mTestCert;
   Buffer mEmbeddedCert;
   Buffer mCaCert;
   Buffer mCaCertSPKI;
@@ -161,73 +161,66 @@ TEST_F(MultiLogCTVerifierTest, VerifiesS
   EncodeSCTListForTesting(InputForBuffer(sct), sctList);
 
   CTVerifyResult result;
   ASSERT_EQ(Success,
             mVerifier.Verify(InputForBuffer(mTestCert), Input(),
                              Input(), InputForBuffer(sctList), Input(),
                              mNow, result));
 
-  CheckForSingleVerifiedSCTInResult(result,
-    SignedCertificateTimestamp::Origin::OCSPResponse);
+  CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::OCSPResponse);
 }
 
 TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromTLS)
 {
   Buffer sct(GetTestSignedCertificateTimestamp());
   Buffer sctList;
   EncodeSCTListForTesting(InputForBuffer(sct), sctList);
 
   CTVerifyResult result;
   ASSERT_EQ(Success,
             mVerifier.Verify(InputForBuffer(mTestCert), Input(),
                              Input(), Input(), InputForBuffer(sctList),
                              mNow, result));
 
-  CheckForSingleVerifiedSCTInResult(result,
-    SignedCertificateTimestamp::Origin::TLSExtension);
+  CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::TLSExtension);
 }
 
 TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromMultipleSources)
 {
   Buffer sct(GetTestSignedCertificateTimestamp());
   Buffer sctList;
   EncodeSCTListForTesting(InputForBuffer(sct), sctList);
 
   CTVerifyResult result;
   ASSERT_EQ(Success,
             mVerifier.Verify(InputForBuffer(mTestCert), Input(), Input(),
                              InputForBuffer(sctList), InputForBuffer(sctList),
                              mNow, result));
 
   // The result should contain verified SCTs from TLS and OCSP origins.
-  EnumSet<SignedCertificateTimestamp::Origin> origins;
-  for (const SignedCertificateTimestamp& sct : result.scts) {
-    EXPECT_EQ(SignedCertificateTimestamp::VerificationStatus::OK,
-              sct.verificationStatus);
-    origins += sct.origin;
+  EnumSet<VerifiedSCT::Origin> origins;
+  for (const VerifiedSCT& verifiedSct : result.verifiedScts) {
+    EXPECT_EQ(VerifiedSCT::Status::Valid, verifiedSct.status);
+    origins += verifiedSct.origin;
   }
-  EXPECT_FALSE(
-    origins.contains(SignedCertificateTimestamp::Origin::Embedded));
-  EXPECT_TRUE(
-    origins.contains(SignedCertificateTimestamp::Origin::OCSPResponse));
-  EXPECT_TRUE(
-    origins.contains(SignedCertificateTimestamp::Origin::TLSExtension));
+  EXPECT_FALSE(origins.contains(VerifiedSCT::Origin::Embedded));
+  EXPECT_TRUE(origins.contains(VerifiedSCT::Origin::OCSPResponse));
+  EXPECT_TRUE(origins.contains(VerifiedSCT::Origin::TLSExtension));
 }
 
 TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog)
 {
   Buffer sctList;
   GetSCTListWithInvalidLogID(sctList);
 
   CTVerifyResult result;
   ASSERT_EQ(Success,
             mVerifier.Verify(InputForBuffer(mTestCert), Input(),
                              Input(), Input(), InputForBuffer(sctList),
                              mNow, result));
 
   EXPECT_EQ(0U, result.decodingErrors);
-  ASSERT_EQ(1U, result.scts.length());
-  EXPECT_EQ(SignedCertificateTimestamp::VerificationStatus::UnknownLog,
-            result.scts[0].verificationStatus);
+  ASSERT_EQ(1U, result.verifiedScts.length());
+  EXPECT_EQ(VerifiedSCT::Status::UnknownLog, result.verifiedScts[0].status);
 }
 
 } } // namespace mozilla::ct
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -1222,52 +1222,52 @@ GatherSuccessfulValidationTelemetry(cons
 {
   GatherBaselineRequirementsTelemetry(certList);
   GatherEKUTelemetry(certList);
   GatherRootCATelemetry(certList);
   GatherEndEntityTelemetry(certList);
 }
 
 void
-GatherTelemetryForSingleSCT(const ct::SignedCertificateTimestamp& sct)
+GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct)
 {
   // See SSL_SCTS_ORIGIN in Histograms.json.
   uint32_t origin = 0;
-  switch (sct.origin) {
-    case ct::SignedCertificateTimestamp::Origin::Embedded:
+  switch (verifiedSct.origin) {
+    case ct::VerifiedSCT::Origin::Embedded:
       origin = 1;
       break;
-    case ct::SignedCertificateTimestamp::Origin::TLSExtension:
+    case ct::VerifiedSCT::Origin::TLSExtension:
       origin = 2;
       break;
-    case ct::SignedCertificateTimestamp::Origin::OCSPResponse:
+    case ct::VerifiedSCT::Origin::OCSPResponse:
       origin = 3;
       break;
     default:
-      MOZ_ASSERT_UNREACHABLE("Unexpected SCT::Origin type");
+      MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Origin type");
   }
   Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, origin);
 
   // See SSL_SCTS_VERIFICATION_STATUS in Histograms.json.
   uint32_t verificationStatus = 0;
-  switch (sct.verificationStatus) {
-    case ct::SignedCertificateTimestamp::VerificationStatus::OK:
+  switch (verifiedSct.status) {
+    case ct::VerifiedSCT::Status::Valid:
       verificationStatus = 1;
       break;
-    case ct::SignedCertificateTimestamp::VerificationStatus::UnknownLog:
+    case ct::VerifiedSCT::Status::UnknownLog:
       verificationStatus = 2;
       break;
-    case ct::SignedCertificateTimestamp::VerificationStatus::InvalidSignature:
+    case ct::VerifiedSCT::Status::InvalidSignature:
       verificationStatus = 3;
       break;
-    case ct::SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp:
+    case ct::VerifiedSCT::Status::InvalidTimestamp:
       verificationStatus = 4;
       break;
     default:
-      MOZ_ASSERT_UNREACHABLE("Unexpected SCT::VerificationStatus type");
+      MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
   }
   Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS,
                         verificationStatus);
 }
 
 void
 GatherCertificateTransparencyTelemetry(const UniqueCERTCertList& certList,
                                        const CertificateTransparencyInfo& info)
@@ -1278,28 +1278,29 @@ GatherCertificateTransparencyTelemetry(c
   }
 
   if (!info.processedSCTs) {
     // We didn't receive any SCT data for this connection.
     Telemetry::Accumulate(Telemetry::SSL_SCTS_PER_CONNECTION, 0);
     return;
   }
 
-  for (const ct::SignedCertificateTimestamp& sct : info.verifyResult.scts) {
+  for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) {
     GatherTelemetryForSingleSCT(sct);
   }
 
   // Decoding errors are reported to the 0th bucket
   // of the SSL_SCTS_VERIFICATION_STATUS enumerated probe.
   for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) {
     Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 0);
   }
 
   // Handle the histogram of SCTs counts.
-  uint32_t sctsCount = static_cast<uint32_t>(info.verifyResult.scts.length());
+  uint32_t sctsCount =
+    static_cast<uint32_t>(info.verifyResult.verifiedScts.length());
   // Note that sctsCount can be 0 in case we've received SCT binary data,
   // but it failed to parse (e.g. due to unsupported CT protocol version).
   Telemetry::Accumulate(Telemetry::SSL_SCTS_PER_CONNECTION, sctsCount);
 }
 
 // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned.
 SECStatus
 AuthCertificate(CertVerifier& certVerifier,
--- a/security/manager/ssl/nsSSLStatus.cpp
+++ b/security/manager/ssl/nsSSLStatus.cpp
@@ -1,21 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "CTVerifyResult.h"
 #include "mozilla/Casting.h"
 #include "nsSSLStatus.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIObjectInputStream.h"
 #include "nsNSSCertificate.h"
-#include "SignedCertificateTimestamp.h"
 #include "ssl.h"
 
 NS_IMETHODIMP
 nsSSLStatus::GetServerCert(nsIX509Cert** aServerCert)
 {
   NS_ENSURE_ARG_POINTER(aServerCert);
 
   nsCOMPtr<nsIX509Cert> cert = mServerCert;
@@ -325,53 +325,53 @@ nsSSLStatus::SetServerCert(nsNSSCertific
   mIsEV = (aEVStatus == EVStatus::EV);
   mHasIsEVStatus = true;
 }
 
 void
 nsSSLStatus::SetCertificateTransparencyInfo(
   const mozilla::psm::CertificateTransparencyInfo& info)
 {
-  using mozilla::ct::SignedCertificateTimestamp;
+  using mozilla::ct::VerifiedSCT;
 
   if (!info.enabled) {
     // CT disabled.
     mCertificateTransparencyStatus =
       nsISSLStatus::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE;
     return;
   }
 
   if (!info.processedSCTs) {
     // No SCTs processed on the connection.
     mCertificateTransparencyStatus =
       nsISSLStatus::CERTIFICATE_TRANSPARENCY_NONE;
     return;
   }
 
-  bool hasOKSCTs = false;
+  bool hasValidSCTs = false;
   bool hasUnknownLogSCTs = false;
   bool hasInvalidSCTs = false;
-  for (const SignedCertificateTimestamp& sct : info.verifyResult.scts) {
-    switch (sct.verificationStatus) {
-      case SignedCertificateTimestamp::VerificationStatus::OK:
-        hasOKSCTs = true;
+  for (const VerifiedSCT& verifiedSct : info.verifyResult.verifiedScts) {
+    switch (verifiedSct.status) {
+      case VerifiedSCT::Status::Valid:
+        hasValidSCTs = true;
         break;
-      case SignedCertificateTimestamp::VerificationStatus::UnknownLog:
+      case VerifiedSCT::Status::UnknownLog:
         hasUnknownLogSCTs = true;
         break;
-      case SignedCertificateTimestamp::VerificationStatus::InvalidSignature:
-      case SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp:
+      case VerifiedSCT::Status::InvalidSignature:
+      case VerifiedSCT::Status::InvalidTimestamp:
         hasInvalidSCTs = true;
         break;
       default:
-        MOZ_ASSERT_UNREACHABLE("Unexpected SCT::VerificationStatus type");
+        MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
     }
   }
 
-  if (hasOKSCTs) {
+  if (hasValidSCTs) {
     mCertificateTransparencyStatus =
       nsISSLStatus::CERTIFICATE_TRANSPARENCY_OK;
   } else if (hasUnknownLogSCTs) {
     mCertificateTransparencyStatus =
       nsISSLStatus::CERTIFICATE_TRANSPARENCY_UNKNOWN_LOG;
   } else if (hasInvalidSCTs) {
     mCertificateTransparencyStatus =
       nsISSLStatus::CERTIFICATE_TRANSPARENCY_INVALID;