Result
MultiLogCTVerifier::AddLog(Input publicKey)
{
  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::VerifySingleSCT(SignedCertificateTimestamp&& sct,
                                    const LogEntry& expectedEntry,
                                    Time time,
                                    CTVerifyResult& result)
{
  CTLogVerifier* matchingLog = nullptr;
  for (auto& log : mLogs) {
    if (log.keyId() == sct.logId) {
      matchingLog = &log;
      break;
    }
  }

  if (!matchingLog) {
    // SCT does not match any known log.
    return StoreVerifiedSct(result, Move(sct),
      SignedCertificateTimestamp::VerificationStatus::UnknownLog);
  }

  if (!matchingLog->SignatureParametersMatch(sct.signature)) {
    // SCT signature parameters do not match the log's.
    return StoreVerifiedSct(result, Move(sct),
      SignedCertificateTimestamp::VerificationStatus::InvalidSignature);
  }

  Result rv = matchingLog->Verify(expectedEntry, sct);
  if (rv != Success) {
    if (rv == Result::ERROR_BAD_SIGNATURE) {
      return StoreVerifiedSct(result, Move(sct),
        SignedCertificateTimestamp::VerificationStatus::InvalidSignature);
    }
    return rv;
  }

  // |sct.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.
  if (sctTime > time) {
    return StoreVerifiedSct(result, Move(sct),
      SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp);
  }

  return StoreVerifiedSct(result, Move(sct),
    SignedCertificateTimestamp::VerificationStatus::OK);
}
Result
MultiLogCTVerifier::VerifySingleSCT(SignedCertificateTimestamp&& sct,
                                    const LogEntry& expectedEntry,
                                    uint64_t time,
                                    CTVerifyResult& result)
{
  CTLogVerifier* matchingLog = nullptr;
  for (auto& log : mLogs) {
    if (log.keyId() == sct.logId) {
      matchingLog = &log;
      break;
    }
  }

  if (!matchingLog) {
    // SCT does not match any known log.
    return StoreVerifiedSct(result, Move(sct), SCTVerifyStatus::UnknownLog);
  }

  if (!matchingLog->SignatureParametersMatch(sct.signature)) {
    // SCT signature parameters do not match the log's.
    return StoreVerifiedSct(result, Move(sct), SCTVerifyStatus::Invalid);
  }

  Result rv = matchingLog->Verify(expectedEntry, sct);
  if (rv != Success) {
    if (rv == Result::ERROR_BAD_SIGNATURE) {
      return StoreVerifiedSct(result, Move(sct), SCTVerifyStatus::Invalid);
    }
    return rv;
  }

  // SCT verified ok, just make sure the timestamp is legitimate.
  if (sct.timestamp > time) {
    return StoreVerifiedSct(result, Move(sct), SCTVerifyStatus::Invalid);
  }

  return StoreVerifiedSct(result, Move(sct), SCTVerifyStatus::OK);
}