ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_openssl.c
Revision: 7192
Committed: Sat Jan 30 18:48:01 2016 UTC (10 years, 5 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

# 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 7152 /*
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 michael 7105 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 michael 7192 #ifndef OPENSSL_NO_ECDH
86 michael 7105 {
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 michael 7192 #ifndef OPENSSL_NO_ECDH
168 michael 7124 if (ConfigServerInfo.ssl_dh_elliptic_curve)
169 michael 7105 {
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 michael 7124
204 michael 7105 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 michael 7190 if (ConfigServerInfo.ssl_cipher_list)
212     SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.ssl_cipher_list);
213    
214 michael 7105 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 michael 7124 return ssl != NULL;
236 michael 7105 }
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 michael 7142 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
383 michael 7105 {
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