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