ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/tls_gnutls.c
Revision: 7120
Committed: Sun Jan 24 20:06:47 2016 UTC (10 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 8483 byte(s)
Log Message:
- tls_gnutls.c:tls_get_cipher(): make the string look similar to the openssl variant (add protocol information)

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-%s",
140 gnutls_protocol_get_name(gnutls_protocol_get_version(tls_data->session)),
141 gnutls_kx_get_name(gnutls_kx_get(tls_data->session)),
142 gnutls_cipher_get_name(gnutls_cipher_get(tls_data->session)),
143 gnutls_mac_get_name(gnutls_mac_get(tls_data->session)));
144
145 return buffer;
146 }
147
148 int
149 tls_isusing(tls_data_t *tls_data)
150 {
151 return tls_data->session != NULL;
152 }
153
154 void
155 tls_free(tls_data_t *tls_data)
156 {
157 gnutls_deinit(tls_data->session);
158 }
159
160 int
161 tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
162 {
163 int length = gnutls_record_recv(tls_data->session, buf, bufsize);
164
165 if (length <= 0)
166 {
167 switch (length)
168 {
169 case GNUTLS_E_AGAIN:
170 case GNUTLS_E_INTERRUPTED:
171 errno = EWOULDBLOCK;
172 case 0: /* Closed */
173 default: /* Other error */
174 return -1;
175 }
176 }
177
178 return length;
179 }
180
181 int
182 tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
183 {
184 int length = gnutls_record_send(tls_data->session, buf, bufsize);
185
186 if (length <= 0)
187 {
188 switch (length)
189 {
190 case GNUTLS_E_AGAIN:
191 case GNUTLS_E_INTERRUPTED:
192 case 0:
193 errno = EWOULDBLOCK;
194 default:
195 return -1;
196 }
197 }
198
199 return length;
200 }
201
202 void
203 tls_shutdown(tls_data_t *tls_data)
204 {
205 gnutls_bye(tls_data->session, GNUTLS_SHUT_WR);
206
207 if (--tls_data->context->refs == 0)
208 tls_free_cred(tls_data->context);
209 }
210
211 int
212 tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
213 {
214 gnutls_init(&tls_data->session, role == TLS_ROLE_SERVER ? GNUTLS_SERVER : GNUTLS_CLIENT);
215
216 tls_data->context = ConfigServerInfo.tls_ctx;
217 ++tls_data->context->refs;
218
219 gnutls_priority_set(tls_data->session, tls_data->context->priorities);
220 gnutls_credentials_set(tls_data->session, GNUTLS_CRD_CERTIFICATE, tls_data->context->x509_cred);
221 gnutls_dh_set_prime_bits(tls_data->session, 1024);
222 gnutls_transport_set_int(tls_data->session, fd);
223
224 if (role == TLS_ROLE_SERVER)
225 /* Request client certificate if any. */
226 gnutls_certificate_server_set_request(tls_data->session, GNUTLS_CERT_REQUEST);
227
228 return 1;
229 }
230
231 int
232 tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
233 {
234 int ret;
235 const char *prioerror;
236
237 gnutls_priority_deinit(tls_data->context->priorities);
238
239 ret = gnutls_priority_init(&tls_data->context->priorities, cipher_list, &prioerror);
240 if (ret < 0)
241 {
242 /* GnuTLS did not understand the user supplied string, log and fall back to the default priorities */
243 ilog(LOG_TYPE_IRCD, "Failed to set GnuTLS priorities to \"%s\": %s Syntax error at position %u, falling back to default (NORMAL)",
244 cipher_list, gnutls_strerror(ret), (unsigned int)(prioerror - cipher_list));
245 gnutls_priority_init(&tls_data->context->priorities, "NORMAL", NULL);
246 return 0;
247 }
248
249 return 1;
250 }
251
252 tls_handshake_status_t
253 tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
254 {
255 int ret = gnutls_handshake(tls_data->session);
256
257 if (ret >= 0)
258 return TLS_HANDSHAKE_DONE;
259
260 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
261 {
262 /* Handshake needs resuming later, read() or write() would have blocked. */
263
264 if (gnutls_record_get_direction(tls_data->session) == 0)
265 {
266 /* gnutls_handshake() wants to read() again. */
267 return TLS_HANDSHAKE_WANT_READ;
268 }
269 else
270 {
271 /* gnutls_handshake() wants to write() again. */
272 return TLS_HANDSHAKE_WANT_WRITE;
273 }
274 }
275 else
276 {
277 const char *error = gnutls_strerror(ret);
278
279 if (errstr)
280 *errstr = error;
281
282 return TLS_HANDSHAKE_ERROR;
283 }
284 }
285
286 int
287 tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint, int *raw_result)
288 {
289 int ret;
290 gnutls_x509_crt_t cert;
291 const gnutls_datum_t *cert_list;
292 unsigned int cert_list_size = 0;
293 unsigned char digestbuf[IRCD_BUFSIZE];
294 size_t digest_size = sizeof(digestbuf);
295 char buf[IRCD_BUFSIZE];
296
297 cert_list = gnutls_certificate_get_peers(tls_data->session, &cert_list_size);
298 if (!cert_list)
299 return 1; /* No certificate */
300
301 ret = gnutls_x509_crt_init(&cert);
302 if (ret < 0)
303 return 1;
304
305 ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
306 if (ret < 0)
307 goto info_done_dealloc;
308
309 ret = gnutls_x509_crt_get_fingerprint(cert, digest, digestbuf, &digest_size);
310 if (ret < 0)
311 goto info_done_dealloc;
312
313 binary_to_hex(digestbuf, buf, digest_size);
314 *fingerprint = xstrdup(buf);
315
316 return 1;
317
318 info_done_dealloc:
319 gnutls_x509_crt_deinit(cert);
320 *raw_result = 0;
321 return 0;
322 }
323 #endif /* HAVE_TLS_GNUTLS */

Properties

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