ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_openssl.c
Revision: 9935
Committed: Thu May 13 07:06:31 2021 UTC (2 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 12261 byte(s)
Log Message:
- tls_openssl: cleanly build with openssl 3.0;  use OSSL_STORE api to retrieve dh parameters;  replace deprecated functions

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 2015 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (c) 2015 Adam <Adam@anope.org>
6 * Copyright (c) 2005-2021 ircd-hybrid development team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23
24 /*! \file tls_openssl.c
25 * \brief Includes all OpenSSL-specific TLS functions
26 * \version $Id$
27 */
28
29 #include "stdinc.h"
30 #include "tls.h"
31 #include "conf.h"
32 #include "log.h"
33 #include "misc.h"
34 #include "memory.h"
35
36 #ifdef HAVE_TLS_OPENSSL
37 #if OPENSSL_VERSION_NUMBER < 0x1010100fL
38 #error "OpenSSL 1.1.1 and above is required to build this module"
39 #endif
40
41 static bool TLS_initialized;
42
43 /*
44 * report_crypto_errors - Dump crypto error list to log
45 */
46 static void
47 report_crypto_errors(void)
48 {
49 unsigned long e;
50
51 while ((e = ERR_get_error()))
52 ilog(LOG_TYPE_IRCD, "SSL error: %s", ERR_error_string(e, 0));
53 }
54
55 static int
56 always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
57 {
58 return 1;
59 }
60
61 bool
62 tls_is_initialized(void)
63 {
64 return TLS_initialized;
65 }
66
67 /* tls_init()
68 *
69 * inputs - nothing
70 * output - nothing
71 * side effects - setups SSL context.
72 */
73 void
74 tls_init(void)
75 {
76 if ((ConfigServerInfo.tls_ctx.server_ctx = SSL_CTX_new(TLS_server_method())) == NULL)
77 {
78 const char *s = ERR_lib_error_string(ERR_get_error());
79
80 ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS server context -- %s", s);
81 exit(EXIT_FAILURE);
82 return; /* Not reached */
83 }
84
85 SSL_CTX_set_min_proto_version(ConfigServerInfo.tls_ctx.server_ctx, TLS1_2_VERSION);
86 SSL_CTX_set_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE|SSL_OP_NO_TICKET);
87 SSL_CTX_set_verify(ConfigServerInfo.tls_ctx.server_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, always_accept_verify_cb);
88 SSL_CTX_set_session_cache_mode(ConfigServerInfo.tls_ctx.server_ctx, SSL_SESS_CACHE_OFF);
89 SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL");
90
91 if ((ConfigServerInfo.tls_ctx.client_ctx = SSL_CTX_new(TLS_client_method())) == NULL)
92 {
93 const char *s = ERR_lib_error_string(ERR_get_error());
94
95 ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS client context -- %s", s);
96 exit(EXIT_FAILURE);
97 return; /* Not reached */
98 }
99
100 SSL_CTX_set_min_proto_version(ConfigServerInfo.tls_ctx.client_ctx, TLS1_2_VERSION);
101 SSL_CTX_set_options(ConfigServerInfo.tls_ctx.client_ctx, SSL_OP_NO_TICKET);
102 SSL_CTX_set_verify(ConfigServerInfo.tls_ctx.client_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, always_accept_verify_cb);
103 SSL_CTX_set_session_cache_mode(ConfigServerInfo.tls_ctx.client_ctx, SSL_SESS_CACHE_OFF);
104 }
105
106 bool
107 tls_new_credentials(void)
108 {
109 TLS_initialized = false;
110
111 if (ConfigServerInfo.tls_certificate_file == NULL || ConfigServerInfo.rsa_private_key_file == NULL)
112 return true;
113
114 if (SSL_CTX_use_certificate_chain_file(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.tls_certificate_file) != 1 ||
115 SSL_CTX_use_certificate_chain_file(ConfigServerInfo.tls_ctx.client_ctx, ConfigServerInfo.tls_certificate_file) != 1)
116 {
117 report_crypto_errors();
118 return false;
119 }
120
121 if (SSL_CTX_use_PrivateKey_file(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.rsa_private_key_file, SSL_FILETYPE_PEM) != 1 ||
122 SSL_CTX_use_PrivateKey_file(ConfigServerInfo.tls_ctx.client_ctx, ConfigServerInfo.rsa_private_key_file, SSL_FILETYPE_PEM) != 1)
123 {
124 report_crypto_errors();
125 return false;
126 }
127
128 if (SSL_CTX_check_private_key(ConfigServerInfo.tls_ctx.server_ctx) != 1 ||
129 SSL_CTX_check_private_key(ConfigServerInfo.tls_ctx.client_ctx) != 1)
130 {
131 report_crypto_errors();
132 return false;
133 }
134
135 if (ConfigServerInfo.tls_dh_param_file)
136 {
137 #if OPENSSL_VERSION_NUMBER < 0x30000000L
138 BIO *file = BIO_new_file(ConfigServerInfo.tls_dh_param_file, "r");
139
140 if (file)
141 {
142 DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL);
143
144 BIO_free(file);
145
146 if (dh)
147 {
148 SSL_CTX_set_tmp_dh(ConfigServerInfo.tls_ctx.server_ctx, dh);
149 DH_free(dh);
150 }
151 }
152 else
153 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::tls_dh_param_file -- could not open/read Diffie-Hellman parameter file");
154 #else
155 EVP_PKEY *dhpkey = NULL;
156 OSSL_STORE_CTX *ctx = OSSL_STORE_open(ConfigServerInfo.tls_dh_param_file, NULL, NULL, NULL, NULL);
157 if (ctx)
158 {
159 if (OSSL_STORE_expect(ctx, OSSL_STORE_INFO_PARAMS))
160 {
161 while (OSSL_STORE_eof(ctx) == 0)
162 {
163 OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
164 if (info)
165 {
166 dhpkey = OSSL_STORE_INFO_get1_PARAMS(info);
167 OSSL_STORE_INFO_free(info);
168
169 if (dhpkey)
170 {
171 if (EVP_PKEY_is_a(dhpkey, "DH"))
172 if (SSL_CTX_set0_tmp_dh_pkey(ConfigServerInfo.tls_ctx.server_ctx, dhpkey))
173 break;
174
175 EVP_PKEY_free(dhpkey);
176 dhpkey = NULL;
177 }
178 }
179 }
180 }
181
182 OSSL_STORE_close(ctx);
183 }
184
185 if (dhpkey == NULL)
186 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::tls_dh_param_file -- could not open/read Diffie-Hellman parameter file");
187 #endif
188 }
189
190 if (ConfigServerInfo.tls_supported_groups == NULL)
191 SSL_CTX_set1_groups_list(ConfigServerInfo.tls_ctx.server_ctx, "X25519:P-256");
192 else if (SSL_CTX_set1_groups_list(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.tls_supported_groups) == 0)
193 {
194 SSL_CTX_set1_groups_list(ConfigServerInfo.tls_ctx.server_ctx, "X25519:P-256");
195 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::tls_supported_groups -- could not set supported group(s)");
196 }
197
198 if (ConfigServerInfo.tls_message_digest_algorithm == NULL)
199 ConfigServerInfo.message_digest_algorithm = EVP_sha256();
200 else if ((ConfigServerInfo.message_digest_algorithm = EVP_get_digestbyname(ConfigServerInfo.tls_message_digest_algorithm)) == NULL)
201 {
202 ConfigServerInfo.message_digest_algorithm = EVP_sha256();
203 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::tls_message_digest_algorithm -- unknown message digest algorithm");
204 }
205
206 if (ConfigServerInfo.tls_cipher_list == NULL)
207 SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL");
208 else if (SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.tls_cipher_list) == 0)
209 {
210 SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL");
211 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::tls_cipher_list -- could not set supported cipher(s)");
212 }
213
214 #ifndef LIBRESSL_VERSION_NUMBER
215 if (ConfigServerInfo.tls_cipher_suites == NULL)
216 SSL_CTX_set_ciphersuites(ConfigServerInfo.tls_ctx.server_ctx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256");
217 else if (SSL_CTX_set_ciphersuites(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.tls_cipher_suites) == 0)
218 {
219 SSL_CTX_set_ciphersuites(ConfigServerInfo.tls_ctx.server_ctx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256");
220 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::tls_cipher_suites -- could not set supported cipher suite(s)");
221 }
222 #endif
223
224 TLS_initialized = true;
225 return true;
226 }
227
228 const char *
229 tls_get_cipher(const tls_data_t *tls_data)
230 {
231 static char buf[128];
232 SSL *ssl = *tls_data;
233
234 snprintf(buf, sizeof(buf), "%s-%s", SSL_get_version(ssl), SSL_get_cipher(ssl));
235 return buf;
236 }
237
238 const char *
239 tls_get_version(void)
240 {
241 static char buf[256];
242
243 snprintf(buf, sizeof(buf), "OpenSSL version: library: %s, header: %s",
244 OpenSSL_version(OPENSSL_VERSION), OPENSSL_VERSION_TEXT);
245 return buf;
246 }
247
248 bool
249 tls_isusing(tls_data_t *tls_data)
250 {
251 SSL *ssl = *tls_data;
252 return ssl != NULL;
253 }
254
255 void
256 tls_free(tls_data_t *tls_data)
257 {
258 SSL_free(*tls_data);
259 *tls_data = NULL;
260 }
261
262 ssize_t
263 tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, bool *want_write)
264 {
265 ERR_clear_error();
266
267 SSL *ssl = *tls_data;
268 ssize_t ret = SSL_read(ssl, buf, bufsize);
269 /* Translate openssl error codes, sigh */
270 if (ret < 0)
271 {
272 switch (SSL_get_error(ssl, ret))
273 {
274 case SSL_ERROR_WANT_WRITE:
275 {
276 /* OpenSSL wants to write, we signal this to the caller and do nothing about that here */
277 *want_write = true;
278 break;
279 }
280 case SSL_ERROR_WANT_READ:
281 errno = EWOULDBLOCK;
282 case SSL_ERROR_SYSCALL:
283 break;
284 case SSL_ERROR_SSL:
285 if (errno == EAGAIN)
286 break;
287 /* Fall through */
288 default:
289 ret = errno = 0;
290 }
291 }
292
293 return ret;
294 }
295
296 ssize_t
297 tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, bool *want_read)
298 {
299 ERR_clear_error();
300
301 SSL *ssl = *tls_data;
302 ssize_t ret = SSL_write(ssl, buf, bufsize);
303 /* Translate openssl error codes, sigh */
304 if (ret < 0)
305 {
306 switch (SSL_get_error(ssl, ret))
307 {
308 case SSL_ERROR_WANT_READ:
309 *want_read = true;
310 break; /* Retry later, don't register for write events */
311 case SSL_ERROR_WANT_WRITE:
312 errno = EWOULDBLOCK;
313 break;
314 case SSL_ERROR_SYSCALL:
315 break;
316 case SSL_ERROR_SSL:
317 if (errno == EAGAIN)
318 break;
319 /* Fall through */
320 default:
321 ret = errno = 0; /* Either an SSL-specific error or EOF */
322 }
323 }
324
325 return ret;
326 }
327
328 void
329 tls_shutdown(tls_data_t *tls_data)
330 {
331 SSL *ssl = *tls_data;
332
333 SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
334
335 if (SSL_shutdown(ssl) == 0)
336 SSL_shutdown(ssl);
337 }
338
339 bool
340 tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
341 {
342 SSL *ssl;
343
344 if (TLS_initialized == false)
345 return false;
346
347 if (role == TLS_ROLE_SERVER)
348 ssl = SSL_new(ConfigServerInfo.tls_ctx.server_ctx);
349 else
350 ssl = SSL_new(ConfigServerInfo.tls_ctx.client_ctx);
351
352 if (ssl == NULL)
353 {
354 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
355 ERR_error_string(ERR_get_error(), NULL));
356 return false;
357 }
358
359 *tls_data = ssl;
360 SSL_set_fd(ssl, fd);
361 return true;
362 }
363
364 bool
365 tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
366 {
367 SSL_set_cipher_list(*tls_data, cipher_list);
368 return true;
369 }
370
371 tls_handshake_status_t
372 tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
373 {
374 SSL *ssl = *tls_data;
375 int ret;
376
377 ERR_clear_error();
378
379 if (role == TLS_ROLE_SERVER)
380 ret = SSL_accept(ssl);
381 else
382 ret = SSL_connect(ssl);
383
384 if (ret > 0)
385 return TLS_HANDSHAKE_DONE;
386
387 switch (SSL_get_error(ssl, ret))
388 {
389 case SSL_ERROR_WANT_WRITE:
390 return TLS_HANDSHAKE_WANT_WRITE;
391 case SSL_ERROR_WANT_READ:
392 return TLS_HANDSHAKE_WANT_READ;
393 default:
394 {
395 const char *error = ERR_error_string(ERR_get_error(), NULL);
396
397 if (errstr)
398 *errstr = error;
399
400 return TLS_HANDSHAKE_ERROR;
401 }
402 }
403 }
404
405 bool
406 tls_verify_certificate(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
407 {
408 SSL *ssl = *tls_data;
409 unsigned int n;
410 char buf[EVP_MAX_MD_SIZE * 2 + 1];
411 unsigned char md[EVP_MAX_MD_SIZE];
412 bool ret = false;
413
414 /* Accept NULL return from SSL_get_peer_certificate */
415 X509 *cert = SSL_get_peer_certificate(ssl);
416 if (cert == NULL)
417 return true;
418
419 switch (SSL_get_verify_result(ssl))
420 {
421 case X509_V_OK:
422 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
423 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
424 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
425 ret = true;
426
427 if (X509_digest(cert, digest, md, &n))
428 {
429 binary_to_hex(md, buf, n);
430 *fingerprint = xstrdup(buf);
431 }
432 default:
433 break;
434 }
435
436 X509_free(cert);
437 return ret;
438 }
439 #endif /* HAVE_TLS_OPENSSL */

Properties

Name Value
svn:eol-style native
svn:keywords Id