OpenVPN 3 Core Library
Loading...
Searching...
No Matches
error.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// OpenSSL exception class that allows a full OpenSSL error stack
13// to be represented.
14
15#ifndef OPENVPN_OPENSSL_UTIL_ERROR_H
16#define OPENVPN_OPENSSL_UTIL_ERROR_H
17
18#include <string>
19#include <openssl/err.h>
20#include <openssl/ssl.h>
21
25
26namespace openvpn {
27
28// string exception class
30{
31 public:
32 OPENVPN_EXCEPTION(ssl_exception_index);
33
34 static constexpr size_t MAX_ERRORS = 8;
35
37 {
38 init_error("OpenSSL");
39 }
40
41 explicit OpenSSLException(const std::string &error_text) noexcept
42 {
43 init_error(error_text.c_str());
44 }
45
46 explicit OpenSSLException(const int ssl_error)
47 {
48 init_ssl_error(ssl_error, "OpenSSL");
49 }
50
51 explicit OpenSSLException(const std::string &error_text, const int ssl_error)
52 {
53 init_ssl_error(ssl_error, error_text.c_str());
54 }
55
56 const char *what() const noexcept override
57 {
58 return errtxt.c_str();
59 }
60 std::string what_str() const
61 {
62 return errtxt;
63 }
64
65 size_t len() const
66 {
67 return n_err;
68 }
69 unsigned long operator[](const size_t i) const
70 {
71 if (i < n_err)
72 return errstack[i];
73 throw ssl_exception_index();
74 }
75
76 int ssl_error() const
77 {
78 return ssl_err;
79 }
80
81 virtual ~OpenSSLException() noexcept = default;
82
83 static const char *ssl_error_text(const int ssl_error, bool *unknown = nullptr)
84 {
85 switch (ssl_error)
86 {
87 case SSL_ERROR_NONE:
88 return "SSL_ERROR_NONE";
89 case SSL_ERROR_ZERO_RETURN:
90 return "SSL_ERROR_ZERO_RETURN";
91 case SSL_ERROR_WANT_READ:
92 return "SSL_ERROR_WANT_READ";
93 case SSL_ERROR_WANT_WRITE:
94 return "SSL_ERROR_WANT_WRITE";
95 case SSL_ERROR_WANT_CONNECT:
96 return "SSL_ERROR_WANT_CONNECT";
97 case SSL_ERROR_WANT_ACCEPT:
98 return "SSL_ERROR_WANT_ACCEPT";
99 case SSL_ERROR_WANT_X509_LOOKUP:
100 return "SSL_ERROR_WANT_X509_LOOKUP";
101 case SSL_ERROR_SYSCALL:
102 return "SSL_ERROR_SYSCALL";
103 case SSL_ERROR_SSL:
104 return "SSL_ERROR_SSL";
105 default:
106 if (unknown)
107 *unknown = true;
108 return "(unknown SSL error)";
109 }
110 }
111
112 private:
113 void init_error(const char *error_text)
114 {
115 std::string prefix = ": ";
116 char buf[256];
117
118 errtxt = error_text;
119
120 n_err = 0;
121 while (unsigned long err = ERR_get_error())
122 {
123 if (n_err < MAX_ERRORS)
124 errstack[n_err++] = err;
125 ERR_error_string_n(err, buf, sizeof(buf));
126 auto reason = ERR_GET_REASON(err);
127 errtxt += prefix + buf;
128 if (reason >= SSL_AD_REASON_OFFSET)
129 {
130 errtxt += std::string{"["} + SSL_alert_desc_string_long(reason - SSL_AD_REASON_OFFSET) + "]";
131 }
132
133 prefix = " / ";
134
135 // for certain OpenSSL errors, translate them to an OpenVPN error code,
136 // so they can be propagated up to the higher levels (such as UI level)
137
138 switch (reason)
139 {
140 case SSL_R_CERTIFICATE_VERIFY_FAILED:
142 break;
143 case PEM_R_BAD_PASSWORD_READ:
144 case PEM_R_BAD_DECRYPT:
146 break;
147 case SSL_R_UNSUPPORTED_PROTOCOL:
149 break;
150 case SSL_R_CA_MD_TOO_WEAK:
152 break;
153 case SSL_R_CA_KEY_TOO_SMALL:
155 break;
156#ifdef SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED
157 /* This error code has been added in OpenSSL 3.0.8 */
158 case SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED:
160 break;
161#endif
162 case SSL_R_DH_KEY_TOO_SMALL:
164 break;
165 case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:
167 break;
168 case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
170 break;
171 case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE:
173 break;
174 case SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED:
176 break;
177 case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
179 break;
180 case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
182 break;
183 case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
185 break;
186 case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:
188 break;
189 default:
190 if (reason > SSL_AD_REASON_OFFSET)
191 {
192 /* all TLS alerts use TLS alert code + SSL_AD_REASON_OFFSET in OpenSSL */
194 }
195 }
196 }
197 }
198
199 void init_ssl_error(const int ssl_error, const char *error_text)
200 {
201 bool unknown = false;
203 const char *text = ssl_error_text(ssl_error, &unknown);
204 if (unknown || ssl_error == SSL_ERROR_SYSCALL || ssl_error == SSL_ERROR_SSL)
205 {
206 init_error(error_text);
207 errtxt += " (";
208 errtxt += text;
209 errtxt += ")";
210 }
211 else
212 {
213 errtxt = error_text;
214 errtxt += ": ";
215 errtxt += text;
216 }
217 }
218
219 size_t n_err = 0;
220 unsigned long errstack[MAX_ERRORS];
221 std::string errtxt;
222 int ssl_err = -1;
223};
224
225// return an OpenSSL error string
226
227inline std::string openssl_error()
228{
230 return err.what_str();
231}
232
233inline std::string openssl_error(const int ssl_error)
234{
235 OpenSSLException err(ssl_error);
236 return err.what_str();
237}
238
240{
241 while (ERR_get_error())
242 ;
243}
244
245} // namespace openvpn
246
247#endif // OPENVPN_OPENSSL_UTIL_ERROR_H
void set_code(const Error::Type code)
Definition excode.hpp:36
static const char * ssl_error_text(const int ssl_error, bool *unknown=nullptr)
Definition error.hpp:83
OpenSSLException(const std::string &error_text) noexcept
Definition error.hpp:41
static constexpr size_t MAX_ERRORS
Definition error.hpp:34
virtual ~OpenSSLException() noexcept=default
std::string what_str() const
Definition error.hpp:60
void init_ssl_error(const int ssl_error, const char *error_text)
Definition error.hpp:199
OpenSSLException(const int ssl_error)
Definition error.hpp:46
unsigned long errstack[MAX_ERRORS]
Definition error.hpp:220
const char * what() const noexcept override
Definition error.hpp:56
unsigned long operator[](const size_t i) const
Definition error.hpp:69
OPENVPN_EXCEPTION(ssl_exception_index)
int ssl_error() const
Definition error.hpp:76
size_t len() const
Definition error.hpp:65
void init_error(const char *error_text)
Definition error.hpp:113
OpenSSLException(const std::string &error_text, const int ssl_error)
Definition error.hpp:51
@ TLS_ALERT_CERTIFICATE_REVOKED
Definition error.hpp:73
@ PEM_PASSWORD_FAIL
Definition error.hpp:79
@ TLS_ALERT_BAD_CERTIFICATE
Definition error.hpp:74
@ SSL_DH_KEY_TOO_SMALL
Definition error.hpp:56
@ TLS_ALERT_CERTIFICATE_EXPIRED
Definition error.hpp:72
@ TLS_ALERT_UNSUPPORTED_CERTIFICATE
Definition error.hpp:75
@ SSL_CA_MD_TOO_WEAK
Definition error.hpp:54
@ TLS_ALERT_PROTOCOL_VERSION
Definition error.hpp:68
@ TLS_ALERT_HANDSHAKE_FAILURE
Definition error.hpp:70
@ SSL_CA_KEY_TOO_SMALL
Definition error.hpp:55
@ TLS_SIGALG_DISALLOWED_OR_UNSUPPORTED
Definition error.hpp:67
@ TLS_ALERT_UNKNOWN_CA
Definition error.hpp:69
@ TLS_ALERT_CERTIFICATE_REQUIRED
Definition error.hpp:71
void openssl_clear_error_stack()
Definition error.hpp:239
std::string openssl_error()
Definition error.hpp:227