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

# User Rev Content
1 michael 7105 /*
2     * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3     *
4 michael 7148 * Copyright (c) 2015 Attila Molnar <attilamolnar@hush.com>
5     * Copyright (c) 2015 Adam <Adam@anope.org>
6 michael 7924 * Copyright (c) 2005-2017 ircd-hybrid development team
7 michael 7105 *
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 michael 7152 #include "misc.h"
34 michael 7105 #include "memory.h"
35    
36     #ifdef HAVE_TLS_OPENSSL
37    
38 michael 7271 static int TLS_initialized;
39    
40 michael 7152 /*
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 michael 7105 static int
53     always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
54     {
55     return 1;
56     }
57    
58 michael 7271 int
59     tls_is_initialized(void)
60     {
61     return TLS_initialized;
62     }
63    
64 michael 7105 /* 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 michael 7278 ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS Server context -- %s", s);
81 michael 7105 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 michael 7192 #ifndef OPENSSL_NO_ECDH
93 michael 7233 EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
94    
95     if (key)
96 michael 7105 {
97 michael 7233 SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
98     EC_KEY_free(key);
99 michael 7105 }
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 michael 7278 ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS Client context -- %s", s);
109 michael 7105 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 michael 7271 TLS_initialized = 0;
124    
125 michael 7105 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 michael 7387 SSL_CTX_set_tmp_dh(ConfigServerInfo.tls_ctx.server_ctx, dh);
162 michael 7105 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 michael 7192 #ifndef OPENSSL_NO_ECDH
170 michael 7124 if (ConfigServerInfo.ssl_dh_elliptic_curve)
171 michael 7105 {
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 michael 7124
206 michael 7105 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 michael 7190 if (ConfigServerInfo.ssl_cipher_list)
214     SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.ssl_cipher_list);
215    
216 michael 7271 TLS_initialized = 1;
217 michael 7105 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 michael 7708 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 michael 7105 int
245     tls_isusing(tls_data_t *tls_data)
246     {
247     SSL *ssl = *tls_data;
248 michael 7124 return ssl != NULL;
249 michael 7105 }
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 michael 7274 if (!TLS_initialized)
339     return 0;
340    
341 michael 7105 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 michael 7142 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
399 michael 7105 {
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