ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_openssl.c
Revision: 7271
Committed: Sat Feb 6 20:47:15 2016 UTC (9 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 10894 byte(s)
Log Message:
- Don't exit out with GnuTLS when there's no key and/or certificate

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

Properties

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