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/>.
21 #include "system/network.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "lib/util/util_file.h"
25 #include "../util/tevent_unix.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/tsocket/tsocket_internal.h"
28 #include "../lib/util/util_net.h"
29 #include "lib/tls/tls.h"
31 #include <gnutls/gnutls.h>
32 #include <gnutls/x509.h>
36 const char *tls_verify_peer_string(enum tls_verify_peer_state verify_peer)
38 switch (verify_peer) {
39 case TLS_VERIFY_PEER_NO_CHECK:
40 return TLS_VERIFY_PEER_NO_CHECK_STRING;
42 case TLS_VERIFY_PEER_CA_ONLY:
43 return TLS_VERIFY_PEER_CA_ONLY_STRING;
45 case TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE:
46 return TLS_VERIFY_PEER_CA_AND_NAME_IF_AVAILABLE_STRING;
48 case TLS_VERIFY_PEER_CA_AND_NAME:
49 return TLS_VERIFY_PEER_CA_AND_NAME_STRING;
51 case TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE:
52 return TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE_STRING;
55 return "unknown tls_verify_peer_state";
58 static const struct tstream_context_ops tstream_tls_ops;
61 struct tstream_context *plain_stream;
64 gnutls_session_t tls_session;
66 enum tls_verify_peer_state verify_peer;
67 const char *peer_name;
69 struct tevent_context *current_ev;
71 struct tevent_immediate *retry_im;
77 struct tevent_req *subreq;
83 struct tevent_req *subreq;
87 struct tevent_req *req;
94 struct tevent_req *req;
100 uint8_t buffer[1024];
101 struct tevent_req *req;
105 struct tevent_req *req;
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,
117 static void tstream_tls_retry(struct tstream_context *stream, bool deferred)
120 struct tstream_tls *tlss =
121 tstream_context_data(stream,
124 if (tlss->disconnect.req) {
125 tstream_tls_retry_disconnect(stream);
129 if (tlss->handshake.req) {
130 tstream_tls_retry_handshake(stream);
134 if (tlss->write.req && tlss->read.req && !deferred) {
135 tevent_schedule_immediate(tlss->retry_im, tlss->current_ev,
136 tstream_tls_retry_trigger,
140 if (tlss->write.req) {
141 tstream_tls_retry_write(stream);
145 if (tlss->read.req) {
146 tstream_tls_retry_read(stream);
151 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
152 struct tevent_immediate *im,
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_done(struct tevent_req *subreq);
164 static ssize_t tstream_tls_push_function(gnutls_transport_ptr_t ptr,
165 const void *buf, size_t size)
167 struct tstream_context *stream =
168 talloc_get_type_abort(ptr,
169 struct tstream_context);
170 struct tstream_tls *tlss =
171 tstream_context_data(stream,
173 struct tevent_req *subreq = NULL;
177 if (tlss->error != 0) {
182 if (tlss->push.subreq) {
187 len = MIN(size, UINT16_MAX - tlss->push.ofs);
194 nbuf = talloc_realloc(tlss, tlss->push.buf,
195 uint8_t, tlss->push.ofs + len);
197 if (tlss->push.buf) {
204 tlss->push.buf = nbuf;
206 memcpy(tlss->push.buf + tlss->push.ofs, buf, len);
207 tlss->push.ofs += len;
209 tlss->push.iov.iov_base = (char *)tlss->push.buf;
210 tlss->push.iov.iov_len = tlss->push.ofs;
212 subreq = tstream_writev_send(tlss,
216 if (subreq == NULL) {
220 tevent_req_set_callback(subreq, tstream_tls_push_done, stream);
222 tlss->push.subreq = subreq;
226 static void tstream_tls_push_done(struct tevent_req *subreq)
228 struct tstream_context *stream =
229 tevent_req_callback_data(subreq,
230 struct tstream_context);
231 struct tstream_tls *tlss =
232 tstream_context_data(stream,
237 tlss->push.subreq = NULL;
238 ZERO_STRUCT(tlss->push.iov);
239 TALLOC_FREE(tlss->push.buf);
242 ret = tstream_writev_recv(subreq, &sys_errno);
245 tlss->error = sys_errno;
246 tstream_tls_retry(stream, false);
250 tstream_tls_retry(stream, false);
253 static void tstream_tls_pull_done(struct tevent_req *subreq);
255 static ssize_t tstream_tls_pull_function(gnutls_transport_ptr_t ptr,
256 void *buf, size_t size)
258 struct tstream_context *stream =
259 talloc_get_type_abort(ptr,
260 struct tstream_context);
261 struct tstream_tls *tlss =
262 tstream_context_data(stream,
264 struct tevent_req *subreq;
267 if (tlss->error != 0) {
272 if (tlss->pull.subreq) {
277 if (tlss->pull.iov.iov_base) {
281 b = (uint8_t *)tlss->pull.iov.iov_base;
283 n = MIN(tlss->pull.iov.iov_len, size);
286 tlss->pull.iov.iov_len -= n;
288 tlss->pull.iov.iov_base = (char *)b;
289 if (tlss->pull.iov.iov_len == 0) {
290 tlss->pull.iov.iov_base = NULL;
291 TALLOC_FREE(tlss->pull.buf);
301 len = MIN(size, UINT16_MAX);
303 tlss->pull.buf = talloc_array(tlss, uint8_t, len);
304 if (tlss->pull.buf == NULL) {
308 tlss->pull.iov.iov_base = (char *)tlss->pull.buf;
309 tlss->pull.iov.iov_len = len;
311 subreq = tstream_readv_send(tlss,
315 if (subreq == NULL) {
319 tevent_req_set_callback(subreq, tstream_tls_pull_done, stream);
321 tlss->pull.subreq = subreq;
326 static void tstream_tls_pull_done(struct tevent_req *subreq)
328 struct tstream_context *stream =
329 tevent_req_callback_data(subreq,
330 struct tstream_context);
331 struct tstream_tls *tlss =
332 tstream_context_data(stream,
337 tlss->pull.subreq = NULL;
339 ret = tstream_readv_recv(subreq, &sys_errno);
342 tlss->error = sys_errno;
343 tstream_tls_retry(stream, false);
347 tstream_tls_retry(stream, false);
350 static int tstream_tls_destructor(struct tstream_tls *tlss)
352 if (tlss->tls_session) {
353 gnutls_deinit(tlss->tls_session);
354 tlss->tls_session = NULL;
360 static ssize_t tstream_tls_pending_bytes(struct tstream_context *stream)
362 struct tstream_tls *tlss =
363 tstream_context_data(stream,
367 if (tlss->error != 0) {
372 ret = gnutls_record_check_pending(tlss->tls_session);
373 ret += tlss->read.left;
378 struct tstream_tls_readv_state {
379 struct tstream_context *stream;
381 struct iovec *vector;
387 static void tstream_tls_readv_crypt_next(struct tevent_req *req);
389 static struct tevent_req *tstream_tls_readv_send(TALLOC_CTX *mem_ctx,
390 struct tevent_context *ev,
391 struct tstream_context *stream,
392 struct iovec *vector,
395 struct tstream_tls *tlss =
396 tstream_context_data(stream,
398 struct tevent_req *req;
399 struct tstream_tls_readv_state *state;
401 tlss->read.req = NULL;
402 tlss->current_ev = ev;
404 req = tevent_req_create(mem_ctx, &state,
405 struct tstream_tls_readv_state);
410 state->stream = stream;
413 if (tlss->error != 0) {
414 tevent_req_error(req, tlss->error);
415 return tevent_req_post(req, ev);
419 * we make a copy of the vector so we can change the structure
421 state->vector = talloc_array(state, struct iovec, count);
422 if (tevent_req_nomem(state->vector, req)) {
423 return tevent_req_post(req, ev);
425 memcpy(state->vector, vector, sizeof(struct iovec) * count);
426 state->count = count;
428 tstream_tls_readv_crypt_next(req);
429 if (!tevent_req_is_in_progress(req)) {
430 return tevent_req_post(req, ev);
436 static void tstream_tls_readv_crypt_next(struct tevent_req *req)
438 struct tstream_tls_readv_state *state =
440 struct tstream_tls_readv_state);
441 struct tstream_tls *tlss =
442 tstream_context_data(state->stream,
446 * copy the pending buffer first
448 while (tlss->read.left > 0 && state->count > 0) {
449 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
450 size_t len = MIN(tlss->read.left, state->vector[0].iov_len);
452 memcpy(base, tlss->read.buffer + tlss->read.ofs, len);
455 state->vector[0].iov_base = (char *) base;
456 state->vector[0].iov_len -= len;
458 tlss->read.ofs += len;
459 tlss->read.left -= len;
461 if (state->vector[0].iov_len == 0) {
469 if (state->count == 0) {
470 tevent_req_done(req);
474 tlss->read.req = req;
475 tstream_tls_retry_read(state->stream);
478 static void tstream_tls_retry_read(struct tstream_context *stream)
480 struct tstream_tls *tlss =
481 tstream_context_data(stream,
483 struct tevent_req *req = tlss->read.req;
486 if (tlss->error != 0) {
487 tevent_req_error(req, tlss->error);
494 ret = gnutls_record_recv(tlss->tls_session,
496 sizeof(tlss->read.buffer));
497 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
501 tlss->read.req = NULL;
503 if (gnutls_error_is_fatal(ret) != 0) {
504 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
506 tevent_req_error(req, tlss->error);
512 tevent_req_error(req, tlss->error);
516 tlss->read.left = ret;
517 tstream_tls_readv_crypt_next(req);
520 static int tstream_tls_readv_recv(struct tevent_req *req,
523 struct tstream_tls_readv_state *state =
525 struct tstream_tls_readv_state);
526 struct tstream_tls *tlss =
527 tstream_context_data(state->stream,
531 tlss->read.req = NULL;
533 ret = tsocket_simple_int_recv(req, perrno);
538 tevent_req_received(req);
542 struct tstream_tls_writev_state {
543 struct tstream_context *stream;
545 struct iovec *vector;
551 static void tstream_tls_writev_crypt_next(struct tevent_req *req);
553 static struct tevent_req *tstream_tls_writev_send(TALLOC_CTX *mem_ctx,
554 struct tevent_context *ev,
555 struct tstream_context *stream,
556 const struct iovec *vector,
559 struct tstream_tls *tlss =
560 tstream_context_data(stream,
562 struct tevent_req *req;
563 struct tstream_tls_writev_state *state;
565 tlss->write.req = NULL;
566 tlss->current_ev = ev;
568 req = tevent_req_create(mem_ctx, &state,
569 struct tstream_tls_writev_state);
574 state->stream = stream;
577 if (tlss->error != 0) {
578 tevent_req_error(req, tlss->error);
579 return tevent_req_post(req, ev);
583 * we make a copy of the vector so we can change the structure
585 state->vector = talloc_array(state, struct iovec, count);
586 if (tevent_req_nomem(state->vector, req)) {
587 return tevent_req_post(req, ev);
589 memcpy(state->vector, vector, sizeof(struct iovec) * count);
590 state->count = count;
592 tstream_tls_writev_crypt_next(req);
593 if (!tevent_req_is_in_progress(req)) {
594 return tevent_req_post(req, ev);
600 static void tstream_tls_writev_crypt_next(struct tevent_req *req)
602 struct tstream_tls_writev_state *state =
604 struct tstream_tls_writev_state);
605 struct tstream_tls *tlss =
606 tstream_context_data(state->stream,
609 tlss->write.left = sizeof(tlss->write.buffer);
613 * first fill our buffer
615 while (tlss->write.left > 0 && state->count > 0) {
616 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
617 size_t len = MIN(tlss->write.left, state->vector[0].iov_len);
619 memcpy(tlss->write.buffer + tlss->write.ofs, base, len);
622 state->vector[0].iov_base = (char *) base;
623 state->vector[0].iov_len -= len;
625 tlss->write.ofs += len;
626 tlss->write.left -= len;
628 if (state->vector[0].iov_len == 0) {
636 if (tlss->write.ofs == 0) {
637 tevent_req_done(req);
641 tlss->write.left = tlss->write.ofs;
644 tlss->write.req = req;
645 tstream_tls_retry_write(state->stream);
648 static void tstream_tls_retry_write(struct tstream_context *stream)
650 struct tstream_tls *tlss =
651 tstream_context_data(stream,
653 struct tevent_req *req = tlss->write.req;
656 if (tlss->error != 0) {
657 tevent_req_error(req, tlss->error);
661 ret = gnutls_record_send(tlss->tls_session,
662 tlss->write.buffer + tlss->write.ofs,
664 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
668 tlss->write.req = NULL;
670 if (gnutls_error_is_fatal(ret) != 0) {
671 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
673 tevent_req_error(req, tlss->error);
679 tevent_req_error(req, tlss->error);
683 tlss->write.ofs += ret;
684 tlss->write.left -= ret;
686 if (tlss->write.left > 0) {
687 tlss->write.req = req;
688 tstream_tls_retry_write(stream);
692 tstream_tls_writev_crypt_next(req);
695 static int tstream_tls_writev_recv(struct tevent_req *req,
698 struct tstream_tls_writev_state *state =
700 struct tstream_tls_writev_state);
701 struct tstream_tls *tlss =
702 tstream_context_data(state->stream,
706 tlss->write.req = NULL;
708 ret = tsocket_simple_int_recv(req, perrno);
713 tevent_req_received(req);
717 struct tstream_tls_disconnect_state {
721 static struct tevent_req *tstream_tls_disconnect_send(TALLOC_CTX *mem_ctx,
722 struct tevent_context *ev,
723 struct tstream_context *stream)
725 struct tstream_tls *tlss =
726 tstream_context_data(stream,
728 struct tevent_req *req;
729 struct tstream_tls_disconnect_state *state;
731 tlss->disconnect.req = NULL;
732 tlss->current_ev = ev;
734 req = tevent_req_create(mem_ctx, &state,
735 struct tstream_tls_disconnect_state);
740 if (tlss->error != 0) {
741 tevent_req_error(req, tlss->error);
742 return tevent_req_post(req, ev);
745 tlss->disconnect.req = req;
746 tstream_tls_retry_disconnect(stream);
747 if (!tevent_req_is_in_progress(req)) {
748 return tevent_req_post(req, ev);
754 static void tstream_tls_retry_disconnect(struct tstream_context *stream)
756 struct tstream_tls *tlss =
757 tstream_context_data(stream,
759 struct tevent_req *req = tlss->disconnect.req;
762 if (tlss->error != 0) {
763 tevent_req_error(req, tlss->error);
767 ret = gnutls_bye(tlss->tls_session, GNUTLS_SHUT_WR);
768 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
772 tlss->disconnect.req = NULL;
774 if (gnutls_error_is_fatal(ret) != 0) {
775 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
777 tevent_req_error(req, tlss->error);
781 if (ret != GNUTLS_E_SUCCESS) {
782 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
784 tevent_req_error(req, tlss->error);
788 tevent_req_done(req);
791 static int tstream_tls_disconnect_recv(struct tevent_req *req,
796 ret = tsocket_simple_int_recv(req, perrno);
798 tevent_req_received(req);
802 static const struct tstream_context_ops tstream_tls_ops = {
805 .pending_bytes = tstream_tls_pending_bytes,
807 .readv_send = tstream_tls_readv_send,
808 .readv_recv = tstream_tls_readv_recv,
810 .writev_send = tstream_tls_writev_send,
811 .writev_recv = tstream_tls_writev_recv,
813 .disconnect_send = tstream_tls_disconnect_send,
814 .disconnect_recv = tstream_tls_disconnect_recv,
817 struct tstream_tls_params_internal {
818 gnutls_certificate_credentials_t x509_cred;
819 gnutls_dh_params_t dh_params;
820 const char *tls_priority;
822 enum tls_verify_peer_state verify_peer;
823 const char *peer_name;
826 struct tstream_tls_params {
827 struct tstream_tls_params_internal *internal;
830 static int tstream_tls_params_internal_destructor(struct tstream_tls_params_internal *tlsp)
832 if (tlsp->x509_cred) {
833 gnutls_certificate_free_credentials(tlsp->x509_cred);
834 tlsp->x509_cred = NULL;
836 if (tlsp->dh_params) {
837 gnutls_dh_params_deinit(tlsp->dh_params);
838 tlsp->dh_params = NULL;
844 bool tstream_tls_params_enabled(struct tstream_tls_params *tls_params)
846 struct tstream_tls_params_internal *tlsp = tls_params->internal;
848 return tlsp->tls_enabled;
851 NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
853 const char *crl_file,
854 const char *tls_priority,
855 enum tls_verify_peer_state verify_peer,
856 const char *peer_name,
857 struct tstream_tls_params **_tlsp)
859 struct tstream_tls_params *__tlsp = NULL;
860 struct tstream_tls_params_internal *tlsp = NULL;
863 __tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
864 if (__tlsp == NULL) {
865 return NT_STATUS_NO_MEMORY;
868 tlsp = talloc_zero(__tlsp, struct tstream_tls_params_internal);
871 return NT_STATUS_NO_MEMORY;
873 talloc_set_destructor(tlsp, tstream_tls_params_internal_destructor);
874 __tlsp->internal = tlsp;
876 tlsp->verify_peer = verify_peer;
877 if (peer_name != NULL) {
878 tlsp->peer_name = talloc_strdup(tlsp, peer_name);
879 if (tlsp->peer_name == NULL) {
881 return NT_STATUS_NO_MEMORY;
883 } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) {
884 DEBUG(0,("TLS failed to missing peer_name - "
885 "with 'tls verify peer = %s'\n",
886 tls_verify_peer_string(tlsp->verify_peer)));
888 return NT_STATUS_INVALID_PARAMETER_MIX;
891 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
892 if (ret != GNUTLS_E_SUCCESS) {
893 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
895 return NT_STATUS_NO_MEMORY;
898 if (ca_file && *ca_file && file_exist(ca_file)) {
899 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
901 GNUTLS_X509_FMT_PEM);
903 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
904 ca_file, gnutls_strerror(ret)));
906 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
908 } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) {
909 DEBUG(0,("TLS failed to missing cafile %s - "
910 "with 'tls verify peer = %s'\n",
912 tls_verify_peer_string(tlsp->verify_peer)));
914 return NT_STATUS_INVALID_PARAMETER_MIX;
917 if (crl_file && *crl_file && file_exist(crl_file)) {
918 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
920 GNUTLS_X509_FMT_PEM);
922 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
923 crl_file, gnutls_strerror(ret)));
925 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
927 } else if (tlsp->verify_peer >= TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE) {
928 DEBUG(0,("TLS failed to missing crlfile %s - "
929 "with 'tls verify peer = %s'\n",
931 tls_verify_peer_string(tlsp->verify_peer)));
933 return NT_STATUS_INVALID_PARAMETER_MIX;
936 tlsp->tls_priority = talloc_strdup(tlsp, tls_priority);
937 if (tlsp->tls_priority == NULL) {
939 return NT_STATUS_NO_MEMORY;
942 tlsp->tls_enabled = true;
948 struct tstream_tls_connect_state {
949 struct tstream_context *tls_stream;
952 struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
953 struct tevent_context *ev,
954 struct tstream_context *plain_stream,
955 struct tstream_tls_params *_tls_params,
956 const char *location)
958 struct tevent_req *req;
959 struct tstream_tls_connect_state *state;
960 const char *error_pos;
961 struct tstream_tls *tlss;
962 struct tstream_tls_params_internal *tls_params = NULL;
964 unsigned int flags = GNUTLS_CLIENT;
966 req = tevent_req_create(mem_ctx, &state,
967 struct tstream_tls_connect_state);
972 state->tls_stream = tstream_context_create(state,
977 if (tevent_req_nomem(state->tls_stream, req)) {
978 return tevent_req_post(req, ev);
981 talloc_set_destructor(tlss, tstream_tls_destructor);
984 * Note we need to make sure x509_cred and dh_params
985 * from tstream_tls_params_internal stay alive for
986 * the whole lifetime of this session!
988 * See 'man gnutls_credentials_set' and
989 * 'man gnutls_certificate_set_dh_params'.
991 * Note: here we use talloc_reference() in a way
992 * that does not expose it to the caller.
995 tls_params = talloc_reference(tlss, _tls_params->internal);
996 if (tevent_req_nomem(tls_params, req)) {
997 return tevent_req_post(req, ev);
1000 tlss->plain_stream = plain_stream;
1001 tlss->verify_peer = tls_params->verify_peer;
1002 if (tls_params->peer_name != NULL) {
1003 tlss->peer_name = talloc_strdup(tlss, tls_params->peer_name);
1004 if (tevent_req_nomem(tlss->peer_name, req)) {
1005 return tevent_req_post(req, ev);
1009 tlss->current_ev = ev;
1010 tlss->retry_im = tevent_create_immediate(tlss);
1011 if (tevent_req_nomem(tlss->retry_im, req)) {
1012 return tevent_req_post(req, ev);
1015 #ifdef GNUTLS_NO_TICKETS
1017 * tls_tstream can't properly handle 'New Session Ticket' messages
1018 * sent 'after' the client sends the 'Finished' message.
1019 * GNUTLS_NO_TICKETS was introduced in GnuTLS 3.5.6. This flag is to
1020 * indicate the session Flag session should not use resumption with
1023 flags |= GNUTLS_NO_TICKETS;
1026 ret = gnutls_init(&tlss->tls_session, flags);
1027 if (ret != GNUTLS_E_SUCCESS) {
1028 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1029 tevent_req_error(req, EINVAL);
1030 return tevent_req_post(req, ev);
1033 ret = gnutls_set_default_priority(tlss->tls_session);
1034 if (ret != GNUTLS_E_SUCCESS) {
1035 DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
1036 __location__, gnutls_strerror(ret));
1037 tevent_req_error(req, EINVAL);
1038 return tevent_req_post(req, ev);
1041 if (strlen(tls_params->tls_priority) > 0) {
1042 ret = gnutls_priority_set_direct(tlss->tls_session,
1043 tls_params->tls_priority,
1045 if (ret != GNUTLS_E_SUCCESS) {
1046 DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
1047 __location__, gnutls_strerror(ret), error_pos));
1048 tevent_req_error(req, EINVAL);
1049 return tevent_req_post(req, ev);
1053 ret = gnutls_credentials_set(tlss->tls_session,
1054 GNUTLS_CRD_CERTIFICATE,
1055 tls_params->x509_cred);
1056 if (ret != GNUTLS_E_SUCCESS) {
1057 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1058 tevent_req_error(req, EINVAL);
1059 return tevent_req_post(req, ev);
1062 gnutls_transport_set_ptr(tlss->tls_session,
1063 (gnutls_transport_ptr_t)state->tls_stream);
1064 gnutls_transport_set_pull_function(tlss->tls_session,
1065 (gnutls_pull_func)tstream_tls_pull_function);
1066 gnutls_transport_set_push_function(tlss->tls_session,
1067 (gnutls_push_func)tstream_tls_push_function);
1069 tlss->handshake.req = req;
1070 tstream_tls_retry_handshake(state->tls_stream);
1071 if (!tevent_req_is_in_progress(req)) {
1072 return tevent_req_post(req, ev);
1078 int tstream_tls_connect_recv(struct tevent_req *req,
1080 TALLOC_CTX *mem_ctx,
1081 struct tstream_context **tls_stream)
1083 struct tstream_tls_connect_state *state =
1084 tevent_req_data(req,
1085 struct tstream_tls_connect_state);
1087 if (tevent_req_is_unix_error(req, perrno)) {
1088 tevent_req_received(req);
1092 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1093 tevent_req_received(req);
1098 initialise global tls state
1100 NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
1101 const char *dns_host_name,
1103 const char *key_file,
1104 const char *cert_file,
1105 const char *ca_file,
1106 const char *crl_file,
1107 const char *dhp_file,
1108 const char *tls_priority,
1109 struct tstream_tls_params **_tlsp)
1111 struct tstream_tls_params *__tlsp = NULL;
1112 struct tstream_tls_params_internal *tlsp = NULL;
1116 if (!enabled || key_file == NULL || *key_file == 0) {
1117 __tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1118 if (__tlsp == NULL) {
1119 return NT_STATUS_NO_MEMORY;
1122 tlsp = talloc_zero(__tlsp, struct tstream_tls_params_internal);
1124 TALLOC_FREE(__tlsp);
1125 return NT_STATUS_NO_MEMORY;
1128 talloc_set_destructor(tlsp, tstream_tls_params_internal_destructor);
1129 __tlsp->internal = tlsp;
1130 tlsp->tls_enabled = false;
1133 return NT_STATUS_OK;
1136 __tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1137 if (__tlsp == NULL) {
1138 return NT_STATUS_NO_MEMORY;
1141 tlsp = talloc_zero(__tlsp, struct tstream_tls_params_internal);
1143 TALLOC_FREE(__tlsp);
1144 return NT_STATUS_NO_MEMORY;
1147 talloc_set_destructor(tlsp, tstream_tls_params_internal_destructor);
1148 __tlsp->internal = tlsp;
1150 if (!file_exist(ca_file)) {
1151 tls_cert_generate(tlsp, dns_host_name,
1152 key_file, cert_file, ca_file);
1155 if (file_exist(key_file) &&
1156 !file_check_permissions(key_file, geteuid(), 0600, &st))
1158 DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n"
1159 "owner uid %u should be %u, mode 0%o should be 0%o\n"
1160 "This is known as CVE-2013-4476.\n"
1161 "Removing all tls .pem files will cause an "
1162 "auto-regeneration with the correct permissions.\n",
1164 (unsigned int)st.st_uid, geteuid(),
1165 (unsigned int)(st.st_mode & 0777), 0600));
1166 TALLOC_FREE(__tlsp);
1167 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1170 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
1171 if (ret != GNUTLS_E_SUCCESS) {
1172 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1173 TALLOC_FREE(__tlsp);
1174 return NT_STATUS_NO_MEMORY;
1177 if (ca_file && *ca_file) {
1178 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1180 GNUTLS_X509_FMT_PEM);
1182 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1183 ca_file, gnutls_strerror(ret)));
1184 TALLOC_FREE(__tlsp);
1185 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1189 if (crl_file && *crl_file) {
1190 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
1192 GNUTLS_X509_FMT_PEM);
1194 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1195 crl_file, gnutls_strerror(ret)));
1196 TALLOC_FREE(__tlsp);
1197 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1201 ret = gnutls_certificate_set_x509_key_file(tlsp->x509_cred,
1202 cert_file, key_file,
1203 GNUTLS_X509_FMT_PEM);
1204 if (ret != GNUTLS_E_SUCCESS) {
1205 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1206 cert_file, key_file, gnutls_strerror(ret)));
1207 TALLOC_FREE(__tlsp);
1208 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1211 ret = gnutls_dh_params_init(&tlsp->dh_params);
1212 if (ret != GNUTLS_E_SUCCESS) {
1213 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1214 TALLOC_FREE(__tlsp);
1215 return NT_STATUS_NO_MEMORY;
1218 if (dhp_file && *dhp_file) {
1219 gnutls_datum_t dhparms;
1222 dhparms.data = (uint8_t *)file_load(dhp_file, &size, 0, tlsp);
1224 if (!dhparms.data) {
1225 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1226 dhp_file, errno, strerror(errno)));
1227 TALLOC_FREE(__tlsp);
1228 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1230 dhparms.size = size;
1232 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1234 GNUTLS_X509_FMT_PEM);
1235 if (ret != GNUTLS_E_SUCCESS) {
1236 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1237 dhp_file, gnutls_strerror(ret)));
1238 TALLOC_FREE(__tlsp);
1239 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1242 ret = gnutls_dh_params_generate2(tlsp->dh_params, DH_BITS);
1243 if (ret != GNUTLS_E_SUCCESS) {
1244 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1245 gnutls_strerror(ret)));
1246 TALLOC_FREE(__tlsp);
1247 return NT_STATUS_INTERNAL_ERROR;
1251 gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
1253 tlsp->tls_priority = talloc_strdup(tlsp, tls_priority);
1254 if (tlsp->tls_priority == NULL) {
1255 TALLOC_FREE(__tlsp);
1256 return NT_STATUS_NO_MEMORY;
1259 tlsp->tls_enabled = true;
1262 return NT_STATUS_OK;
1265 struct tstream_tls_accept_state {
1266 struct tstream_context *tls_stream;
1269 struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
1270 struct tevent_context *ev,
1271 struct tstream_context *plain_stream,
1272 struct tstream_tls_params *_tlsp,
1273 const char *location)
1275 struct tevent_req *req;
1276 struct tstream_tls_accept_state *state;
1277 struct tstream_tls *tlss;
1278 const char *error_pos;
1279 struct tstream_tls_params_internal *tlsp = NULL;
1282 req = tevent_req_create(mem_ctx, &state,
1283 struct tstream_tls_accept_state);
1288 state->tls_stream = tstream_context_create(state,
1293 if (tevent_req_nomem(state->tls_stream, req)) {
1294 return tevent_req_post(req, ev);
1297 talloc_set_destructor(tlss, tstream_tls_destructor);
1300 * Note we need to make sure x509_cred and dh_params
1301 * from tstream_tls_params_internal stay alive for
1302 * the whole lifetime of this session!
1304 * See 'man gnutls_credentials_set' and
1305 * 'man gnutls_certificate_set_dh_params'.
1307 * Note: here we use talloc_reference() in a way
1308 * that does not expose it to the caller.
1310 tlsp = talloc_reference(tlss, _tlsp->internal);
1311 if (tevent_req_nomem(tlsp, req)) {
1312 return tevent_req_post(req, ev);
1315 tlss->plain_stream = plain_stream;
1317 tlss->current_ev = ev;
1318 tlss->retry_im = tevent_create_immediate(tlss);
1319 if (tevent_req_nomem(tlss->retry_im, req)) {
1320 return tevent_req_post(req, ev);
1323 ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
1324 if (ret != GNUTLS_E_SUCCESS) {
1325 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1326 tevent_req_error(req, EINVAL);
1327 return tevent_req_post(req, ev);
1330 ret = gnutls_set_default_priority(tlss->tls_session);
1331 if (ret != GNUTLS_E_SUCCESS) {
1332 DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
1333 __location__, gnutls_strerror(ret));
1334 tevent_req_error(req, EINVAL);
1335 return tevent_req_post(req, ev);
1338 if (strlen(tlsp->tls_priority) > 0) {
1339 ret = gnutls_priority_set_direct(tlss->tls_session,
1342 if (ret != GNUTLS_E_SUCCESS) {
1343 DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
1344 __location__, gnutls_strerror(ret), error_pos));
1345 tevent_req_error(req, EINVAL);
1346 return tevent_req_post(req, ev);
1350 ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
1352 if (ret != GNUTLS_E_SUCCESS) {
1353 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1354 tevent_req_error(req, EINVAL);
1355 return tevent_req_post(req, ev);
1358 gnutls_certificate_server_set_request(tlss->tls_session,
1359 GNUTLS_CERT_REQUEST);
1360 gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
1362 gnutls_transport_set_ptr(tlss->tls_session,
1363 (gnutls_transport_ptr_t)state->tls_stream);
1364 gnutls_transport_set_pull_function(tlss->tls_session,
1365 (gnutls_pull_func)tstream_tls_pull_function);
1366 gnutls_transport_set_push_function(tlss->tls_session,
1367 (gnutls_push_func)tstream_tls_push_function);
1369 tlss->handshake.req = req;
1370 tstream_tls_retry_handshake(state->tls_stream);
1371 if (!tevent_req_is_in_progress(req)) {
1372 return tevent_req_post(req, ev);
1378 static void tstream_tls_retry_handshake(struct tstream_context *stream)
1380 struct tstream_tls *tlss =
1381 tstream_context_data(stream,
1382 struct tstream_tls);
1383 struct tevent_req *req = tlss->handshake.req;
1386 if (tlss->error != 0) {
1387 tevent_req_error(req, tlss->error);
1391 ret = gnutls_handshake(tlss->tls_session);
1392 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1396 tlss->handshake.req = NULL;
1398 if (gnutls_error_is_fatal(ret) != 0) {
1399 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1401 tevent_req_error(req, tlss->error);
1405 if (ret != GNUTLS_E_SUCCESS) {
1406 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1408 tevent_req_error(req, tlss->error);
1412 if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_ONLY) {
1413 unsigned int status = UINT32_MAX;
1415 const char *hostname = NULL;
1417 if (tlss->peer_name != NULL) {
1418 ip = is_ipaddress(tlss->peer_name);
1422 hostname = tlss->peer_name;
1425 if (tlss->verify_peer == TLS_VERIFY_PEER_CA_ONLY) {
1429 if (tlss->verify_peer >= TLS_VERIFY_PEER_CA_AND_NAME) {
1430 if (hostname == NULL) {
1431 DEBUG(1,("TLS %s - no hostname available for "
1432 "verify_peer[%s] and peer_name[%s]\n",
1434 tls_verify_peer_string(tlss->verify_peer),
1436 tlss->error = EINVAL;
1437 tevent_req_error(req, tlss->error);
1442 ret = gnutls_certificate_verify_peers3(tlss->tls_session,
1445 if (ret != GNUTLS_E_SUCCESS) {
1446 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1448 tevent_req_error(req, tlss->error);
1453 DEBUG(1,("TLS %s - check failed for "
1454 "verify_peer[%s] and peer_name[%s] "
1455 "status 0x%x (%s%s%s%s%s%s%s%s)\n",
1457 tls_verify_peer_string(tlss->verify_peer),
1460 status & GNUTLS_CERT_INVALID ? "invalid " : "",
1461 status & GNUTLS_CERT_REVOKED ? "revoked " : "",
1462 status & GNUTLS_CERT_SIGNER_NOT_FOUND ?
1463 "signer_not_found " : "",
1464 status & GNUTLS_CERT_SIGNER_NOT_CA ?
1465 "signer_not_ca " : "",
1466 status & GNUTLS_CERT_INSECURE_ALGORITHM ?
1467 "insecure_algorithm " : "",
1468 status & GNUTLS_CERT_NOT_ACTIVATED ?
1469 "not_activated " : "",
1470 status & GNUTLS_CERT_EXPIRED ?
1472 status & GNUTLS_CERT_UNEXPECTED_OWNER ?
1473 "unexpected_owner " : ""));
1474 tlss->error = EINVAL;
1475 tevent_req_error(req, tlss->error);
1480 tevent_req_done(req);
1483 int tstream_tls_accept_recv(struct tevent_req *req,
1485 TALLOC_CTX *mem_ctx,
1486 struct tstream_context **tls_stream)
1488 struct tstream_tls_accept_state *state =
1489 tevent_req_data(req,
1490 struct tstream_tls_accept_state);
1492 if (tevent_req_is_unix_error(req, perrno)) {
1493 tevent_req_received(req);
1497 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1498 tevent_req_received(req);