]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/ErrorDetail.cc
Remove many uses of String::defined()
[thirdparty/squid.git] / src / ssl / ErrorDetail.cc
1 #include "squid.h"
2 #include "errorpage.h"
3 #include "ssl/ErrorDetail.h"
4 #if HAVE_MAP
5 #include <map>
6 #endif
7 #if HAVE_CLIMITS
8 #include <climits>
9 #endif
10
11 struct SslErrorEntry {
12 Ssl::ssl_error_t value;
13 const char *name;
14 };
15
16 static const char *SslErrorDetailDefaultStr = "SSL handshake error (%err_name)";
17 //Use std::map to optimize search
18 typedef std::map<Ssl::ssl_error_t, const SslErrorEntry *> SslErrors;
19 SslErrors TheSslErrors;
20
21 static SslErrorEntry TheSslErrorArray[] = {
22 {SQUID_X509_V_ERR_INFINITE_VALIDATION,
23 "SQUID_X509_V_ERR_INFINITE_VALIDATION"},
24 {SQUID_X509_V_ERR_CERT_CHANGE,
25 "SQUID_X509_V_ERR_CERT_CHANGE"},
26 {SQUID_ERR_SSL_HANDSHAKE,
27 "SQUID_ERR_SSL_HANDSHAKE"},
28 {SQUID_X509_V_ERR_DOMAIN_MISMATCH,
29 "SQUID_X509_V_ERR_DOMAIN_MISMATCH"},
30 {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
31 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"},
32 {X509_V_ERR_UNABLE_TO_GET_CRL,
33 "X509_V_ERR_UNABLE_TO_GET_CRL"},
34 {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
35 "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"},
36 {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
37 "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"},
38 {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
39 "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"},
40 {X509_V_ERR_CERT_SIGNATURE_FAILURE,
41 "X509_V_ERR_CERT_SIGNATURE_FAILURE"},
42 {X509_V_ERR_CRL_SIGNATURE_FAILURE,
43 "X509_V_ERR_CRL_SIGNATURE_FAILURE"},
44 {X509_V_ERR_CERT_NOT_YET_VALID,
45 "X509_V_ERR_CERT_NOT_YET_VALID"},
46 {X509_V_ERR_CERT_HAS_EXPIRED,
47 "X509_V_ERR_CERT_HAS_EXPIRED"},
48 {X509_V_ERR_CRL_NOT_YET_VALID,
49 "X509_V_ERR_CRL_NOT_YET_VALID"},
50 {X509_V_ERR_CRL_HAS_EXPIRED,
51 "X509_V_ERR_CRL_HAS_EXPIRED"},
52 {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
53 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"},
54 {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
55 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"},
56 {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
57 "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"},
58 {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
59 "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"},
60 {X509_V_ERR_OUT_OF_MEM,
61 "X509_V_ERR_OUT_OF_MEM"},
62 {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
63 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"},
64 {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
65 "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"},
66 {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
67 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"},
68 {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
69 "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"},
70 {X509_V_ERR_CERT_CHAIN_TOO_LONG,
71 "X509_V_ERR_CERT_CHAIN_TOO_LONG"},
72 {X509_V_ERR_CERT_REVOKED,
73 "X509_V_ERR_CERT_REVOKED"},
74 {X509_V_ERR_INVALID_CA,
75 "X509_V_ERR_INVALID_CA"},
76 {X509_V_ERR_PATH_LENGTH_EXCEEDED,
77 "X509_V_ERR_PATH_LENGTH_EXCEEDED"},
78 {X509_V_ERR_INVALID_PURPOSE,
79 "X509_V_ERR_INVALID_PURPOSE"},
80 {X509_V_ERR_CERT_UNTRUSTED,
81 "X509_V_ERR_CERT_UNTRUSTED"},
82 {X509_V_ERR_CERT_REJECTED,
83 "X509_V_ERR_CERT_REJECTED"},
84 {X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
85 "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"},
86 {X509_V_ERR_AKID_SKID_MISMATCH,
87 "X509_V_ERR_AKID_SKID_MISMATCH"},
88 {X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
89 "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"},
90 {X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
91 "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"},
92 #if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)
93 {
94 X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, //33
95 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"
96 },
97 #endif
98 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
99 {
100 X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, //34
101 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
102 },
103 #endif
104 #if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)
105 {
106 X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, //35
107 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"
108 },
109 #endif
110 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)
111 {
112 X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, //36
113 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"
114 },
115 #endif
116 #if defined(X509_V_ERR_INVALID_NON_CA)
117 {
118 X509_V_ERR_INVALID_NON_CA, //37
119 "X509_V_ERR_INVALID_NON_CA"
120 },
121 #endif
122 #if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)
123 {
124 X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, //38
125 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
126 },
127 #endif
128 #if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE)
129 {
130 X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, //39
131 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"
132 },
133 #endif
134 #if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)
135 {
136 X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, //40
137 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"
138 },
139 #endif
140 #if defined(X509_V_ERR_INVALID_EXTENSION)
141 {
142 X509_V_ERR_INVALID_EXTENSION, //41
143 "X509_V_ERR_INVALID_EXTENSION"
144 },
145 #endif
146 #if defined(X509_V_ERR_INVALID_POLICY_EXTENSION)
147 {
148 X509_V_ERR_INVALID_POLICY_EXTENSION, //42
149 "X509_V_ERR_INVALID_POLICY_EXTENSION"
150 },
151 #endif
152 #if defined(X509_V_ERR_NO_EXPLICIT_POLICY)
153 {
154 X509_V_ERR_NO_EXPLICIT_POLICY, //43
155 "X509_V_ERR_NO_EXPLICIT_POLICY"
156 },
157 #endif
158 #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE)
159 {
160 X509_V_ERR_DIFFERENT_CRL_SCOPE, //44
161 "X509_V_ERR_DIFFERENT_CRL_SCOPE"
162 },
163 #endif
164 #if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE)
165 {
166 X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, //45
167 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"
168 },
169 #endif
170 #if defined(X509_V_ERR_UNNESTED_RESOURCE)
171 {
172 X509_V_ERR_UNNESTED_RESOURCE, //46
173 "X509_V_ERR_UNNESTED_RESOURCE"
174 },
175 #endif
176 #if defined(X509_V_ERR_PERMITTED_VIOLATION)
177 {
178 X509_V_ERR_PERMITTED_VIOLATION, //47
179 "X509_V_ERR_PERMITTED_VIOLATION"
180 },
181 #endif
182 #if defined(X509_V_ERR_EXCLUDED_VIOLATION)
183 {
184 X509_V_ERR_EXCLUDED_VIOLATION, //48
185 "X509_V_ERR_EXCLUDED_VIOLATION"
186 },
187 #endif
188 #if defined(X509_V_ERR_SUBTREE_MINMAX)
189 {
190 X509_V_ERR_SUBTREE_MINMAX, //49
191 "X509_V_ERR_SUBTREE_MINMAX"
192 },
193 #endif
194 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE)
195 {
196 X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, //51
197 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"
198 },
199 #endif
200 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX)
201 {
202 X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, //52
203 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"
204 },
205 #endif
206 #if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX)
207 {
208 X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, //53
209 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"
210 },
211 #endif
212 #if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR)
213 {
214 X509_V_ERR_CRL_PATH_VALIDATION_ERROR, //54
215 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"
216 },
217 #endif
218 {X509_V_ERR_APPLICATION_VERIFICATION,
219 "X509_V_ERR_APPLICATION_VERIFICATION"},
220 { SSL_ERROR_NONE, "SSL_ERROR_NONE"},
221 {SSL_ERROR_NONE, NULL}
222 };
223
224 static const char *OptionalSslErrors[] = {
225 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER",
226 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION",
227 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN",
228 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION",
229 "X509_V_ERR_INVALID_NON_CA",
230 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED",
231 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE",
232 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED",
233 "X509_V_ERR_INVALID_EXTENSION",
234 "X509_V_ERR_INVALID_POLICY_EXTENSION",
235 "X509_V_ERR_NO_EXPLICIT_POLICY",
236 "X509_V_ERR_DIFFERENT_CRL_SCOPE",
237 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE",
238 "X509_V_ERR_UNNESTED_RESOURCE",
239 "X509_V_ERR_PERMITTED_VIOLATION",
240 "X509_V_ERR_EXCLUDED_VIOLATION",
241 "X509_V_ERR_SUBTREE_MINMAX",
242 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE",
243 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX",
244 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX",
245 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR",
246 NULL
247 };
248
249 struct SslErrorAlias {
250 const char *name;
251 const Ssl::ssl_error_t *errors;
252 };
253
254 static const Ssl::ssl_error_t hasExpired[] = {X509_V_ERR_CERT_HAS_EXPIRED, SSL_ERROR_NONE};
255 static const Ssl::ssl_error_t notYetValid[] = {X509_V_ERR_CERT_NOT_YET_VALID, SSL_ERROR_NONE};
256 static const Ssl::ssl_error_t domainMismatch[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH, SSL_ERROR_NONE};
257 static const Ssl::ssl_error_t certUntrusted[] = {X509_V_ERR_INVALID_CA,
258 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
259 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
260 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
261 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
262 X509_V_ERR_CERT_UNTRUSTED, SSL_ERROR_NONE
263 };
264 static const Ssl::ssl_error_t certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE};
265
266 // The list of error name shortcuts for use with ssl_error acls.
267 // The keys without the "ssl::" scope prefix allow shorter error
268 // names within the SSL options scope. This is easier than
269 // carefully stripping the scope prefix in Ssl::ParseErrorString().
270 static SslErrorAlias TheSslErrorShortcutsArray[] = {
271 {"ssl::certHasExpired", hasExpired},
272 {"certHasExpired", hasExpired},
273 {"ssl::certNotYetValid", notYetValid},
274 {"certNotYetValid", notYetValid},
275 {"ssl::certDomainMismatch", domainMismatch},
276 {"certDomainMismatch", domainMismatch},
277 {"ssl::certUntrusted", certUntrusted},
278 {"certUntrusted", certUntrusted},
279 {"ssl::certSelfSigned", certSelfSigned},
280 {"certSelfSigned", certSelfSigned},
281 {NULL, NULL}
282 };
283
284 // Use std::map to optimize search.
285 typedef std::map<std::string, const Ssl::ssl_error_t *> SslErrorShortcuts;
286 SslErrorShortcuts TheSslErrorShortcuts;
287
288 static void loadSslErrorMap()
289 {
290 assert(TheSslErrors.empty());
291 for (int i = 0; TheSslErrorArray[i].name; ++i) {
292 TheSslErrors[TheSslErrorArray[i].value] = &TheSslErrorArray[i];
293 }
294 }
295
296 static void loadSslErrorShortcutsMap()
297 {
298 assert(TheSslErrorShortcuts.empty());
299 for (int i = 0; TheSslErrorShortcutsArray[i].name; ++i)
300 TheSslErrorShortcuts[TheSslErrorShortcutsArray[i].name] = TheSslErrorShortcutsArray[i].errors;
301 }
302
303 Ssl::ssl_error_t Ssl::GetErrorCode(const char *name)
304 {
305 //TODO: use a std::map?
306 for (int i = 0; TheSslErrorArray[i].name != NULL; ++i) {
307 if (strcmp(name, TheSslErrorArray[i].name) == 0)
308 return TheSslErrorArray[i].value;
309 }
310 return SSL_ERROR_NONE;
311 }
312
313 Ssl::Errors *
314 Ssl::ParseErrorString(const char *name)
315 {
316 assert(name);
317
318 const Ssl::ssl_error_t ssl_error = GetErrorCode(name);
319 if (ssl_error != SSL_ERROR_NONE)
320 return new Ssl::Errors(ssl_error);
321
322 if (xisdigit(*name)) {
323 const long int value = strtol(name, NULL, 0);
324 if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX)
325 return new Ssl::Errors(value);
326 fatalf("Too small or too bug SSL error code '%s'", name);
327 }
328
329 if (TheSslErrorShortcuts.empty())
330 loadSslErrorShortcutsMap();
331
332 const SslErrorShortcuts::const_iterator it = TheSslErrorShortcuts.find(name);
333 if (it != TheSslErrorShortcuts.end()) {
334 // Should not be empty...
335 assert(it->second[0] != SSL_ERROR_NONE);
336 Ssl::Errors *errors = new Ssl::Errors(it->second[0]);
337 for (int i =1; it->second[i] != SSL_ERROR_NONE; ++i) {
338 errors->push_back_unique(it->second[i]);
339 }
340 return errors;
341 }
342
343 fatalf("Unknown SSL error name '%s'", name);
344 return NULL; // not reached
345 }
346
347 const char *Ssl::GetErrorName(Ssl::ssl_error_t value)
348 {
349 if (TheSslErrors.empty())
350 loadSslErrorMap();
351
352 const SslErrors::const_iterator it = TheSslErrors.find(value);
353 if (it != TheSslErrors.end())
354 return it->second->name;
355
356 return NULL;
357 }
358
359 bool
360 Ssl::ErrorIsOptional(const char *name)
361 {
362 for (int i = 0; OptionalSslErrors[i] != NULL; ++i) {
363 if (strcmp(name, OptionalSslErrors[i]) == 0)
364 return true;
365 }
366 return false;
367 }
368
369 const char *
370 Ssl::GetErrorDescr(Ssl::ssl_error_t value)
371 {
372 return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value);
373 }
374
375 Ssl::ErrorDetail::err_frm_code Ssl::ErrorDetail::ErrorFormatingCodes[] = {
376 {"ssl_subject", &Ssl::ErrorDetail::subject},
377 {"ssl_ca_name", &Ssl::ErrorDetail::ca_name},
378 {"ssl_cn", &Ssl::ErrorDetail::cn},
379 {"ssl_notbefore", &Ssl::ErrorDetail::notbefore},
380 {"ssl_notafter", &Ssl::ErrorDetail::notafter},
381 {"err_name", &Ssl::ErrorDetail::err_code},
382 {"ssl_error_descr", &Ssl::ErrorDetail::err_descr},
383 {"ssl_lib_error", &Ssl::ErrorDetail::err_lib_error},
384 {NULL,NULL}
385 };
386
387 /**
388 * The subject of the current certification in text form
389 */
390 const char *Ssl::ErrorDetail::subject() const
391 {
392 if (!broken_cert)
393 return "[Not available]";
394
395 static char tmpBuffer[256]; // A temporary buffer
396 X509_NAME_oneline(X509_get_subject_name(broken_cert.get()), tmpBuffer,
397 sizeof(tmpBuffer));
398 return tmpBuffer;
399 }
400
401 // helper function to be used with Ssl::matchX509CommonNames
402 static int copy_cn(void *check_data, ASN1_STRING *cn_data)
403 {
404 String *str = (String *)check_data;
405 if (!str) // no data? abort
406 return 0;
407 if (str->size() > 0)
408 str->append(", ");
409 str->append((const char *)cn_data->data, cn_data->length);
410 return 1;
411 }
412
413 /**
414 * The list with certificates cn and alternate names
415 */
416 const char *Ssl::ErrorDetail::cn() const
417 {
418 if (!broken_cert)
419 return "[Not available]";
420
421 static String tmpStr; ///< A temporary string buffer
422 tmpStr.clean();
423 Ssl::matchX509CommonNames(broken_cert.get(), &tmpStr, copy_cn);
424 return tmpStr.termedBuf();
425 }
426
427 /**
428 * The issuer name
429 */
430 const char *Ssl::ErrorDetail::ca_name() const
431 {
432 if (!broken_cert)
433 return "[Not available]";
434
435 static char tmpBuffer[256]; // A temporary buffer
436 X509_NAME_oneline(X509_get_issuer_name(broken_cert.get()), tmpBuffer, sizeof(tmpBuffer));
437 return tmpBuffer;
438 }
439
440 /**
441 * The certificate "not before" field
442 */
443 const char *Ssl::ErrorDetail::notbefore() const
444 {
445 if (!broken_cert)
446 return "[Not available]";
447
448 static char tmpBuffer[256]; // A temporary buffer
449 ASN1_UTCTIME * tm = X509_get_notBefore(broken_cert.get());
450 Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
451 return tmpBuffer;
452 }
453
454 /**
455 * The certificate "not after" field
456 */
457 const char *Ssl::ErrorDetail::notafter() const
458 {
459 if (!broken_cert)
460 return "[Not available]";
461
462 static char tmpBuffer[256]; // A temporary buffer
463 ASN1_UTCTIME * tm = X509_get_notAfter(broken_cert.get());
464 Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
465 return tmpBuffer;
466 }
467
468 /**
469 * The string representation of the error_no
470 */
471 const char *Ssl::ErrorDetail::err_code() const
472 {
473 static char tmpBuffer[64];
474 // We can use the GetErrorName but using the detailEntry is faster,
475 // so try it first.
476 const char *err = detailEntry.name.termedBuf();
477
478 // error details not loaded yet or not defined in error_details.txt,
479 // try the GetErrorName...
480 if (!err)
481 err = GetErrorName(error_no);
482
483 if (!err) {
484 snprintf(tmpBuffer, 64, "%d", (int)error_no);
485 err = tmpBuffer;
486 }
487 return err;
488 }
489
490 /**
491 * A short description of the error_no
492 */
493 const char *Ssl::ErrorDetail::err_descr() const
494 {
495 if (error_no == SSL_ERROR_NONE)
496 return "[No Error]";
497 if (const char *err = detailEntry.descr.termedBuf())
498 return err;
499 return "[Not available]";
500 }
501
502 const char *Ssl::ErrorDetail::err_lib_error() const
503 {
504 if (errReason.size() > 0)
505 return errReason.termedBuf();
506 else if (lib_error_no != SSL_ERROR_NONE)
507 return ERR_error_string(lib_error_no, NULL);
508 else
509 return "[No Error]";
510 }
511
512 /**
513 * Converts the code to a string value. Supported formating codes are:
514 *
515 * Error meta information:
516 * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*)
517 * %ssl_error_descr: A short description of the SSL error
518 * %ssl_lib_error: human-readable low-level error string by ERR_error_string(3SSL)
519 *
520 * Certificate information extracted from broken (not necessarily peer!) cert
521 * %ssl_cn: The comma-separated list of common and alternate names
522 * %ssl_subject: The certificate subject
523 * %ssl_ca_name: The certificate issuer name
524 * %ssl_notbefore: The certificate "not before" field
525 * %ssl_notafter: The certificate "not after" field
526 *
527 \retval the length of the code (the number of characters will be replaced by value)
528 */
529 int Ssl::ErrorDetail::convert(const char *code, const char **value) const
530 {
531 *value = "-";
532 for (int i=0; ErrorFormatingCodes[i].code!=NULL; ++i) {
533 const int len = strlen(ErrorFormatingCodes[i].code);
534 if (strncmp(code,ErrorFormatingCodes[i].code, len)==0) {
535 ErrorDetail::fmt_action_t action = ErrorFormatingCodes[i].fmt_action;
536 *value = (this->*action)();
537 return len;
538 }
539 }
540 return 0;
541 }
542
543 /**
544 * It uses the convert method to build the string errDetailStr using
545 * a template message for the current SSL error. The template messages
546 * can also contain normal error pages formating codes.
547 * Currently the error template messages are hard-coded
548 */
549 void Ssl::ErrorDetail::buildDetail() const
550 {
551 char const *s = NULL;
552 char const *p;
553 char const *t;
554 int code_len = 0;
555
556 if (ErrorDetailsManager::GetInstance().getErrorDetail(error_no, request, detailEntry))
557 s = detailEntry.detail.termedBuf();
558
559 if (!s)
560 s = SslErrorDetailDefaultStr;
561
562 assert(s);
563 while ((p = strchr(s, '%'))) {
564 errDetailStr.append(s, p - s);
565 code_len = convert(++p, &t);
566 if (code_len)
567 errDetailStr.append(t);
568 else
569 errDetailStr.append("%");
570 s = p + code_len;
571 }
572 errDetailStr.append(s, strlen(s));
573 }
574
575 const String &Ssl::ErrorDetail::toString() const
576 {
577 if (errDetailStr.size() == 0)
578 buildDetail();
579 return errDetailStr;
580 }
581
582 Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert, X509 *broken, const char *aReason): error_no (err_no), lib_error_no(SSL_ERROR_NONE), errReason(aReason)
583 {
584 if (cert)
585 peer_cert.resetAndLock(cert);
586
587 if (broken)
588 broken_cert.resetAndLock(broken);
589 else
590 broken_cert.resetAndLock(cert);
591
592 detailEntry.error_no = SSL_ERROR_NONE;
593 }
594
595 Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail const &anErrDetail)
596 {
597 error_no = anErrDetail.error_no;
598 request = anErrDetail.request;
599
600 if (anErrDetail.peer_cert.get()) {
601 peer_cert.resetAndLock(anErrDetail.peer_cert.get());
602 }
603
604 if (anErrDetail.broken_cert.get()) {
605 broken_cert.resetAndLock(anErrDetail.broken_cert.get());
606 }
607
608 detailEntry = anErrDetail.detailEntry;
609
610 lib_error_no = anErrDetail.lib_error_no;
611 }