ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/tls_openssl.c
Revision: 7191
Committed: Sat Jan 30 18:47:50 2016 UTC (9 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 10778 byte(s)
Log Message:
- tls_openssl.c: removed test on OPENSSL_VERSION_NUMBER which is no longer needed

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

Properties

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