ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_gnutls.c
Revision: 7134
Committed: Mon Jan 25 19:51:47 2016 UTC (9 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 8579 byte(s)
Log Message:
- tls_gnutls.h, tls_gnutls.c: minor cleanups

File Contents

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

Properties

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