| // 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 <sstream> | 
 |  | 
 | 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<CertErrorParams> 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<CertErrorParams> params) { | 
 |   nodes_.emplace_back(severity, id, std::move(params)); | 
 | } | 
 |  | 
 | void CertErrors::AddError(CertErrorId id, | 
 |                           std::unique_ptr<CertErrorParams> 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<CertErrorParams> 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<CertErrorId> CertPathErrors::FindSingleHighSeverityError( | 
 |     ptrdiff_t &out_depth) const { | 
 |   std::optional<CertErrorId> 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 |