]>
Commit | Line | Data |
---|---|---|
582c2af2 | 1 | #include "squid.h" |
02259ff8 | 2 | #include "errorpage.h" |
4d16918e | 3 | #include "ssl/ErrorDetail.h" |
cf09bec7 CT |
4 | #if HAVE_MAP |
5 | #include <map> | |
6 | #endif | |
582c2af2 FC |
7 | #if HAVE_CLIMITS |
8 | #include <climits> | |
9 | #endif | |
4d16918e | 10 | |
dc49061a | 11 | struct SslErrorEntry { |
461b9576 | 12 | Ssl::ssl_error_t value; |
4d16918e | 13 | const char *name; |
4d16918e CT |
14 | }; |
15 | ||
8e9bae99 | 16 | static const char *SslErrorDetailDefaultStr = "SSL handshake error (%err_name)"; |
cf09bec7 | 17 | //Use std::map to optimize search |
02259ff8 CT |
18 | typedef std::map<Ssl::ssl_error_t, const SslErrorEntry *> SslErrors; |
19 | SslErrors TheSslErrors; | |
cf09bec7 | 20 | |
02259ff8 | 21 | static SslErrorEntry TheSslErrorArray[] = { |
e7bcc25f | 22 | {SQUID_X509_V_ERR_CERT_CHANGE, |
87f237a9 | 23 | "SQUID_X509_V_ERR_CERT_CHANGE"}, |
8e9bae99 | 24 | {SQUID_ERR_SSL_HANDSHAKE, |
87f237a9 | 25 | "SQUID_ERR_SSL_HANDSHAKE"}, |
7698a79c | 26 | {SQUID_X509_V_ERR_DOMAIN_MISMATCH, |
ef5fbcff | 27 | "SQUID_X509_V_ERR_DOMAIN_MISMATCH"}, |
2c3d5aec | 28 | {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, |
0db46e4f | 29 | "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"}, |
2c3d5aec | 30 | {X509_V_ERR_UNABLE_TO_GET_CRL, |
02259ff8 | 31 | "X509_V_ERR_UNABLE_TO_GET_CRL"}, |
2c3d5aec | 32 | {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, |
02259ff8 | 33 | "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"}, |
2c3d5aec | 34 | {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, |
02259ff8 | 35 | "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"}, |
2c3d5aec | 36 | {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, |
02259ff8 | 37 | "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"}, |
2c3d5aec | 38 | {X509_V_ERR_CERT_SIGNATURE_FAILURE, |
02259ff8 | 39 | "X509_V_ERR_CERT_SIGNATURE_FAILURE"}, |
cf09bec7 | 40 | {X509_V_ERR_CRL_SIGNATURE_FAILURE, |
02259ff8 | 41 | "X509_V_ERR_CRL_SIGNATURE_FAILURE"}, |
cf09bec7 | 42 | {X509_V_ERR_CERT_NOT_YET_VALID, |
02259ff8 | 43 | "X509_V_ERR_CERT_NOT_YET_VALID"}, |
cf09bec7 | 44 | {X509_V_ERR_CERT_HAS_EXPIRED, |
02259ff8 | 45 | "X509_V_ERR_CERT_HAS_EXPIRED"}, |
cf09bec7 | 46 | {X509_V_ERR_CRL_NOT_YET_VALID, |
02259ff8 | 47 | "X509_V_ERR_CRL_NOT_YET_VALID"}, |
cf09bec7 | 48 | {X509_V_ERR_CRL_HAS_EXPIRED, |
02259ff8 | 49 | "X509_V_ERR_CRL_HAS_EXPIRED"}, |
cf09bec7 | 50 | {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, |
02259ff8 | 51 | "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"}, |
cf09bec7 | 52 | {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, |
02259ff8 | 53 | "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"}, |
cf09bec7 | 54 | {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, |
02259ff8 | 55 | "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"}, |
cf09bec7 | 56 | {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, |
02259ff8 | 57 | "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"}, |
cf09bec7 | 58 | {X509_V_ERR_OUT_OF_MEM, |
02259ff8 | 59 | "X509_V_ERR_OUT_OF_MEM"}, |
4d16918e | 60 | {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, |
02259ff8 | 61 | "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"}, |
cf09bec7 | 62 | {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, |
02259ff8 | 63 | "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"}, |
cf09bec7 | 64 | {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, |
02259ff8 | 65 | "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"}, |
cf09bec7 | 66 | {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, |
02259ff8 | 67 | "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"}, |
cf09bec7 | 68 | {X509_V_ERR_CERT_CHAIN_TOO_LONG, |
02259ff8 | 69 | "X509_V_ERR_CERT_CHAIN_TOO_LONG"}, |
cf09bec7 | 70 | {X509_V_ERR_CERT_REVOKED, |
02259ff8 | 71 | "X509_V_ERR_CERT_REVOKED"}, |
cf09bec7 | 72 | {X509_V_ERR_INVALID_CA, |
02259ff8 | 73 | "X509_V_ERR_INVALID_CA"}, |
cf09bec7 | 74 | {X509_V_ERR_PATH_LENGTH_EXCEEDED, |
02259ff8 | 75 | "X509_V_ERR_PATH_LENGTH_EXCEEDED"}, |
cf09bec7 | 76 | {X509_V_ERR_INVALID_PURPOSE, |
02259ff8 | 77 | "X509_V_ERR_INVALID_PURPOSE"}, |
cf09bec7 | 78 | {X509_V_ERR_CERT_UNTRUSTED, |
02259ff8 | 79 | "X509_V_ERR_CERT_UNTRUSTED"}, |
cf09bec7 | 80 | {X509_V_ERR_CERT_REJECTED, |
02259ff8 | 81 | "X509_V_ERR_CERT_REJECTED"}, |
cf09bec7 | 82 | {X509_V_ERR_SUBJECT_ISSUER_MISMATCH, |
02259ff8 | 83 | "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"}, |
cf09bec7 | 84 | {X509_V_ERR_AKID_SKID_MISMATCH, |
02259ff8 | 85 | "X509_V_ERR_AKID_SKID_MISMATCH"}, |
cf09bec7 | 86 | {X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, |
02259ff8 | 87 | "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"}, |
cf09bec7 | 88 | {X509_V_ERR_KEYUSAGE_NO_CERTSIGN, |
02259ff8 | 89 | "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"}, |
cf09bec7 | 90 | {X509_V_ERR_APPLICATION_VERIFICATION, |
02259ff8 CT |
91 | "X509_V_ERR_APPLICATION_VERIFICATION"}, |
92 | { SSL_ERROR_NONE, "SSL_ERROR_NONE"}, | |
93 | {SSL_ERROR_NONE, NULL} | |
4d16918e CT |
94 | }; |
95 | ||
cf1c09f6 CT |
96 | struct SslErrorAlias { |
97 | const char *name; | |
98 | const Ssl::ssl_error_t *errors; | |
99 | }; | |
100 | ||
101 | static const Ssl::ssl_error_t hasExpired[] = {X509_V_ERR_CERT_HAS_EXPIRED, SSL_ERROR_NONE}; | |
102 | static const Ssl::ssl_error_t notYetValid[] = {X509_V_ERR_CERT_NOT_YET_VALID, SSL_ERROR_NONE}; | |
103 | static const Ssl::ssl_error_t domainMismatch[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH, SSL_ERROR_NONE}; | |
104 | static const Ssl::ssl_error_t certUntrusted[] = {X509_V_ERR_INVALID_CA, | |
87f237a9 A |
105 | X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, |
106 | X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, | |
107 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, | |
108 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, | |
109 | X509_V_ERR_CERT_UNTRUSTED, SSL_ERROR_NONE | |
110 | }; | |
cf1c09f6 CT |
111 | static const Ssl::ssl_error_t certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE}; |
112 | ||
113 | // The list of error name shortcuts for use with ssl_error acls. | |
114 | // The keys without the "ssl::" scope prefix allow shorter error | |
115 | // names within the SSL options scope. This is easier than | |
7a957a93 | 116 | // carefully stripping the scope prefix in Ssl::ParseErrorString(). |
cf1c09f6 CT |
117 | static SslErrorAlias TheSslErrorShortcutsArray[] = { |
118 | {"ssl::certHasExpired", hasExpired}, | |
119 | {"certHasExpired", hasExpired}, | |
120 | {"ssl::certNotYetValid", notYetValid}, | |
121 | {"certNotYetValid", notYetValid}, | |
122 | {"ssl::certDomainMismatch", domainMismatch}, | |
123 | {"certDomainMismatch", domainMismatch}, | |
124 | {"ssl::certUntrusted", certUntrusted}, | |
125 | {"certUntrusted", certUntrusted}, | |
126 | {"ssl::certSelfSigned", certSelfSigned}, | |
127 | {"certSelfSigned", certSelfSigned}, | |
128 | {NULL, NULL} | |
129 | }; | |
130 | ||
7a957a93 | 131 | // Use std::map to optimize search. |
cf1c09f6 CT |
132 | typedef std::map<std::string, const Ssl::ssl_error_t *> SslErrorShortcuts; |
133 | SslErrorShortcuts TheSslErrorShortcuts; | |
134 | ||
02259ff8 | 135 | static void loadSslErrorMap() |
cf09bec7 | 136 | { |
02259ff8 CT |
137 | assert(TheSslErrors.empty()); |
138 | for (int i = 0; TheSslErrorArray[i].name; ++i) { | |
139 | TheSslErrors[TheSslErrorArray[i].value] = &TheSslErrorArray[i]; | |
cf09bec7 CT |
140 | } |
141 | } | |
142 | ||
cf1c09f6 CT |
143 | static void loadSslErrorShortcutsMap() |
144 | { | |
145 | assert(TheSslErrorShortcuts.empty()); | |
a38ec4b1 | 146 | for (int i = 0; TheSslErrorShortcutsArray[i].name; ++i) |
cf1c09f6 CT |
147 | TheSslErrorShortcuts[TheSslErrorShortcutsArray[i].name] = TheSslErrorShortcutsArray[i].errors; |
148 | } | |
149 | ||
02259ff8 CT |
150 | Ssl::ssl_error_t Ssl::GetErrorCode(const char *name) |
151 | { | |
d7ae3534 FC |
152 | //TODO: use a std::map? |
153 | for (int i = 0; TheSslErrorArray[i].name != NULL; ++i) { | |
02259ff8 CT |
154 | if (strcmp(name, TheSslErrorArray[i].name) == 0) |
155 | return TheSslErrorArray[i].value; | |
156 | } | |
157 | return SSL_ERROR_NONE; | |
158 | } | |
159 | ||
cf1c09f6 | 160 | Ssl::Errors * |
5e430bf3 | 161 | Ssl::ParseErrorString(const char *name) |
4d16918e CT |
162 | { |
163 | assert(name); | |
164 | ||
02259ff8 CT |
165 | const Ssl::ssl_error_t ssl_error = GetErrorCode(name); |
166 | if (ssl_error != SSL_ERROR_NONE) | |
cf1c09f6 | 167 | return new Ssl::Errors(ssl_error); |
4d16918e CT |
168 | |
169 | if (xisdigit(*name)) { | |
170 | const long int value = strtol(name, NULL, 0); | |
171 | if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX) | |
cf1c09f6 | 172 | return new Ssl::Errors(value); |
4d16918e CT |
173 | fatalf("Too small or too bug SSL error code '%s'", name); |
174 | } | |
175 | ||
cf1c09f6 CT |
176 | if (TheSslErrorShortcuts.empty()) |
177 | loadSslErrorShortcutsMap(); | |
178 | ||
179 | const SslErrorShortcuts::const_iterator it = TheSslErrorShortcuts.find(name); | |
180 | if (it != TheSslErrorShortcuts.end()) { | |
181 | // Should not be empty... | |
87f237a9 | 182 | assert(it->second[0] != SSL_ERROR_NONE); |
cf1c09f6 | 183 | Ssl::Errors *errors = new Ssl::Errors(it->second[0]); |
a38ec4b1 | 184 | for (int i =1; it->second[i] != SSL_ERROR_NONE; ++i) { |
cf1c09f6 CT |
185 | errors->push_back_unique(it->second[i]); |
186 | } | |
187 | return errors; | |
188 | } | |
189 | ||
4d16918e | 190 | fatalf("Unknown SSL error name '%s'", name); |
cf1c09f6 | 191 | return NULL; // not reached |
4d16918e CT |
192 | } |
193 | ||
02259ff8 | 194 | const char *Ssl::GetErrorName(Ssl::ssl_error_t value) |
cf09bec7 | 195 | { |
02259ff8 CT |
196 | if (TheSslErrors.empty()) |
197 | loadSslErrorMap(); | |
cf09bec7 | 198 | |
02259ff8 CT |
199 | const SslErrors::const_iterator it = TheSslErrors.find(value); |
200 | if (it != TheSslErrors.end()) | |
201 | return it->second->name; | |
4d16918e CT |
202 | |
203 | return NULL; | |
204 | } | |
205 | ||
cf09bec7 CT |
206 | const char * |
207 | Ssl::GetErrorDescr(Ssl::ssl_error_t value) | |
208 | { | |
02259ff8 | 209 | return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value); |
cf09bec7 CT |
210 | } |
211 | ||
e34763f4 | 212 | Ssl::ErrorDetail::err_frm_code Ssl::ErrorDetail::ErrorFormatingCodes[] = { |
4d16918e CT |
213 | {"ssl_subject", &Ssl::ErrorDetail::subject}, |
214 | {"ssl_ca_name", &Ssl::ErrorDetail::ca_name}, | |
215 | {"ssl_cn", &Ssl::ErrorDetail::cn}, | |
216 | {"ssl_notbefore", &Ssl::ErrorDetail::notbefore}, | |
217 | {"ssl_notafter", &Ssl::ErrorDetail::notafter}, | |
218 | {"err_name", &Ssl::ErrorDetail::err_code}, | |
cf09bec7 | 219 | {"ssl_error_descr", &Ssl::ErrorDetail::err_descr}, |
8e9bae99 | 220 | {"ssl_lib_error", &Ssl::ErrorDetail::err_lib_error}, |
4d16918e CT |
221 | {NULL,NULL} |
222 | }; | |
223 | ||
224 | /** | |
225 | * The subject of the current certification in text form | |
226 | */ | |
227 | const char *Ssl::ErrorDetail::subject() const | |
228 | { | |
ff3bc018 | 229 | if (!broken_cert) |
4d16918e CT |
230 | return "[Not available]"; |
231 | ||
232 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 233 | X509_NAME_oneline(X509_get_subject_name(broken_cert.get()), tmpBuffer, |
e34763f4 A |
234 | sizeof(tmpBuffer)); |
235 | return tmpBuffer; | |
4d16918e CT |
236 | } |
237 | ||
238 | // helper function to be used with Ssl::matchX509CommonNames | |
239 | static int copy_cn(void *check_data, ASN1_STRING *cn_data) | |
240 | { | |
241 | String *str = (String *)check_data; | |
242 | if (!str) // no data? abort | |
243 | return 0; | |
244 | if (str->defined()) | |
245 | str->append(", "); | |
246 | str->append((const char *)cn_data->data, cn_data->length); | |
247 | return 1; | |
248 | } | |
249 | ||
250 | /** | |
251 | * The list with certificates cn and alternate names | |
252 | */ | |
253 | const char *Ssl::ErrorDetail::cn() const | |
254 | { | |
ff3bc018 | 255 | if (!broken_cert) |
4d16918e CT |
256 | return "[Not available]"; |
257 | ||
258 | static String tmpStr; ///< A temporary string buffer | |
259 | tmpStr.clean(); | |
ff3bc018 | 260 | Ssl::matchX509CommonNames(broken_cert.get(), &tmpStr, copy_cn); |
4d16918e CT |
261 | return tmpStr.termedBuf(); |
262 | } | |
263 | ||
264 | /** | |
265 | * The issuer name | |
266 | */ | |
267 | const char *Ssl::ErrorDetail::ca_name() const | |
268 | { | |
ff3bc018 | 269 | if (!broken_cert) |
4d16918e CT |
270 | return "[Not available]"; |
271 | ||
272 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 273 | X509_NAME_oneline(X509_get_issuer_name(broken_cert.get()), tmpBuffer, sizeof(tmpBuffer)); |
4d16918e CT |
274 | return tmpBuffer; |
275 | } | |
276 | ||
277 | /** | |
278 | * The certificate "not before" field | |
279 | */ | |
280 | const char *Ssl::ErrorDetail::notbefore() const | |
281 | { | |
ff3bc018 | 282 | if (!broken_cert) |
4d16918e CT |
283 | return "[Not available]"; |
284 | ||
285 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 286 | ASN1_UTCTIME * tm = X509_get_notBefore(broken_cert.get()); |
4d16918e CT |
287 | Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer)); |
288 | return tmpBuffer; | |
289 | } | |
290 | ||
291 | /** | |
292 | * The certificate "not after" field | |
293 | */ | |
294 | const char *Ssl::ErrorDetail::notafter() const | |
295 | { | |
ff3bc018 | 296 | if (!broken_cert) |
4d16918e CT |
297 | return "[Not available]"; |
298 | ||
299 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 300 | ASN1_UTCTIME * tm = X509_get_notAfter(broken_cert.get()); |
4d16918e CT |
301 | Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer)); |
302 | return tmpBuffer; | |
303 | } | |
304 | ||
305 | /** | |
306 | * The string representation of the error_no | |
307 | */ | |
308 | const char *Ssl::ErrorDetail::err_code() const | |
309 | { | |
8211c314 | 310 | static char tmpBuffer[64]; |
02259ff8 CT |
311 | // We can use the GetErrorName but using the detailEntry is faster, |
312 | // so try it first. | |
313 | const char *err = detailEntry.name.termedBuf(); | |
314 | ||
315 | // error details not loaded yet or not defined in error_details.txt, | |
316 | // try the GetErrorName... | |
317 | if (!err) | |
318 | err = GetErrorName(error_no); | |
319 | ||
8211c314 | 320 | if (!err) { |
605b80ca | 321 | snprintf(tmpBuffer, 64, "%d", (int)error_no); |
8211c314 CT |
322 | err = tmpBuffer; |
323 | } | |
4d16918e CT |
324 | return err; |
325 | } | |
326 | ||
cf09bec7 CT |
327 | /** |
328 | * A short description of the error_no | |
329 | */ | |
330 | const char *Ssl::ErrorDetail::err_descr() const | |
331 | { | |
02259ff8 CT |
332 | if (error_no == SSL_ERROR_NONE) |
333 | return "[No Error]"; | |
334 | if (const char *err = detailEntry.descr.termedBuf()) | |
cf09bec7 CT |
335 | return err; |
336 | return "[Not available]"; | |
337 | } | |
338 | ||
8e9bae99 CT |
339 | const char *Ssl::ErrorDetail::err_lib_error() const |
340 | { | |
341 | if (lib_error_no != SSL_ERROR_NONE) | |
342 | return ERR_error_string(lib_error_no, NULL); | |
343 | else | |
344 | return "[No Error]"; | |
345 | } | |
346 | ||
4d16918e | 347 | /** |
7a957a93 | 348 | * Converts the code to a string value. Supported formating codes are: |
ff3bc018 AR |
349 | * |
350 | * Error meta information: | |
8e9bae99 | 351 | * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*) |
cf09bec7 | 352 | * %ssl_error_descr: A short description of the SSL error |
ff3bc018 AR |
353 | * %ssl_lib_error: human-readable low-level error string by ERR_error_string(3SSL) |
354 | * | |
355 | * Certificate information extracted from broken (not necessarily peer!) cert | |
4d16918e CT |
356 | * %ssl_cn: The comma-separated list of common and alternate names |
357 | * %ssl_subject: The certificate subject | |
358 | * %ssl_ca_name: The certificate issuer name | |
359 | * %ssl_notbefore: The certificate "not before" field | |
360 | * %ssl_notafter: The certificate "not after" field | |
87f237a9 | 361 | * |
4d16918e CT |
362 | \retval the length of the code (the number of characters will be replaced by value) |
363 | */ | |
364 | int Ssl::ErrorDetail::convert(const char *code, const char **value) const | |
365 | { | |
366 | *value = "-"; | |
d7ae3534 | 367 | for (int i=0; ErrorFormatingCodes[i].code!=NULL; ++i) { |
4d16918e CT |
368 | const int len = strlen(ErrorFormatingCodes[i].code); |
369 | if (strncmp(code,ErrorFormatingCodes[i].code, len)==0) { | |
370 | ErrorDetail::fmt_action_t action = ErrorFormatingCodes[i].fmt_action; | |
371 | *value = (this->*action)(); | |
372 | return len; | |
373 | } | |
e34763f4 | 374 | } |
4d16918e CT |
375 | return 0; |
376 | } | |
377 | ||
378 | /** | |
e34763f4 A |
379 | * It uses the convert method to build the string errDetailStr using |
380 | * a template message for the current SSL error. The template messages | |
4d16918e CT |
381 | * can also contain normal error pages formating codes. |
382 | * Currently the error template messages are hard-coded | |
383 | */ | |
384 | void Ssl::ErrorDetail::buildDetail() const | |
385 | { | |
02259ff8 | 386 | char const *s = NULL; |
4d16918e CT |
387 | char const *p; |
388 | char const *t; | |
389 | int code_len = 0; | |
390 | ||
02259ff8 CT |
391 | if (ErrorDetailsManager::GetInstance().getErrorDetail(error_no, request.raw(), detailEntry)) |
392 | s = detailEntry.detail.termedBuf(); | |
393 | ||
394 | if (!s) | |
395 | s = SslErrorDetailDefaultStr; | |
396 | ||
8211c314 | 397 | assert(s); |
4d16918e CT |
398 | while ((p = strchr(s, '%'))) { |
399 | errDetailStr.append(s, p - s); | |
400 | code_len = convert(++p, &t); | |
401 | if (code_len) | |
402 | errDetailStr.append(t); | |
403 | else | |
404 | errDetailStr.append("%"); | |
405 | s = p + code_len; | |
406 | } | |
407 | errDetailStr.append(s, strlen(s)); | |
408 | } | |
409 | ||
e34763f4 A |
410 | const String &Ssl::ErrorDetail::toString() const |
411 | { | |
4d16918e CT |
412 | if (!errDetailStr.defined()) |
413 | buildDetail(); | |
414 | return errDetailStr; | |
415 | } | |
416 | ||
de878a55 | 417 | Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert, X509 *broken): error_no (err_no), lib_error_no(SSL_ERROR_NONE) |
4d16918e | 418 | { |
8e9bae99 | 419 | if (cert) |
de878a55 CT |
420 | peer_cert.resetAndLock(cert); |
421 | ||
422 | if (broken) | |
423 | broken_cert.resetAndLock(broken); | |
424 | else | |
425 | broken_cert.resetAndLock(cert); | |
8e9bae99 | 426 | |
02259ff8 | 427 | detailEntry.error_no = SSL_ERROR_NONE; |
4d16918e CT |
428 | } |
429 | ||
430 | Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail const &anErrDetail) | |
431 | { | |
432 | error_no = anErrDetail.error_no; | |
02259ff8 CT |
433 | request = anErrDetail.request; |
434 | ||
4d16918e | 435 | if (anErrDetail.peer_cert.get()) { |
de878a55 CT |
436 | peer_cert.resetAndLock(anErrDetail.peer_cert.get()); |
437 | } | |
438 | ||
439 | if (anErrDetail.broken_cert.get()) { | |
440 | broken_cert.resetAndLock(anErrDetail.broken_cert.get()); | |
4d16918e | 441 | } |
02259ff8 CT |
442 | |
443 | detailEntry = anErrDetail.detailEntry; | |
8e9bae99 CT |
444 | |
445 | lib_error_no = anErrDetail.lib_error_no; | |
4d16918e | 446 | } |