ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_gnutls.c
Revision: 7196
Committed: Sat Jan 30 19:42:30 2016 UTC (9 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 8962 byte(s)
Log Message:
- tls_gnutls.c: explicitly disable SSLv3 for releases prior to 3.4

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 2015 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (c) 2015 Adam <Adam@anope.org>
6 * Copyright (c) 2015-2016 ircd-hybrid development team
7 *
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_gnutls.c
25 * \brief Includes all GnuTLS-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 #include "misc.h"
34 #include "memory.h"
35
36 #ifdef HAVE_TLS_GNUTLS
37
38 void
39 tls_init(void)
40 {
41 }
42
43 static void
44 tls_free_cred(tls_context_t cred)
45 {
46 gnutls_priority_deinit(cred->priorities);
47 gnutls_dh_params_deinit(cred->dh_params);
48 gnutls_certificate_free_credentials(cred->x509_cred);
49
50 gnutls_global_deinit();
51
52 xfree(cred);
53 }
54
55 int
56 tls_new_cred(void)
57 {
58 int ret;
59 struct gnutls_context *context;
60
61 if (!ConfigServerInfo.ssl_certificate_file || !ConfigServerInfo.rsa_private_key_file)
62 return 0;
63
64 context = xcalloc(sizeof(*context));
65
66 gnutls_global_init();
67
68 ret = gnutls_certificate_allocate_credentials(&context->x509_cred);
69 if (ret != GNUTLS_E_SUCCESS)
70 {
71 ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS credentials -- %s", gnutls_strerror(ret));
72 xfree(context);
73 return 0;
74 }
75
76 /* TBD: set ciphers based on serverinfo::ssl_cipher_list */
77
78 gnutls_priority_init(&context->priorities, "NORMAL:%SERVER_PRECEDENCE:!VERS-SSL3.0", NULL);
79
80 ret = gnutls_certificate_set_x509_key_file(context->x509_cred, ConfigServerInfo.ssl_certificate_file, ConfigServerInfo.rsa_private_key_file, GNUTLS_X509_FMT_PEM);
81 if (ret != GNUTLS_E_SUCCESS)
82 {
83 ilog(LOG_TYPE_IRCD, "Could not set TLS keys -- %s", gnutls_strerror(ret));
84
85 gnutls_certificate_free_credentials(context->x509_cred);
86 gnutls_priority_deinit(context->priorities);
87 xfree(context);
88 return 0;
89 }
90
91 gnutls_dh_params_init(&context->dh_params);
92
93 if (ConfigServerInfo.ssl_dh_param_file)
94 {
95 gnutls_datum_t data;
96
97 ret = gnutls_load_file(ConfigServerInfo.ssl_dh_param_file, &data);
98
99 if (ret != GNUTLS_E_SUCCESS)
100 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- unable to load file -- %s", gnutls_strerror(ret));
101 else
102 {
103 ret = gnutls_dh_params_import_pkcs3(context->dh_params, &data, GNUTLS_X509_FMT_PEM);
104
105 if (ret != GNUTLS_E_SUCCESS)
106 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- unable to import dh params -- %s", gnutls_strerror(ret));
107
108 gnutls_free(data.data);
109 }
110 }
111
112 gnutls_certificate_set_dh_params(context->x509_cred, context->dh_params);
113
114 if (ConfigServerInfo.ssl_message_digest_algorithm == NULL)
115 ConfigServerInfo.message_digest_algorithm = GNUTLS_DIG_SHA256;
116 else
117 {
118 ConfigServerInfo.message_digest_algorithm = gnutls_digest_get_id(ConfigServerInfo.ssl_message_digest_algorithm);
119
120 if (ConfigServerInfo.message_digest_algorithm == GNUTLS_DIG_UNKNOWN)
121 {
122 ConfigServerInfo.message_digest_algorithm = GNUTLS_DIG_SHA256;
123 ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_message_digest_algorithm -- unknown message digest algorithm");
124 }
125 }
126
127 if (ConfigServerInfo.tls_ctx && --ConfigServerInfo.tls_ctx->refs == 0)
128 tls_free_cred(ConfigServerInfo.tls_ctx);
129
130 ConfigServerInfo.tls_ctx = context;
131 ++context->refs;
132
133 return 1;
134 }
135
136 const char *
137 tls_get_cipher(const tls_data_t *tls_data)
138 {
139 static char buffer[IRCD_BUFSIZE];
140
141 snprintf(buffer, sizeof(buffer), "%s-%s-%s-%s",
142 gnutls_protocol_get_name(gnutls_protocol_get_version(tls_data->session)),
143 gnutls_kx_get_name(gnutls_kx_get(tls_data->session)),
144 gnutls_cipher_get_name(gnutls_cipher_get(tls_data->session)),
145 gnutls_mac_get_name(gnutls_mac_get(tls_data->session)));
146
147 return buffer;
148 }
149
150 int
151 tls_isusing(tls_data_t *tls_data)
152 {
153 return tls_data->session != NULL;
154 }
155
156 void
157 tls_free(tls_data_t *tls_data)
158 {
159 gnutls_deinit(tls_data->session);
160 }
161
162 int
163 tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
164 {
165 int length = gnutls_record_recv(tls_data->session, buf, bufsize);
166
167 if (length <= 0)
168 {
169 switch (length)
170 {
171 case GNUTLS_E_AGAIN:
172 case GNUTLS_E_INTERRUPTED:
173 errno = EWOULDBLOCK;
174 return -1;
175 case 0: /* Closed */
176 default: /* Other error */
177 /* XXX can gnutls_strerror(length) if <0 for gnutls's idea of the reason */
178 return 0;
179 }
180 }
181
182 return length;
183 }
184
185 int
186 tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
187 {
188 int length = gnutls_record_send(tls_data->session, buf, bufsize);
189
190 if (length <= 0)
191 {
192 switch (length)
193 {
194 case GNUTLS_E_AGAIN:
195 case GNUTLS_E_INTERRUPTED:
196 case 0:
197 errno = EWOULDBLOCK;
198 return -1;
199 default:
200 return 0;
201 }
202 }
203
204 return length;
205 }
206
207 void
208 tls_shutdown(tls_data_t *tls_data)
209 {
210 gnutls_bye(tls_data->session, GNUTLS_SHUT_WR);
211
212 if (--tls_data->context->refs == 0)
213 tls_free_cred(tls_data->context);
214 }
215
216 int
217 tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
218 {
219 gnutls_init(&tls_data->session, role == TLS_ROLE_SERVER ? GNUTLS_SERVER : GNUTLS_CLIENT);
220
221 tls_data->context = ConfigServerInfo.tls_ctx;
222 ++tls_data->context->refs;
223
224 gnutls_priority_set(tls_data->session, tls_data->context->priorities);
225 gnutls_credentials_set(tls_data->session, GNUTLS_CRD_CERTIFICATE, tls_data->context->x509_cred);
226 gnutls_dh_set_prime_bits(tls_data->session, 1024);
227 gnutls_transport_set_int(tls_data->session, fd);
228
229 if (role == TLS_ROLE_SERVER)
230 /* Request client certificate if any. */
231 gnutls_certificate_server_set_request(tls_data->session, GNUTLS_CERT_REQUEST);
232
233 return 1;
234 }
235
236 int
237 tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
238 {
239 int ret;
240 const char *prioerror;
241
242 gnutls_priority_deinit(tls_data->context->priorities);
243
244 ret = gnutls_priority_init(&tls_data->context->priorities, cipher_list, &prioerror);
245 if (ret != GNUTLS_E_SUCCESS)
246 {
247 /* GnuTLS did not understand the user supplied string, log and fall back to the default priorities */
248 ilog(LOG_TYPE_IRCD, "Failed to set GnuTLS priorities to \"%s\": %s Syntax error at position %u, falling back to default (NORMAL:%%SERVER_PRECEDENCE:!VERS-SSL3.0)",
249 cipher_list, gnutls_strerror(ret), (unsigned int)(prioerror - cipher_list));
250 gnutls_priority_init(&tls_data->context->priorities, "NORMAL:%SERVER_PRECEDENCE:!VERS-SSL3.0", NULL);
251 return 0;
252 }
253
254 return 1;
255 }
256
257 tls_handshake_status_t
258 tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
259 {
260 int ret = gnutls_handshake(tls_data->session);
261
262 if (ret >= 0)
263 return TLS_HANDSHAKE_DONE;
264
265 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
266 {
267 /* Handshake needs resuming later, read() or write() would have blocked. */
268
269 if (gnutls_record_get_direction(tls_data->session) == 0)
270 {
271 /* gnutls_handshake() wants to read() again. */
272 return TLS_HANDSHAKE_WANT_READ;
273 }
274 else
275 {
276 /* gnutls_handshake() wants to write() again. */
277 return TLS_HANDSHAKE_WANT_WRITE;
278 }
279 }
280 else
281 {
282 const char *error = gnutls_strerror(ret);
283
284 if (errstr)
285 *errstr = error;
286
287 return TLS_HANDSHAKE_ERROR;
288 }
289 }
290
291 int
292 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
293 {
294 int ret;
295 gnutls_x509_crt_t cert;
296 const gnutls_datum_t *cert_list;
297 unsigned int cert_list_size = 0;
298 unsigned char digestbuf[TLS_GNUTLS_MAX_HASH_SIZE];
299 size_t digest_size = sizeof(digestbuf);
300 char buf[TLS_GNUTLS_MAX_HASH_SIZE * 2 + 1];
301
302 cert_list = gnutls_certificate_get_peers(tls_data->session, &cert_list_size);
303 if (!cert_list)
304 return 1; /* No certificate */
305
306 ret = gnutls_x509_crt_init(&cert);
307 if (ret != GNUTLS_E_SUCCESS)
308 return 1;
309
310 ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
311 if (ret != GNUTLS_E_SUCCESS)
312 goto info_done_dealloc;
313
314 ret = gnutls_x509_crt_get_fingerprint(cert, digest, digestbuf, &digest_size);
315 if (ret != GNUTLS_E_SUCCESS)
316 goto info_done_dealloc;
317
318 binary_to_hex(digestbuf, buf, digest_size);
319 *fingerprint = xstrdup(buf);
320
321 gnutls_x509_crt_deinit(cert);
322 return 1;
323
324 info_done_dealloc:
325 gnutls_x509_crt_deinit(cert);
326 return 0;
327 }
328 #endif /* HAVE_TLS_GNUTLS */

Properties

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