// Copyright 2016 The Chromium Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "cert_errors.h" #include "cert_error_params.h" #include "parse_name.h" #include "parsed_certificate.h" #include BSSL_NAMESPACE_BEGIN namespace { void AppendLinesWithIndentation(const std::string &text, const std::string &indentation, std::string *out) { std::istringstream stream(text); for (std::string line; std::getline(stream, line, '\n');) { out->append(indentation); out->append(line); out->append("\n"); } } } // namespace CertError::CertError() = default; CertError::CertError(Severity in_severity, CertErrorId in_id, std::unique_ptr in_params) : severity(in_severity), id(in_id), params(std::move(in_params)) {} CertError::CertError(CertError &&other) = default; CertError &CertError::operator=(CertError &&) = default; CertError::~CertError() = default; std::string CertError::ToDebugString() const { std::string result; switch (severity) { case SEVERITY_WARNING: result += "WARNING: "; break; case SEVERITY_HIGH: result += "ERROR: "; break; } result += CertErrorIdToDebugString(id); result += +"\n"; if (params) { AppendLinesWithIndentation(params->ToDebugString(), " ", &result); } return result; } CertErrors::CertErrors() = default; CertErrors::CertErrors(CertErrors &&other) = default; CertErrors &CertErrors::operator=(CertErrors &&) = default; CertErrors::~CertErrors() = default; void CertErrors::Add(CertError::Severity severity, CertErrorId id, std::unique_ptr params) { nodes_.emplace_back(severity, id, std::move(params)); } void CertErrors::AddError(CertErrorId id, std::unique_ptr params) { Add(CertError::SEVERITY_HIGH, id, std::move(params)); } void CertErrors::AddError(CertErrorId id) { AddError(id, nullptr); } void CertErrors::AddWarning(CertErrorId id, std::unique_ptr params) { Add(CertError::SEVERITY_WARNING, id, std::move(params)); } void CertErrors::AddWarning(CertErrorId id) { AddWarning(id, nullptr); } std::string CertErrors::ToDebugString() const { std::string result; for (const CertError &node : nodes_) { result += node.ToDebugString(); } return result; } bool CertErrors::ContainsErrorWithSeverity(CertErrorId id, CertError::Severity severity) const { for (const CertError &node : nodes_) { if (node.id == id && node.severity == severity) { return true; } } return false; } bool CertErrors::ContainsError(CertErrorId id) const { return ContainsErrorWithSeverity(id, CertError::SEVERITY_HIGH); } bool CertErrors::ContainsAnyErrorWithSeverity( CertError::Severity severity) const { for (const CertError &node : nodes_) { if (node.severity == severity) { return true; } } return false; } CertPathErrors::CertPathErrors() = default; CertPathErrors::CertPathErrors(CertPathErrors &&other) = default; CertPathErrors &CertPathErrors::operator=(CertPathErrors &&) = default; CertPathErrors::~CertPathErrors() = default; CertErrors *CertPathErrors::GetErrorsForCert(size_t cert_index) { if (cert_index >= cert_errors_.size()) { cert_errors_.resize(cert_index + 1); } return &cert_errors_[cert_index]; } const CertErrors *CertPathErrors::GetErrorsForCert(size_t cert_index) const { if (cert_index >= cert_errors_.size()) { return nullptr; } return &cert_errors_[cert_index]; } CertErrors *CertPathErrors::GetOtherErrors() { return &other_errors_; } const CertErrors *CertPathErrors::GetOtherErrors() const { return &other_errors_; } bool CertPathErrors::ContainsError(CertErrorId id) const { for (const CertErrors &errors : cert_errors_) { if (errors.ContainsError(id)) { return true; } } if (other_errors_.ContainsError(id)) { return true; } return false; } bool CertPathErrors::ContainsAnyErrorWithSeverity( CertError::Severity severity) const { for (const CertErrors &errors : cert_errors_) { if (errors.ContainsAnyErrorWithSeverity(severity)) { return true; } } if (other_errors_.ContainsAnyErrorWithSeverity(severity)) { return true; } return false; } std::optional CertPathErrors::FindSingleHighSeverityError( ptrdiff_t &out_depth) const { std::optional id_seen; for (ptrdiff_t i = -1; i < (ptrdiff_t)cert_errors_.size(); ++i) { const CertErrors *errors = (i < 0) ? GetOtherErrors() : GetErrorsForCert(i); for (const CertError &node : errors->nodes_) { if (node.severity == CertError::SEVERITY_HIGH) { if (!id_seen.has_value()) { id_seen = node.id; out_depth = i; } else { if (id_seen.value() != node.id) { return {}; } } } } } return id_seen; } std::string CertPathErrors::ToDebugString( const ParsedCertificateList &certs) const { std::ostringstream result; for (size_t i = 0; i < cert_errors_.size(); ++i) { // Pretty print the current CertErrors. If there were no errors/warnings, // then continue. const CertErrors &errors = cert_errors_[i]; std::string cert_errors_string = errors.ToDebugString(); if (cert_errors_string.empty()) { continue; } // Add a header that identifies which certificate this CertErrors pertains // to. std::string cert_name_debug_str; if (i < certs.size() && certs[i]) { RDNSequence subject; if (ParseName(certs[i]->tbs().subject_tlv, &subject) && ConvertToRFC2253(subject, &cert_name_debug_str)) { cert_name_debug_str = " (" + cert_name_debug_str + ")"; } } result << "----- Certificate i=" << i << cert_name_debug_str << " -----\n"; result << cert_errors_string << "\n"; } // Print any other errors that aren't associated with a particular certificate // in the chain. std::string other_errors = other_errors_.ToDebugString(); if (!other_errors.empty()) { result << "----- Other errors (not certificate specific) -----\n"; result << other_errors << "\n"; } return result.str(); } BSSL_NAMESPACE_END