ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_openssl.c
Revision: 7105
Committed: Sat Jan 23 20:11:27 2016 UTC (8 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 10450 byte(s)
Log Message:
- Incorporate gnutls support by Adam & Attila

File Contents

# Content
1 /*
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 if (ConfigServerInfo.ssl_dh_elliptic_curve != NULL)
155 {
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 {
186 ConfigServerInfo.message_digest_algorithm = EVP_sha256();
187 }
188 else
189 {
190 ConfigServerInfo.message_digest_algorithm = EVP_get_digestbyname(ConfigServerInfo.ssl_message_digest_algorithm);
191 if (ConfigServerInfo.message_digest_algorithm == NULL)
192 {
193 ConfigServerInfo.message_digest_algorithm = EVP_sha256();
194 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_message_digest_algorithm -- unknown message digest algorithm");
195 }
196 }
197
198 return 1;
199 }
200
201 const char *
202 tls_get_cipher(const tls_data_t *tls_data)
203 {
204 static char buffer[IRCD_BUFSIZE];
205 int bits = 0;
206 SSL *ssl = *tls_data;
207
208 SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), &bits);
209
210 snprintf(buffer, sizeof(buffer), "%s-%s-%d", SSL_get_version(ssl),
211 SSL_get_cipher(ssl), bits);
212 return buffer;
213 }
214
215 int
216 tls_isusing(tls_data_t *tls_data)
217 {
218 SSL *ssl = *tls_data;
219 return (ssl != NULL);
220 }
221
222 void
223 tls_free(tls_data_t *tls_data)
224 {
225 SSL_free(*tls_data);
226 *tls_data = NULL;
227 }
228
229 int
230 tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
231 {
232 SSL *ssl = *tls_data;
233 int length = SSL_read(ssl, buf, bufsize);
234
235 /* Translate openssl error codes, sigh */
236 if (length < 0)
237 {
238 switch (SSL_get_error(ssl, length))
239 {
240 case SSL_ERROR_WANT_WRITE:
241 {
242 /* OpenSSL wants to write, we signal this to the caller and do nothing about that here */
243 *want_write = 1;
244 break;
245 }
246 case SSL_ERROR_WANT_READ:
247 errno = EWOULDBLOCK;
248 case SSL_ERROR_SYSCALL:
249 break;
250 case SSL_ERROR_SSL:
251 if (errno == EAGAIN)
252 break;
253 /* Fall through */
254 default:
255 length = errno = 0;
256 }
257 }
258
259 return length;
260 }
261
262 int
263 tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
264 {
265 SSL *ssl = *tls_data;
266 int retlen = SSL_write(ssl, buf, bufsize);
267
268 /* Translate openssl error codes, sigh */
269 if (retlen < 0)
270 {
271 switch (SSL_get_error(ssl, retlen))
272 {
273 case SSL_ERROR_WANT_READ:
274 *want_read = 1;
275 break; /* Retry later, don't register for write events */
276 case SSL_ERROR_WANT_WRITE:
277 errno = EWOULDBLOCK;
278 break;
279 case SSL_ERROR_SYSCALL:
280 break;
281 case SSL_ERROR_SSL:
282 if (errno == EAGAIN)
283 break;
284 /* Fall through */
285 default:
286 retlen = errno = 0; /* Either an SSL-specific error or EOF */
287 }
288 }
289
290 return retlen;
291 }
292
293 void
294 tls_shutdown(tls_data_t *tls_data)
295 {
296 SSL *ssl = *tls_data;
297
298 SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
299
300 if (!SSL_shutdown(ssl))
301 SSL_shutdown(ssl);
302 }
303
304 int
305 tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
306 {
307 SSL *ssl;
308
309 if (role == TLS_ROLE_SERVER)
310 ssl = SSL_new(ConfigServerInfo.tls_ctx.server_ctx);
311 else
312 ssl = SSL_new(ConfigServerInfo.tls_ctx.client_ctx);
313
314 if (!ssl)
315 {
316 ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
317 ERR_error_string(ERR_get_error(), NULL));
318 return 0;
319 }
320
321 *tls_data = ssl;
322 SSL_set_fd(ssl, fd);
323 return 1;
324 }
325
326 int
327 tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
328 {
329 SSL_set_cipher_list(*tls_data, cipher_list);
330 return 1;
331 }
332
333 tls_handshake_status_t
334 tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
335 {
336 SSL *ssl = *tls_data;
337 int ret;
338
339 if (role == TLS_ROLE_SERVER)
340 ret = SSL_accept(ssl);
341 else
342 ret = SSL_connect(ssl);
343
344 if (ret > 0)
345 return TLS_HANDSHAKE_DONE;
346
347 switch (SSL_get_error(ssl, ret))
348 {
349 case SSL_ERROR_WANT_WRITE:
350 return TLS_HANDSHAKE_WANT_WRITE;
351 case SSL_ERROR_WANT_READ:
352 return TLS_HANDSHAKE_WANT_READ;
353 default:
354 {
355 const char *error = ERR_error_string(ERR_get_error(), NULL);
356
357 if (errstr)
358 *errstr = error;
359
360 return TLS_HANDSHAKE_ERROR;
361 }
362 }
363 }
364
365 int
366 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint, int *raw_result)
367 {
368 SSL *ssl = *tls_data;
369 X509 *cert = SSL_get_peer_certificate(ssl);
370 unsigned int n;
371 char buf[EVP_MAX_MD_SIZE * 2 + 1];
372 unsigned char md[EVP_MAX_MD_SIZE];
373 int ret = 0;
374
375 /* Accept NULL return from SSL_get_peer_certificate */
376 if (!cert)
377 return 1;
378
379 int res = SSL_get_verify_result(ssl);
380 if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
381 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
382 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
383 {
384 ret = 1;
385
386 if (X509_digest(cert, digest, md, &n))
387 {
388 binary_to_hex(md, buf, n);
389 *fingerprint = xstrdup(buf);
390 }
391 }
392
393 X509_free(cert);
394 *raw_result = res;
395 return ret;
396 }
397 #endif /* HAVE_TLS_OPENSSL */