ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_gnutls.c
Revision: 7112
Committed: Sat Jan 23 20:25:03 2016 UTC (9 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 8395 byte(s)
Log Message:
- propset

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

Properties

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