1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/cert/pki/cert_errors.h"
6 
7 #include "net/cert/pki/cert_error_params.h"
8 #include "net/cert/pki/parse_name.h"
9 #include "net/cert/pki/parsed_certificate.h"
10 
11 #include <sstream>
12 
13 namespace net {
14 
15 namespace {
16 
AppendLinesWithIndentation(const std::string & text,const std::string & indentation,std::string * out)17 void AppendLinesWithIndentation(const std::string& text,
18                                 const std::string& indentation,
19                                 std::string* out) {
20   std::istringstream stream(text);
21   for (std::string line; std::getline(stream, line, '\n');) {
22     out->append(indentation);
23     out->append(line);
24     out->append("\n");
25   }
26 }
27 
28 }  // namespace
29 
30 CertError::CertError() = default;
31 
CertError(Severity severity,CertErrorId id,std::unique_ptr<CertErrorParams> params)32 CertError::CertError(Severity severity,
33                      CertErrorId id,
34                      std::unique_ptr<CertErrorParams> params)
35     : severity(severity), id(id), params(std::move(params)) {}
36 
37 CertError::CertError(CertError&& other) = default;
38 
39 CertError& CertError::operator=(CertError&&) = default;
40 
41 CertError::~CertError() = default;
42 
ToDebugString() const43 std::string CertError::ToDebugString() const {
44   std::string result;
45   switch (severity) {
46     case SEVERITY_WARNING:
47       result += "WARNING: ";
48       break;
49     case SEVERITY_HIGH:
50       result += "ERROR: ";
51       break;
52   }
53   result += CertErrorIdToDebugString(id);
54   result += +"\n";
55 
56   if (params)
57     AppendLinesWithIndentation(params->ToDebugString(), "  ", &result);
58 
59   return result;
60 }
61 
62 CertErrors::CertErrors() = default;
63 CertErrors::CertErrors(CertErrors&& other) = default;
64 CertErrors& CertErrors::operator=(CertErrors&&) = default;
65 CertErrors::~CertErrors() = default;
66 
Add(CertError::Severity severity,CertErrorId id,std::unique_ptr<CertErrorParams> params)67 void CertErrors::Add(CertError::Severity severity,
68                      CertErrorId id,
69                      std::unique_ptr<CertErrorParams> params) {
70   nodes_.emplace_back(severity, id, std::move(params));
71 }
72 
AddError(CertErrorId id,std::unique_ptr<CertErrorParams> params)73 void CertErrors::AddError(CertErrorId id,
74                           std::unique_ptr<CertErrorParams> params) {
75   Add(CertError::SEVERITY_HIGH, id, std::move(params));
76 }
77 
AddError(CertErrorId id)78 void CertErrors::AddError(CertErrorId id) {
79   AddError(id, nullptr);
80 }
81 
AddWarning(CertErrorId id,std::unique_ptr<CertErrorParams> params)82 void CertErrors::AddWarning(CertErrorId id,
83                             std::unique_ptr<CertErrorParams> params) {
84   Add(CertError::SEVERITY_WARNING, id, std::move(params));
85 }
86 
AddWarning(CertErrorId id)87 void CertErrors::AddWarning(CertErrorId id) {
88   AddWarning(id, nullptr);
89 }
90 
ToDebugString() const91 std::string CertErrors::ToDebugString() const {
92   std::string result;
93   for (const CertError& node : nodes_)
94     result += node.ToDebugString();
95 
96   return result;
97 }
98 
ContainsError(CertErrorId id) const99 bool CertErrors::ContainsError(CertErrorId id) const {
100   for (const CertError& node : nodes_) {
101     if (node.id == id)
102       return true;
103   }
104   return false;
105 }
106 
ContainsAnyErrorWithSeverity(CertError::Severity severity) const107 bool CertErrors::ContainsAnyErrorWithSeverity(
108     CertError::Severity severity) const {
109   for (const CertError& node : nodes_) {
110     if (node.severity == severity)
111       return true;
112   }
113   return false;
114 }
115 
116 CertPathErrors::CertPathErrors() = default;
117 
118 CertPathErrors::CertPathErrors(CertPathErrors&& other) = default;
119 CertPathErrors& CertPathErrors::operator=(CertPathErrors&&) = default;
120 
121 CertPathErrors::~CertPathErrors() = default;
122 
GetErrorsForCert(size_t cert_index)123 CertErrors* CertPathErrors::GetErrorsForCert(size_t cert_index) {
124   if (cert_index >= cert_errors_.size())
125     cert_errors_.resize(cert_index + 1);
126   return &cert_errors_[cert_index];
127 }
128 
GetErrorsForCert(size_t cert_index) const129 const CertErrors* CertPathErrors::GetErrorsForCert(size_t cert_index) const {
130   if (cert_index >= cert_errors_.size())
131     return nullptr;
132   return &cert_errors_[cert_index];
133 }
134 
GetOtherErrors()135 CertErrors* CertPathErrors::GetOtherErrors() {
136   return &other_errors_;
137 }
138 
ContainsError(CertErrorId id) const139 bool CertPathErrors::ContainsError(CertErrorId id) const {
140   for (const CertErrors& errors : cert_errors_) {
141     if (errors.ContainsError(id))
142       return true;
143   }
144 
145   if (other_errors_.ContainsError(id))
146     return true;
147 
148   return false;
149 }
150 
ContainsAnyErrorWithSeverity(CertError::Severity severity) const151 bool CertPathErrors::ContainsAnyErrorWithSeverity(
152     CertError::Severity severity) const {
153   for (const CertErrors& errors : cert_errors_) {
154     if (errors.ContainsAnyErrorWithSeverity(severity))
155       return true;
156   }
157 
158   if (other_errors_.ContainsAnyErrorWithSeverity(severity))
159     return true;
160 
161   return false;
162 }
163 
ToDebugString(const ParsedCertificateList & certs) const164 std::string CertPathErrors::ToDebugString(
165     const ParsedCertificateList& certs) const {
166   std::ostringstream result;
167 
168   for (size_t i = 0; i < cert_errors_.size(); ++i) {
169     // Pretty print the current CertErrors. If there were no errors/warnings,
170     // then continue.
171     const CertErrors& errors = cert_errors_[i];
172     std::string cert_errors_string = errors.ToDebugString();
173     if (cert_errors_string.empty())
174       continue;
175 
176     // Add a header that identifies which certificate this CertErrors pertains
177     // to.
178     std::string cert_name_debug_str;
179     if (i < certs.size() && certs[i]) {
180       RDNSequence subject;
181       if (ParseName(certs[i]->tbs().subject_tlv, &subject) &&
182           ConvertToRFC2253(subject, &cert_name_debug_str)) {
183         cert_name_debug_str = " (" + cert_name_debug_str + ")";
184       }
185     }
186     result << "----- Certificate i=" << i << cert_name_debug_str << " -----\n";
187     result << cert_errors_string << "\n";
188   }
189 
190   // Print any other errors that aren't associated with a particular certificate
191   // in the chain.
192   std::string other_errors = other_errors_.ToDebugString();
193   if (!other_errors.empty()) {
194     result << "----- Other errors (not certificate specific) -----\n";
195     result << other_errors << "\n";
196   }
197 
198   return result.str();
199 }
200 
201 }  // namespace net
202