s4:tls_tstream: create tstream_tls_params_internal
[Samba.git] / source4 / lib / tls / tls_tstream.c
blob58500a54ac500d0ad74215688b2c6dccf0021594
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2010
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 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "../util/tevent_unix.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "../lib/tsocket/tsocket_internal.h"
27 #include "../lib/util/util_net.h"
28 #include "lib/tls/tls.h"
30 #include <gnutls/gnutls.h>
31 #include <gnutls/x509.h>
33 #define DH_BITS 2048
35 const char *tls_verify_peer_string(enum tls_verify_peer_state verify_peer)
37 switch (verify_peer) {
38 case TLS_VERIFY_PEER_NO_CHECK:
39 return TLS_VERIFY_PEER_NO_CHECK_STRING;
41 case TLS_VERIFY_PEER_CA_ONLY:
42 return TLS_VERIFY_PEER_CA_ONLY_STRING;
44 case TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE:
45 return TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING;
47 case TLS_VERIFY_PEER_CA_AND_NAME:
48 return TLS_VERIFY_PEER_CA_AND_NAME_STRING;
50 case TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE:
51 return TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING;
54 return "unknown tls_verify_peer_state";
57 static const struct tstream_context_ops tstream_tls_ops;
59 struct tstream_tls {
60 struct tstream_context *plain_stream;
61 int error;
63 gnutls_session_t tls_session;
65 enum tls_verify_peer_state verify_peer;
66 const char *peer_name;
68 struct tevent_context *current_ev;
70 struct tevent_immediate *retry_im;
72 struct {
73 uint8_t *buf;
74 off_t ofs;
75 struct iovec iov;
76 struct tevent_req *subreq;
77 struct tevent_immediate *im;
78 } push;
80 struct {
81 uint8_t *buf;
82 struct iovec iov;
83 struct tevent_req *subreq;
84 } pull;
86 struct {
87 struct tevent_req *req;
88 } handshake;
90 struct {
91 off_t ofs;
92 size_t left;
93 uint8_t buffer[1024];
94 struct tevent_req *req;
95 } write;
97 struct {
98 off_t ofs;
99 size_t left;
100 uint8_t buffer[1024];
101 struct tevent_req *req;
102 } read;
104 struct {
105 struct tevent_req *req;
106 } disconnect;
109 static void tstream_tls_retry_handshake(struct tstream_context *stream);
110 static void tstream_tls_retry_read(struct tstream_context *stream);
111 static void tstream_tls_retry_write(struct tstream_context *stream);
112 static void tstream_tls_retry_disconnect(struct tstream_context *stream);
113 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
114 struct tevent_immediate *im,
115 void *private_data);
117 static void tstream_tls_retry(struct tstream_context *stream, bool deferred)
120 struct tstream_tls *tlss =
121 tstream_context_data(stream,
122 struct tstream_tls);
124 if (tlss->disconnect.req) {
125 tstream_tls_retry_disconnect(stream);
126 return;
129 if (tlss->handshake.req) {
130 tstream_tls_retry_handshake(stream);
131 return;
134 if (tlss->write.req && tlss->read.req && !deferred) {
135 tevent_schedule_immediate(tlss->retry_im, tlss->current_ev,
136 tstream_tls_retry_trigger,
137 stream);
140 if (tlss->write.req) {
141 tstream_tls_retry_write(stream);
142 return;
145 if (tlss->read.req) {
146 tstream_tls_retry_read(stream);
147 return;
151 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
152 struct tevent_immediate *im,
153 void *private_data)
155 struct tstream_context *stream =
156 talloc_get_type_abort(private_data,
157 struct tstream_context);
159 tstream_tls_retry(stream, true);
162 static void tstream_tls_push_trigger_write(struct tevent_context *ev,
163 struct tevent_immediate *im,
164 void *private_data);
166 static ssize_t tstream_tls_push_function(gnutls_transport_ptr_t ptr,
167 const void *buf, size_t size)
169 struct tstream_context *stream =
170 talloc_get_type_abort(ptr,
171 struct tstream_context);
172 struct tstream_tls *tlss =
173 tstream_context_data(stream,
174 struct tstream_tls);
175 uint8_t *nbuf;
176 size_t len;
178 if (tlss->error != 0) {
179 errno = tlss->error;
180 return -1;
183 if (tlss->push.subreq) {
184 errno = EAGAIN;
185 return -1;
188 len = MIN(size, UINT16_MAX - tlss->push.ofs);
190 if (len == 0) {
191 errno = EAGAIN;
192 return -1;
195 nbuf = talloc_realloc(tlss, tlss->push.buf,
196 uint8_t, tlss->push.ofs + len);
197 if (nbuf == NULL) {
198 if (tlss->push.buf) {
199 errno = EAGAIN;
200 return -1;
203 return -1;
205 tlss->push.buf = nbuf;
207 memcpy(tlss->push.buf + tlss->push.ofs, buf, len);
209 if (tlss->push.im == NULL) {
210 tlss->push.im = tevent_create_immediate(tlss);
211 if (tlss->push.im == NULL) {
212 errno = ENOMEM;
213 return -1;
217 if (tlss->push.ofs == 0) {
219 * We'll do start the tstream_writev
220 * in the next event cycle.
222 * This way we can batch all push requests,
223 * if they fit into a UINT16_MAX buffer.
225 * This is important as gnutls_handshake()
226 * had a bug in some versions e.g. 2.4.1
227 * and others (See bug #7218) and it doesn't
228 * handle EAGAIN.
230 tevent_schedule_immediate(tlss->push.im,
231 tlss->current_ev,
232 tstream_tls_push_trigger_write,
233 stream);
236 tlss->push.ofs += len;
237 return len;
240 static void tstream_tls_push_done(struct tevent_req *subreq);
242 static void tstream_tls_push_trigger_write(struct tevent_context *ev,
243 struct tevent_immediate *im,
244 void *private_data)
246 struct tstream_context *stream =
247 talloc_get_type_abort(private_data,
248 struct tstream_context);
249 struct tstream_tls *tlss =
250 tstream_context_data(stream,
251 struct tstream_tls);
252 struct tevent_req *subreq;
254 if (tlss->push.subreq) {
255 /* nothing todo */
256 return;
259 tlss->push.iov.iov_base = (char *)tlss->push.buf;
260 tlss->push.iov.iov_len = tlss->push.ofs;
262 subreq = tstream_writev_send(tlss,
263 tlss->current_ev,
264 tlss->plain_stream,
265 &tlss->push.iov, 1);
266 if (subreq == NULL) {
267 tlss->error = ENOMEM;
268 tstream_tls_retry(stream, false);
269 return;
271 tevent_req_set_callback(subreq, tstream_tls_push_done, stream);
273 tlss->push.subreq = subreq;
276 static void tstream_tls_push_done(struct tevent_req *subreq)
278 struct tstream_context *stream =
279 tevent_req_callback_data(subreq,
280 struct tstream_context);
281 struct tstream_tls *tlss =
282 tstream_context_data(stream,
283 struct tstream_tls);
284 int ret;
285 int sys_errno;
287 tlss->push.subreq = NULL;
288 ZERO_STRUCT(tlss->push.iov);
289 TALLOC_FREE(tlss->push.buf);
290 tlss->push.ofs = 0;
292 ret = tstream_writev_recv(subreq, &sys_errno);
293 TALLOC_FREE(subreq);
294 if (ret == -1) {
295 tlss->error = sys_errno;
296 tstream_tls_retry(stream, false);
297 return;
300 tstream_tls_retry(stream, false);
303 static void tstream_tls_pull_done(struct tevent_req *subreq);
305 static ssize_t tstream_tls_pull_function(gnutls_transport_ptr_t ptr,
306 void *buf, size_t size)
308 struct tstream_context *stream =
309 talloc_get_type_abort(ptr,
310 struct tstream_context);
311 struct tstream_tls *tlss =
312 tstream_context_data(stream,
313 struct tstream_tls);
314 struct tevent_req *subreq;
315 size_t len;
317 if (tlss->error != 0) {
318 errno = tlss->error;
319 return -1;
322 if (tlss->pull.subreq) {
323 errno = EAGAIN;
324 return -1;
327 if (tlss->pull.iov.iov_base) {
328 uint8_t *b;
329 size_t n;
331 b = (uint8_t *)tlss->pull.iov.iov_base;
333 n = MIN(tlss->pull.iov.iov_len, size);
334 memcpy(buf, b, n);
336 tlss->pull.iov.iov_len -= n;
337 b += n;
338 tlss->pull.iov.iov_base = (char *)b;
339 if (tlss->pull.iov.iov_len == 0) {
340 tlss->pull.iov.iov_base = NULL;
341 TALLOC_FREE(tlss->pull.buf);
344 return n;
347 if (size == 0) {
348 return 0;
351 len = MIN(size, UINT16_MAX);
353 tlss->pull.buf = talloc_array(tlss, uint8_t, len);
354 if (tlss->pull.buf == NULL) {
355 return -1;
358 tlss->pull.iov.iov_base = (char *)tlss->pull.buf;
359 tlss->pull.iov.iov_len = len;
361 subreq = tstream_readv_send(tlss,
362 tlss->current_ev,
363 tlss->plain_stream,
364 &tlss->pull.iov, 1);
365 if (subreq == NULL) {
366 errno = ENOMEM;
367 return -1;
369 tevent_req_set_callback(subreq, tstream_tls_pull_done, stream);
371 tlss->pull.subreq = subreq;
372 errno = EAGAIN;
373 return -1;
376 static void tstream_tls_pull_done(struct tevent_req *subreq)
378 struct tstream_context *stream =
379 tevent_req_callback_data(subreq,
380 struct tstream_context);
381 struct tstream_tls *tlss =
382 tstream_context_data(stream,
383 struct tstream_tls);
384 int ret;
385 int sys_errno;
387 tlss->pull.subreq = NULL;
389 ret = tstream_readv_recv(subreq, &sys_errno);
390 TALLOC_FREE(subreq);
391 if (ret == -1) {
392 tlss->error = sys_errno;
393 tstream_tls_retry(stream, false);
394 return;
397 tstream_tls_retry(stream, false);
400 static int tstream_tls_destructor(struct tstream_tls *tlss)
402 if (tlss->tls_session) {
403 gnutls_deinit(tlss->tls_session);
404 tlss->tls_session = NULL;
407 return 0;
410 static ssize_t tstream_tls_pending_bytes(struct tstream_context *stream)
412 struct tstream_tls *tlss =
413 tstream_context_data(stream,
414 struct tstream_tls);
415 size_t ret;
417 if (tlss->error != 0) {
418 errno = tlss->error;
419 return -1;
422 ret = gnutls_record_check_pending(tlss->tls_session);
423 ret += tlss->read.left;
425 return ret;
428 struct tstream_tls_readv_state {
429 struct tstream_context *stream;
431 struct iovec *vector;
432 int count;
434 int ret;
437 static void tstream_tls_readv_crypt_next(struct tevent_req *req);
439 static struct tevent_req *tstream_tls_readv_send(TALLOC_CTX *mem_ctx,
440 struct tevent_context *ev,
441 struct tstream_context *stream,
442 struct iovec *vector,
443 size_t count)
445 struct tstream_tls *tlss =
446 tstream_context_data(stream,
447 struct tstream_tls);
448 struct tevent_req *req;
449 struct tstream_tls_readv_state *state;
451 tlss->read.req = NULL;
452 tlss->current_ev = ev;
454 req = tevent_req_create(mem_ctx, &state,
455 struct tstream_tls_readv_state);
456 if (req == NULL) {
457 return NULL;
460 state->stream = stream;
461 state->ret = 0;
463 if (tlss->error != 0) {
464 tevent_req_error(req, tlss->error);
465 return tevent_req_post(req, ev);
469 * we make a copy of the vector so we can change the structure
471 state->vector = talloc_array(state, struct iovec, count);
472 if (tevent_req_nomem(state->vector, req)) {
473 return tevent_req_post(req, ev);
475 memcpy(state->vector, vector, sizeof(struct iovec) * count);
476 state->count = count;
478 tstream_tls_readv_crypt_next(req);
479 if (!tevent_req_is_in_progress(req)) {
480 return tevent_req_post(req, ev);
483 return req;
486 static void tstream_tls_readv_crypt_next(struct tevent_req *req)
488 struct tstream_tls_readv_state *state =
489 tevent_req_data(req,
490 struct tstream_tls_readv_state);
491 struct tstream_tls *tlss =
492 tstream_context_data(state->stream,
493 struct tstream_tls);
496 * copy the pending buffer first
498 while (tlss->read.left > 0 && state->count > 0) {
499 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
500 size_t len = MIN(tlss->read.left, state->vector[0].iov_len);
502 memcpy(base, tlss->read.buffer + tlss->read.ofs, len);
504 base += len;
505 state->vector[0].iov_base = (char *) base;
506 state->vector[0].iov_len -= len;
508 tlss->read.ofs += len;
509 tlss->read.left -= len;
511 if (state->vector[0].iov_len == 0) {
512 state->vector += 1;
513 state->count -= 1;
516 state->ret += len;
519 if (state->count == 0) {
520 tevent_req_done(req);
521 return;
524 tlss->read.req = req;
525 tstream_tls_retry_read(state->stream);
528 static void tstream_tls_retry_read(struct tstream_context *stream)
530 struct tstream_tls *tlss =
531 tstream_context_data(stream,
532 struct tstream_tls);
533 struct tevent_req *req = tlss->read.req;
534 int ret;
536 if (tlss->error != 0) {
537 tevent_req_error(req, tlss->error);
538 return;
541 tlss->read.left = 0;
542 tlss->read.ofs = 0;
544 ret = gnutls_record_recv(tlss->tls_session,
545 tlss->read.buffer,
546 sizeof(tlss->read.buffer));
547 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
548 return;
551 tlss->read.req = NULL;
553 if (gnutls_error_is_fatal(ret) != 0) {
554 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
555 tlss->error = EIO;
556 tevent_req_error(req, tlss->error);
557 return;
560 if (ret == 0) {
561 tlss->error = EPIPE;
562 tevent_req_error(req, tlss->error);
563 return;
566 tlss->read.left = ret;
567 tstream_tls_readv_crypt_next(req);
570 static int tstream_tls_readv_recv(struct tevent_req *req,
571 int *perrno)
573 struct tstream_tls_readv_state *state =
574 tevent_req_data(req,
575 struct tstream_tls_readv_state);
576 struct tstream_tls *tlss =
577 tstream_context_data(state->stream,
578 struct tstream_tls);
579 int ret;
581 tlss->read.req = NULL;
583 ret = tsocket_simple_int_recv(req, perrno);
584 if (ret == 0) {
585 ret = state->ret;
588 tevent_req_received(req);
589 return ret;
592 struct tstream_tls_writev_state {
593 struct tstream_context *stream;
595 struct iovec *vector;
596 int count;
598 int ret;
601 static void tstream_tls_writev_crypt_next(struct tevent_req *req);
603 static struct tevent_req *tstream_tls_writev_send(TALLOC_CTX *mem_ctx,
604 struct tevent_context *ev,
605 struct tstream_context *stream,
606 const struct iovec *vector,
607 size_t count)
609 struct tstream_tls *tlss =
610 tstream_context_data(stream,
611 struct tstream_tls);
612 struct tevent_req *req;
613 struct tstream_tls_writev_state *state;
615 tlss->write.req = NULL;
616 tlss->current_ev = ev;
618 req = tevent_req_create(mem_ctx, &state,
619 struct tstream_tls_writev_state);
620 if (req == NULL) {
621 return NULL;
624 state->stream = stream;
625 state->ret = 0;
627 if (tlss->error != 0) {
628 tevent_req_error(req, tlss->error);
629 return tevent_req_post(req, ev);
633 * we make a copy of the vector so we can change the structure
635 state->vector = talloc_array(state, struct iovec, count);
636 if (tevent_req_nomem(state->vector, req)) {
637 return tevent_req_post(req, ev);
639 memcpy(state->vector, vector, sizeof(struct iovec) * count);
640 state->count = count;
642 tstream_tls_writev_crypt_next(req);
643 if (!tevent_req_is_in_progress(req)) {
644 return tevent_req_post(req, ev);
647 return req;
650 static void tstream_tls_writev_crypt_next(struct tevent_req *req)
652 struct tstream_tls_writev_state *state =
653 tevent_req_data(req,
654 struct tstream_tls_writev_state);
655 struct tstream_tls *tlss =
656 tstream_context_data(state->stream,
657 struct tstream_tls);
659 tlss->write.left = sizeof(tlss->write.buffer);
660 tlss->write.ofs = 0;
663 * first fill our buffer
665 while (tlss->write.left > 0 && state->count > 0) {
666 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
667 size_t len = MIN(tlss->write.left, state->vector[0].iov_len);
669 memcpy(tlss->write.buffer + tlss->write.ofs, base, len);
671 base += len;
672 state->vector[0].iov_base = (char *) base;
673 state->vector[0].iov_len -= len;
675 tlss->write.ofs += len;
676 tlss->write.left -= len;
678 if (state->vector[0].iov_len == 0) {
679 state->vector += 1;
680 state->count -= 1;
683 state->ret += len;
686 if (tlss->write.ofs == 0) {
687 tevent_req_done(req);
688 return;
691 tlss->write.left = tlss->write.ofs;
692 tlss->write.ofs = 0;
694 tlss->write.req = req;
695 tstream_tls_retry_write(state->stream);
698 static void tstream_tls_retry_write(struct tstream_context *stream)
700 struct tstream_tls *tlss =
701 tstream_context_data(stream,
702 struct tstream_tls);
703 struct tevent_req *req = tlss->write.req;
704 int ret;
706 if (tlss->error != 0) {
707 tevent_req_error(req, tlss->error);
708 return;
711 ret = gnutls_record_send(tlss->tls_session,
712 tlss->write.buffer + tlss->write.ofs,
713 tlss->write.left);
714 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
715 return;
718 tlss->write.req = NULL;
720 if (gnutls_error_is_fatal(ret) != 0) {
721 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
722 tlss->error = EIO;
723 tevent_req_error(req, tlss->error);
724 return;
727 if (ret == 0) {
728 tlss->error = EPIPE;
729 tevent_req_error(req, tlss->error);
730 return;
733 tlss->write.ofs += ret;
734 tlss->write.left -= ret;
736 if (tlss->write.left > 0) {
737 tlss->write.req = req;
738 tstream_tls_retry_write(stream);
739 return;
742 tstream_tls_writev_crypt_next(req);
745 static int tstream_tls_writev_recv(struct tevent_req *req,
746 int *perrno)
748 struct tstream_tls_writev_state *state =
749 tevent_req_data(req,
750 struct tstream_tls_writev_state);
751 struct tstream_tls *tlss =
752 tstream_context_data(state->stream,
753 struct tstream_tls);
754 int ret;
756 tlss->write.req = NULL;
758 ret = tsocket_simple_int_recv(req, perrno);
759 if (ret == 0) {
760 ret = state->ret;
763 tevent_req_received(req);
764 return ret;
767 struct tstream_tls_disconnect_state {
768 uint8_t _dummy;
771 static struct tevent_req *tstream_tls_disconnect_send(TALLOC_CTX *mem_ctx,
772 struct tevent_context *ev,
773 struct tstream_context *stream)
775 struct tstream_tls *tlss =
776 tstream_context_data(stream,
777 struct tstream_tls);
778 struct tevent_req *req;
779 struct tstream_tls_disconnect_state *state;
781 tlss->disconnect.req = NULL;
782 tlss->current_ev = ev;
784 req = tevent_req_create(mem_ctx, &state,
785 struct tstream_tls_disconnect_state);
786 if (req == NULL) {
787 return NULL;
790 if (tlss->error != 0) {
791 tevent_req_error(req, tlss->error);
792 return tevent_req_post(req, ev);
795 tlss->disconnect.req = req;
796 tstream_tls_retry_disconnect(stream);
797 if (!tevent_req_is_in_progress(req)) {
798 return tevent_req_post(req, ev);
801 return req;
804 static void tstream_tls_retry_disconnect(struct tstream_context *stream)
806 struct tstream_tls *tlss =
807 tstream_context_data(stream,
808 struct tstream_tls);
809 struct tevent_req *req = tlss->disconnect.req;
810 int ret;
812 if (tlss->error != 0) {
813 tevent_req_error(req, tlss->error);
814 return;
817 ret = gnutls_bye(tlss->tls_session, GNUTLS_SHUT_WR);
818 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
819 return;
822 tlss->disconnect.req = NULL;
824 if (gnutls_error_is_fatal(ret) != 0) {
825 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
826 tlss->error = EIO;
827 tevent_req_error(req, tlss->error);
828 return;
831 if (ret != GNUTLS_E_SUCCESS) {
832 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
833 tlss->error = EIO;
834 tevent_req_error(req, tlss->error);
835 return;
838 tevent_req_done(req);
841 static int tstream_tls_disconnect_recv(struct tevent_req *req,
842 int *perrno)
844 int ret;
846 ret = tsocket_simple_int_recv(req, perrno);
848 tevent_req_received(req);
849 return ret;
852 static const struct tstream_context_ops tstream_tls_ops = {
853 .name = "tls",
855 .pending_bytes = tstream_tls_pending_bytes,
857 .readv_send = tstream_tls_readv_send,
858 .readv_recv = tstream_tls_readv_recv,
860 .writev_send = tstream_tls_writev_send,
861 .writev_recv = tstream_tls_writev_recv,
863 .disconnect_send = tstream_tls_disconnect_send,
864 .disconnect_recv = tstream_tls_disconnect_recv,
867 struct tstream_tls_params_internal {
868 gnutls_certificate_credentials_t x509_cred;
869 gnutls_dh_params_t dh_params;
870 const char *tls_priority;
871 bool tls_enabled;
872 enum tls_verify_peer_state verify_peer;
873 const char *peer_name;
876 struct tstream_tls_params {
877 struct tstream_tls_params_internal *internal;
880 static int tstream_tls_params_internal_destructor(struct tstream_tls_params_internal *tlsp)
882 if (tlsp->x509_cred) {
883 gnutls_certificate_free_credentials(tlsp->x509_cred);
884 tlsp->x509_cred = NULL;
886 if (tlsp->dh_params) {
887 gnutls_dh_params_deinit(tlsp->dh_params);
888 tlsp->dh_params = NULL;
891 return 0;
894 bool tstream_tls_params_enabled(struct tstream_tls_params *tls_params)
896 struct tstream_tls_params_internal *tlsp = tls_params->internal;
898 return tlsp->tls_enabled;
901 NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
902 const char *ca_file,
903 const char *crl_file,
904 const char *tls_priority,
905 enum tls_verify_peer_state verify_peer,
906 const char *peer_name,
907 struct tstream_tls_params **_tlsp)
909 struct tstream_tls_params *__tlsp = NULL;
910 struct tstream_tls_params_internal *tlsp = NULL;
911 int ret;
913 __tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
914 if (__tlsp == NULL) {
915 return NT_STATUS_NO_MEMORY;
918 tlsp = talloc_zero(__tlsp, struct tstream_tls_params_internal);
919 if (tlsp == NULL) {
920 TALLOC_FREE(__tlsp);
921 return NT_STATUS_NO_MEMORY;
923 talloc_set_destructor(tlsp, tstream_tls_params_internal_destructor);
924 __tlsp->internal = tlsp;
926 tlsp->verify_peer = verify_peer;
927 if (peer_name != NULL) {
928 tlsp->peer_name = talloc_strdup(tlsp, peer_name);
929 if (tlsp->peer_name == NULL) {
930 TALLOC_FREE(__tlsp);
931 return NT_STATUS_NO_MEMORY;
933 } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) {
934 DEBUG(0,("TLS failed to missing peer_name - "
935 "with 'tls verify peer = %s'\n",
936 tls_verify_peer_string(tlsp->verify_peer)));
937 TALLOC_FREE(__tlsp);
938 return NT_STATUS_INVALID_PARAMETER_MIX;
941 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
942 if (ret != GNUTLS_E_SUCCESS) {
943 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
944 TALLOC_FREE(__tlsp);
945 return NT_STATUS_NO_MEMORY;
948 if (ca_file && *ca_file && file_exist(ca_file)) {
949 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
950 ca_file,
951 GNUTLS_X509_FMT_PEM);
952 if (ret < 0) {
953 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
954 ca_file, gnutls_strerror(ret)));
955 TALLOC_FREE(__tlsp);
956 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
958 } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) {
959 DEBUG(0,("TLS failed to missing cafile %s - "
960 "with 'tls verify peer = %s'\n",
961 ca_file,
962 tls_verify_peer_string(tlsp->verify_peer)));
963 TALLOC_FREE(__tlsp);
964 return NT_STATUS_INVALID_PARAMETER_MIX;
967 if (crl_file && *crl_file && file_exist(crl_file)) {
968 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
969 crl_file,
970 GNUTLS_X509_FMT_PEM);
971 if (ret < 0) {
972 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
973 crl_file, gnutls_strerror(ret)));
974 TALLOC_FREE(__tlsp);
975 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
977 } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE) {
978 DEBUG(0,("TLS failed to missing crlfile %s - "
979 "with 'tls verify peer = %s'\n",
980 crl_file,
981 tls_verify_peer_string(tlsp->verify_peer)));
982 TALLOC_FREE(__tlsp);
983 return NT_STATUS_INVALID_PARAMETER_MIX;
986 tlsp->tls_priority = talloc_strdup(tlsp, tls_priority);
987 if (tlsp->tls_priority == NULL) {
988 TALLOC_FREE(__tlsp);
989 return NT_STATUS_NO_MEMORY;
992 tlsp->tls_enabled = true;
994 *_tlsp = __tlsp;
995 return NT_STATUS_OK;
998 struct tstream_tls_connect_state {
999 struct tstream_context *tls_stream;
1002 struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
1003 struct tevent_context *ev,
1004 struct tstream_context *plain_stream,
1005 struct tstream_tls_params *_tls_params,
1006 const char *location)
1008 struct tevent_req *req;
1009 struct tstream_tls_connect_state *state;
1010 const char *error_pos;
1011 struct tstream_tls *tlss;
1012 struct tstream_tls_params_internal *tls_params = NULL;
1013 int ret;
1014 unsigned int flags = GNUTLS_CLIENT;
1016 req = tevent_req_create(mem_ctx, &state,
1017 struct tstream_tls_connect_state);
1018 if (req == NULL) {
1019 return NULL;
1022 state->tls_stream = tstream_context_create(state,
1023 &tstream_tls_ops,
1024 &tlss,
1025 struct tstream_tls,
1026 location);
1027 if (tevent_req_nomem(state->tls_stream, req)) {
1028 return tevent_req_post(req, ev);
1030 ZERO_STRUCTP(tlss);
1031 talloc_set_destructor(tlss, tstream_tls_destructor);
1034 * Note we need to make sure x509_cred and dh_params
1035 * from tstream_tls_params_internal stay alive for
1036 * the whole lifetime of this session!
1038 * See 'man gnutls_credentials_set' and
1039 * 'man gnutls_certificate_set_dh_params'.
1041 * Note: here we use talloc_reference() in a way
1042 * that does not expose it to the caller.
1045 tls_params = talloc_reference(tlss, _tls_params->internal);
1046 if (tevent_req_nomem(tls_params, req)) {
1047 return tevent_req_post(req, ev);
1050 tlss->plain_stream = plain_stream;
1051 tlss->verify_peer = tls_params->verify_peer;
1052 if (tls_params->peer_name != NULL) {
1053 tlss->peer_name = talloc_strdup(tlss, tls_params->peer_name);
1054 if (tevent_req_nomem(tlss->peer_name, req)) {
1055 return tevent_req_post(req, ev);
1059 tlss->current_ev = ev;
1060 tlss->retry_im = tevent_create_immediate(tlss);
1061 if (tevent_req_nomem(tlss->retry_im, req)) {
1062 return tevent_req_post(req, ev);
1065 #ifdef GNUTLS_NO_TICKETS
1067 * tls_tstream can't properly handle 'New Session Ticket' messages
1068 * sent 'after' the client sends the 'Finished' message.
1069 * GNUTLS_NO_TICKETS was introduced in GnuTLS 3.5.6. This flag is to
1070 * indicate the session Flag session should not use resumption with
1071 * session tickets.
1073 flags |= GNUTLS_NO_TICKETS;
1074 #endif
1076 ret = gnutls_init(&tlss->tls_session, flags);
1077 if (ret != GNUTLS_E_SUCCESS) {
1078 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1079 tevent_req_error(req, EINVAL);
1080 return tevent_req_post(req, ev);
1083 ret = gnutls_set_default_priority(tlss->tls_session);
1084 if (ret != GNUTLS_E_SUCCESS) {
1085 DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
1086 __location__, gnutls_strerror(ret));
1087 tevent_req_error(req, EINVAL);
1088 return tevent_req_post(req, ev);
1091 if (strlen(tls_params->tls_priority) > 0) {
1092 ret = gnutls_priority_set_direct(tlss->tls_session,
1093 tls_params->tls_priority,
1094 &error_pos);
1095 if (ret != GNUTLS_E_SUCCESS) {
1096 DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
1097 __location__, gnutls_strerror(ret), error_pos));
1098 tevent_req_error(req, EINVAL);
1099 return tevent_req_post(req, ev);
1103 ret = gnutls_credentials_set(tlss->tls_session,
1104 GNUTLS_CRD_CERTIFICATE,
1105 tls_params->x509_cred);
1106 if (ret != GNUTLS_E_SUCCESS) {
1107 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1108 tevent_req_error(req, EINVAL);
1109 return tevent_req_post(req, ev);
1112 gnutls_transport_set_ptr(tlss->tls_session,
1113 (gnutls_transport_ptr_t)state->tls_stream);
1114 gnutls_transport_set_pull_function(tlss->tls_session,
1115 (gnutls_pull_func)tstream_tls_pull_function);
1116 gnutls_transport_set_push_function(tlss->tls_session,
1117 (gnutls_push_func)tstream_tls_push_function);
1119 tlss->handshake.req = req;
1120 tstream_tls_retry_handshake(state->tls_stream);
1121 if (!tevent_req_is_in_progress(req)) {
1122 return tevent_req_post(req, ev);
1125 return req;
1128 int tstream_tls_connect_recv(struct tevent_req *req,
1129 int *perrno,
1130 TALLOC_CTX *mem_ctx,
1131 struct tstream_context **tls_stream)
1133 struct tstream_tls_connect_state *state =
1134 tevent_req_data(req,
1135 struct tstream_tls_connect_state);
1137 if (tevent_req_is_unix_error(req, perrno)) {
1138 tevent_req_received(req);
1139 return -1;
1142 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1143 tevent_req_received(req);
1144 return 0;
1148 initialise global tls state
1150 NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
1151 const char *dns_host_name,
1152 bool enabled,
1153 const char *key_file,
1154 const char *cert_file,
1155 const char *ca_file,
1156 const char *crl_file,
1157 const char *dhp_file,
1158 const char *tls_priority,
1159 struct tstream_tls_params **_tlsp)
1161 struct tstream_tls_params *__tlsp = NULL;
1162 struct tstream_tls_params_internal *tlsp = NULL;
1163 int ret;
1164 struct stat st;
1166 if (!enabled || key_file == NULL || *key_file == 0) {
1167 __tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1168 if (__tlsp == NULL) {
1169 return NT_STATUS_NO_MEMORY;
1172 tlsp = talloc_zero(__tlsp, struct tstream_tls_params_internal);
1173 if (tlsp == NULL) {
1174 TALLOC_FREE(__tlsp);
1175 return NT_STATUS_NO_MEMORY;
1178 talloc_set_destructor(tlsp, tstream_tls_params_internal_destructor);
1179 __tlsp->internal = tlsp;
1180 tlsp->tls_enabled = false;
1182 *_tlsp = __tlsp;
1183 return NT_STATUS_OK;
1186 __tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1187 if (__tlsp == NULL) {
1188 return NT_STATUS_NO_MEMORY;
1191 tlsp = talloc_zero(__tlsp, struct tstream_tls_params_internal);
1192 if (tlsp == NULL) {
1193 TALLOC_FREE(__tlsp);
1194 return NT_STATUS_NO_MEMORY;
1197 talloc_set_destructor(tlsp, tstream_tls_params_internal_destructor);
1198 __tlsp->internal = tlsp;
1200 if (!file_exist(ca_file)) {
1201 tls_cert_generate(tlsp, dns_host_name,
1202 key_file, cert_file, ca_file);
1205 if (file_exist(key_file) &&
1206 !file_check_permissions(key_file, geteuid(), 0600, &st))
1208 DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n"
1209 "owner uid %u should be %u, mode 0%o should be 0%o\n"
1210 "This is known as CVE-2013-4476.\n"
1211 "Removing all tls .pem files will cause an "
1212 "auto-regeneration with the correct permissions.\n",
1213 key_file,
1214 (unsigned int)st.st_uid, geteuid(),
1215 (unsigned int)(st.st_mode & 0777), 0600));
1216 TALLOC_FREE(__tlsp);
1217 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1220 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
1221 if (ret != GNUTLS_E_SUCCESS) {
1222 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1223 TALLOC_FREE(__tlsp);
1224 return NT_STATUS_NO_MEMORY;
1227 if (ca_file && *ca_file) {
1228 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1229 ca_file,
1230 GNUTLS_X509_FMT_PEM);
1231 if (ret < 0) {
1232 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1233 ca_file, gnutls_strerror(ret)));
1234 TALLOC_FREE(__tlsp);
1235 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1239 if (crl_file && *crl_file) {
1240 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
1241 crl_file,
1242 GNUTLS_X509_FMT_PEM);
1243 if (ret < 0) {
1244 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1245 crl_file, gnutls_strerror(ret)));
1246 TALLOC_FREE(__tlsp);
1247 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1251 ret = gnutls_certificate_set_x509_key_file(tlsp->x509_cred,
1252 cert_file, key_file,
1253 GNUTLS_X509_FMT_PEM);
1254 if (ret != GNUTLS_E_SUCCESS) {
1255 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1256 cert_file, key_file, gnutls_strerror(ret)));
1257 TALLOC_FREE(__tlsp);
1258 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1261 ret = gnutls_dh_params_init(&tlsp->dh_params);
1262 if (ret != GNUTLS_E_SUCCESS) {
1263 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1264 TALLOC_FREE(__tlsp);
1265 return NT_STATUS_NO_MEMORY;
1268 if (dhp_file && *dhp_file) {
1269 gnutls_datum_t dhparms;
1270 size_t size;
1272 dhparms.data = (uint8_t *)file_load(dhp_file, &size, 0, tlsp);
1274 if (!dhparms.data) {
1275 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1276 dhp_file, errno, strerror(errno)));
1277 TALLOC_FREE(__tlsp);
1278 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1280 dhparms.size = size;
1282 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1283 &dhparms,
1284 GNUTLS_X509_FMT_PEM);
1285 if (ret != GNUTLS_E_SUCCESS) {
1286 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1287 dhp_file, gnutls_strerror(ret)));
1288 TALLOC_FREE(__tlsp);
1289 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1291 } else {
1292 ret = gnutls_dh_params_generate2(tlsp->dh_params, DH_BITS);
1293 if (ret != GNUTLS_E_SUCCESS) {
1294 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1295 gnutls_strerror(ret)));
1296 TALLOC_FREE(__tlsp);
1297 return NT_STATUS_INTERNAL_ERROR;
1301 gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
1303 tlsp->tls_priority = talloc_strdup(tlsp, tls_priority);
1304 if (tlsp->tls_priority == NULL) {
1305 TALLOC_FREE(__tlsp);
1306 return NT_STATUS_NO_MEMORY;
1309 tlsp->tls_enabled = true;
1311 *_tlsp = __tlsp;
1312 return NT_STATUS_OK;
1315 struct tstream_tls_accept_state {
1316 struct tstream_context *tls_stream;
1319 struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
1320 struct tevent_context *ev,
1321 struct tstream_context *plain_stream,
1322 struct tstream_tls_params *_tlsp,
1323 const char *location)
1325 struct tevent_req *req;
1326 struct tstream_tls_accept_state *state;
1327 struct tstream_tls *tlss;
1328 const char *error_pos;
1329 struct tstream_tls_params_internal *tlsp = NULL;
1330 int ret;
1332 req = tevent_req_create(mem_ctx, &state,
1333 struct tstream_tls_accept_state);
1334 if (req == NULL) {
1335 return NULL;
1338 state->tls_stream = tstream_context_create(state,
1339 &tstream_tls_ops,
1340 &tlss,
1341 struct tstream_tls,
1342 location);
1343 if (tevent_req_nomem(state->tls_stream, req)) {
1344 return tevent_req_post(req, ev);
1346 ZERO_STRUCTP(tlss);
1347 talloc_set_destructor(tlss, tstream_tls_destructor);
1350 * Note we need to make sure x509_cred and dh_params
1351 * from tstream_tls_params_internal stay alive for
1352 * the whole lifetime of this session!
1354 * See 'man gnutls_credentials_set' and
1355 * 'man gnutls_certificate_set_dh_params'.
1357 * Note: here we use talloc_reference() in a way
1358 * that does not expose it to the caller.
1360 tlsp = talloc_reference(tlss, _tlsp->internal);
1361 if (tevent_req_nomem(tlsp, req)) {
1362 return tevent_req_post(req, ev);
1365 tlss->plain_stream = plain_stream;
1367 tlss->current_ev = ev;
1368 tlss->retry_im = tevent_create_immediate(tlss);
1369 if (tevent_req_nomem(tlss->retry_im, req)) {
1370 return tevent_req_post(req, ev);
1373 ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
1374 if (ret != GNUTLS_E_SUCCESS) {
1375 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1376 tevent_req_error(req, EINVAL);
1377 return tevent_req_post(req, ev);
1380 ret = gnutls_set_default_priority(tlss->tls_session);
1381 if (ret != GNUTLS_E_SUCCESS) {
1382 DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
1383 __location__, gnutls_strerror(ret));
1384 tevent_req_error(req, EINVAL);
1385 return tevent_req_post(req, ev);
1388 if (strlen(tlsp->tls_priority) > 0) {
1389 ret = gnutls_priority_set_direct(tlss->tls_session,
1390 tlsp->tls_priority,
1391 &error_pos);
1392 if (ret != GNUTLS_E_SUCCESS) {
1393 DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
1394 __location__, gnutls_strerror(ret), error_pos));
1395 tevent_req_error(req, EINVAL);
1396 return tevent_req_post(req, ev);
1400 ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
1401 tlsp->x509_cred);
1402 if (ret != GNUTLS_E_SUCCESS) {
1403 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1404 tevent_req_error(req, EINVAL);
1405 return tevent_req_post(req, ev);
1408 gnutls_certificate_server_set_request(tlss->tls_session,
1409 GNUTLS_CERT_REQUEST);
1410 gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
1412 gnutls_transport_set_ptr(tlss->tls_session,
1413 (gnutls_transport_ptr_t)state->tls_stream);
1414 gnutls_transport_set_pull_function(tlss->tls_session,
1415 (gnutls_pull_func)tstream_tls_pull_function);
1416 gnutls_transport_set_push_function(tlss->tls_session,
1417 (gnutls_push_func)tstream_tls_push_function);
1419 tlss->handshake.req = req;
1420 tstream_tls_retry_handshake(state->tls_stream);
1421 if (!tevent_req_is_in_progress(req)) {
1422 return tevent_req_post(req, ev);
1425 return req;
1428 static void tstream_tls_retry_handshake(struct tstream_context *stream)
1430 struct tstream_tls *tlss =
1431 tstream_context_data(stream,
1432 struct tstream_tls);
1433 struct tevent_req *req = tlss->handshake.req;
1434 int ret;
1436 if (tlss->error != 0) {
1437 tevent_req_error(req, tlss->error);
1438 return;
1441 ret = gnutls_handshake(tlss->tls_session);
1442 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1443 return;
1446 tlss->handshake.req = NULL;
1448 if (gnutls_error_is_fatal(ret) != 0) {
1449 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1450 tlss->error = EIO;
1451 tevent_req_error(req, tlss->error);
1452 return;
1455 if (ret != GNUTLS_E_SUCCESS) {
1456 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1457 tlss->error = EIO;
1458 tevent_req_error(req, tlss->error);
1459 return;
1462 if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) {
1463 unsigned int status = UINT32_MAX;
1464 bool ip = true;
1465 const char *hostname = NULL;
1467 if (tlss->peer_name != NULL) {
1468 ip = is_ipaddress(tlss->peer_name);
1471 if (!ip) {
1472 hostname = tlss->peer_name;
1475 if (tlss->verify_peer == TLS_VERIFY_PEER_CA_ONLY) {
1476 hostname = NULL;
1479 if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) {
1480 if (hostname == NULL) {
1481 DEBUG(1,("TLS %s - no hostname available for "
1482 "verify_peer[%s] and peer_name[%s]\n",
1483 __location__,
1484 tls_verify_peer_string(tlss->verify_peer),
1485 tlss->peer_name));
1486 tlss->error = EINVAL;
1487 tevent_req_error(req, tlss->error);
1488 return;
1492 ret = gnutls_certificate_verify_peers3(tlss->tls_session,
1493 hostname,
1494 &status);
1495 if (ret != GNUTLS_E_SUCCESS) {
1496 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1497 tlss->error = EIO;
1498 tevent_req_error(req, tlss->error);
1499 return;
1502 if (status != 0) {
1503 DEBUG(1,("TLS %s - check failed for "
1504 "verify_peer[%s] and peer_name[%s] "
1505 "status 0x%x (%s%s%s%s%s%s%s%s)\n",
1506 __location__,
1507 tls_verify_peer_string(tlss->verify_peer),
1508 tlss->peer_name,
1509 status,
1510 status & GNUTLS_CERT_INVALID ? "invalid " : "",
1511 status & GNUTLS_CERT_REVOKED ? "revoked " : "",
1512 status & GNUTLS_CERT_SIGNER_NOT_FOUND ?
1513 "signer_not_found " : "",
1514 status & GNUTLS_CERT_SIGNER_NOT_CA ?
1515 "signer_not_ca " : "",
1516 status & GNUTLS_CERT_INSECURE_ALGORITHM ?
1517 "insecure_algorithm " : "",
1518 status & GNUTLS_CERT_NOT_ACTIVATED ?
1519 "not_activated " : "",
1520 status & GNUTLS_CERT_EXPIRED ?
1521 "expired " : "",
1522 status & GNUTLS_CERT_UNEXPECTED_OWNER ?
1523 "unexptected_owner " : ""));
1524 tlss->error = EINVAL;
1525 tevent_req_error(req, tlss->error);
1526 return;
1530 tevent_req_done(req);
1533 int tstream_tls_accept_recv(struct tevent_req *req,
1534 int *perrno,
1535 TALLOC_CTX *mem_ctx,
1536 struct tstream_context **tls_stream)
1538 struct tstream_tls_accept_state *state =
1539 tevent_req_data(req,
1540 struct tstream_tls_accept_state);
1542 if (tevent_req_is_unix_error(req, perrno)) {
1543 tevent_req_received(req);
1544 return -1;
1547 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1548 tevent_req_received(req);
1549 return 0;