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