s4:lib/tls: fix build with gnutls 3.4
[Samba.git] / source4 / lib / tls / tls.c
blob2fe4ff7a3fc86dda52c6e4cb6c47dfa22d2a8869
1 /*
2 Unix SMB/CIFS implementation.
4 transport layer security handling code
6 Copyright (C) Andrew Tridgell 2004-2005
7 Copyright (C) Stefan Metzmacher 2004
8 Copyright (C) Andrew Bartlett 2006
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "lib/events/events.h"
27 #include "lib/socket/socket.h"
28 #include "lib/tls/tls.h"
29 #include "param/param.h"
31 #if ENABLE_GNUTLS
32 #include <gnutls/gnutls.h>
34 #define DH_BITS 1024
36 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
37 typedef gnutls_datum gnutls_datum_t;
38 #endif
40 /* hold persistent tls data */
41 struct tls_params {
42 gnutls_certificate_credentials x509_cred;
43 gnutls_dh_params dh_params;
44 bool tls_enabled;
46 #endif
48 /* hold per connection tls data */
49 struct tls_context {
50 struct socket_context *socket;
51 struct tevent_fd *fde;
52 bool tls_enabled;
53 #if ENABLE_GNUTLS
54 gnutls_session session;
55 bool done_handshake;
56 bool have_first_byte;
57 uint8_t first_byte;
58 bool tls_detect;
59 const char *plain_chars;
60 bool output_pending;
61 gnutls_certificate_credentials xcred;
62 bool interrupted;
63 #endif
66 bool tls_enabled(struct socket_context *sock)
68 struct tls_context *tls;
69 if (!sock) {
70 return false;
72 if (strcmp(sock->backend_name, "tls") != 0) {
73 return false;
75 tls = talloc_get_type(sock->private_data, struct tls_context);
76 if (!tls) {
77 return false;
79 return tls->tls_enabled;
83 #if ENABLE_GNUTLS
85 static const struct socket_ops tls_socket_ops;
87 static NTSTATUS tls_socket_init(struct socket_context *sock)
89 switch (sock->type) {
90 case SOCKET_TYPE_STREAM:
91 break;
92 default:
93 return NT_STATUS_INVALID_PARAMETER;
96 sock->backend_name = "tls";
98 return NT_STATUS_OK;
101 #define TLSCHECK(call) do { \
102 ret = call; \
103 if (ret < 0) { \
104 DEBUG(0,("TLS %s - %s\n", #call, gnutls_strerror(ret))); \
105 goto failed; \
107 } while (0)
111 callback for reading from a socket
113 static ssize_t tls_pull(gnutls_transport_ptr ptr, void *buf, size_t size)
115 struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
116 NTSTATUS status;
117 size_t nread;
119 if (tls->have_first_byte) {
120 *(uint8_t *)buf = tls->first_byte;
121 tls->have_first_byte = false;
122 return 1;
125 status = socket_recv(tls->socket, buf, size, &nread);
126 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
127 return 0;
129 if (NT_STATUS_IS_ERR(status)) {
130 TEVENT_FD_NOT_READABLE(tls->fde);
131 TEVENT_FD_NOT_WRITEABLE(tls->fde);
132 errno = EBADF;
133 return -1;
135 if (!NT_STATUS_IS_OK(status)) {
136 TEVENT_FD_READABLE(tls->fde);
137 errno = EAGAIN;
138 return -1;
140 if (tls->output_pending) {
141 TEVENT_FD_WRITEABLE(tls->fde);
143 if (size != nread) {
144 TEVENT_FD_READABLE(tls->fde);
146 return nread;
150 callback for writing to a socket
152 static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
154 struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
155 NTSTATUS status;
156 size_t nwritten, total_nwritten = 0;
157 DATA_BLOB b;
159 if (!tls->tls_enabled) {
160 return size;
163 b.data = discard_const(buf);
164 b.length = size;
166 /* Cope with socket_wrapper 1500 byte chunking for PCAP */
167 do {
168 status = socket_send(tls->socket, &b, &nwritten);
170 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
171 errno = EAGAIN;
172 return -1;
174 if (!NT_STATUS_IS_OK(status)) {
175 TEVENT_FD_WRITEABLE(tls->fde);
176 return -1;
179 total_nwritten += nwritten;
181 if (size == nwritten) {
182 break;
185 b.data += nwritten;
186 b.length -= nwritten;
188 TEVENT_FD_WRITEABLE(tls->fde);
189 } while (b.length);
191 return total_nwritten;
195 destroy a tls session
197 static int tls_destructor(struct tls_context *tls)
199 int ret;
200 ret = gnutls_bye(tls->session, GNUTLS_SHUT_WR);
201 if (ret < 0) {
202 DEBUG(4,("TLS gnutls_bye failed - %s\n", gnutls_strerror(ret)));
204 return 0;
209 possibly continue the handshake process
211 static NTSTATUS tls_handshake(struct tls_context *tls)
213 int ret;
215 if (tls->done_handshake) {
216 return NT_STATUS_OK;
219 ret = gnutls_handshake(tls->session);
220 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
221 if (gnutls_record_get_direction(tls->session) == 1) {
222 TEVENT_FD_WRITEABLE(tls->fde);
224 return STATUS_MORE_ENTRIES;
226 if (ret < 0) {
227 DEBUG(0,("TLS gnutls_handshake failed - %s\n", gnutls_strerror(ret)));
228 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
230 tls->done_handshake = true;
231 return NT_STATUS_OK;
235 possibly continue an interrupted operation
237 static NTSTATUS tls_interrupted(struct tls_context *tls)
239 int ret;
241 if (!tls->interrupted) {
242 return NT_STATUS_OK;
244 if (gnutls_record_get_direction(tls->session) == 1) {
245 ret = gnutls_record_send(tls->session, NULL, 0);
246 } else {
247 ret = gnutls_record_recv(tls->session, NULL, 0);
249 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
250 return STATUS_MORE_ENTRIES;
252 tls->interrupted = false;
253 return NT_STATUS_OK;
257 see how many bytes are pending on the connection
259 static NTSTATUS tls_socket_pending(struct socket_context *sock, size_t *npending)
261 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
262 if (!tls->tls_enabled || tls->tls_detect) {
263 return socket_pending(tls->socket, npending);
265 *npending = gnutls_record_check_pending(tls->session);
266 if (*npending == 0) {
267 NTSTATUS status = socket_pending(tls->socket, npending);
268 if (*npending == 0) {
269 /* seems to be a gnutls bug */
270 (*npending) = 100;
272 return status;
274 return NT_STATUS_OK;
278 receive data either by tls or normal socket_recv
280 static NTSTATUS tls_socket_recv(struct socket_context *sock, void *buf,
281 size_t wantlen, size_t *nread)
283 int ret;
284 NTSTATUS status;
285 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
287 if (tls->tls_enabled && tls->tls_detect) {
288 status = socket_recv(tls->socket, &tls->first_byte, 1, nread);
289 NT_STATUS_NOT_OK_RETURN(status);
290 if (*nread == 0) return NT_STATUS_OK;
291 tls->tls_detect = false;
292 /* look for the first byte of a valid HTTP operation */
293 if (strchr(tls->plain_chars, tls->first_byte)) {
294 /* not a tls link */
295 tls->tls_enabled = false;
296 *(uint8_t *)buf = tls->first_byte;
297 return NT_STATUS_OK;
299 tls->have_first_byte = true;
302 if (!tls->tls_enabled) {
303 return socket_recv(tls->socket, buf, wantlen, nread);
306 status = tls_handshake(tls);
307 NT_STATUS_NOT_OK_RETURN(status);
309 status = tls_interrupted(tls);
310 NT_STATUS_NOT_OK_RETURN(status);
312 ret = gnutls_record_recv(tls->session, buf, wantlen);
313 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
314 if (gnutls_record_get_direction(tls->session) == 1) {
315 TEVENT_FD_WRITEABLE(tls->fde);
317 tls->interrupted = true;
318 return STATUS_MORE_ENTRIES;
320 if (ret < 0) {
321 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
323 *nread = ret;
324 return NT_STATUS_OK;
329 send data either by tls or normal socket_recv
331 static NTSTATUS tls_socket_send(struct socket_context *sock,
332 const DATA_BLOB *blob, size_t *sendlen)
334 NTSTATUS status;
335 int ret;
336 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
338 if (!tls->tls_enabled) {
339 return socket_send(tls->socket, blob, sendlen);
342 status = tls_handshake(tls);
343 NT_STATUS_NOT_OK_RETURN(status);
345 status = tls_interrupted(tls);
346 NT_STATUS_NOT_OK_RETURN(status);
348 ret = gnutls_record_send(tls->session, blob->data, blob->length);
349 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
350 if (gnutls_record_get_direction(tls->session) == 1) {
351 TEVENT_FD_WRITEABLE(tls->fde);
353 tls->interrupted = true;
354 return STATUS_MORE_ENTRIES;
356 if (ret < 0) {
357 DEBUG(0,("gnutls_record_send of %d failed - %s\n", (int)blob->length, gnutls_strerror(ret)));
358 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
360 *sendlen = ret;
361 tls->output_pending = (ret < blob->length);
362 return NT_STATUS_OK;
367 initialise global tls state
369 struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
371 struct tls_params *params;
372 int ret;
373 struct stat st;
374 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
375 const char *keyfile = lpcfg_tls_keyfile(tmp_ctx, lp_ctx);
376 const char *certfile = lpcfg_tls_certfile(tmp_ctx, lp_ctx);
377 const char *cafile = lpcfg_tls_cafile(tmp_ctx, lp_ctx);
378 const char *crlfile = lpcfg_tls_crlfile(tmp_ctx, lp_ctx);
379 const char *dhpfile = lpcfg_tls_dhpfile(tmp_ctx, lp_ctx);
380 void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *);
381 params = talloc(mem_ctx, struct tls_params);
382 if (params == NULL) {
383 talloc_free(tmp_ctx);
384 return NULL;
387 if (!lpcfg_tls_enabled(lp_ctx) || keyfile == NULL || *keyfile == 0) {
388 params->tls_enabled = false;
389 talloc_free(tmp_ctx);
390 return params;
393 if (!file_exist(cafile)) {
394 char *hostname = talloc_asprintf(mem_ctx, "%s.%s",
395 lpcfg_netbios_name(lp_ctx),
396 lpcfg_dnsdomain(lp_ctx));
397 if (hostname == NULL) {
398 ret = GNUTLS_E_MEMORY_ERROR;
399 goto init_failed;
401 tls_cert_generate(params, hostname, keyfile, certfile, cafile);
402 talloc_free(hostname);
405 if (file_exist(keyfile) &&
406 !file_check_permissions(keyfile, geteuid(), 0600, &st))
408 DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n"
409 "owner uid %u should be %u, mode 0%o should be 0%o\n"
410 "This is known as CVE-2013-4476.\n"
411 "Removing all tls .pem files will cause an "
412 "auto-regeneration with the correct permissions.\n",
413 keyfile,
414 (unsigned int)st.st_uid, geteuid(),
415 (unsigned int)(st.st_mode & 0777), 0600));
416 talloc_free(tmp_ctx);
417 return NULL;
420 ret = gnutls_global_init();
421 if (ret < 0) goto init_failed;
423 gnutls_certificate_allocate_credentials(&params->x509_cred);
424 if (ret < 0) goto init_failed;
426 if (cafile && *cafile) {
427 ret = gnutls_certificate_set_x509_trust_file(params->x509_cred, cafile,
428 GNUTLS_X509_FMT_PEM);
429 if (ret < 0) {
430 DEBUG(0,("TLS failed to initialise cafile %s\n", cafile));
431 goto init_failed;
435 if (crlfile && *crlfile) {
436 ret = gnutls_certificate_set_x509_crl_file(params->x509_cred,
437 crlfile,
438 GNUTLS_X509_FMT_PEM);
439 if (ret < 0) {
440 DEBUG(0,("TLS failed to initialise crlfile %s\n", crlfile));
441 goto init_failed;
445 ret = gnutls_certificate_set_x509_key_file(params->x509_cred,
446 certfile, keyfile,
447 GNUTLS_X509_FMT_PEM);
448 if (ret < 0) {
449 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s\n",
450 certfile, keyfile));
451 goto init_failed;
454 ret = gnutls_dh_params_init(&params->dh_params);
455 if (ret < 0) goto init_failed;
457 if (dhpfile && *dhpfile) {
458 gnutls_datum_t dhparms;
459 size_t size;
460 dhparms.data = (uint8_t *)file_load(dhpfile, &size, 0, mem_ctx);
462 if (!dhparms.data) {
463 DEBUG(0,("Failed to read DH Parms from %s\n", dhpfile));
464 goto init_failed;
466 dhparms.size = size;
468 ret = gnutls_dh_params_import_pkcs3(params->dh_params, &dhparms, GNUTLS_X509_FMT_PEM);
469 if (ret < 0) goto init_failed;
470 } else {
471 ret = gnutls_dh_params_generate2(params->dh_params, DH_BITS);
472 if (ret < 0) goto init_failed;
475 gnutls_certificate_set_dh_params(params->x509_cred, params->dh_params);
477 params->tls_enabled = true;
479 talloc_free(tmp_ctx);
480 return params;
482 init_failed:
483 DEBUG(0,("GNUTLS failed to initialise - %s\n", gnutls_strerror(ret)));
484 params->tls_enabled = false;
485 talloc_free(tmp_ctx);
486 return params;
491 setup for a new connection
493 struct socket_context *tls_init_server(struct tls_params *params,
494 struct socket_context *socket_ctx,
495 struct tevent_fd *fde,
496 const char *plain_chars)
498 struct tls_context *tls;
499 int ret;
500 struct socket_context *new_sock;
501 NTSTATUS nt_status;
503 nt_status = socket_create_with_ops(socket_ctx, &tls_socket_ops, &new_sock,
504 SOCKET_TYPE_STREAM,
505 socket_ctx->flags | SOCKET_FLAG_ENCRYPT);
506 if (!NT_STATUS_IS_OK(nt_status)) {
507 return NULL;
510 tls = talloc(new_sock, struct tls_context);
511 if (tls == NULL) {
512 return NULL;
515 tls->socket = socket_ctx;
516 talloc_steal(tls, socket_ctx);
517 tls->fde = fde;
519 new_sock->private_data = tls;
521 if (!params->tls_enabled) {
522 talloc_free(new_sock);
523 return NULL;
526 TLSCHECK(gnutls_init(&tls->session, GNUTLS_SERVER));
528 talloc_set_destructor(tls, tls_destructor);
530 TLSCHECK(gnutls_set_default_priority(tls->session));
531 TLSCHECK(gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
532 params->x509_cred));
533 gnutls_certificate_server_set_request(tls->session, GNUTLS_CERT_REQUEST);
534 gnutls_dh_set_prime_bits(tls->session, DH_BITS);
535 gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
536 gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
537 gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
538 #if GNUTLS_VERSION_MAJOR < 3
539 gnutls_transport_set_lowat(tls->session, 0);
540 #endif
542 tls->plain_chars = plain_chars;
543 if (plain_chars) {
544 tls->tls_detect = true;
545 } else {
546 tls->tls_detect = false;
549 tls->output_pending = false;
550 tls->done_handshake = false;
551 tls->have_first_byte = false;
552 tls->tls_enabled = true;
553 tls->interrupted = false;
555 new_sock->state = SOCKET_STATE_SERVER_CONNECTED;
557 return new_sock;
559 failed:
560 DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
561 talloc_free(new_sock);
562 return NULL;
567 setup for a new client connection
569 struct socket_context *tls_init_client(struct socket_context *socket_ctx,
570 struct tevent_fd *fde,
571 const char *ca_path)
573 struct tls_context *tls;
574 int ret = 0;
575 struct socket_context *new_sock;
576 NTSTATUS nt_status;
578 nt_status = socket_create_with_ops(socket_ctx, &tls_socket_ops, &new_sock,
579 SOCKET_TYPE_STREAM,
580 socket_ctx->flags | SOCKET_FLAG_ENCRYPT);
581 if (!NT_STATUS_IS_OK(nt_status)) {
582 return NULL;
585 tls = talloc(new_sock, struct tls_context);
586 if (tls == NULL) return NULL;
588 tls->socket = socket_ctx;
589 talloc_steal(tls, socket_ctx);
590 tls->fde = fde;
592 new_sock->private_data = tls;
594 gnutls_global_init();
596 gnutls_certificate_allocate_credentials(&tls->xcred);
597 gnutls_certificate_set_x509_trust_file(tls->xcred, ca_path, GNUTLS_X509_FMT_PEM);
598 TLSCHECK(gnutls_init(&tls->session, GNUTLS_CLIENT));
599 TLSCHECK(gnutls_set_default_priority(tls->session));
600 gnutls_priority_set_direct(tls->session, "NORMAL:+CTYPE-OPENPGP", NULL);
601 TLSCHECK(gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, tls->xcred));
603 talloc_set_destructor(tls, tls_destructor);
605 gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
606 gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
607 gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
608 #if GNUTLS_VERSION_MAJOR < 3
609 gnutls_transport_set_lowat(tls->session, 0);
610 #endif
611 tls->tls_detect = false;
613 tls->output_pending = false;
614 tls->done_handshake = false;
615 tls->have_first_byte = false;
616 tls->tls_enabled = true;
617 tls->interrupted = false;
619 new_sock->state = SOCKET_STATE_CLIENT_CONNECTED;
621 return new_sock;
623 failed:
624 DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
625 tls->tls_enabled = false;
626 return new_sock;
629 static NTSTATUS tls_socket_set_option(struct socket_context *sock, const char *option, const char *val)
631 set_socket_options(socket_get_fd(sock), option);
632 return NT_STATUS_OK;
635 static char *tls_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
637 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
638 return socket_get_peer_name(tls->socket, mem_ctx);
641 static struct socket_address *tls_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
643 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
644 return socket_get_peer_addr(tls->socket, mem_ctx);
647 static struct socket_address *tls_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
649 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
650 return socket_get_my_addr(tls->socket, mem_ctx);
653 static int tls_socket_get_fd(struct socket_context *sock)
655 struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
656 return socket_get_fd(tls->socket);
659 static const struct socket_ops tls_socket_ops = {
660 .name = "tls",
661 .fn_init = tls_socket_init,
662 .fn_recv = tls_socket_recv,
663 .fn_send = tls_socket_send,
664 .fn_pending = tls_socket_pending,
666 .fn_set_option = tls_socket_set_option,
668 .fn_get_peer_name = tls_socket_get_peer_name,
669 .fn_get_peer_addr = tls_socket_get_peer_addr,
670 .fn_get_my_addr = tls_socket_get_my_addr,
671 .fn_get_fd = tls_socket_get_fd
674 #else
676 /* for systems without tls we just fail the operations, and the caller
677 * will retain the original socket */
679 struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
681 return talloc_new(mem_ctx);
685 setup for a new connection
687 struct socket_context *tls_init_server(struct tls_params *params,
688 struct socket_context *socket,
689 struct tevent_fd *fde,
690 const char *plain_chars)
692 return NULL;
697 setup for a new client connection
699 struct socket_context *tls_init_client(struct socket_context *socket,
700 struct tevent_fd *fde,
701 const char *ca_path)
703 return NULL;
706 #endif