ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_openssl.c
Revision: 7142
Committed: Thu Jan 28 09:56:49 2016 UTC (9 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 10395 byte(s)
Log Message:
- Remove useless raw_result -- from Adam

File Contents

# User Rev Content
1 michael 7105 /*
2     * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3     *
4     * Copyright (c) 2005-2016 ircd-hybrid development team
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19     * USA
20     */
21    
22     /*! \file tls_openssl.c
23     * \brief Includes all OpenSSL-specific TLS functions
24     * \version $Id$
25     */
26    
27     #include "stdinc.h"
28     #include "tls.h"
29     #include "conf.h"
30     #include "log.h"
31     #include "rsa.h"
32     #include "memory.h"
33    
34     #ifdef HAVE_TLS_OPENSSL
35    
36     static int
37     always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
38     {
39     return 1;
40     }
41    
42     /* tls_init()
43     *
44     * inputs - nothing
45     * output - nothing
46     * side effects - setups SSL context.
47     */
48     void
49     tls_init(void)
50     {
51     SSL_load_error_strings();
52     SSLeay_add_ssl_algorithms();
53    
54     if (!(ConfigServerInfo.tls_ctx.server_ctx = SSL_CTX_new(SSLv23_server_method())))
55     {
56     const char *s = ERR_lib_error_string(ERR_get_error());
57    
58     fprintf(stderr, "ERROR: Could not initialize the SSL Server context -- %s\n", s);
59     ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the SSL Server context -- %s", s);
60     exit(EXIT_FAILURE);
61     return; /* Not reached */
62     }
63    
64     SSL_CTX_set_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET);
65     SSL_CTX_set_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_SINGLE_DH_USE|SSL_OP_CIPHER_SERVER_PREFERENCE);
66     SSL_CTX_set_verify(ConfigServerInfo.tls_ctx.server_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
67     always_accept_verify_cb);
68     SSL_CTX_set_session_cache_mode(ConfigServerInfo.tls_ctx.server_ctx, SSL_SESS_CACHE_OFF);
69     SSL_CTX_set_cipher_list(ConfigServerInfo.tls_ctx.server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL");
70    
71     #if OPENSSL_VERSION_NUMBER >= 0x009080FFL && !defined(OPENSSL_NO_ECDH)
72     {
73     EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
74    
75     if (key)
76     {
77     SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
78     EC_KEY_free(key);
79     }
80     }
81    
82     SSL_CTX_set_options(ConfigServerInfo.tls_ctx.server_ctx, SSL_OP_SINGLE_ECDH_USE);
83     #endif
84    
85     if (!(ConfigServerInfo.tls_ctx.client_ctx = SSL_CTX_new(SSLv23_client_method())))
86     {
87     const char *s = ERR_lib_error_string(ERR_get_error());
88    
89     fprintf(stderr, "ERROR: Could not initialize the SSL Client context -- %s\n", s);
90     ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the SSL Client context -- %s", s);
91     exit(EXIT_FAILURE);
92     return; /* Not reached */
93     }
94    
95     SSL_CTX_set_options(ConfigServerInfo.tls_ctx.client_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET);
96     SSL_CTX_set_options(ConfigServerInfo.tls_ctx.client_ctx, SSL_OP_SINGLE_DH_USE);
97     SSL_CTX_set_verify(ConfigServerInfo.tls_ctx.client_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
98     always_accept_verify_cb);
99     SSL_CTX_set_session_cache_mode(ConfigServerInfo.tls_ctx.client_ctx, SSL_SESS_CACHE_OFF);
100     }
101    
102     int
103     tls_new_cred(void)
104     {
105     if (!ConfigServerInfo.ssl_certificate_file || !ConfigServerInfo.rsa_private_key_file)
106     return 1;
107    
108     if (SSL_CTX_use_certificate_chain_file(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.ssl_certificate_file) <= 0 ||
109     SSL_CTX_use_certificate_chain_file(ConfigServerInfo.tls_ctx.client_ctx, ConfigServerInfo.ssl_certificate_file) <= 0)
110     {
111     report_crypto_errors();
112     return 0;
113     }
114    
115     if (SSL_CTX_use_PrivateKey_file(ConfigServerInfo.tls_ctx.server_ctx, ConfigServerInfo.rsa_private_key_file, SSL_FILETYPE_PEM) <= 0 ||
116     SSL_CTX_use_PrivateKey_file(ConfigServerInfo.tls_ctx.client_ctx, ConfigServerInfo.rsa_private_key_file, SSL_FILETYPE_PEM) <= 0)
117     {
118     report_crypto_errors();
119     return 0;
120     }
121    
122     if (!SSL_CTX_check_private_key(ConfigServerInfo.tls_ctx.server_ctx) ||
123     !SSL_CTX_check_private_key(ConfigServerInfo.tls_ctx.client_ctx))
124     {
125     report_crypto_errors();
126     return 0;
127     }
128    
129     if (ConfigServerInfo.ssl_dh_param_file)
130     {
131     BIO *file = BIO_new_file(ConfigServerInfo.ssl_dh_param_file, "r");
132    
133     if (file)
134     {
135     DH *dh = PEM_read_bio_DHparams(file, NULL, NULL, NULL);
136    
137     BIO_free(file);
138    
139     if (dh)
140     {
141     if (DH_size(dh) >= 256)
142     SSL_CTX_set_tmp_dh(ConfigServerInfo.tls_ctx.server_ctx, dh);
143     else
144     ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- need at least a 2048 bit DH prime size");
145    
146     DH_free(dh);
147     }
148     }
149     else
150     ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- could not open/read Diffie-Hellman parameter file");
151     }
152    
153     #if OPENSSL_VERSION_NUMBER >= 0x009080FFL && !defined(OPENSSL_NO_ECDH)
154 michael 7124 if (ConfigServerInfo.ssl_dh_elliptic_curve)
155 michael 7105 {
156     int nid = 0;
157     EC_KEY *key = NULL;
158    
159     if ((nid = OBJ_sn2nid(ConfigServerInfo.ssl_dh_elliptic_curve)) == 0)
160     goto set_default_curve;
161    
162     if ((key = EC_KEY_new_by_curve_name(nid)) == NULL)
163     goto set_default_curve;
164    
165     SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
166     EC_KEY_free(key);
167     }
168     else
169     {
170     EC_KEY *key;
171    
172     set_default_curve:
173    
174     key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
175    
176     if (key)
177     {
178     SSL_CTX_set_tmp_ecdh(ConfigServerInfo.tls_ctx.server_ctx, key);
179     EC_KEY_free(key);
180     }
181     }
182     #endif
183    
184     if (ConfigServerInfo.ssl_message_digest_algorithm == NULL)
185     ConfigServerInfo.message_digest_algorithm = EVP_sha256();
186     else
187     {
188     ConfigServerInfo.message_digest_algorithm = EVP_get_digestbyname(ConfigServerInfo.ssl_message_digest_algorithm);
189 michael 7124
190 michael 7105 if (ConfigServerInfo.message_digest_algorithm == NULL)
191     {
192     ConfigServerInfo.message_digest_algorithm = EVP_sha256();
193     ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_message_digest_algorithm -- unknown message digest algorithm");
194     }
195     }
196    
197     return 1;
198     }
199    
200     const char *
201     tls_get_cipher(const tls_data_t *tls_data)
202     {
203     static char buffer[IRCD_BUFSIZE];
204     int bits = 0;
205     SSL *ssl = *tls_data;
206    
207     SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &bits);
208    
209     snprintf(buffer, sizeof(buffer), "%s-%s-%d", SSL_get_version(ssl),
210     SSL_get_cipher(ssl), bits);
211     return buffer;
212     }
213    
214     int
215     tls_isusing(tls_data_t *tls_data)
216     {
217     SSL *ssl = *tls_data;
218 michael 7124 return ssl != NULL;
219 michael 7105 }
220    
221     void
222     tls_free(tls_data_t *tls_data)
223     {
224     SSL_free(*tls_data);
225     *tls_data = NULL;
226     }
227    
228     int
229     tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
230     {
231     SSL *ssl = *tls_data;
232     int length = SSL_read(ssl, buf, bufsize);
233    
234     /* Translate openssl error codes, sigh */
235     if (length < 0)
236     {
237     switch (SSL_get_error(ssl, length))
238     {
239     case SSL_ERROR_WANT_WRITE:
240     {
241     /* OpenSSL wants to write, we signal this to the caller and do nothing about that here */
242     *want_write = 1;
243     break;
244     }
245     case SSL_ERROR_WANT_READ:
246     errno = EWOULDBLOCK;
247     case SSL_ERROR_SYSCALL:
248     break;
249     case SSL_ERROR_SSL:
250     if (errno == EAGAIN)
251     break;
252     /* Fall through */
253     default:
254     length = errno = 0;
255     }
256     }
257    
258     return length;
259     }
260    
261     int
262     tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
263     {
264     SSL *ssl = *tls_data;
265     int retlen = SSL_write(ssl, buf, bufsize);
266    
267     /* Translate openssl error codes, sigh */
268     if (retlen < 0)
269     {
270     switch (SSL_get_error(ssl, retlen))
271     {
272     case SSL_ERROR_WANT_READ:
273     *want_read = 1;
274     break; /* Retry later, don't register for write events */
275     case SSL_ERROR_WANT_WRITE:
276     errno = EWOULDBLOCK;
277     break;
278     case SSL_ERROR_SYSCALL:
279     break;
280     case SSL_ERROR_SSL:
281     if (errno == EAGAIN)
282     break;
283     /* Fall through */
284     default:
285     retlen = errno = 0; /* Either an SSL-specific error or EOF */
286     }
287     }
288    
289     return retlen;
290     }
291    
292     void
293     tls_shutdown(tls_data_t *tls_data)
294     {
295     SSL *ssl = *tls_data;
296    
297     SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
298    
299     if (!SSL_shutdown(ssl))
300     SSL_shutdown(ssl);
301     }
302    
303     int
304     tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
305     {
306     SSL *ssl;
307    
308     if (role == TLS_ROLE_SERVER)
309     ssl = SSL_new(ConfigServerInfo.tls_ctx.server_ctx);
310     else
311     ssl = SSL_new(ConfigServerInfo.tls_ctx.client_ctx);
312    
313     if (!ssl)
314     {
315     ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
316     ERR_error_string(ERR_get_error(), NULL));
317     return 0;
318     }
319    
320     *tls_data = ssl;
321     SSL_set_fd(ssl, fd);
322     return 1;
323     }
324    
325     int
326     tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
327     {
328     SSL_set_cipher_list(*tls_data, cipher_list);
329     return 1;
330     }
331    
332     tls_handshake_status_t
333     tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
334     {
335     SSL *ssl = *tls_data;
336     int ret;
337    
338     if (role == TLS_ROLE_SERVER)
339     ret = SSL_accept(ssl);
340     else
341     ret = SSL_connect(ssl);
342    
343     if (ret > 0)
344     return TLS_HANDSHAKE_DONE;
345    
346     switch (SSL_get_error(ssl, ret))
347     {
348     case SSL_ERROR_WANT_WRITE:
349     return TLS_HANDSHAKE_WANT_WRITE;
350     case SSL_ERROR_WANT_READ:
351     return TLS_HANDSHAKE_WANT_READ;
352     default:
353     {
354     const char *error = ERR_error_string(ERR_get_error(), NULL);
355    
356     if (errstr)
357     *errstr = error;
358    
359     return TLS_HANDSHAKE_ERROR;
360     }
361     }
362     }
363    
364     int
365 michael 7142 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
366 michael 7105 {
367     SSL *ssl = *tls_data;
368     X509 *cert = SSL_get_peer_certificate(ssl);
369     unsigned int n;
370     char buf[EVP_MAX_MD_SIZE * 2 + 1];
371     unsigned char md[EVP_MAX_MD_SIZE];
372     int ret = 0;
373    
374     /* Accept NULL return from SSL_get_peer_certificate */
375     if (!cert)
376     return 1;
377    
378     int res = SSL_get_verify_result(ssl);
379     if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
380     res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
381     res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
382     {
383     ret = 1;
384    
385     if (X509_digest(cert, digest, md, &n))
386     {
387     binary_to_hex(md, buf, n);
388     *fingerprint = xstrdup(buf);
389     }
390     }
391    
392     X509_free(cert);
393     return ret;
394     }
395     #endif /* HAVE_TLS_OPENSSL */

Properties

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