2 * Copyright (C) 1996-2021 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 "error/SysErrorDetail.h"
11 #include "html_quote.h"
12 #include "sbuf/SBuf.h"
13 #include "sbuf/Stream.h"
14 #include "security/ErrorDetail.h"
15 #include "security/forward.h"
16 #include "security/Io.h"
20 #include "ssl/ErrorDetailManager.h"
22 #if HAVE_GNUTLS_GNUTLS_H
23 #include <gnutls/gnutls.h>
30 // we use std::map to optimize search; TODO: Use std::unordered_map instead?
31 typedef std::map
<ErrorCode
, const char *> ErrorCodeNames
;
32 static const ErrorCodeNames TheErrorCodeNames
= {
33 { SQUID_TLS_ERR_ACCEPT
,
34 "SQUID_TLS_ERR_ACCEPT"
36 { SQUID_TLS_ERR_CONNECT
,
37 "SQUID_TLS_ERR_CONNECT"
39 { SQUID_X509_V_ERR_INFINITE_VALIDATION
,
40 "SQUID_X509_V_ERR_INFINITE_VALIDATION"
42 { SQUID_X509_V_ERR_CERT_CHANGE
,
43 "SQUID_X509_V_ERR_CERT_CHANGE"
45 { SQUID_X509_V_ERR_DOMAIN_MISMATCH
,
46 "SQUID_X509_V_ERR_DOMAIN_MISMATCH"
49 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
50 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"
52 { X509_V_ERR_UNABLE_TO_GET_CRL
,
53 "X509_V_ERR_UNABLE_TO_GET_CRL"
55 { X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE
,
56 "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"
58 { X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE
,
59 "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"
61 { X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
,
62 "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"
64 { X509_V_ERR_CERT_SIGNATURE_FAILURE
,
65 "X509_V_ERR_CERT_SIGNATURE_FAILURE"
67 { X509_V_ERR_CRL_SIGNATURE_FAILURE
,
68 "X509_V_ERR_CRL_SIGNATURE_FAILURE"
70 { X509_V_ERR_CERT_NOT_YET_VALID
,
71 "X509_V_ERR_CERT_NOT_YET_VALID"
73 { X509_V_ERR_CERT_HAS_EXPIRED
,
74 "X509_V_ERR_CERT_HAS_EXPIRED"
76 { X509_V_ERR_CRL_NOT_YET_VALID
,
77 "X509_V_ERR_CRL_NOT_YET_VALID"
79 { X509_V_ERR_CRL_HAS_EXPIRED
,
80 "X509_V_ERR_CRL_HAS_EXPIRED"
82 { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
,
83 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"
85 { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
,
86 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"
88 { X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD
,
89 "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"
91 { X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD
,
92 "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"
94 { X509_V_ERR_OUT_OF_MEM
,
95 "X509_V_ERR_OUT_OF_MEM"
97 { X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
,
98 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"
100 { X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
,
101 "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"
103 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
104 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
106 { X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
,
107 "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"
109 { X509_V_ERR_CERT_CHAIN_TOO_LONG
,
110 "X509_V_ERR_CERT_CHAIN_TOO_LONG"
112 { X509_V_ERR_CERT_REVOKED
,
113 "X509_V_ERR_CERT_REVOKED"
115 { X509_V_ERR_INVALID_CA
,
116 "X509_V_ERR_INVALID_CA"
118 { X509_V_ERR_PATH_LENGTH_EXCEEDED
,
119 "X509_V_ERR_PATH_LENGTH_EXCEEDED"
121 { X509_V_ERR_INVALID_PURPOSE
,
122 "X509_V_ERR_INVALID_PURPOSE"
124 { X509_V_ERR_CERT_UNTRUSTED
,
125 "X509_V_ERR_CERT_UNTRUSTED"
127 { X509_V_ERR_CERT_REJECTED
,
128 "X509_V_ERR_CERT_REJECTED"
130 { X509_V_ERR_SUBJECT_ISSUER_MISMATCH
,
131 "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"
133 { X509_V_ERR_AKID_SKID_MISMATCH
,
134 "X509_V_ERR_AKID_SKID_MISMATCH"
136 { X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH
,
137 "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"
139 { X509_V_ERR_KEYUSAGE_NO_CERTSIGN
,
140 "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"
142 #if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)
144 X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
, // 33
145 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"
148 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
150 X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION
, // 34
151 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
154 #if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)
156 X509_V_ERR_KEYUSAGE_NO_CRL_SIGN
, // 35
157 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"
160 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)
162 X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION
, // 36
163 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"
166 #if defined(X509_V_ERR_INVALID_NON_CA)
168 X509_V_ERR_INVALID_NON_CA
, // 37
169 "X509_V_ERR_INVALID_NON_CA"
172 #if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)
174 X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED
, // 38
175 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
178 #if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE)
180 X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE
, // 39
181 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"
184 #if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)
186 X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED
, // 40
187 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"
190 #if defined(X509_V_ERR_INVALID_EXTENSION)
192 X509_V_ERR_INVALID_EXTENSION
, // 41
193 "X509_V_ERR_INVALID_EXTENSION"
196 #if defined(X509_V_ERR_INVALID_POLICY_EXTENSION)
198 X509_V_ERR_INVALID_POLICY_EXTENSION
, // 42
199 "X509_V_ERR_INVALID_POLICY_EXTENSION"
202 #if defined(X509_V_ERR_NO_EXPLICIT_POLICY)
204 X509_V_ERR_NO_EXPLICIT_POLICY
, // 43
205 "X509_V_ERR_NO_EXPLICIT_POLICY"
208 #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE)
210 X509_V_ERR_DIFFERENT_CRL_SCOPE
, // 44
211 "X509_V_ERR_DIFFERENT_CRL_SCOPE"
214 #if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE)
216 X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE
, // 45
217 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"
220 #if defined(X509_V_ERR_UNNESTED_RESOURCE)
222 X509_V_ERR_UNNESTED_RESOURCE
, // 46
223 "X509_V_ERR_UNNESTED_RESOURCE"
226 #if defined(X509_V_ERR_PERMITTED_VIOLATION)
228 X509_V_ERR_PERMITTED_VIOLATION
, // 47
229 "X509_V_ERR_PERMITTED_VIOLATION"
232 #if defined(X509_V_ERR_EXCLUDED_VIOLATION)
234 X509_V_ERR_EXCLUDED_VIOLATION
, // 48
235 "X509_V_ERR_EXCLUDED_VIOLATION"
238 #if defined(X509_V_ERR_SUBTREE_MINMAX)
240 X509_V_ERR_SUBTREE_MINMAX
, // 49
241 "X509_V_ERR_SUBTREE_MINMAX"
244 { X509_V_ERR_APPLICATION_VERIFICATION
, // 50
245 "X509_V_ERR_APPLICATION_VERIFICATION"
247 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE)
249 X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE
, // 51
250 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"
253 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX)
255 X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX
, // 52
256 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"
259 #if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX)
261 X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
, // 53
262 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"
265 #if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR)
267 X509_V_ERR_CRL_PATH_VALIDATION_ERROR
, // 54
268 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"
271 #if defined(X509_V_ERR_PATH_LOOP)
273 X509_V_ERR_PATH_LOOP
, // 55
274 "X509_V_ERR_PATH_LOOP"
277 #if defined(X509_V_ERR_SUITE_B_INVALID_VERSION)
279 X509_V_ERR_SUITE_B_INVALID_VERSION
, // 56
280 "X509_V_ERR_SUITE_B_INVALID_VERSION"
283 #if defined(X509_V_ERR_SUITE_B_INVALID_ALGORITHM)
285 X509_V_ERR_SUITE_B_INVALID_ALGORITHM
, // 57
286 "X509_V_ERR_SUITE_B_INVALID_ALGORITHM"
289 #if defined(X509_V_ERR_SUITE_B_INVALID_CURVE)
291 X509_V_ERR_SUITE_B_INVALID_CURVE
, // 58
292 "X509_V_ERR_SUITE_B_INVALID_CURVE"
295 #if defined(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM)
297 X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM
, // 59
298 "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM"
301 #if defined(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED)
303 X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED
, // 60
304 "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED"
307 #if defined(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256)
309 X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256
, // 61
310 "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256"
313 #if defined(X509_V_ERR_HOSTNAME_MISMATCH)
315 X509_V_ERR_HOSTNAME_MISMATCH
, // 62
316 "X509_V_ERR_HOSTNAME_MISMATCH"
319 #if defined(X509_V_ERR_EMAIL_MISMATCH)
321 X509_V_ERR_EMAIL_MISMATCH
, // 63
322 "X509_V_ERR_EMAIL_MISMATCH"
325 #if defined(X509_V_ERR_IP_ADDRESS_MISMATCH)
327 X509_V_ERR_IP_ADDRESS_MISMATCH
, // 64
328 "X509_V_ERR_IP_ADDRESS_MISMATCH"
331 #if defined(X509_V_ERR_DANE_NO_MATCH)
333 X509_V_ERR_DANE_NO_MATCH
, // 65
334 "X509_V_ERR_DANE_NO_MATCH"
337 #if defined(X509_V_ERR_EE_KEY_TOO_SMALL)
339 X509_V_ERR_EE_KEY_TOO_SMALL
, // 66
340 "X509_V_ERR_EE_KEY_TOO_SMALL"
343 #if defined(X509_V_ERR_CA_KEY_TOO_SMALL)
345 X509_V_ERR_CA_KEY_TOO_SMALL
, // 67
346 "X509_V_ERR_CA_KEY_TOO_SMALL"
349 #if defined(X509_V_ERR_CA_MD_TOO_WEAK)
351 X509_V_ERR_CA_MD_TOO_WEAK
, // 68
352 "X509_V_ERR_CA_MD_TOO_WEAK"
355 #if defined(X509_V_ERR_INVALID_CALL)
357 X509_V_ERR_INVALID_CALL
, // 69
358 "X509_V_ERR_INVALID_CALL"
361 #if defined(X509_V_ERR_STORE_LOOKUP)
363 X509_V_ERR_STORE_LOOKUP
, // 70
364 "X509_V_ERR_STORE_LOOKUP"
367 #if defined(X509_V_ERR_NO_VALID_SCTS)
369 X509_V_ERR_NO_VALID_SCTS
, // 71
370 "X509_V_ERR_NO_VALID_SCTS"
373 #if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION)
375 X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION
, // 72
376 "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION"
379 #if defined(X509_V_ERR_OCSP_VERIFY_NEEDED)
381 X509_V_ERR_OCSP_VERIFY_NEEDED
, // 73
382 "X509_V_ERR_OCSP_VERIFY_NEEDED"
385 #if defined(X509_V_ERR_OCSP_VERIFY_FAILED)
387 X509_V_ERR_OCSP_VERIFY_FAILED
, // 74
388 "X509_V_ERR_OCSP_VERIFY_FAILED"
391 #if defined(X509_V_ERR_OCSP_CERT_UNKNOWN)
393 X509_V_ERR_OCSP_CERT_UNKNOWN
, // 75
394 "X509_V_ERR_OCSP_CERT_UNKNOWN"
401 #endif // USE_OPENSSL
404 } // namespace Security
407 Security::ErrorCodeFromName(const char *name
)
409 static auto TheCmp
= [](const char *a
, const char *b
) {return strcmp(a
, b
) < 0;};
410 static std::map
<const char *, ErrorCode
, decltype(TheCmp
)> TheErrorCodeByNameIndx(TheCmp
);
411 if (TheErrorCodeByNameIndx
.empty()) {
412 for (const auto &i
: TheErrorCodeNames
)
413 TheErrorCodeByNameIndx
.insert(std::make_pair(i
.second
, i
.first
));
415 // redirector to support legacy error translations
416 TheErrorCodeByNameIndx
.insert(std::make_pair("SQUID_ERR_SSL_HANDSHAKE", SQUID_TLS_ERR_CONNECT
));
419 const auto it
= TheErrorCodeByNameIndx
.find(name
);
420 if (it
!= TheErrorCodeByNameIndx
.end())
427 Security::ErrorNameFromCode(const ErrorCode err
, const bool prefixRawCode
)
429 const auto it
= TheErrorCodeNames
.find(err
);
430 if (it
!= TheErrorCodeNames
.end())
433 static char tmpBuffer
[128];
434 snprintf(tmpBuffer
, sizeof(tmpBuffer
), "%s%d",
435 (prefixRawCode
? "SSL_ERR=" : ""), static_cast<int>(err
));
439 /* Security::ErrorDetail */
441 /// helper constructor implementing the logic shared by the two public ones
442 Security::ErrorDetail::ErrorDetail(const ErrorCode err
, const int aSysErrorNo
):
444 // We could restrict errno(3) collection to cases where the TLS library
445 // explicitly talks about the errno being set, but correctly detecting those
446 // cases is difficult. We simplify in hope that all other cases will either
447 // have a useful errno or a zero errno.
448 sysErrorNo(aSysErrorNo
)
451 /// Extract and remember errors stored internally by the TLS library.
452 if ((lib_error_no
= ERR_get_error())) {
453 debugs(83, 7, "got " << asHex(lib_error_no
));
454 // more errors may be stacked
455 // TODO: Save/detail all stacked errors by always flushing stale ones.
459 // other libraries return errors explicitly instead of auto-storing them
463 Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode
, const CertPointer
&cert
, const CertPointer
&broken
, const char *aReason
):
464 ErrorDetail(anErrorCode
, 0)
468 broken_cert
= broken
? broken
: cert
;
472 Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode
, const int anIoErrorNo
, const int aSysErrorNo
):
473 ErrorDetail(anErrorCode
, aSysErrorNo
)
475 ioErrorNo
= anIoErrorNo
;
479 Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode
, const LibErrorCode aLibErrorNo
, const int aSysErrorNo
):
480 ErrorDetail(anErrorCode
, aSysErrorNo
)
482 lib_error_no
= aLibErrorNo
;
487 Security::ErrorDetail::setPeerCertificate(const CertPointer
&cert
)
491 assert(!broken_cert
);
493 // unlike the constructor, the supplied certificate is not a broken_cert
497 Security::ErrorDetail::brief() const
499 SBuf
buf(err_code()); // TODO: Upgrade err_code()/etc. to return SBuf.
503 // TODO: Log ERR_error_string_n() instead, despite length, whitespace?
504 // Example: `error:1408F09C:SSL routines:ssl3_get_record:http request`.
505 buf
.append(ToSBuf("+TLS_LIB_ERR=", std::hex
, std::uppercase
, lib_error_no
));
507 buf
.append(ToSBuf("+", gnutls_strerror_name(lib_error_no
)));
512 // TODO: Consider logging long but human-friendly names (e.g.,
513 // SSL_ERROR_SYSCALL).
515 buf
.append(ToSBuf("+TLS_IO_ERR=", ioErrorNo
));
520 buf
.append(SysErrorDetail::Brief(sysErrorNo
));
524 buf
.append("+broken_cert");
530 Security::ErrorDetail::verbose(const HttpRequestPointer
&request
) const
532 char const *format
= nullptr;
534 if (Ssl::ErrorDetailsManager::GetInstance().getErrorDetail(error_no
, request
, detailEntry
))
535 format
= detailEntry
.detail
.termedBuf();
540 format
= "SSL handshake error (%err_name)";
544 auto remainder
= format
;
545 while (auto p
= strchr(remainder
, '%')) {
546 errDetailStr
.append(remainder
, p
- remainder
);
547 char const *converted
= nullptr;
548 const auto formattingCodeLen
= convert(++p
, &converted
);
549 if (formattingCodeLen
)
550 errDetailStr
.append(converted
);
552 errDetailStr
.append("%");
553 remainder
= p
+ formattingCodeLen
;
555 errDetailStr
.append(remainder
, strlen(remainder
));
559 /// textual representation of the subject of the broken certificate
561 Security::ErrorDetail::subject() const
564 if (broken_cert
.get()) {
565 static char tmpBuffer
[256]; // A temporary buffer
566 if (X509_NAME_oneline(X509_get_subject_name(broken_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
))) {
567 // quote to avoid possible html code injection through
568 // certificate subject
569 return html_quote(tmpBuffer
);
572 #endif // USE_OPENSSL
573 return "[Not available]";
577 /// helper function to collect CNs using Ssl::matchX509CommonNames()
579 copy_cn(void *check_data
, ASN1_STRING
*cn_data
)
581 const auto str
= static_cast<String
*>(check_data
);
582 if (!str
) // no data? abort
584 if (cn_data
&& cn_data
->length
) {
587 str
->append(reinterpret_cast<const char *>(cn_data
->data
), cn_data
->length
);
591 #endif // USE_OPENSSL
593 /// a list of the broken certificates CN and alternate names
595 Security::ErrorDetail::cn() const
598 if (broken_cert
.get()) {
599 static String tmpStr
;
601 Ssl::matchX509CommonNames(broken_cert
.get(), &tmpStr
, copy_cn
);
603 // quote to avoid possible HTML code injection through
604 // certificate subject
605 return html_quote(tmpStr
.termedBuf());
608 #endif // USE_OPENSSL
609 return "[Not available]";
612 /// the issuer of the broken certificate
614 Security::ErrorDetail::ca_name() const
617 if (broken_cert
.get()) {
618 static char tmpBuffer
[256]; // A temporary buffer
619 if (X509_NAME_oneline(X509_get_issuer_name(broken_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
))) {
620 // quote to avoid possible html code injection through
621 // certificate issuer subject
622 return html_quote(tmpBuffer
);
625 #endif // USE_OPENSSL
626 return "[Not available]";
629 /// textual representation of the "not before" field of the broken certificate
631 Security::ErrorDetail::notbefore() const
634 if (broken_cert
.get()) {
635 if (const auto tm
= X509_getm_notBefore(broken_cert
.get())) {
636 static char tmpBuffer
[256]; // A temporary buffer
637 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
641 #endif // USE_OPENSSL
642 return "[Not available]";
645 /// textual representation of the "not after" field of the broken certificate
647 Security::ErrorDetail::notafter() const
650 if (broken_cert
.get()) {
651 if (const auto tm
= X509_getm_notAfter(broken_cert
.get())) {
652 static char tmpBuffer
[256]; // A temporary buffer
653 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
657 #endif // USE_OPENSSL
658 return "[Not available]";
661 /// textual representation of error_no
663 Security::ErrorDetail::err_code() const
666 // try detailEntry first because it is faster
667 if (const char *err
= detailEntry
.name
.termedBuf())
671 return ErrorNameFromCode(error_no
);
674 /// short description of error_no
676 Security::ErrorDetail::err_descr() const
681 if (const char *err
= detailEntry
.descr
.termedBuf())
684 return "[Not available]";
687 /// textual representation of lib_error_no
689 Security::ErrorDetail::err_lib_error() const
691 if (errReason
.size() > 0)
692 return errReason
.termedBuf();
693 else if (lib_error_no
)
694 return ErrorString(lib_error_no
);
697 return "[Not available]";
701 * Converts the code to a string value. Supported formatting codes are:
703 * Error meta information:
704 * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*)
705 * %ssl_error_descr: A short description of the SSL error
706 * %ssl_lib_error: human-readable low-level error string by ErrorString()
708 * Certificate information extracted from broken (not necessarily peer!) cert
709 * %ssl_cn: The comma-separated list of common and alternate names
710 * %ssl_subject: The certificate subject
711 * %ssl_ca_name: The certificate issuer name
712 * %ssl_notbefore: The certificate "not before" field
713 * %ssl_notafter: The certificate "not after" field
715 \returns the length of the code (the number of characters to be replaced by value)
716 \retval 0 for unsupported codes
719 Security::ErrorDetail::convert(const char *code
, const char **value
) const
721 typedef const char *(ErrorDetail::*PartDescriber
)() const;
722 static const std::map
<const char*, PartDescriber
> PartDescriberByCode
= {
723 {"ssl_subject", &ErrorDetail::subject
},
724 {"ssl_ca_name", &ErrorDetail::ca_name
},
725 {"ssl_cn", &ErrorDetail::cn
},
726 {"ssl_notbefore", &ErrorDetail::notbefore
},
727 {"ssl_notafter", &ErrorDetail::notafter
},
728 {"err_name", &ErrorDetail::err_code
},
729 {"ssl_error_descr", &ErrorDetail::err_descr
},
730 {"ssl_lib_error", &ErrorDetail::err_lib_error
}
733 for (const auto &pair
: PartDescriberByCode
) {
734 const auto len
= strlen(pair
.first
);
735 if (strncmp(code
, pair
.first
, len
) == 0) {
736 const auto method
= pair
.second
;
737 *value
= (this->*method
)();
742 // TODO: Support logformat %codes.
743 *value
= ""; // unused with zero return