2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
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.
10 #include "errorpage.h"
12 #include "html_quote.h"
13 #include "ssl/ErrorDetail.h"
18 struct SslErrorEntry
{
19 Security::ErrorCode value
;
23 static const char *SslErrorDetailDefaultStr
= "SSL handshake error (%err_name)";
24 //Use std::map to optimize search
25 typedef std::map
<Security::ErrorCode
, const SslErrorEntry
*> SslErrors
;
26 SslErrors TheSslErrors
;
28 static SslErrorEntry TheSslErrorArray
[] = {
29 { SQUID_X509_V_ERR_INFINITE_VALIDATION
,
30 "SQUID_X509_V_ERR_INFINITE_VALIDATION"
32 { SQUID_X509_V_ERR_CERT_CHANGE
,
33 "SQUID_X509_V_ERR_CERT_CHANGE"
35 { SQUID_ERR_SSL_HANDSHAKE
,
36 "SQUID_ERR_SSL_HANDSHAKE"
38 { SQUID_X509_V_ERR_DOMAIN_MISMATCH
,
39 "SQUID_X509_V_ERR_DOMAIN_MISMATCH"
41 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
42 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"
44 { X509_V_ERR_UNABLE_TO_GET_CRL
,
45 "X509_V_ERR_UNABLE_TO_GET_CRL"
47 { X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE
,
48 "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"
50 { X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE
,
51 "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"
53 { X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
,
54 "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"
56 { X509_V_ERR_CERT_SIGNATURE_FAILURE
,
57 "X509_V_ERR_CERT_SIGNATURE_FAILURE"
59 { X509_V_ERR_CRL_SIGNATURE_FAILURE
,
60 "X509_V_ERR_CRL_SIGNATURE_FAILURE"
62 { X509_V_ERR_CERT_NOT_YET_VALID
,
63 "X509_V_ERR_CERT_NOT_YET_VALID"
65 { X509_V_ERR_CERT_HAS_EXPIRED
,
66 "X509_V_ERR_CERT_HAS_EXPIRED"
68 { X509_V_ERR_CRL_NOT_YET_VALID
,
69 "X509_V_ERR_CRL_NOT_YET_VALID"
71 { X509_V_ERR_CRL_HAS_EXPIRED
,
72 "X509_V_ERR_CRL_HAS_EXPIRED"
74 { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
,
75 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"
77 { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
,
78 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"
80 { X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD
,
81 "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"
83 { X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD
,
84 "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"
86 { X509_V_ERR_OUT_OF_MEM
,
87 "X509_V_ERR_OUT_OF_MEM"
89 { X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
,
90 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"
92 { X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
,
93 "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"
95 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
96 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
98 { X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
,
99 "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"
101 { X509_V_ERR_CERT_CHAIN_TOO_LONG
,
102 "X509_V_ERR_CERT_CHAIN_TOO_LONG"
104 { X509_V_ERR_CERT_REVOKED
,
105 "X509_V_ERR_CERT_REVOKED"
107 { X509_V_ERR_INVALID_CA
,
108 "X509_V_ERR_INVALID_CA"
110 { X509_V_ERR_PATH_LENGTH_EXCEEDED
,
111 "X509_V_ERR_PATH_LENGTH_EXCEEDED"
113 { X509_V_ERR_INVALID_PURPOSE
,
114 "X509_V_ERR_INVALID_PURPOSE"
116 { X509_V_ERR_CERT_UNTRUSTED
,
117 "X509_V_ERR_CERT_UNTRUSTED"
119 { X509_V_ERR_CERT_REJECTED
,
120 "X509_V_ERR_CERT_REJECTED"
122 { X509_V_ERR_SUBJECT_ISSUER_MISMATCH
,
123 "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"
125 { X509_V_ERR_AKID_SKID_MISMATCH
,
126 "X509_V_ERR_AKID_SKID_MISMATCH"
128 { X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH
,
129 "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"
131 { X509_V_ERR_KEYUSAGE_NO_CERTSIGN
,
132 "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"
134 #if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)
136 X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
, //33
137 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"
140 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
142 X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION
, //34
143 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
146 #if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)
148 X509_V_ERR_KEYUSAGE_NO_CRL_SIGN
, //35
149 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"
152 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)
154 X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION
, //36
155 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"
158 #if defined(X509_V_ERR_INVALID_NON_CA)
160 X509_V_ERR_INVALID_NON_CA
, //37
161 "X509_V_ERR_INVALID_NON_CA"
164 #if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)
166 X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED
, //38
167 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
170 #if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE)
172 X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE
, //39
173 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"
176 #if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)
178 X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED
, //40
179 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"
182 #if defined(X509_V_ERR_INVALID_EXTENSION)
184 X509_V_ERR_INVALID_EXTENSION
, //41
185 "X509_V_ERR_INVALID_EXTENSION"
188 #if defined(X509_V_ERR_INVALID_POLICY_EXTENSION)
190 X509_V_ERR_INVALID_POLICY_EXTENSION
, //42
191 "X509_V_ERR_INVALID_POLICY_EXTENSION"
194 #if defined(X509_V_ERR_NO_EXPLICIT_POLICY)
196 X509_V_ERR_NO_EXPLICIT_POLICY
, //43
197 "X509_V_ERR_NO_EXPLICIT_POLICY"
200 #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE)
202 X509_V_ERR_DIFFERENT_CRL_SCOPE
, //44
203 "X509_V_ERR_DIFFERENT_CRL_SCOPE"
206 #if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE)
208 X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE
, //45
209 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"
212 #if defined(X509_V_ERR_UNNESTED_RESOURCE)
214 X509_V_ERR_UNNESTED_RESOURCE
, //46
215 "X509_V_ERR_UNNESTED_RESOURCE"
218 #if defined(X509_V_ERR_PERMITTED_VIOLATION)
220 X509_V_ERR_PERMITTED_VIOLATION
, //47
221 "X509_V_ERR_PERMITTED_VIOLATION"
224 #if defined(X509_V_ERR_EXCLUDED_VIOLATION)
226 X509_V_ERR_EXCLUDED_VIOLATION
, //48
227 "X509_V_ERR_EXCLUDED_VIOLATION"
230 #if defined(X509_V_ERR_SUBTREE_MINMAX)
232 X509_V_ERR_SUBTREE_MINMAX
, //49
233 "X509_V_ERR_SUBTREE_MINMAX"
236 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE)
238 X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE
, //51
239 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"
242 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX)
244 X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX
, //52
245 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"
248 #if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX)
250 X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
, //53
251 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"
254 #if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR)
256 X509_V_ERR_CRL_PATH_VALIDATION_ERROR
, //54
257 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"
260 { X509_V_ERR_APPLICATION_VERIFICATION
,
261 "X509_V_ERR_APPLICATION_VERIFICATION"
263 { SSL_ERROR_NONE
, "SSL_ERROR_NONE"},
264 {SSL_ERROR_NONE
, NULL
}
267 static const char *OptionalSslErrors
[] = {
268 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER",
269 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION",
270 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN",
271 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION",
272 "X509_V_ERR_INVALID_NON_CA",
273 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED",
274 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE",
275 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED",
276 "X509_V_ERR_INVALID_EXTENSION",
277 "X509_V_ERR_INVALID_POLICY_EXTENSION",
278 "X509_V_ERR_NO_EXPLICIT_POLICY",
279 "X509_V_ERR_DIFFERENT_CRL_SCOPE",
280 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE",
281 "X509_V_ERR_UNNESTED_RESOURCE",
282 "X509_V_ERR_PERMITTED_VIOLATION",
283 "X509_V_ERR_EXCLUDED_VIOLATION",
284 "X509_V_ERR_SUBTREE_MINMAX",
285 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE",
286 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX",
287 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX",
288 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR",
292 struct SslErrorAlias
{
294 const Security::ErrorCode
*errors
;
297 static const Security::ErrorCode hasExpired
[] = {X509_V_ERR_CERT_HAS_EXPIRED
, SSL_ERROR_NONE
};
298 static const Security::ErrorCode notYetValid
[] = {X509_V_ERR_CERT_NOT_YET_VALID
, SSL_ERROR_NONE
};
299 static const Security::ErrorCode domainMismatch
[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH
, SSL_ERROR_NONE
};
300 static const Security::ErrorCode certUntrusted
[] = {X509_V_ERR_INVALID_CA
,
301 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
,
302 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
,
303 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
304 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
305 X509_V_ERR_CERT_UNTRUSTED
, SSL_ERROR_NONE
307 static const Security::ErrorCode certSelfSigned
[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
, SSL_ERROR_NONE
};
309 // The list of error name shortcuts for use with ssl_error acls.
310 // The keys without the "ssl::" scope prefix allow shorter error
311 // names within the SSL options scope. This is easier than
312 // carefully stripping the scope prefix in Ssl::ParseErrorString().
313 static SslErrorAlias TheSslErrorShortcutsArray
[] = {
314 {"ssl::certHasExpired", hasExpired
},
315 {"certHasExpired", hasExpired
},
316 {"ssl::certNotYetValid", notYetValid
},
317 {"certNotYetValid", notYetValid
},
318 {"ssl::certDomainMismatch", domainMismatch
},
319 {"certDomainMismatch", domainMismatch
},
320 {"ssl::certUntrusted", certUntrusted
},
321 {"certUntrusted", certUntrusted
},
322 {"ssl::certSelfSigned", certSelfSigned
},
323 {"certSelfSigned", certSelfSigned
},
327 // Use std::map to optimize search.
328 typedef std::map
<std::string
, const Security::ErrorCode
*> SslErrorShortcuts
;
329 SslErrorShortcuts TheSslErrorShortcuts
;
331 static void loadSslErrorMap()
333 assert(TheSslErrors
.empty());
334 for (int i
= 0; TheSslErrorArray
[i
].name
; ++i
) {
335 TheSslErrors
[TheSslErrorArray
[i
].value
] = &TheSslErrorArray
[i
];
339 static void loadSslErrorShortcutsMap()
341 assert(TheSslErrorShortcuts
.empty());
342 for (int i
= 0; TheSslErrorShortcutsArray
[i
].name
; ++i
)
343 TheSslErrorShortcuts
[TheSslErrorShortcutsArray
[i
].name
] = TheSslErrorShortcutsArray
[i
].errors
;
346 Security::ErrorCode
Ssl::GetErrorCode(const char *name
)
348 //TODO: use a std::map?
349 for (int i
= 0; TheSslErrorArray
[i
].name
!= NULL
; ++i
) {
350 if (strcmp(name
, TheSslErrorArray
[i
].name
) == 0)
351 return TheSslErrorArray
[i
].value
;
353 return SSL_ERROR_NONE
;
357 Ssl::ParseErrorString(const char *name
, Security::Errors
&errors
)
361 const Security::ErrorCode ssl_error
= GetErrorCode(name
);
362 if (ssl_error
!= SSL_ERROR_NONE
) {
363 errors
.emplace(ssl_error
);
367 if (xisdigit(*name
)) {
368 const long int value
= strtol(name
, NULL
, 0);
369 if (SQUID_SSL_ERROR_MIN
<= value
&& value
<= SQUID_SSL_ERROR_MAX
) {
370 errors
.emplace(value
);
373 fatalf("Too small or too big TLS error code '%s'", name
);
376 if (TheSslErrorShortcuts
.empty())
377 loadSslErrorShortcutsMap();
379 const SslErrorShortcuts::const_iterator it
= TheSslErrorShortcuts
.find(name
);
380 if (it
!= TheSslErrorShortcuts
.end()) {
381 // Should not be empty...
382 assert(it
->second
[0] != SSL_ERROR_NONE
);
383 for (int i
= 0; it
->second
[i
] != SSL_ERROR_NONE
; ++i
) {
384 errors
.emplace(it
->second
[i
]);
389 fatalf("Unknown TLS error name '%s'", name
);
390 return false; // not reached
393 const char *Ssl::GetErrorName(Security::ErrorCode value
)
395 if (TheSslErrors
.empty())
398 const SslErrors::const_iterator it
= TheSslErrors
.find(value
);
399 if (it
!= TheSslErrors
.end())
400 return it
->second
->name
;
406 Ssl::ErrorIsOptional(const char *name
)
408 for (int i
= 0; OptionalSslErrors
[i
] != NULL
; ++i
) {
409 if (strcmp(name
, OptionalSslErrors
[i
]) == 0)
416 Ssl::GetErrorDescr(Security::ErrorCode value
)
418 return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value
);
421 Ssl::ErrorDetail::err_frm_code
Ssl::ErrorDetail::ErrorFormatingCodes
[] = {
422 {"ssl_subject", &Ssl::ErrorDetail::subject
},
423 {"ssl_ca_name", &Ssl::ErrorDetail::ca_name
},
424 {"ssl_cn", &Ssl::ErrorDetail::cn
},
425 {"ssl_notbefore", &Ssl::ErrorDetail::notbefore
},
426 {"ssl_notafter", &Ssl::ErrorDetail::notafter
},
427 {"err_name", &Ssl::ErrorDetail::err_code
},
428 {"ssl_error_descr", &Ssl::ErrorDetail::err_descr
},
429 {"ssl_lib_error", &Ssl::ErrorDetail::err_lib_error
},
434 * The subject of the current certification in text form
436 const char *Ssl::ErrorDetail::subject() const
438 if (broken_cert
.get()) {
439 static char tmpBuffer
[256]; // A temporary buffer
440 if (X509_NAME_oneline(X509_get_subject_name(broken_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
))) {
441 // quote to avoid possible html code injection through
442 // certificate subject
443 return html_quote(tmpBuffer
);
446 return "[Not available]";
449 // helper function to be used with Ssl::matchX509CommonNames
450 static int copy_cn(void *check_data
, ASN1_STRING
*cn_data
)
452 String
*str
= (String
*)check_data
;
453 if (!str
) // no data? abort
455 if (cn_data
&& cn_data
->length
) {
458 str
->append((const char *)cn_data
->data
, cn_data
->length
);
464 * The list with certificates cn and alternate names
466 const char *Ssl::ErrorDetail::cn() const
468 if (broken_cert
.get()) {
469 static String tmpStr
; ///< A temporary string buffer
471 Ssl::matchX509CommonNames(broken_cert
.get(), &tmpStr
, copy_cn
);
473 // quote to avoid possible html code injection through
474 // certificate subject
475 return html_quote(tmpStr
.termedBuf());
478 return "[Not available]";
484 const char *Ssl::ErrorDetail::ca_name() const
486 if (broken_cert
.get()) {
487 static char tmpBuffer
[256]; // A temporary buffer
488 if (X509_NAME_oneline(X509_get_issuer_name(broken_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
))) {
489 // quote to avoid possible html code injection through
490 // certificate issuer subject
491 return html_quote(tmpBuffer
);
494 return "[Not available]";
498 * The certificate "not before" field
500 const char *Ssl::ErrorDetail::notbefore() const
502 if (broken_cert
.get()) {
503 if (const auto tm
= X509_getm_notBefore(broken_cert
.get())) {
504 static char tmpBuffer
[256]; // A temporary buffer
505 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
509 return "[Not available]";
513 * The certificate "not after" field
515 const char *Ssl::ErrorDetail::notafter() const
517 if (broken_cert
.get()) {
518 if (const auto tm
= X509_getm_notAfter(broken_cert
.get())) {
519 static char tmpBuffer
[256]; // A temporary buffer
520 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
524 return "[Not available]";
528 * The string representation of the error_no
530 const char *Ssl::ErrorDetail::err_code() const
532 static char tmpBuffer
[64];
533 // We can use the GetErrorName but using the detailEntry is faster,
535 const char *err
= detailEntry
.name
.termedBuf();
537 // error details not loaded yet or not defined in error_details.txt,
538 // try the GetErrorName...
540 err
= GetErrorName(error_no
);
543 snprintf(tmpBuffer
, 64, "%d", (int)error_no
);
550 * A short description of the error_no
552 const char *Ssl::ErrorDetail::err_descr() const
554 if (error_no
== SSL_ERROR_NONE
)
556 if (const char *err
= detailEntry
.descr
.termedBuf())
558 return "[Not available]";
561 const char *Ssl::ErrorDetail::err_lib_error() const
563 if (errReason
.size() > 0)
564 return errReason
.termedBuf();
565 else if (lib_error_no
!= SSL_ERROR_NONE
)
566 return Security::ErrorString(lib_error_no
);
572 * Converts the code to a string value. Supported formating codes are:
574 * Error meta information:
575 * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*)
576 * %ssl_error_descr: A short description of the SSL error
577 * %ssl_lib_error: human-readable low-level error string by Security::ErrorString()
579 * Certificate information extracted from broken (not necessarily peer!) cert
580 * %ssl_cn: The comma-separated list of common and alternate names
581 * %ssl_subject: The certificate subject
582 * %ssl_ca_name: The certificate issuer name
583 * %ssl_notbefore: The certificate "not before" field
584 * %ssl_notafter: The certificate "not after" field
586 \retval the length of the code (the number of characters will be replaced by value)
588 int Ssl::ErrorDetail::convert(const char *code
, const char **value
) const
591 for (int i
=0; ErrorFormatingCodes
[i
].code
!=NULL
; ++i
) {
592 const int len
= strlen(ErrorFormatingCodes
[i
].code
);
593 if (strncmp(code
,ErrorFormatingCodes
[i
].code
, len
)==0) {
594 ErrorDetail::fmt_action_t action
= ErrorFormatingCodes
[i
].fmt_action
;
595 *value
= (this->*action
)();
599 // TODO: Support logformat %codes.
604 * It uses the convert method to build the string errDetailStr using
605 * a template message for the current SSL error. The template messages
606 * can also contain normal error pages formating codes.
607 * Currently the error template messages are hard-coded
609 void Ssl::ErrorDetail::buildDetail() const
611 char const *s
= NULL
;
616 if (ErrorDetailsManager::GetInstance().getErrorDetail(error_no
, request
, detailEntry
))
617 s
= detailEntry
.detail
.termedBuf();
620 s
= SslErrorDetailDefaultStr
;
623 while ((p
= strchr(s
, '%'))) {
624 errDetailStr
.append(s
, p
- s
);
625 code_len
= convert(++p
, &t
);
627 errDetailStr
.append(t
);
629 errDetailStr
.append("%");
632 errDetailStr
.append(s
, strlen(s
));
635 const String
&Ssl::ErrorDetail::toString() const
637 if (errDetailStr
.size() == 0)
642 Ssl::ErrorDetail::ErrorDetail( Security::ErrorCode err_no
, X509
*cert
, X509
*broken
, const char *aReason
): error_no (err_no
), lib_error_no(SSL_ERROR_NONE
), errReason(aReason
)
645 peer_cert
.resetAndLock(cert
);
648 broken_cert
.resetAndLock(broken
);
650 broken_cert
.resetAndLock(cert
);
652 detailEntry
.error_no
= SSL_ERROR_NONE
;
655 Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail
const &anErrDetail
)
657 error_no
= anErrDetail
.error_no
;
658 request
= anErrDetail
.request
;
660 if (anErrDetail
.peer_cert
.get()) {
661 peer_cert
.resetAndLock(anErrDetail
.peer_cert
.get());
664 if (anErrDetail
.broken_cert
.get()) {
665 broken_cert
.resetAndLock(anErrDetail
.broken_cert
.get());
668 detailEntry
= anErrDetail
.detailEntry
;
670 lib_error_no
= anErrDetail
.lib_error_no
;