1 // Copyright 2016 The Chromium Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "cert_errors.h"
16
17 #include "cert_error_params.h"
18 #include "parse_name.h"
19 #include "parsed_certificate.h"
20
21 #include <sstream>
22
23 BSSL_NAMESPACE_BEGIN
24
25 namespace {
26
AppendLinesWithIndentation(const std::string & text,const std::string & indentation,std::string * out)27 void AppendLinesWithIndentation(const std::string &text,
28 const std::string &indentation,
29 std::string *out) {
30 std::istringstream stream(text);
31 for (std::string line; std::getline(stream, line, '\n');) {
32 out->append(indentation);
33 out->append(line);
34 out->append("\n");
35 }
36 }
37
38 } // namespace
39
40 CertError::CertError() = default;
41
CertError(Severity in_severity,CertErrorId in_id,std::unique_ptr<CertErrorParams> in_params)42 CertError::CertError(Severity in_severity, CertErrorId in_id,
43 std::unique_ptr<CertErrorParams> in_params)
44 : severity(in_severity), id(in_id), params(std::move(in_params)) {}
45
46 CertError::CertError(CertError &&other) = default;
47
48 CertError &CertError::operator=(CertError &&) = default;
49
50 CertError::~CertError() = default;
51
ToDebugString() const52 std::string CertError::ToDebugString() const {
53 std::string result;
54 switch (severity) {
55 case SEVERITY_WARNING:
56 result += "WARNING: ";
57 break;
58 case SEVERITY_HIGH:
59 result += "ERROR: ";
60 break;
61 }
62 result += CertErrorIdToDebugString(id);
63 result += +"\n";
64
65 if (params) {
66 AppendLinesWithIndentation(params->ToDebugString(), " ", &result);
67 }
68
69 return result;
70 }
71
72 CertErrors::CertErrors() = default;
73 CertErrors::CertErrors(CertErrors &&other) = default;
74 CertErrors &CertErrors::operator=(CertErrors &&) = default;
75 CertErrors::~CertErrors() = default;
76
Add(CertError::Severity severity,CertErrorId id,std::unique_ptr<CertErrorParams> params)77 void CertErrors::Add(CertError::Severity severity, CertErrorId id,
78 std::unique_ptr<CertErrorParams> params) {
79 nodes_.emplace_back(severity, id, std::move(params));
80 }
81
AddError(CertErrorId id,std::unique_ptr<CertErrorParams> params)82 void CertErrors::AddError(CertErrorId id,
83 std::unique_ptr<CertErrorParams> params) {
84 Add(CertError::SEVERITY_HIGH, id, std::move(params));
85 }
86
AddError(CertErrorId id)87 void CertErrors::AddError(CertErrorId id) { AddError(id, nullptr); }
88
AddWarning(CertErrorId id,std::unique_ptr<CertErrorParams> params)89 void CertErrors::AddWarning(CertErrorId id,
90 std::unique_ptr<CertErrorParams> params) {
91 Add(CertError::SEVERITY_WARNING, id, std::move(params));
92 }
93
AddWarning(CertErrorId id)94 void CertErrors::AddWarning(CertErrorId id) { AddWarning(id, nullptr); }
95
ToDebugString() const96 std::string CertErrors::ToDebugString() const {
97 std::string result;
98 for (const CertError &node : nodes_) {
99 result += node.ToDebugString();
100 }
101
102 return result;
103 }
104
ContainsErrorWithSeverity(CertErrorId id,CertError::Severity severity) const105 bool CertErrors::ContainsErrorWithSeverity(CertErrorId id,
106 CertError::Severity severity) const {
107 for (const CertError &node : nodes_) {
108 if (node.id == id && node.severity == severity) {
109 return true;
110 }
111 }
112 return false;
113 }
114
ContainsError(CertErrorId id) const115 bool CertErrors::ContainsError(CertErrorId id) const {
116 return ContainsErrorWithSeverity(id, CertError::SEVERITY_HIGH);
117 }
118
ContainsAnyErrorWithSeverity(CertError::Severity severity) const119 bool CertErrors::ContainsAnyErrorWithSeverity(
120 CertError::Severity severity) const {
121 for (const CertError &node : nodes_) {
122 if (node.severity == severity) {
123 return true;
124 }
125 }
126 return false;
127 }
128
129 CertPathErrors::CertPathErrors() = default;
130
131 CertPathErrors::CertPathErrors(CertPathErrors &&other) = default;
132 CertPathErrors &CertPathErrors::operator=(CertPathErrors &&) = default;
133
134 CertPathErrors::~CertPathErrors() = default;
135
GetErrorsForCert(size_t cert_index)136 CertErrors *CertPathErrors::GetErrorsForCert(size_t cert_index) {
137 if (cert_index >= cert_errors_.size()) {
138 cert_errors_.resize(cert_index + 1);
139 }
140 return &cert_errors_[cert_index];
141 }
142
GetErrorsForCert(size_t cert_index) const143 const CertErrors *CertPathErrors::GetErrorsForCert(size_t cert_index) const {
144 if (cert_index >= cert_errors_.size()) {
145 return nullptr;
146 }
147 return &cert_errors_[cert_index];
148 }
149
GetOtherErrors()150 CertErrors *CertPathErrors::GetOtherErrors() { return &other_errors_; }
151
GetOtherErrors() const152 const CertErrors *CertPathErrors::GetOtherErrors() const {
153 return &other_errors_;
154 }
155
ContainsError(CertErrorId id) const156 bool CertPathErrors::ContainsError(CertErrorId id) const {
157 for (const CertErrors &errors : cert_errors_) {
158 if (errors.ContainsError(id)) {
159 return true;
160 }
161 }
162
163 if (other_errors_.ContainsError(id)) {
164 return true;
165 }
166
167 return false;
168 }
169
ContainsAnyErrorWithSeverity(CertError::Severity severity) const170 bool CertPathErrors::ContainsAnyErrorWithSeverity(
171 CertError::Severity severity) const {
172 for (const CertErrors &errors : cert_errors_) {
173 if (errors.ContainsAnyErrorWithSeverity(severity)) {
174 return true;
175 }
176 }
177
178 if (other_errors_.ContainsAnyErrorWithSeverity(severity)) {
179 return true;
180 }
181
182 return false;
183 }
184
FindSingleHighSeverityError(ptrdiff_t & out_depth) const185 std::optional<CertErrorId> CertPathErrors::FindSingleHighSeverityError(
186 ptrdiff_t &out_depth) const {
187 std::optional<CertErrorId> id_seen;
188 for (ptrdiff_t i = -1; i < (ptrdiff_t)cert_errors_.size(); ++i) {
189 const CertErrors *errors =
190 (i < 0) ? GetOtherErrors() : GetErrorsForCert(i);
191 for (const CertError &node : errors->nodes_) {
192 if (node.severity == CertError::SEVERITY_HIGH) {
193 if (!id_seen.has_value()) {
194 id_seen = node.id;
195 out_depth = i;
196 } else {
197 if (id_seen.value() != node.id) {
198 return {};
199 }
200 }
201 }
202 }
203 }
204 return id_seen;
205 }
206
ToDebugString(const ParsedCertificateList & certs) const207 std::string CertPathErrors::ToDebugString(
208 const ParsedCertificateList &certs) const {
209 std::ostringstream result;
210
211 for (size_t i = 0; i < cert_errors_.size(); ++i) {
212 // Pretty print the current CertErrors. If there were no errors/warnings,
213 // then continue.
214 const CertErrors &errors = cert_errors_[i];
215 std::string cert_errors_string = errors.ToDebugString();
216 if (cert_errors_string.empty()) {
217 continue;
218 }
219
220 // Add a header that identifies which certificate this CertErrors pertains
221 // to.
222 std::string cert_name_debug_str;
223 if (i < certs.size() && certs[i]) {
224 RDNSequence subject;
225 if (ParseName(certs[i]->tbs().subject_tlv, &subject) &&
226 ConvertToRFC2253(subject, &cert_name_debug_str)) {
227 cert_name_debug_str = " (" + cert_name_debug_str + ")";
228 }
229 }
230 result << "----- Certificate i=" << i << cert_name_debug_str << " -----\n";
231 result << cert_errors_string << "\n";
232 }
233
234 // Print any other errors that aren't associated with a particular certificate
235 // in the chain.
236 std::string other_errors = other_errors_.ToDebugString();
237 if (!other_errors.empty()) {
238 result << "----- Other errors (not certificate specific) -----\n";
239 result << other_errors << "\n";
240 }
241
242 return result.str();
243 }
244
245 BSSL_NAMESPACE_END
246