ErrorDetail.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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
9#include "squid.h"
10#include "base/IoManip.h"
12#include "html/Quoting.h"
13#include "sbuf/SBuf.h"
14#include "sbuf/Stream.h"
17#include "security/forward.h"
18#include "security/Io.h"
19#include "util.h"
20
21#if USE_OPENSSL
23#elif USE_GNUTLS
24#if HAVE_GNUTLS_GNUTLS_H
25#include <gnutls/gnutls.h>
26#endif
27#endif
28#include <map>
29#include <optional>
30
31namespace Security {
32
33// we use std::map to optimize search; TODO: Use std::unordered_map instead?
34typedef std::map<ErrorCode, const char *> ErrorCodeNames;
37 "SQUID_TLS_ERR_ACCEPT"
38 },
40 "SQUID_TLS_ERR_CONNECT"
41 },
43 "SQUID_X509_V_ERR_INFINITE_VALIDATION"
44 },
46 "SQUID_X509_V_ERR_CERT_CHANGE"
47 },
49 "SQUID_X509_V_ERR_DOMAIN_MISMATCH"
50 },
51#if USE_OPENSSL
52 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
53 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"
54 },
55 { X509_V_ERR_UNABLE_TO_GET_CRL,
56 "X509_V_ERR_UNABLE_TO_GET_CRL"
57 },
58 { X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
59 "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"
60 },
61 { X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
62 "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"
63 },
64 { X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
65 "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"
66 },
67 { X509_V_ERR_CERT_SIGNATURE_FAILURE,
68 "X509_V_ERR_CERT_SIGNATURE_FAILURE"
69 },
70 { X509_V_ERR_CRL_SIGNATURE_FAILURE,
71 "X509_V_ERR_CRL_SIGNATURE_FAILURE"
72 },
73 { X509_V_ERR_CERT_NOT_YET_VALID,
74 "X509_V_ERR_CERT_NOT_YET_VALID"
75 },
76 { X509_V_ERR_CERT_HAS_EXPIRED,
77 "X509_V_ERR_CERT_HAS_EXPIRED"
78 },
79 { X509_V_ERR_CRL_NOT_YET_VALID,
80 "X509_V_ERR_CRL_NOT_YET_VALID"
81 },
82 { X509_V_ERR_CRL_HAS_EXPIRED,
83 "X509_V_ERR_CRL_HAS_EXPIRED"
84 },
85 { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
86 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"
87 },
88 { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
89 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"
90 },
91 { X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
92 "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"
93 },
94 { X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
95 "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"
96 },
97 { X509_V_ERR_OUT_OF_MEM,
98 "X509_V_ERR_OUT_OF_MEM"
99 },
100 { X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
101 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"
102 },
103 { X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
104 "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"
105 },
106 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
107 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
108 },
109 { X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
110 "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"
111 },
112 { X509_V_ERR_CERT_CHAIN_TOO_LONG,
113 "X509_V_ERR_CERT_CHAIN_TOO_LONG"
114 },
115 { X509_V_ERR_CERT_REVOKED,
116 "X509_V_ERR_CERT_REVOKED"
117 },
118 { X509_V_ERR_INVALID_CA,
119 "X509_V_ERR_INVALID_CA"
120 },
121 { X509_V_ERR_PATH_LENGTH_EXCEEDED,
122 "X509_V_ERR_PATH_LENGTH_EXCEEDED"
123 },
124 { X509_V_ERR_INVALID_PURPOSE,
125 "X509_V_ERR_INVALID_PURPOSE"
126 },
127 { X509_V_ERR_CERT_UNTRUSTED,
128 "X509_V_ERR_CERT_UNTRUSTED"
129 },
130 { X509_V_ERR_CERT_REJECTED,
131 "X509_V_ERR_CERT_REJECTED"
132 },
133 { X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
134 "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"
135 },
136 { X509_V_ERR_AKID_SKID_MISMATCH,
137 "X509_V_ERR_AKID_SKID_MISMATCH"
138 },
139 { X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
140 "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"
141 },
142 { X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
143 "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"
144 },
145#if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)
146 {
147 X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, // 33
148 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"
149 },
150#endif
151#if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
152 {
153 X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, // 34
154 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
155 },
156#endif
157#if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)
158 {
159 X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, // 35
160 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"
161 },
162#endif
163#if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)
164 {
165 X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, // 36
166 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"
167 },
168#endif
169#if defined(X509_V_ERR_INVALID_NON_CA)
170 {
171 X509_V_ERR_INVALID_NON_CA, // 37
172 "X509_V_ERR_INVALID_NON_CA"
173 },
174#endif
175#if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)
176 {
177 X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, // 38
178 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
179 },
180#endif
181#if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE)
182 {
183 X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, // 39
184 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"
185 },
186#endif
187#if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)
188 {
189 X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, // 40
190 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"
191 },
192#endif
193#if defined(X509_V_ERR_INVALID_EXTENSION)
194 {
195 X509_V_ERR_INVALID_EXTENSION, // 41
196 "X509_V_ERR_INVALID_EXTENSION"
197 },
198#endif
199#if defined(X509_V_ERR_INVALID_POLICY_EXTENSION)
200 {
201 X509_V_ERR_INVALID_POLICY_EXTENSION, // 42
202 "X509_V_ERR_INVALID_POLICY_EXTENSION"
203 },
204#endif
205#if defined(X509_V_ERR_NO_EXPLICIT_POLICY)
206 {
207 X509_V_ERR_NO_EXPLICIT_POLICY, // 43
208 "X509_V_ERR_NO_EXPLICIT_POLICY"
209 },
210#endif
211#if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE)
212 {
213 X509_V_ERR_DIFFERENT_CRL_SCOPE, // 44
214 "X509_V_ERR_DIFFERENT_CRL_SCOPE"
215 },
216#endif
217#if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE)
218 {
219 X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, // 45
220 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"
221 },
222#endif
223#if defined(X509_V_ERR_UNNESTED_RESOURCE)
224 {
225 X509_V_ERR_UNNESTED_RESOURCE, // 46
226 "X509_V_ERR_UNNESTED_RESOURCE"
227 },
228#endif
229#if defined(X509_V_ERR_PERMITTED_VIOLATION)
230 {
231 X509_V_ERR_PERMITTED_VIOLATION, // 47
232 "X509_V_ERR_PERMITTED_VIOLATION"
233 },
234#endif
235#if defined(X509_V_ERR_EXCLUDED_VIOLATION)
236 {
237 X509_V_ERR_EXCLUDED_VIOLATION, // 48
238 "X509_V_ERR_EXCLUDED_VIOLATION"
239 },
240#endif
241#if defined(X509_V_ERR_SUBTREE_MINMAX)
242 {
243 X509_V_ERR_SUBTREE_MINMAX, // 49
244 "X509_V_ERR_SUBTREE_MINMAX"
245 },
246#endif
247 { X509_V_ERR_APPLICATION_VERIFICATION, // 50
248 "X509_V_ERR_APPLICATION_VERIFICATION"
249 },
250#if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE)
251 {
252 X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, // 51
253 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"
254 },
255#endif
256#if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX)
257 {
258 X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, // 52
259 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"
260 },
261#endif
262#if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX)
263 {
264 X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, // 53
265 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"
266 },
267#endif
268#if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR)
269 {
270 X509_V_ERR_CRL_PATH_VALIDATION_ERROR, // 54
271 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"
272 },
273#endif
274#if defined(X509_V_ERR_PATH_LOOP)
275 {
276 X509_V_ERR_PATH_LOOP, // 55
277 "X509_V_ERR_PATH_LOOP"
278 },
279#endif
280#if defined(X509_V_ERR_SUITE_B_INVALID_VERSION)
281 {
282 X509_V_ERR_SUITE_B_INVALID_VERSION, // 56
283 "X509_V_ERR_SUITE_B_INVALID_VERSION"
284 },
285#endif
286#if defined(X509_V_ERR_SUITE_B_INVALID_ALGORITHM)
287 {
288 X509_V_ERR_SUITE_B_INVALID_ALGORITHM, // 57
289 "X509_V_ERR_SUITE_B_INVALID_ALGORITHM"
290 },
291#endif
292#if defined(X509_V_ERR_SUITE_B_INVALID_CURVE)
293 {
294 X509_V_ERR_SUITE_B_INVALID_CURVE, // 58
295 "X509_V_ERR_SUITE_B_INVALID_CURVE"
296 },
297#endif
298#if defined(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM)
299 {
300 X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM, // 59
301 "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM"
302 },
303#endif
304#if defined(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED)
305 {
306 X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED, // 60
307 "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED"
308 },
309#endif
310#if defined(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256)
311 {
312 X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256, // 61
313 "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256"
314 },
315#endif
316#if defined(X509_V_ERR_HOSTNAME_MISMATCH)
317 {
318 X509_V_ERR_HOSTNAME_MISMATCH, // 62
319 "X509_V_ERR_HOSTNAME_MISMATCH"
320 },
321#endif
322#if defined(X509_V_ERR_EMAIL_MISMATCH)
323 {
324 X509_V_ERR_EMAIL_MISMATCH, // 63
325 "X509_V_ERR_EMAIL_MISMATCH"
326 },
327#endif
328#if defined(X509_V_ERR_IP_ADDRESS_MISMATCH)
329 {
330 X509_V_ERR_IP_ADDRESS_MISMATCH, // 64
331 "X509_V_ERR_IP_ADDRESS_MISMATCH"
332 },
333#endif
334#if defined(X509_V_ERR_DANE_NO_MATCH)
335 {
336 X509_V_ERR_DANE_NO_MATCH, // 65
337 "X509_V_ERR_DANE_NO_MATCH"
338 },
339#endif
340#if defined(X509_V_ERR_EE_KEY_TOO_SMALL)
341 {
342 X509_V_ERR_EE_KEY_TOO_SMALL, // 66
343 "X509_V_ERR_EE_KEY_TOO_SMALL"
344 },
345#endif
346#if defined(X509_V_ERR_CA_KEY_TOO_SMALL)
347 {
348 X509_V_ERR_CA_KEY_TOO_SMALL, // 67
349 "X509_V_ERR_CA_KEY_TOO_SMALL"
350 },
351#endif
352#if defined(X509_V_ERR_CA_MD_TOO_WEAK)
353 {
354 X509_V_ERR_CA_MD_TOO_WEAK, // 68
355 "X509_V_ERR_CA_MD_TOO_WEAK"
356 },
357#endif
358#if defined(X509_V_ERR_INVALID_CALL)
359 {
360 X509_V_ERR_INVALID_CALL, // 69
361 "X509_V_ERR_INVALID_CALL"
362 },
363#endif
364#if defined(X509_V_ERR_STORE_LOOKUP)
365 {
366 X509_V_ERR_STORE_LOOKUP, // 70
367 "X509_V_ERR_STORE_LOOKUP"
368 },
369#endif
370#if defined(X509_V_ERR_NO_VALID_SCTS)
371 {
372 X509_V_ERR_NO_VALID_SCTS, // 71
373 "X509_V_ERR_NO_VALID_SCTS"
374 },
375#endif
376#if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION)
377 {
378 X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION, // 72
379 "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION"
380 },
381#endif
382#if defined(X509_V_ERR_OCSP_VERIFY_NEEDED)
383 {
384 X509_V_ERR_OCSP_VERIFY_NEEDED, // 73
385 "X509_V_ERR_OCSP_VERIFY_NEEDED"
386 },
387#endif
388#if defined(X509_V_ERR_OCSP_VERIFY_FAILED)
389 {
390 X509_V_ERR_OCSP_VERIFY_FAILED, // 74
391 "X509_V_ERR_OCSP_VERIFY_FAILED"
392 },
393#endif
394#if defined(X509_V_ERR_OCSP_CERT_UNKNOWN)
395 {
396 X509_V_ERR_OCSP_CERT_UNKNOWN, // 75
397 "X509_V_ERR_OCSP_CERT_UNKNOWN"
398 },
399#endif
400 {
401 SSL_ERROR_NONE,
402 "SSL_ERROR_NONE"
403 },
404#endif // USE_OPENSSL
405};
406
407} // namespace Security
408
411{
412 static auto TheCmp = [](const char *a, const char *b) {return strcmp(a, b) < 0;};
413 static std::map<const char *, ErrorCode, decltype(TheCmp)> TheErrorCodeByNameIndx(TheCmp);
414 if (TheErrorCodeByNameIndx.empty()) {
415 for (const auto &i: TheErrorCodeNames)
416 TheErrorCodeByNameIndx.insert(std::make_pair(i.second, i.first));
417
418 // redirector to support legacy error translations
419 TheErrorCodeByNameIndx.insert(std::make_pair("SQUID_ERR_SSL_HANDSHAKE", SQUID_TLS_ERR_CONNECT));
420 }
421
422 const auto it = TheErrorCodeByNameIndx.find(name);
423 if (it != TheErrorCodeByNameIndx.end())
424 return it->second;
425
426 return 0;
427}
428
429const char *
430Security::ErrorNameFromCode(const ErrorCode err, const bool prefixRawCode)
431{
432 const auto it = TheErrorCodeNames.find(err);
433 if (it != TheErrorCodeNames.end())
434 return it->second;
435
436 static char tmpBuffer[128];
437 snprintf(tmpBuffer, sizeof(tmpBuffer), "%s%d",
438 (prefixRawCode ? "SSL_ERR=" : ""), static_cast<int>(err));
439 return tmpBuffer;
440}
441
442/* Security::ErrorDetail */
443
445Security::ErrorDetail::ErrorDetail(const ErrorCode err, const int aSysErrorNo):
446 error_no(err),
447 // We could restrict errno(3) collection to cases where the TLS library
448 // explicitly talks about the errno being set, but correctly detecting those
449 // cases is difficult. We simplify in hope that all other cases will either
450 // have a useful errno or a zero errno.
451 sysErrorNo(aSysErrorNo)
452{
453#if USE_OPENSSL
455 if ((lib_error_no = ERR_get_error())) {
456 debugs(83, 7, "got " << asHex(lib_error_no));
457 // more errors may be stacked
458 // TODO: Save/detail all stacked errors by always flushing stale ones.
459 ForgetErrors();
460 }
461#else
462 // other libraries return errors explicitly instead of auto-storing them
463#endif
464}
465
466Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode, const CertPointer &cert, const CertPointer &broken, const char *aReason):
467 ErrorDetail(anErrorCode, 0)
468{
469 errReason = aReason;
470 peer_cert = cert;
471 broken_cert = broken ? broken : cert;
472}
473
474#if USE_OPENSSL
475Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode, const int anIoErrorNo, const int aSysErrorNo):
476 ErrorDetail(anErrorCode, aSysErrorNo)
477{
478 ioErrorNo = anIoErrorNo;
479}
480
481#elif USE_GNUTLS
482Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode, const LibErrorCode aLibErrorNo, const int aSysErrorNo):
483 ErrorDetail(anErrorCode, aSysErrorNo)
484{
485 lib_error_no = aLibErrorNo;
486}
487#endif
488
489void
491{
492 assert(cert);
493 assert(!peer_cert);
494 assert(!broken_cert);
495 peer_cert = cert;
496 // unlike the constructor, the supplied certificate is not a broken_cert
497}
498
499SBuf
501{
502 SBufStream os;
503
504 printErrorCode(os);
505
506 if (lib_error_no) {
507#if USE_OPENSSL
508 // TODO: Log ERR_error_string_n() instead, despite length, whitespace?
509 // Example: `error:1408F09C:SSL routines:ssl3_get_record:http request`.
510 os << "+TLS_LIB_ERR=" << std::hex << std::uppercase << lib_error_no << std::nouppercase << std::dec;
511#elif USE_GNUTLS
512 os << '+' << gnutls_strerror_name(lib_error_no);
513#endif
514 }
515
516#if USE_OPENSSL
517 // TODO: Consider logging long but human-friendly names (e.g.,
518 // SSL_ERROR_SYSCALL).
519 if (ioErrorNo)
520 os << "+TLS_IO_ERR=" << ioErrorNo;
521#endif
522
523 if (sysErrorNo) {
524 os << '+' << SysErrorDetail::Brief(sysErrorNo);
525 }
526
527 if (broken_cert)
528 os << "+broken_cert";
529
530 return os.buf();
531}
532
533SBuf
535{
536 std::optional<SBuf> customFormat;
537#if USE_OPENSSL
538 if (const auto errorDetail = Ssl::ErrorDetailsManager::GetInstance().findDetail(error_no, request))
539 customFormat = errorDetail->detail;
540#else
541 (void)request;
542#endif
543 auto format = customFormat ? customFormat->c_str() : "SSL handshake error (%err_name)";
544
545 SBufStream os;
546 assert(format);
547 auto remainder = format;
548 while (auto p = strchr(remainder, '%')) {
549 os.write(remainder, p - remainder);
550 const auto formattingCodeLen = convertErrorCodeToDescription(++p, os);
551 if (!formattingCodeLen)
552 os << '%';
553 remainder = p + formattingCodeLen;
554 }
555 os << remainder;
556 return os.buf();
557}
558
560void
562{
563 if (broken_cert) {
564 auto buf = SubjectName(*broken_cert);
565 if (!buf.isEmpty()) {
566 // TODO: Convert html_quote() into an std::ostream manipulator.
567 // quote to avoid possible html code injection through
568 // certificate subject
569 os << html_quote(buf.c_str());
570 return;
571 }
572 }
573 os << "[Not available]";
574}
575
576#if USE_OPENSSL
579{
580public:
581 explicit CommonNamesPrinter(std::ostream &os): os_(os) {}
582
584 static int PrintName(void *, ASN1_STRING *);
585
587 bool printed = false;
588
589private:
590 void printName(const ASN1_STRING *);
591
592 std::ostream &os_;
593};
594
595int
596CommonNamesPrinter::PrintName(void * const printer, ASN1_STRING * const name)
597{
598 assert(printer);
599 static_cast<CommonNamesPrinter*>(printer)->printName(name);
600 return 1;
601}
602
605void
606CommonNamesPrinter::printName(const ASN1_STRING * const name)
607{
608 if (name && name->length) {
609 if (printed)
610 os_ << ", ";
611
612 // TODO: Convert html_quote() into an std::ostream manipulator accepting (buf, n).
613 SBuf buf(reinterpret_cast<const char *>(name->data), name->length);
614 os_ << html_quote(buf.c_str());
615
616 printed = true;
617 }
618}
619#endif // USE_OPENSSL
620
622void
624{
625#if USE_OPENSSL
626 if (broken_cert.get()) {
627 CommonNamesPrinter printer(os);
628 Ssl::matchX509CommonNames(broken_cert.get(), &printer, printer.PrintName);
629 if (printer.printed)
630 return;
631 }
632#endif // USE_OPENSSL
633 os << "[Not available]";
634}
635
637void
639{
640 if (broken_cert) {
641 auto buf = IssuerName(*broken_cert);
642 if (!buf.isEmpty()) {
643 // quote to avoid possible html code injection through
644 // certificate issuer subject
645 os << html_quote(buf.c_str());
646 return;
647 }
648 }
649 os << "[Not available]";
650}
651
653void
655{
656#if USE_OPENSSL
657 if (broken_cert.get()) {
658 if (const auto tm = X509_getm_notBefore(broken_cert.get())) {
659 // TODO: Add and use an ASN1_TIME printing operator instead.
660 static char tmpBuffer[256]; // A temporary buffer
661 Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
662 os << tmpBuffer;
663 return;
664 }
665 }
666#endif // USE_OPENSSL
667 os << "[Not available]";
668}
669
671void
673{
674#if USE_OPENSSL
675 if (broken_cert.get()) {
676 if (const auto tm = X509_getm_notAfter(broken_cert.get())) {
677 // XXX: Reduce code duplication.
678 static char tmpBuffer[256]; // A temporary buffer
679 Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
680 os << tmpBuffer;
681 return;
682 }
683 }
684#endif // USE_OPENSSL
685 os << "[Not available]";
686}
687
689void
691{
692#if USE_OPENSSL
693 // try detailEntry first because it is faster
694 if (detailEntry) {
695 os << detailEntry->name;
696 return;
697 }
698#endif
699 os << ErrorNameFromCode(error_no);
700}
701
703void
705{
706 if (!error_no) {
707 os << "[No Error]";
708 return;
709 }
710
711#if USE_OPENSSL
712 if (detailEntry) {
713 os << detailEntry->descr;
714 return;
715 }
716#endif
717
718 os << "[Not available]";
719}
720
722void
724{
725 if (errReason.size() > 0)
726 os << errReason;
727 else if (lib_error_no)
728 os << ErrorString(lib_error_no);
729 else
730 os << "[No Error]";
731}
732
751size_t
752Security::ErrorDetail::convertErrorCodeToDescription(const char * const code, std::ostream &os) const
753{
754 using PartDescriber = void (ErrorDetail::*)(std::ostream &os) const;
755 static const std::map<const char*, PartDescriber> PartDescriberByCode = {
756 {"ssl_subject", &ErrorDetail::printSubject},
757 {"ssl_ca_name", &ErrorDetail::printCaName},
758 {"ssl_cn", &ErrorDetail::printCommonName},
759 {"ssl_notbefore", &ErrorDetail::printNotBefore},
760 {"ssl_notafter", &ErrorDetail::printNotAfter},
761 {"err_name", &ErrorDetail::printErrorCode},
762 {"ssl_error_descr", &ErrorDetail::printErrorDescription},
763 {"ssl_lib_error", &ErrorDetail::printErrorLibError}
764 };
765
766 // We can refactor the map to find matches without looping, but that
767 // requires a "starts with" comparison function -- `code` length is unknown.
768 for (const auto &pair: PartDescriberByCode) {
769 const auto len = strlen(pair.first);
770 if (strncmp(code, pair.first, len) == 0) {
771 const auto method = pair.second;
772 (this->*method)(os);
773 return len;
774 }
775 }
776
777 // TODO: Support logformat %codes.
778 return 0;
779}
780
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition: IoManip.h:99
#define assert(EX)
Definition: assert.h:17
a helper class to print CNs extracted using Ssl::matchX509CommonNames()
Definition: ErrorDetail.cc:579
CommonNamesPrinter(std::ostream &os)
Definition: ErrorDetail.cc:581
void printName(const ASN1_STRING *)
Definition: ErrorDetail.cc:606
static int PrintName(void *, ASN1_STRING *)
Ssl::matchX509CommonNames() visitor that reports the given name (if any)
Definition: ErrorDetail.cc:596
bool printed
whether any names have been printed so far
Definition: ErrorDetail.cc:587
std::ostream & os_
destination for printed names
Definition: ErrorDetail.cc:592
SBuf buf()
bytes written so far
Definition: Stream.h:41
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
void printErrorCode(std::ostream &os) const
textual representation of error_no
Definition: ErrorDetail.cc:690
SBuf verbose(const HttpRequestPointer &) const override
Definition: ErrorDetail.cc:534
void printCommonName(std::ostream &os) const
a list of the broken certificates CN and alternate names
Definition: ErrorDetail.cc:623
LibErrorCode lib_error_no
TLS library-reported non-validation error or zero;.
Definition: ErrorDetail.h:105
ErrorDetail(ErrorCode err_no, const CertPointer &peer, const CertPointer &broken, const char *aReason=nullptr)
Definition: ErrorDetail.cc:466
CertPointer broken_cert
A pointer to the broken certificate (peer or intermediate)
Definition: ErrorDetail.h:99
void printSubject(std::ostream &os) const
textual representation of the subject of the broken certificate
Definition: ErrorDetail.cc:561
size_t convertErrorCodeToDescription(const char *code, std::ostream &os) const
Definition: ErrorDetail.cc:752
void printErrorLibError(std::ostream &os) const
textual representation of lib_error_no
Definition: ErrorDetail.cc:723
void printErrorDescription(std::ostream &os) const
short description of error_no
Definition: ErrorDetail.cc:704
String errReason
a custom reason for the error
Definition: ErrorDetail.h:123
void setPeerCertificate(const CertPointer &)
Definition: ErrorDetail.cc:490
SBuf brief() const override
Definition: ErrorDetail.cc:500
void printNotBefore(std::ostream &os) const
textual representation of the "not before" field of the broken certificate
Definition: ErrorDetail.cc:654
void printCaName(std::ostream &os) const
the issuer of the broken certificate
Definition: ErrorDetail.cc:638
void printNotAfter(std::ostream &os) const
textual representation of the "not after" field of the broken certificate
Definition: ErrorDetail.cc:672
CertPointer peer_cert
A pointer to the peer certificate.
Definition: ErrorDetail.h:98
static ErrorDetailsManager & GetInstance()
Instance class.
static SBuf Brief(int errorNo)
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
int asn1timeToString(ASN1_TIME *tm, char *buf, int len)
Definition: support.cc:181
int matchX509CommonNames(X509 *peer_cert, void *check_data, int(*check_func)(void *check_data, ASN1_STRING *cn_data))
Definition: support.cc:195
char * html_quote(const char *string)
Definition: Quoting.cc:49
Network/connection security abstraction layer.
Definition: Connection.h:34
SBuf IssuerName(Certificate &)
The Issuer field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:28
std::map< ErrorCode, const char * > ErrorCodeNames
Definition: ErrorDetail.cc:34
int ErrorCode
Squid-defined error code (<0), an error code returned by X.509 API, or zero.
Definition: forward.h:132
const char * ErrorNameFromCode(ErrorCode err, bool prefixRawCode=false)
Definition: ErrorDetail.cc:430
unsigned long LibErrorCode
TLS library-reported non-validation error.
Definition: forward.h:139
ErrorCode ErrorCodeFromName(const char *name)
Definition: ErrorDetail.cc:410
SBuf SubjectName(Certificate &)
The SubjectName field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:68
const char * ErrorString(const LibErrorCode code)
converts numeric LibErrorCode into a human-friendlier string
Definition: forward.h:150
static const ErrorCodeNames TheErrorCodeNames
Definition: ErrorDetail.cc:35
void ForgetErrors()
clear any errors that a TLS library has accumulated in its global storage
Definition: Io.cc:57
#define X509_getm_notAfter
Definition: openssl.h:247
#define X509_getm_notBefore
Definition: openssl.h:248
@ SQUID_X509_V_ERR_INFINITE_VALIDATION
Definition: forward.h:235
@ SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: forward.h:234
@ SQUID_TLS_ERR_CONNECT
failure to establish a connection with a TLS server
Definition: forward.h:230
@ SQUID_TLS_ERR_ACCEPT
failure to accept a connection from a TLS client
Definition: forward.h:229
@ SQUID_X509_V_ERR_CERT_CHANGE
Definition: forward.h:233
int code
Definition: smb-errors.c:145

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors