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 enum
35 {
36 MAX_ERRORS = 8
37 };
38
40 {
41 ssl_err = -1;
42 init_error("OpenSSL");
43 }
44
45 explicit OpenSSLException(const std::string &error_text) noexcept
46 {
47 ssl_err = -1;
48 init_error(error_text.c_str());
49 }
50
51 explicit OpenSSLException(const int ssl_error)
52 {
53 init_ssl_error(ssl_error, "OpenSSL");
54 }
55
56 explicit OpenSSLException(const std::string &error_text, const int ssl_error)
57 {
58 init_ssl_error(ssl_error, error_text.c_str());
59 }
60
61 const char *what() const noexcept override
62 {
63 return errtxt.c_str();
64 }
65 std::string what_str() const
66 {
67 return errtxt;
68 }
69
70 size_t len() const
71 {
72 return n_err;
73 }
74 unsigned long operator[](const size_t i) const
75 {
76 if (i < n_err)
77 return errstack[i];
78 else
79 throw ssl_exception_index();
80 }
81
82 int ssl_error() const
83 {
84 return ssl_err;
85 }
86
87 virtual ~OpenSSLException() noexcept = default;
88
89 static const char *ssl_error_text(const int ssl_error, bool *unknown = nullptr)
90 {
91 switch (ssl_error)
92 {
93 case SSL_ERROR_NONE:
94 return "SSL_ERROR_NONE";
95 case SSL_ERROR_ZERO_RETURN:
96 return "SSL_ERROR_ZERO_RETURN";
97 case SSL_ERROR_WANT_READ:
98 return "SSL_ERROR_WANT_READ";
99 case SSL_ERROR_WANT_WRITE:
100 return "SSL_ERROR_WANT_WRITE";
101 case SSL_ERROR_WANT_CONNECT:
102 return "SSL_ERROR_WANT_CONNECT";
103 case SSL_ERROR_WANT_ACCEPT:
104 return "SSL_ERROR_WANT_ACCEPT";
105 case SSL_ERROR_WANT_X509_LOOKUP:
106 return "SSL_ERROR_WANT_X509_LOOKUP";
107 case SSL_ERROR_SYSCALL:
108 return "SSL_ERROR_SYSCALL";
109 case SSL_ERROR_SSL:
110 return "SSL_ERROR_SSL";
111 default:
112 if (unknown)
113 *unknown = true;
114 return "(unknown SSL error)";
115 }
116 }
117
118 private:
119 void init_error(const char *error_text)
120 {
121 const char *prefix = ": ";
122 std::ostringstream tmp;
123 char buf[256];
124
125 tmp << error_text;
126
127 n_err = 0;
128 while (unsigned long err = ERR_get_error())
129 {
130 if (n_err < MAX_ERRORS)
131 errstack[n_err++] = err;
132 ERR_error_string_n(err, buf, sizeof(buf));
133 auto reason = ERR_GET_REASON(err);
134 tmp << prefix << buf;
135 if (reason >= SSL_AD_REASON_OFFSET)
136 {
137 tmp << "[" << SSL_alert_desc_string_long(reason - SSL_AD_REASON_OFFSET) << "]";
138 }
139
140 prefix = " / ";
141
142 // for certain OpenSSL errors, translate them to an OpenVPN error code,
143 // so they can be propagated up to the higher levels (such as UI level)
144
145 switch (reason)
146 {
147 case SSL_R_CERTIFICATE_VERIFY_FAILED:
149 break;
150 case PEM_R_BAD_PASSWORD_READ:
151 case PEM_R_BAD_DECRYPT:
153 break;
154 case SSL_R_UNSUPPORTED_PROTOCOL:
156 break;
157 case SSL_R_CA_MD_TOO_WEAK:
159 break;
160 case SSL_R_CA_KEY_TOO_SMALL:
162 break;
163#if defined(SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED)
164 /* This error code has been added in OpenSSL 3.0.8 */
165 case SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED:
167 break;
168#endif
169 case SSL_R_DH_KEY_TOO_SMALL:
171 break;
172 case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:
174 break;
175 case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
177 break;
178 case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE:
180 break;
181 case SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED:
183 break;
184 case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
186 break;
187 case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
189 break;
190 case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
192 break;
193 case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:
195 break;
196 default:
197 if (reason > SSL_AD_REASON_OFFSET)
198 {
199 /* all TLS alerts use TLS alert code + SSL_AD_REASON_OFFSET in OpenSSL */
201 }
202 }
203 }
204 errtxt = tmp.str();
205 }
206
207 void init_ssl_error(const int ssl_error, const char *error_text)
208 {
209 bool unknown = false;
211 const char *text = ssl_error_text(ssl_error, &unknown);
212 if (unknown || ssl_error == SSL_ERROR_SYSCALL || ssl_error == SSL_ERROR_SSL)
213 {
214 init_error(error_text);
215 errtxt += " (";
216 errtxt += text;
217 errtxt += ")";
218 }
219 else
220 {
221 errtxt = error_text;
222 errtxt += ": ";
223 errtxt += text;
224 }
225 }
226
227 size_t n_err;
228 unsigned long errstack[MAX_ERRORS];
229 std::string errtxt;
231};
232
233// return an OpenSSL error string
234
235inline std::string openssl_error()
236{
238 return err.what_str();
239}
240
241inline std::string openssl_error(const int ssl_error)
242{
243 OpenSSLException err(ssl_error);
244 return err.what_str();
245}
246
248{
249 while (ERR_get_error())
250 ;
251}
252
253} // namespace openvpn
254
255#endif // OPENVPN_OPENSSL_UTIL_ERROR_H
void set_code(const Error::Type code)
Definition excode.hpp:44
static const char * ssl_error_text(const int ssl_error, bool *unknown=nullptr)
Definition error.hpp:89
OpenSSLException(const std::string &error_text) noexcept
Definition error.hpp:45
virtual ~OpenSSLException() noexcept=default
std::string what_str() const
Definition error.hpp:65
void init_ssl_error(const int ssl_error, const char *error_text)
Definition error.hpp:207
OpenSSLException(const int ssl_error)
Definition error.hpp:51
unsigned long errstack[MAX_ERRORS]
Definition error.hpp:228
const char * what() const noexcept override
Definition error.hpp:61
unsigned long operator[](const size_t i) const
Definition error.hpp:74
OPENVPN_EXCEPTION(ssl_exception_index)
int ssl_error() const
Definition error.hpp:82
size_t len() const
Definition error.hpp:70
void init_error(const char *error_text)
Definition error.hpp:119
OpenSSLException(const std::string &error_text, const int ssl_error)
Definition error.hpp:56
@ 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
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
void openssl_clear_error_stack()
Definition error.hpp:247
std::string openssl_error()
Definition error.hpp:235