2 * Copyright (C) 1996-2023 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.
9 #ifndef SQUID_SRC_SECURITY_ERRORDETAIL_H
10 #define SQUID_SRC_SECURITY_ERRORDETAIL_H
12 #include "base/RefCount.h"
13 #include "error/Detail.h"
14 #include "http/forward.h"
15 #include "security/forward.h"
16 #include "SquidString.h"
19 #include "ssl/ErrorDetailManager.h"
28 /// Details a TLS-related error. Two kinds of errors can be detailed:
29 /// * certificate validation errors (including built-in and helper-driven) and
30 /// * TLS logic and I/O errors (detected by Squid or the TLS library).
32 /// The following details may be available (only the first one is required):
33 /// * for all errors: problem classification (\see ErrorCode)
34 /// * for all errors: peer certificate
35 /// * for certificate validation errors: the broken certificate
36 /// * for certificate validation errors: validation failure reason
37 /// * for non-validation errors: TLS library-reported error(s)
38 /// * for non-validation errors: system call errno(3)
39 class ErrorDetail
: public ::ErrorDetail
41 MEMPROXY_CLASS(Security::ErrorDetail
);
44 typedef ErrorDetailPointer Pointer
;
46 /// Details a server-side certificate verification failure.
47 /// If `broken` is nil, then the broken certificate is the peer certificate.
48 ErrorDetail(ErrorCode err_no
, const CertPointer
&peer
, const CertPointer
&broken
, const char *aReason
= nullptr);
51 /// Details (or starts detailing) a non-validation failure.
52 /// \param anIoErrorNo TLS I/O function outcome; \see ErrorDetail::ioErrorNo
53 /// \param aSysErrorNo saved errno(3); \see ErrorDetail::sysErrorNo
54 ErrorDetail(ErrorCode anErrorCode
, int anIoErrorNo
, int aSysErrorNo
);
56 /// Details (or starts detailing) a non-validation failure.
57 /// \param anLibErrorNo TLS function outcome; \see ErrorDetail::lib_error_no
58 /// \param aSysErrorNo saved errno(3); \see ErrorDetail::sysErrorNo
59 ErrorDetail(ErrorCode anErrorCode
, LibErrorCode aLibErrorNo
, int aSysErrorNo
);
63 SBuf
brief() const override
;
64 SBuf
verbose(const HttpRequestPointer
&) const override
;
66 /// \returns error category; \see ErrorCode
67 ErrorCode
errorNo() const { return error_no
; }
69 /// \returns the previously saved errno(3) or zero
70 int sysError() const { return sysErrorNo
; }
72 /* Certificate manipulation API. TODO: Add GnuTLS implementations, users. */
74 /// the peer certificate (or nil)
75 Certificate
*peerCert() { return peer_cert
.get(); }
77 /// peer or intermediate certificate that failed validation (or nil)
78 Certificate
*brokenCert() {return broken_cert
.get(); }
80 /// remember the SSL certificate of our peer; requires nil peerCert()
81 /// unlike the cert-setting constructor, does not assume the cert is bad
82 void setPeerCertificate(const CertPointer
&);
85 ErrorDetail(ErrorCode err
, int aSysErrorNo
);
87 /* methods for formatting error details using admin-configurable %codes */
88 void printSubject(std::ostream
&os
) const;
89 void printCaName(std::ostream
&os
) const;
90 void printCommonName(std::ostream
&os
) const;
91 void printNotBefore(std::ostream
&os
) const;
92 void printNotAfter(std::ostream
&os
) const;
93 void printErrorCode(std::ostream
&os
) const;
94 void printErrorDescription(std::ostream
&os
) const;
95 void printErrorLibError(std::ostream
&os
) const;
96 size_t convertErrorCodeToDescription(const char *code
, std::ostream
&os
) const;
98 CertPointer peer_cert
; ///< A pointer to the peer certificate
99 CertPointer broken_cert
; ///< A pointer to the broken certificate (peer or intermediate)
101 /// Squid-discovered error, validation error, or zero; \see ErrorCode
102 ErrorCode error_no
= 0;
104 /// TLS library-reported non-validation error or zero; \see LibErrorCode
105 LibErrorCode lib_error_no
= 0;
107 /// errno(3); system call failure code or zero
111 /// OpenSSL-specific (first-level or intermediate) TLS I/O operation result
112 /// reported by SSL_get_error(3SSL) (e.g., SSL_ERROR_SYSCALL) or zero.
113 /// Unlike lib_error_no, this error is mostly meant for I/O control and has
114 /// no OpenSSL-provided human-friendly text representation.
117 using ErrorDetailEntry
= Ssl::ErrorDetailEntry
;
118 mutable std::optional
<ErrorDetailEntry
> detailEntry
;
120 // other TLS libraries do not use custom ErrorDetail members
123 String errReason
; ///< a custom reason for the error
126 /// \returns ErrorCode with a given name (or zero)
127 ErrorCode
ErrorCodeFromName(const char *name
);
129 /// \returns string representation of ErrorCode, including raw X.509 error codes
130 /// \param prefixRawCode whether to prefix raw codes with "SSL_ERR="
131 const char *ErrorNameFromCode(ErrorCode err
, bool prefixRawCode
= false);
133 /// Dump the given Security::ErrorDetail via a possibly nil pointer (for
134 /// debugging). Unfortunately, without this, compilers pick generic RefCount<T>
135 /// operator "<<" overload (with T=Security::ErrorDetail) instead of the
136 /// overload provided by the parent ErrorDetail class (that we call here).
137 inline std::ostream
&
138 operator <<(std::ostream
&os
, const ErrorDetail::Pointer
&p
)
140 return operator <<(os
, ::ErrorDetail::Pointer(p
));
143 } // namespace Security
145 #endif /* SQUID_SRC_SECURITY_ERRORDETAIL_H */