ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_openssl.c
Revision: 7924
Committed: Sat Dec 31 13:57:08 2016 UTC (8 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 10825 byte(s)
Log Message:
- Update copyright years

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-2017 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
38 static int TLS_initialized;
39
40 /*
41 * report_crypto_errors - Dump crypto error list to log
42 */
43 static void
44 report_crypto_errors(void)
45 {
46 unsigned long e = 0;
47
48 while ((e = ERR_get_error()))
49 ilog(LOG_TYPE_IRCD, "SSL error: %s", ERR_error_string(e, 0));
50 }
51
52 static int
53 always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
54 {
55 return 1;
56 }
57
58 int
59 tls_is_initialized(void)
60 {
61 return TLS_initialized;
62 }
63
64 /* tls_init()
65 *
66 * inputs - nothing
67 * output - nothing
68 * side effects - setups SSL context.
69 */
70 void
71 tls_init(void)
72 {
73 SSL_load_error_strings();
74 SSLeay_add_ssl_algorithms();
75
76 if (!(ConfigServerInfo.tls_ctx.server_ctx = SSL_CTX_new(SSLv23_server_method())))
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_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET);
86 SSL_CTX_set_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_SINGLE_DH_USE|SSL_OP_CIPHER_SERVER_PREFERENCE);
87 SSL_CTX_set_verify(ConfigServerInfo.tls_ctx.server_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
88 always_accept_verify_cb);
89 SSL_CTX_set_session_cache_mode(ConfigServerInfo.tls_ctx.server_ctx, SSL_SESS_CACHE_OFF);
90 SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL");
91
92 #ifndef OPENSSL_NO_ECDH
93 EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
94
95 if (key)
96 {
97 SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
98 EC_KEY_free(key);
99 }
100
101 SSL_CTX_set_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_SINGLE_ECDH_USE);
102 #endif
103
104 if (!(ConfigServerInfo.tls_ctx.client_ctx = SSL_CTX_new(SSLv23_client_method())))
105 {
106 const char *s = ERR_lib_error_string(ERR_get_error());
107
108 ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS Client context -- %s", s);
109 exit(EXIT_FAILURE);
110 return; /* Not reached */
111 }
112
113 SSL_CTX_set_options(ConfigServerInfo.tls_ctx.client_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET);
114 SSL_CTX_set_options(ConfigServerInfo.tls_ctx.client_ctx, SSL_OP_SINGLE_DH_USE);
115 SSL_CTX_set_verify(ConfigServerInfo.tls_ctx.client_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
116 always_accept_verify_cb);
117 SSL_CTX_set_session_cache_mode(ConfigServerInfo.tls_ctx.client_ctx, SSL_SESS_CACHE_OFF);
118 }
119
120 int
121 tls_new_cred(void)
122 {
123 TLS_initialized = 0;
124
125 if (!ConfigServerInfo.ssl_certificate_file || !ConfigServerInfo.rsa_private_key_file)
126 return 1;
127
128 if (SSL_CTX_use_certificate_chain_file(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.ssl_certificate_file) <= 0 ||
129 SSL_CTX_use_certificate_chain_file(ConfigServerInfo.tls_ctx.client_ctx, ConfigServerInfo.ssl_certificate_file) <= 0)
130 {
131 report_crypto_errors();
132 return 0;
133 }
134
135 if (SSL_CTX_use_PrivateKey_file(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.rsa_private_key_file, SSL_FILETYPE_PEM) <= 0 ||
136 SSL_CTX_use_PrivateKey_file(ConfigServerInfo.tls_ctx.client_ctx, ConfigServerInfo.rsa_private_key_file, SSL_FILETYPE_PEM) <= 0)
137 {
138 report_crypto_errors();
139 return 0;
140 }
141
142 if (!SSL_CTX_check_private_key(ConfigServerInfo.tls_ctx.server_ctx) ||
143 !SSL_CTX_check_private_key(ConfigServerInfo.tls_ctx.client_ctx))
144 {
145 report_crypto_errors();
146 return 0;
147 }
148
149 if (ConfigServerInfo.ssl_dh_param_file)
150 {
151 BIO *file = BIO_new_file(ConfigServerInfo.ssl_dh_param_file, "r");
152
153 if (file)
154 {
155 DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL);
156
157 BIO_free(file);
158
159 if (dh)
160 {
161 SSL_CTX_set_tmp_dh(ConfigServerInfo.tls_ctx.server_ctx, dh);
162 DH_free(dh);
163 }
164 }
165 else
166 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- could not open/read Diffie-Hellman parameter file");
167 }
168
169 #ifndef OPENSSL_NO_ECDH
170 if (ConfigServerInfo.ssl_dh_elliptic_curve)
171 {
172 int nid = 0;
173 EC_KEY *key = NULL;
174
175 if ((nid = OBJ_sn2nid(ConfigServerInfo.ssl_dh_elliptic_curve)) == 0)
176 goto set_default_curve;
177
178 if ((key = EC_KEY_new_by_curve_name(nid)) == NULL)
179 goto set_default_curve;
180
181 SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
182 EC_KEY_free(key);
183 }
184 else
185 {
186 EC_KEY *key;
187
188 set_default_curve:
189
190 key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
191
192 if (key)
193 {
194 SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
195 EC_KEY_free(key);
196 }
197 }
198 #endif
199
200 if (ConfigServerInfo.ssl_message_digest_algorithm == NULL)
201 ConfigServerInfo.message_digest_algorithm = EVP_sha256();
202 else
203 {
204 ConfigServerInfo.message_digest_algorithm = EVP_get_digestbyname(ConfigServerInfo.ssl_message_digest_algorithm);
205
206 if (ConfigServerInfo.message_digest_algorithm == NULL)
207 {
208 ConfigServerInfo.message_digest_algorithm = EVP_sha256();
209 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_message_digest_algorithm -- unknown message digest algorithm");
210 }
211 }
212
213 if (ConfigServerInfo.ssl_cipher_list)
214 SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.ssl_cipher_list);
215
216 TLS_initialized = 1;
217 return 1;
218 }
219
220 const char *
221 tls_get_cipher(const tls_data_t *tls_data)
222 {
223 static char buffer[IRCD_BUFSIZE];
224 int bits = 0;
225 SSL *ssl = *tls_data;
226
227 SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &bits);
228
229 snprintf(buffer, sizeof(buffer), "%s-%s-%d", SSL_get_version(ssl),
230 SSL_get_cipher(ssl), bits);
231 return buffer;
232 }
233
234 const char *
235 tls_get_version(void)
236 {
237 static char buf[IRCD_BUFSIZE];
238
239 snprintf(buf, sizeof(buf), "OpenSSL version: library: %s, header: %s",
240 SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT);
241 return buf;
242 }
243
244 int
245 tls_isusing(tls_data_t *tls_data)
246 {
247 SSL *ssl = *tls_data;
248 return ssl != NULL;
249 }
250
251 void
252 tls_free(tls_data_t *tls_data)
253 {
254 SSL_free(*tls_data);
255 *tls_data = NULL;
256 }
257
258 int
259 tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
260 {
261 SSL *ssl = *tls_data;
262 int length = SSL_read(ssl, buf, bufsize);
263
264 /* Translate openssl error codes, sigh */
265 if (length < 0)
266 {
267 switch (SSL_get_error(ssl, length))
268 {
269 case SSL_ERROR_WANT_WRITE:
270 {
271 /* OpenSSL wants to write, we signal this to the caller and do nothing about that here */
272 *want_write = 1;
273 break;
274 }
275 case SSL_ERROR_WANT_READ:
276 errno = EWOULDBLOCK;
277 case SSL_ERROR_SYSCALL:
278 break;
279 case SSL_ERROR_SSL:
280 if (errno == EAGAIN)
281 break;
282 /* Fall through */
283 default:
284 length = errno = 0;
285 }
286 }
287
288 return length;
289 }
290
291 int
292 tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
293 {
294 SSL *ssl = *tls_data;
295 int retlen = SSL_write(ssl, buf, bufsize);
296
297 /* Translate openssl error codes, sigh */
298 if (retlen < 0)
299 {
300 switch (SSL_get_error(ssl, retlen))
301 {
302 case SSL_ERROR_WANT_READ:
303 *want_read = 1;
304 break; /* Retry later, don't register for write events */
305 case SSL_ERROR_WANT_WRITE:
306 errno = EWOULDBLOCK;
307 break;
308 case SSL_ERROR_SYSCALL:
309 break;
310 case SSL_ERROR_SSL:
311 if (errno == EAGAIN)
312 break;
313 /* Fall through */
314 default:
315 retlen = errno = 0; /* Either an SSL-specific error or EOF */
316 }
317 }
318
319 return retlen;
320 }
321
322 void
323 tls_shutdown(tls_data_t *tls_data)
324 {
325 SSL *ssl = *tls_data;
326
327 SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
328
329 if (!SSL_shutdown(ssl))
330 SSL_shutdown(ssl);
331 }
332
333 int
334 tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
335 {
336 SSL *ssl;
337
338 if (!TLS_initialized)
339 return 0;
340
341 if (role == TLS_ROLE_SERVER)
342 ssl = SSL_new(ConfigServerInfo.tls_ctx.server_ctx);
343 else
344 ssl = SSL_new(ConfigServerInfo.tls_ctx.client_ctx);
345
346 if (!ssl)
347 {
348 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
349 ERR_error_string(ERR_get_error(), NULL));
350 return 0;
351 }
352
353 *tls_data = ssl;
354 SSL_set_fd(ssl, fd);
355 return 1;
356 }
357
358 int
359 tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
360 {
361 SSL_set_cipher_list(*tls_data, cipher_list);
362 return 1;
363 }
364
365 tls_handshake_status_t
366 tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
367 {
368 SSL *ssl = *tls_data;
369 int ret;
370
371 if (role == TLS_ROLE_SERVER)
372 ret = SSL_accept(ssl);
373 else
374 ret = SSL_connect(ssl);
375
376 if (ret > 0)
377 return TLS_HANDSHAKE_DONE;
378
379 switch (SSL_get_error(ssl, ret))
380 {
381 case SSL_ERROR_WANT_WRITE:
382 return TLS_HANDSHAKE_WANT_WRITE;
383 case SSL_ERROR_WANT_READ:
384 return TLS_HANDSHAKE_WANT_READ;
385 default:
386 {
387 const char *error = ERR_error_string(ERR_get_error(), NULL);
388
389 if (errstr)
390 *errstr = error;
391
392 return TLS_HANDSHAKE_ERROR;
393 }
394 }
395 }
396
397 int
398 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
399 {
400 SSL *ssl = *tls_data;
401 X509 *cert = SSL_get_peer_certificate(ssl);
402 unsigned int n;
403 char buf[EVP_MAX_MD_SIZE * 2 + 1];
404 unsigned char md[EVP_MAX_MD_SIZE];
405 int ret = 0;
406
407 /* Accept NULL return from SSL_get_peer_certificate */
408 if (!cert)
409 return 1;
410
411 int res = SSL_get_verify_result(ssl);
412 if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
413 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
414 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
415 {
416 ret = 1;
417
418 if (X509_digest(cert, digest, md, &n))
419 {
420 binary_to_hex(md, buf, n);
421 *fingerprint = xstrdup(buf);
422 }
423 }
424
425 X509_free(cert);
426 return ret;
427 }
428 #endif /* HAVE_TLS_OPENSSL */

Properties

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