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