MultiLogCTVerifier.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "MultiLogCTVerifier.h"
  6. #include "CTObjectsExtractor.h"
  7. #include "CTSerialization.h"
  8. #include "mozilla/Assertions.h"
  9. #include "mozilla/Move.h"
  10. namespace mozilla { namespace ct {
  11. using namespace mozilla::pkix;
  12. // Note: this moves |sct| to the target list in |result|, invalidating |sct|.
  13. static Result
  14. StoreVerifiedSct(CTVerifyResult& result,
  15. SignedCertificateTimestamp&& sct,
  16. SignedCertificateTimestamp::VerificationStatus status)
  17. {
  18. sct.verificationStatus = status;
  19. if (!result.scts.append(Move(sct))) {
  20. return Result::FATAL_ERROR_NO_MEMORY;
  21. }
  22. return Success;
  23. }
  24. Result
  25. MultiLogCTVerifier::AddLog(Input publicKey)
  26. {
  27. CTLogVerifier log;
  28. Result rv = log.Init(publicKey);
  29. if (rv != Success) {
  30. return rv;
  31. }
  32. if (!mLogs.append(Move(log))) {
  33. return Result::FATAL_ERROR_NO_MEMORY;
  34. }
  35. return Success;
  36. }
  37. Result
  38. MultiLogCTVerifier::Verify(Input cert,
  39. Input issuerSubjectPublicKeyInfo,
  40. Input sctListFromCert,
  41. Input sctListFromOCSPResponse,
  42. Input sctListFromTLSExtension,
  43. Time time,
  44. CTVerifyResult& result)
  45. {
  46. MOZ_ASSERT(cert.GetLength() > 0);
  47. result.Reset();
  48. Result rv;
  49. // Verify embedded SCTs
  50. if (issuerSubjectPublicKeyInfo.GetLength() > 0 &&
  51. sctListFromCert.GetLength() > 0) {
  52. LogEntry precertEntry;
  53. rv = GetPrecertLogEntry(cert, issuerSubjectPublicKeyInfo, precertEntry);
  54. if (rv != Success) {
  55. return rv;
  56. }
  57. rv = VerifySCTs(sctListFromCert, precertEntry,
  58. SignedCertificateTimestamp::Origin::Embedded, time,
  59. result);
  60. if (rv != Success) {
  61. return rv;
  62. }
  63. }
  64. LogEntry x509Entry;
  65. rv = GetX509LogEntry(cert, x509Entry);
  66. if (rv != Success) {
  67. return rv;
  68. }
  69. // Verify SCTs from a stapled OCSP response
  70. if (sctListFromOCSPResponse.GetLength() > 0) {
  71. rv = VerifySCTs(sctListFromOCSPResponse, x509Entry,
  72. SignedCertificateTimestamp::Origin::OCSPResponse, time,
  73. result);
  74. if (rv != Success) {
  75. return rv;
  76. }
  77. }
  78. // Verify SCTs from a TLS extension
  79. if (sctListFromTLSExtension.GetLength() > 0) {
  80. rv = VerifySCTs(sctListFromTLSExtension, x509Entry,
  81. SignedCertificateTimestamp::Origin::TLSExtension, time,
  82. result);
  83. if (rv != Success) {
  84. return rv;
  85. }
  86. }
  87. return Success;
  88. }
  89. Result
  90. MultiLogCTVerifier::VerifySCTs(Input encodedSctList,
  91. const LogEntry& expectedEntry,
  92. SignedCertificateTimestamp::Origin origin,
  93. Time time,
  94. CTVerifyResult& result)
  95. {
  96. Reader listReader;
  97. Result rv = DecodeSCTList(encodedSctList, listReader);
  98. if (rv != Success) {
  99. result.decodingErrors++;
  100. return Success;
  101. }
  102. while (!listReader.AtEnd()) {
  103. Input encodedSct;
  104. rv = ReadSCTListItem(listReader, encodedSct);
  105. if (rv != Success) {
  106. result.decodingErrors++;
  107. return Success;
  108. }
  109. Reader encodedSctReader(encodedSct);
  110. SignedCertificateTimestamp sct;
  111. rv = DecodeSignedCertificateTimestamp(encodedSctReader, sct);
  112. if (rv != Success) {
  113. result.decodingErrors++;
  114. continue;
  115. }
  116. sct.origin = origin;
  117. rv = VerifySingleSCT(Move(sct), expectedEntry, time, result);
  118. if (rv != Success) {
  119. return rv;
  120. }
  121. }
  122. return Success;
  123. }
  124. Result
  125. MultiLogCTVerifier::VerifySingleSCT(SignedCertificateTimestamp&& sct,
  126. const LogEntry& expectedEntry,
  127. Time time,
  128. CTVerifyResult& result)
  129. {
  130. CTLogVerifier* matchingLog = nullptr;
  131. for (auto& log : mLogs) {
  132. if (log.keyId() == sct.logId) {
  133. matchingLog = &log;
  134. break;
  135. }
  136. }
  137. if (!matchingLog) {
  138. // SCT does not match any known log.
  139. return StoreVerifiedSct(result, Move(sct),
  140. SignedCertificateTimestamp::VerificationStatus::UnknownLog);
  141. }
  142. if (!matchingLog->SignatureParametersMatch(sct.signature)) {
  143. // SCT signature parameters do not match the log's.
  144. return StoreVerifiedSct(result, Move(sct),
  145. SignedCertificateTimestamp::VerificationStatus::InvalidSignature);
  146. }
  147. Result rv = matchingLog->Verify(expectedEntry, sct);
  148. if (rv != Success) {
  149. if (rv == Result::ERROR_BAD_SIGNATURE) {
  150. return StoreVerifiedSct(result, Move(sct),
  151. SignedCertificateTimestamp::VerificationStatus::InvalidSignature);
  152. }
  153. return rv;
  154. }
  155. // |sct.timestamp| is measured in milliseconds since the epoch,
  156. // ignoring leap seconds. When converting it to a second-level precision
  157. // pkix::Time, we need to round it either up or down. In our case, rounding up
  158. // is more "secure", although practically it does not matter.
  159. Time sctTime = TimeFromEpochInSeconds((sct.timestamp + 999u) / 1000u);
  160. // SCT verified ok, just make sure the timestamp is legitimate.
  161. if (sctTime > time) {
  162. return StoreVerifiedSct(result, Move(sct),
  163. SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp);
  164. }
  165. return StoreVerifiedSct(result, Move(sct),
  166. SignedCertificateTimestamp::VerificationStatus::OK);
  167. }
  168. } } // namespace mozilla::ct