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
;
74 struct tevent_req
*mgmt_req
;
81 struct tevent_req
*subreq
;
87 struct tevent_req
*subreq
;
91 struct tevent_req
*req
;
98 struct tevent_req
*req
;
104 uint8_t buffer
[1024];
105 struct tevent_req
*req
;
109 struct tevent_req
*req
;
113 static void tstream_tls_retry_handshake(struct tstream_context
*stream
);
114 static void tstream_tls_retry_read(struct tstream_context
*stream
);
115 static void tstream_tls_retry_write(struct tstream_context
*stream
);
116 static void tstream_tls_retry_disconnect(struct tstream_context
*stream
);
117 static void tstream_tls_retry_trigger(struct tevent_context
*ctx
,
118 struct tevent_immediate
*im
,
121 static void tstream_tls_retry(struct tstream_context
*stream
, bool deferred
)
124 struct tstream_tls
*tlss
=
125 tstream_context_data(stream
,
128 if (tlss
->push
.subreq
== NULL
&& tlss
->pull
.subreq
== NULL
) {
129 if (tlss
->waiting_flush
.mgmt_req
!= NULL
) {
130 struct tevent_req
*req
= tlss
->waiting_flush
.mgmt_req
;
132 tlss
->waiting_flush
.mgmt_req
= NULL
;
134 tevent_req_done(req
);
139 if (tlss
->disconnect
.req
) {
140 tstream_tls_retry_disconnect(stream
);
144 if (tlss
->handshake
.req
) {
145 tstream_tls_retry_handshake(stream
);
149 if (tlss
->write
.req
&& tlss
->read
.req
&& !deferred
) {
150 tevent_schedule_immediate(tlss
->retry_im
, tlss
->current_ev
,
151 tstream_tls_retry_trigger
,
155 if (tlss
->write
.req
) {
156 tstream_tls_retry_write(stream
);
160 if (tlss
->read
.req
) {
161 tstream_tls_retry_read(stream
);
166 static void tstream_tls_retry_trigger(struct tevent_context
*ctx
,
167 struct tevent_immediate
*im
,
170 struct tstream_context
*stream
=
171 talloc_get_type_abort(private_data
,
172 struct tstream_context
);
174 tstream_tls_retry(stream
, true);
177 static void tstream_tls_push_done(struct tevent_req
*subreq
);
179 static ssize_t
tstream_tls_push_function(gnutls_transport_ptr_t ptr
,
180 const void *buf
, size_t size
)
182 struct tstream_context
*stream
=
183 talloc_get_type_abort(ptr
,
184 struct tstream_context
);
185 struct tstream_tls
*tlss
=
186 tstream_context_data(stream
,
188 struct tevent_req
*subreq
= NULL
;
192 if (tlss
->error
!= 0) {
197 if (tlss
->push
.subreq
) {
202 len
= MIN(size
, UINT16_MAX
- tlss
->push
.ofs
);
209 nbuf
= talloc_realloc(tlss
, tlss
->push
.buf
,
210 uint8_t, tlss
->push
.ofs
+ len
);
212 if (tlss
->push
.buf
) {
219 tlss
->push
.buf
= nbuf
;
221 memcpy(tlss
->push
.buf
+ tlss
->push
.ofs
, buf
, len
);
222 tlss
->push
.ofs
+= len
;
224 tlss
->push
.iov
.iov_base
= (char *)tlss
->push
.buf
;
225 tlss
->push
.iov
.iov_len
= tlss
->push
.ofs
;
227 subreq
= tstream_writev_send(tlss
,
231 if (subreq
== NULL
) {
235 tevent_req_set_callback(subreq
, tstream_tls_push_done
, stream
);
237 tlss
->push
.subreq
= subreq
;
241 static void tstream_tls_push_done(struct tevent_req
*subreq
)
243 struct tstream_context
*stream
=
244 tevent_req_callback_data(subreq
,
245 struct tstream_context
);
246 struct tstream_tls
*tlss
=
247 tstream_context_data(stream
,
252 tlss
->push
.subreq
= NULL
;
253 ZERO_STRUCT(tlss
->push
.iov
);
254 TALLOC_FREE(tlss
->push
.buf
);
257 ret
= tstream_writev_recv(subreq
, &sys_errno
);
260 tlss
->error
= sys_errno
;
261 tstream_tls_retry(stream
, false);
265 tstream_tls_retry(stream
, false);
268 static void tstream_tls_pull_done(struct tevent_req
*subreq
);
270 static ssize_t
tstream_tls_pull_function(gnutls_transport_ptr_t ptr
,
271 void *buf
, size_t size
)
273 struct tstream_context
*stream
=
274 talloc_get_type_abort(ptr
,
275 struct tstream_context
);
276 struct tstream_tls
*tlss
=
277 tstream_context_data(stream
,
279 struct tevent_req
*subreq
;
282 if (tlss
->error
!= 0) {
287 if (tlss
->pull
.subreq
) {
292 if (tlss
->pull
.iov
.iov_base
) {
296 b
= (uint8_t *)tlss
->pull
.iov
.iov_base
;
298 n
= MIN(tlss
->pull
.iov
.iov_len
, size
);
301 tlss
->pull
.iov
.iov_len
-= n
;
303 tlss
->pull
.iov
.iov_base
= (char *)b
;
304 if (tlss
->pull
.iov
.iov_len
== 0) {
305 tlss
->pull
.iov
.iov_base
= NULL
;
306 TALLOC_FREE(tlss
->pull
.buf
);
316 len
= MIN(size
, UINT16_MAX
);
318 tlss
->pull
.buf
= talloc_array(tlss
, uint8_t, len
);
319 if (tlss
->pull
.buf
== NULL
) {
323 tlss
->pull
.iov
.iov_base
= (char *)tlss
->pull
.buf
;
324 tlss
->pull
.iov
.iov_len
= len
;
326 subreq
= tstream_readv_send(tlss
,
330 if (subreq
== NULL
) {
334 tevent_req_set_callback(subreq
, tstream_tls_pull_done
, stream
);
336 tlss
->pull
.subreq
= subreq
;
341 static void tstream_tls_pull_done(struct tevent_req
*subreq
)
343 struct tstream_context
*stream
=
344 tevent_req_callback_data(subreq
,
345 struct tstream_context
);
346 struct tstream_tls
*tlss
=
347 tstream_context_data(stream
,
352 tlss
->pull
.subreq
= NULL
;
354 ret
= tstream_readv_recv(subreq
, &sys_errno
);
357 tlss
->error
= sys_errno
;
358 tstream_tls_retry(stream
, false);
362 tstream_tls_retry(stream
, false);
365 static int tstream_tls_destructor(struct tstream_tls
*tlss
)
367 if (tlss
->tls_session
) {
368 gnutls_deinit(tlss
->tls_session
);
369 tlss
->tls_session
= NULL
;
375 static ssize_t
tstream_tls_pending_bytes(struct tstream_context
*stream
)
377 struct tstream_tls
*tlss
=
378 tstream_context_data(stream
,
382 if (tlss
->error
!= 0) {
387 ret
= gnutls_record_check_pending(tlss
->tls_session
);
388 ret
+= tlss
->read
.left
;
393 struct tstream_tls_readv_state
{
394 struct tstream_context
*stream
;
396 struct iovec
*vector
;
402 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
);
404 static struct tevent_req
*tstream_tls_readv_send(TALLOC_CTX
*mem_ctx
,
405 struct tevent_context
*ev
,
406 struct tstream_context
*stream
,
407 struct iovec
*vector
,
410 struct tstream_tls
*tlss
=
411 tstream_context_data(stream
,
413 struct tevent_req
*req
;
414 struct tstream_tls_readv_state
*state
;
416 tlss
->read
.req
= NULL
;
418 if (tlss
->current_ev
!= ev
) {
419 SMB_ASSERT(tlss
->push
.subreq
== NULL
);
420 SMB_ASSERT(tlss
->pull
.subreq
== NULL
);
423 tlss
->current_ev
= ev
;
425 req
= tevent_req_create(mem_ctx
, &state
,
426 struct tstream_tls_readv_state
);
431 state
->stream
= stream
;
434 if (tlss
->error
!= 0) {
435 tevent_req_error(req
, tlss
->error
);
436 return tevent_req_post(req
, ev
);
440 * we make a copy of the vector so we can change the structure
442 state
->vector
= talloc_array(state
, struct iovec
, count
);
443 if (tevent_req_nomem(state
->vector
, req
)) {
444 return tevent_req_post(req
, ev
);
446 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
447 state
->count
= count
;
449 tstream_tls_readv_crypt_next(req
);
450 if (!tevent_req_is_in_progress(req
)) {
451 return tevent_req_post(req
, ev
);
457 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
)
459 struct tstream_tls_readv_state
*state
=
461 struct tstream_tls_readv_state
);
462 struct tstream_tls
*tlss
=
463 tstream_context_data(state
->stream
,
467 * copy the pending buffer first
469 while (tlss
->read
.left
> 0 && state
->count
> 0) {
470 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
471 size_t len
= MIN(tlss
->read
.left
, state
->vector
[0].iov_len
);
473 memcpy(base
, tlss
->read
.buffer
+ tlss
->read
.ofs
, len
);
476 state
->vector
[0].iov_base
= (char *) base
;
477 state
->vector
[0].iov_len
-= len
;
479 tlss
->read
.ofs
+= len
;
480 tlss
->read
.left
-= len
;
482 if (state
->vector
[0].iov_len
== 0) {
490 if (state
->count
== 0) {
491 tevent_req_done(req
);
495 tlss
->read
.req
= req
;
496 tstream_tls_retry_read(state
->stream
);
499 static void tstream_tls_retry_read(struct tstream_context
*stream
)
501 struct tstream_tls
*tlss
=
502 tstream_context_data(stream
,
504 struct tevent_req
*req
= tlss
->read
.req
;
507 if (tlss
->error
!= 0) {
508 tevent_req_error(req
, tlss
->error
);
515 ret
= gnutls_record_recv(tlss
->tls_session
,
517 sizeof(tlss
->read
.buffer
));
518 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
522 tlss
->read
.req
= NULL
;
524 if (gnutls_error_is_fatal(ret
) != 0) {
525 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
527 tevent_req_error(req
, tlss
->error
);
533 tevent_req_error(req
, tlss
->error
);
537 tlss
->read
.left
= ret
;
538 tstream_tls_readv_crypt_next(req
);
541 static int tstream_tls_readv_recv(struct tevent_req
*req
,
544 struct tstream_tls_readv_state
*state
=
546 struct tstream_tls_readv_state
);
547 struct tstream_tls
*tlss
=
548 tstream_context_data(state
->stream
,
552 tlss
->read
.req
= NULL
;
554 ret
= tsocket_simple_int_recv(req
, perrno
);
559 tevent_req_received(req
);
563 struct tstream_tls_writev_state
{
564 struct tstream_context
*stream
;
566 struct iovec
*vector
;
572 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
);
574 static struct tevent_req
*tstream_tls_writev_send(TALLOC_CTX
*mem_ctx
,
575 struct tevent_context
*ev
,
576 struct tstream_context
*stream
,
577 const struct iovec
*vector
,
580 struct tstream_tls
*tlss
=
581 tstream_context_data(stream
,
583 struct tevent_req
*req
;
584 struct tstream_tls_writev_state
*state
;
586 tlss
->write
.req
= NULL
;
588 if (tlss
->current_ev
!= ev
) {
589 SMB_ASSERT(tlss
->push
.subreq
== NULL
);
590 SMB_ASSERT(tlss
->pull
.subreq
== NULL
);
593 tlss
->current_ev
= ev
;
595 req
= tevent_req_create(mem_ctx
, &state
,
596 struct tstream_tls_writev_state
);
601 state
->stream
= stream
;
604 if (tlss
->error
!= 0) {
605 tevent_req_error(req
, tlss
->error
);
606 return tevent_req_post(req
, ev
);
610 * we make a copy of the vector so we can change the structure
612 state
->vector
= talloc_array(state
, struct iovec
, count
);
613 if (tevent_req_nomem(state
->vector
, req
)) {
614 return tevent_req_post(req
, ev
);
616 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
617 state
->count
= count
;
619 tstream_tls_writev_crypt_next(req
);
620 if (!tevent_req_is_in_progress(req
)) {
621 return tevent_req_post(req
, ev
);
627 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
)
629 struct tstream_tls_writev_state
*state
=
631 struct tstream_tls_writev_state
);
632 struct tstream_tls
*tlss
=
633 tstream_context_data(state
->stream
,
636 tlss
->write
.left
= sizeof(tlss
->write
.buffer
);
640 * first fill our buffer
642 while (tlss
->write
.left
> 0 && state
->count
> 0) {
643 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
644 size_t len
= MIN(tlss
->write
.left
, state
->vector
[0].iov_len
);
646 memcpy(tlss
->write
.buffer
+ tlss
->write
.ofs
, base
, len
);
649 state
->vector
[0].iov_base
= (char *) base
;
650 state
->vector
[0].iov_len
-= len
;
652 tlss
->write
.ofs
+= len
;
653 tlss
->write
.left
-= len
;
655 if (state
->vector
[0].iov_len
== 0) {
663 if (tlss
->write
.ofs
== 0) {
664 tevent_req_done(req
);
668 tlss
->write
.left
= tlss
->write
.ofs
;
671 tlss
->write
.req
= req
;
672 tstream_tls_retry_write(state
->stream
);
675 static void tstream_tls_retry_write(struct tstream_context
*stream
)
677 struct tstream_tls
*tlss
=
678 tstream_context_data(stream
,
680 struct tevent_req
*req
= tlss
->write
.req
;
683 if (tlss
->error
!= 0) {
684 tevent_req_error(req
, tlss
->error
);
688 ret
= gnutls_record_send(tlss
->tls_session
,
689 tlss
->write
.buffer
+ tlss
->write
.ofs
,
691 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
695 tlss
->write
.req
= NULL
;
697 if (gnutls_error_is_fatal(ret
) != 0) {
698 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
700 tevent_req_error(req
, tlss
->error
);
706 tevent_req_error(req
, tlss
->error
);
710 tlss
->write
.ofs
+= ret
;
711 tlss
->write
.left
-= ret
;
713 if (tlss
->write
.left
> 0) {
714 tlss
->write
.req
= req
;
715 tstream_tls_retry_write(stream
);
719 tstream_tls_writev_crypt_next(req
);
722 static int tstream_tls_writev_recv(struct tevent_req
*req
,
725 struct tstream_tls_writev_state
*state
=
727 struct tstream_tls_writev_state
);
728 struct tstream_tls
*tlss
=
729 tstream_context_data(state
->stream
,
733 tlss
->write
.req
= NULL
;
735 ret
= tsocket_simple_int_recv(req
, perrno
);
740 tevent_req_received(req
);
744 struct tstream_tls_disconnect_state
{
748 static struct tevent_req
*tstream_tls_disconnect_send(TALLOC_CTX
*mem_ctx
,
749 struct tevent_context
*ev
,
750 struct tstream_context
*stream
)
752 struct tstream_tls
*tlss
=
753 tstream_context_data(stream
,
755 struct tevent_req
*req
;
756 struct tstream_tls_disconnect_state
*state
;
758 tlss
->disconnect
.req
= NULL
;
760 if (tlss
->current_ev
!= ev
) {
761 SMB_ASSERT(tlss
->push
.subreq
== NULL
);
762 SMB_ASSERT(tlss
->pull
.subreq
== NULL
);
765 tlss
->current_ev
= ev
;
767 req
= tevent_req_create(mem_ctx
, &state
,
768 struct tstream_tls_disconnect_state
);
773 if (tlss
->error
!= 0) {
774 tevent_req_error(req
, tlss
->error
);
775 return tevent_req_post(req
, ev
);
778 tlss
->disconnect
.req
= req
;
779 tstream_tls_retry_disconnect(stream
);
780 if (!tevent_req_is_in_progress(req
)) {
781 return tevent_req_post(req
, ev
);
787 static void tstream_tls_retry_disconnect(struct tstream_context
*stream
)
789 struct tstream_tls
*tlss
=
790 tstream_context_data(stream
,
792 struct tevent_req
*req
= tlss
->disconnect
.req
;
795 if (tlss
->error
!= 0) {
796 tevent_req_error(req
, tlss
->error
);
800 ret
= gnutls_bye(tlss
->tls_session
, GNUTLS_SHUT_WR
);
801 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
805 tlss
->disconnect
.req
= NULL
;
807 if (gnutls_error_is_fatal(ret
) != 0) {
808 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
810 tevent_req_error(req
, tlss
->error
);
814 if (ret
!= GNUTLS_E_SUCCESS
) {
815 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
817 tevent_req_error(req
, tlss
->error
);
821 if (tlss
->push
.subreq
!= NULL
|| tlss
->pull
.subreq
!= NULL
) {
822 tlss
->waiting_flush
.mgmt_req
= req
;
826 tevent_req_done(req
);
829 static int tstream_tls_disconnect_recv(struct tevent_req
*req
,
834 ret
= tsocket_simple_int_recv(req
, perrno
);
836 tevent_req_received(req
);
840 static const struct tstream_context_ops tstream_tls_ops
= {
843 .pending_bytes
= tstream_tls_pending_bytes
,
845 .readv_send
= tstream_tls_readv_send
,
846 .readv_recv
= tstream_tls_readv_recv
,
848 .writev_send
= tstream_tls_writev_send
,
849 .writev_recv
= tstream_tls_writev_recv
,
851 .disconnect_send
= tstream_tls_disconnect_send
,
852 .disconnect_recv
= tstream_tls_disconnect_recv
,
855 struct tstream_tls_params_internal
{
856 gnutls_certificate_credentials_t x509_cred
;
857 gnutls_dh_params_t dh_params
;
858 const char *tls_priority
;
860 enum tls_verify_peer_state verify_peer
;
861 const char *peer_name
;
864 struct tstream_tls_params
{
865 struct tstream_tls_params_internal
*internal
;
868 static int tstream_tls_params_internal_destructor(struct tstream_tls_params_internal
*tlsp
)
870 if (tlsp
->x509_cred
) {
871 gnutls_certificate_free_credentials(tlsp
->x509_cred
);
872 tlsp
->x509_cred
= NULL
;
874 if (tlsp
->dh_params
) {
875 gnutls_dh_params_deinit(tlsp
->dh_params
);
876 tlsp
->dh_params
= NULL
;
882 bool tstream_tls_params_enabled(struct tstream_tls_params
*tls_params
)
884 struct tstream_tls_params_internal
*tlsp
= tls_params
->internal
;
886 return tlsp
->tls_enabled
;
889 NTSTATUS
tstream_tls_params_client(TALLOC_CTX
*mem_ctx
,
891 const char *crl_file
,
892 const char *tls_priority
,
893 enum tls_verify_peer_state verify_peer
,
894 const char *peer_name
,
895 struct tstream_tls_params
**_tlsp
)
897 struct tstream_tls_params
*__tlsp
= NULL
;
898 struct tstream_tls_params_internal
*tlsp
= NULL
;
901 __tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
902 if (__tlsp
== NULL
) {
903 return NT_STATUS_NO_MEMORY
;
906 tlsp
= talloc_zero(__tlsp
, struct tstream_tls_params_internal
);
909 return NT_STATUS_NO_MEMORY
;
911 talloc_set_destructor(tlsp
, tstream_tls_params_internal_destructor
);
912 __tlsp
->internal
= tlsp
;
914 tlsp
->verify_peer
= verify_peer
;
915 if (peer_name
!= NULL
) {
916 tlsp
->peer_name
= talloc_strdup(tlsp
, peer_name
);
917 if (tlsp
->peer_name
== NULL
) {
919 return NT_STATUS_NO_MEMORY
;
921 } else if (tlsp
->verify_peer
>= TLS_VERIFY_PEER_CA_AND_NAME
) {
922 DEBUG(0,("TLS failed to missing peer_name - "
923 "with 'tls verify peer = %s'\n",
924 tls_verify_peer_string(tlsp
->verify_peer
)));
926 return NT_STATUS_INVALID_PARAMETER_MIX
;
929 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
930 if (ret
!= GNUTLS_E_SUCCESS
) {
931 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
933 return NT_STATUS_NO_MEMORY
;
936 if (ca_file
&& *ca_file
&& file_exist(ca_file
)) {
937 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
939 GNUTLS_X509_FMT_PEM
);
941 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
942 ca_file
, gnutls_strerror(ret
)));
944 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
946 } else if (tlsp
->verify_peer
>= TLS_VERIFY_PEER_CA_ONLY
) {
947 DEBUG(0,("TLS failed to missing cafile %s - "
948 "with 'tls verify peer = %s'\n",
950 tls_verify_peer_string(tlsp
->verify_peer
)));
952 return NT_STATUS_INVALID_PARAMETER_MIX
;
955 if (crl_file
&& *crl_file
&& file_exist(crl_file
)) {
956 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
958 GNUTLS_X509_FMT_PEM
);
960 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
961 crl_file
, gnutls_strerror(ret
)));
963 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
965 } else if (tlsp
->verify_peer
>= TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE
) {
966 DEBUG(0,("TLS failed to missing crlfile %s - "
967 "with 'tls verify peer = %s'\n",
969 tls_verify_peer_string(tlsp
->verify_peer
)));
971 return NT_STATUS_INVALID_PARAMETER_MIX
;
974 tlsp
->tls_priority
= talloc_strdup(tlsp
, tls_priority
);
975 if (tlsp
->tls_priority
== NULL
) {
977 return NT_STATUS_NO_MEMORY
;
980 tlsp
->tls_enabled
= true;
986 struct tstream_tls_connect_state
{
987 struct tstream_context
*tls_stream
;
990 struct tevent_req
*_tstream_tls_connect_send(TALLOC_CTX
*mem_ctx
,
991 struct tevent_context
*ev
,
992 struct tstream_context
*plain_stream
,
993 struct tstream_tls_params
*_tls_params
,
994 const char *location
)
996 struct tevent_req
*req
;
997 struct tstream_tls_connect_state
*state
;
998 const char *error_pos
;
999 struct tstream_tls
*tlss
;
1000 struct tstream_tls_params_internal
*tls_params
= NULL
;
1002 unsigned int flags
= GNUTLS_CLIENT
;
1004 req
= tevent_req_create(mem_ctx
, &state
,
1005 struct tstream_tls_connect_state
);
1010 state
->tls_stream
= tstream_context_create(state
,
1015 if (tevent_req_nomem(state
->tls_stream
, req
)) {
1016 return tevent_req_post(req
, ev
);
1019 talloc_set_destructor(tlss
, tstream_tls_destructor
);
1022 * Note we need to make sure x509_cred and dh_params
1023 * from tstream_tls_params_internal stay alive for
1024 * the whole lifetime of this session!
1026 * See 'man gnutls_credentials_set' and
1027 * 'man gnutls_certificate_set_dh_params'.
1029 * Note: here we use talloc_reference() in a way
1030 * that does not expose it to the caller.
1033 tls_params
= talloc_reference(tlss
, _tls_params
->internal
);
1034 if (tevent_req_nomem(tls_params
, req
)) {
1035 return tevent_req_post(req
, ev
);
1038 tlss
->plain_stream
= plain_stream
;
1039 tlss
->verify_peer
= tls_params
->verify_peer
;
1040 if (tls_params
->peer_name
!= NULL
) {
1041 tlss
->peer_name
= talloc_strdup(tlss
, tls_params
->peer_name
);
1042 if (tevent_req_nomem(tlss
->peer_name
, req
)) {
1043 return tevent_req_post(req
, ev
);
1047 tlss
->current_ev
= ev
;
1048 tlss
->retry_im
= tevent_create_immediate(tlss
);
1049 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
1050 return tevent_req_post(req
, ev
);
1053 #ifdef GNUTLS_NO_TICKETS
1055 * tls_tstream can't properly handle 'New Session Ticket' messages
1056 * sent 'after' the client sends the 'Finished' message.
1057 * GNUTLS_NO_TICKETS was introduced in GnuTLS 3.5.6. This flag is to
1058 * indicate the session Flag session should not use resumption with
1061 flags
|= GNUTLS_NO_TICKETS
;
1064 ret
= gnutls_init(&tlss
->tls_session
, flags
);
1065 if (ret
!= GNUTLS_E_SUCCESS
) {
1066 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1067 tevent_req_error(req
, EINVAL
);
1068 return tevent_req_post(req
, ev
);
1071 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1072 if (ret
!= GNUTLS_E_SUCCESS
) {
1073 DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
1074 __location__
, gnutls_strerror(ret
));
1075 tevent_req_error(req
, EINVAL
);
1076 return tevent_req_post(req
, ev
);
1079 if (strlen(tls_params
->tls_priority
) > 0) {
1080 ret
= gnutls_priority_set_direct(tlss
->tls_session
,
1081 tls_params
->tls_priority
,
1083 if (ret
!= GNUTLS_E_SUCCESS
) {
1084 DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
1085 __location__
, gnutls_strerror(ret
), error_pos
));
1086 tevent_req_error(req
, EINVAL
);
1087 return tevent_req_post(req
, ev
);
1091 ret
= gnutls_credentials_set(tlss
->tls_session
,
1092 GNUTLS_CRD_CERTIFICATE
,
1093 tls_params
->x509_cred
);
1094 if (ret
!= GNUTLS_E_SUCCESS
) {
1095 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1096 tevent_req_error(req
, EINVAL
);
1097 return tevent_req_post(req
, ev
);
1100 gnutls_transport_set_ptr(tlss
->tls_session
,
1101 (gnutls_transport_ptr_t
)state
->tls_stream
);
1102 gnutls_transport_set_pull_function(tlss
->tls_session
,
1103 (gnutls_pull_func
)tstream_tls_pull_function
);
1104 gnutls_transport_set_push_function(tlss
->tls_session
,
1105 (gnutls_push_func
)tstream_tls_push_function
);
1107 tlss
->handshake
.req
= req
;
1108 tstream_tls_retry_handshake(state
->tls_stream
);
1109 if (!tevent_req_is_in_progress(req
)) {
1110 return tevent_req_post(req
, ev
);
1116 int tstream_tls_connect_recv(struct tevent_req
*req
,
1118 TALLOC_CTX
*mem_ctx
,
1119 struct tstream_context
**tls_stream
)
1121 struct tstream_tls_connect_state
*state
=
1122 tevent_req_data(req
,
1123 struct tstream_tls_connect_state
);
1125 if (tevent_req_is_unix_error(req
, perrno
)) {
1126 tevent_req_received(req
);
1130 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1131 tevent_req_received(req
);
1136 initialise global tls state
1138 NTSTATUS
tstream_tls_params_server(TALLOC_CTX
*mem_ctx
,
1139 const char *dns_host_name
,
1141 const char *key_file
,
1142 const char *cert_file
,
1143 const char *ca_file
,
1144 const char *crl_file
,
1145 const char *dhp_file
,
1146 const char *tls_priority
,
1147 struct tstream_tls_params
**_tlsp
)
1149 struct tstream_tls_params
*__tlsp
= NULL
;
1150 struct tstream_tls_params_internal
*tlsp
= NULL
;
1154 if (!enabled
|| key_file
== NULL
|| *key_file
== 0) {
1155 __tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1156 if (__tlsp
== NULL
) {
1157 return NT_STATUS_NO_MEMORY
;
1160 tlsp
= talloc_zero(__tlsp
, struct tstream_tls_params_internal
);
1162 TALLOC_FREE(__tlsp
);
1163 return NT_STATUS_NO_MEMORY
;
1166 talloc_set_destructor(tlsp
, tstream_tls_params_internal_destructor
);
1167 __tlsp
->internal
= tlsp
;
1168 tlsp
->tls_enabled
= false;
1171 return NT_STATUS_OK
;
1174 __tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1175 if (__tlsp
== NULL
) {
1176 return NT_STATUS_NO_MEMORY
;
1179 tlsp
= talloc_zero(__tlsp
, struct tstream_tls_params_internal
);
1181 TALLOC_FREE(__tlsp
);
1182 return NT_STATUS_NO_MEMORY
;
1185 talloc_set_destructor(tlsp
, tstream_tls_params_internal_destructor
);
1186 __tlsp
->internal
= tlsp
;
1188 if (!file_exist(ca_file
)) {
1189 tls_cert_generate(tlsp
, dns_host_name
,
1190 key_file
, cert_file
, ca_file
);
1193 if (file_exist(key_file
) &&
1194 !file_check_permissions(key_file
, geteuid(), 0600, &st
))
1196 DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n"
1197 "owner uid %u should be %u, mode 0%o should be 0%o\n"
1198 "This is known as CVE-2013-4476.\n"
1199 "Removing all tls .pem files will cause an "
1200 "auto-regeneration with the correct permissions.\n",
1202 (unsigned int)st
.st_uid
, geteuid(),
1203 (unsigned int)(st
.st_mode
& 0777), 0600));
1204 TALLOC_FREE(__tlsp
);
1205 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1208 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
1209 if (ret
!= GNUTLS_E_SUCCESS
) {
1210 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1211 TALLOC_FREE(__tlsp
);
1212 return NT_STATUS_NO_MEMORY
;
1215 if (ca_file
&& *ca_file
) {
1216 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
1218 GNUTLS_X509_FMT_PEM
);
1220 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1221 ca_file
, gnutls_strerror(ret
)));
1222 TALLOC_FREE(__tlsp
);
1223 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1227 if (crl_file
&& *crl_file
) {
1228 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
1230 GNUTLS_X509_FMT_PEM
);
1232 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1233 crl_file
, gnutls_strerror(ret
)));
1234 TALLOC_FREE(__tlsp
);
1235 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1239 ret
= gnutls_certificate_set_x509_key_file(tlsp
->x509_cred
,
1240 cert_file
, key_file
,
1241 GNUTLS_X509_FMT_PEM
);
1242 if (ret
!= GNUTLS_E_SUCCESS
) {
1243 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1244 cert_file
, key_file
, gnutls_strerror(ret
)));
1245 TALLOC_FREE(__tlsp
);
1246 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1249 ret
= gnutls_dh_params_init(&tlsp
->dh_params
);
1250 if (ret
!= GNUTLS_E_SUCCESS
) {
1251 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1252 TALLOC_FREE(__tlsp
);
1253 return NT_STATUS_NO_MEMORY
;
1256 if (dhp_file
&& *dhp_file
) {
1257 gnutls_datum_t dhparms
;
1260 dhparms
.data
= (uint8_t *)file_load(dhp_file
, &size
, 0, tlsp
);
1262 if (!dhparms
.data
) {
1263 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1264 dhp_file
, errno
, strerror(errno
)));
1265 TALLOC_FREE(__tlsp
);
1266 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1268 dhparms
.size
= size
;
1270 ret
= gnutls_dh_params_import_pkcs3(tlsp
->dh_params
,
1272 GNUTLS_X509_FMT_PEM
);
1273 if (ret
!= GNUTLS_E_SUCCESS
) {
1274 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1275 dhp_file
, gnutls_strerror(ret
)));
1276 TALLOC_FREE(__tlsp
);
1277 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1280 ret
= gnutls_dh_params_generate2(tlsp
->dh_params
, DH_BITS
);
1281 if (ret
!= GNUTLS_E_SUCCESS
) {
1282 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1283 gnutls_strerror(ret
)));
1284 TALLOC_FREE(__tlsp
);
1285 return NT_STATUS_INTERNAL_ERROR
;
1289 gnutls_certificate_set_dh_params(tlsp
->x509_cred
, tlsp
->dh_params
);
1291 tlsp
->tls_priority
= talloc_strdup(tlsp
, tls_priority
);
1292 if (tlsp
->tls_priority
== NULL
) {
1293 TALLOC_FREE(__tlsp
);
1294 return NT_STATUS_NO_MEMORY
;
1297 tlsp
->tls_enabled
= true;
1300 return NT_STATUS_OK
;
1303 struct tstream_tls_accept_state
{
1304 struct tstream_context
*tls_stream
;
1307 struct tevent_req
*_tstream_tls_accept_send(TALLOC_CTX
*mem_ctx
,
1308 struct tevent_context
*ev
,
1309 struct tstream_context
*plain_stream
,
1310 struct tstream_tls_params
*_tlsp
,
1311 const char *location
)
1313 struct tevent_req
*req
;
1314 struct tstream_tls_accept_state
*state
;
1315 struct tstream_tls
*tlss
;
1316 const char *error_pos
;
1317 struct tstream_tls_params_internal
*tlsp
= NULL
;
1320 req
= tevent_req_create(mem_ctx
, &state
,
1321 struct tstream_tls_accept_state
);
1326 state
->tls_stream
= tstream_context_create(state
,
1331 if (tevent_req_nomem(state
->tls_stream
, req
)) {
1332 return tevent_req_post(req
, ev
);
1335 talloc_set_destructor(tlss
, tstream_tls_destructor
);
1338 * Note we need to make sure x509_cred and dh_params
1339 * from tstream_tls_params_internal stay alive for
1340 * the whole lifetime of this session!
1342 * See 'man gnutls_credentials_set' and
1343 * 'man gnutls_certificate_set_dh_params'.
1345 * Note: here we use talloc_reference() in a way
1346 * that does not expose it to the caller.
1348 tlsp
= talloc_reference(tlss
, _tlsp
->internal
);
1349 if (tevent_req_nomem(tlsp
, req
)) {
1350 return tevent_req_post(req
, ev
);
1353 tlss
->plain_stream
= plain_stream
;
1355 tlss
->current_ev
= ev
;
1356 tlss
->retry_im
= tevent_create_immediate(tlss
);
1357 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
1358 return tevent_req_post(req
, ev
);
1361 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_SERVER
);
1362 if (ret
!= GNUTLS_E_SUCCESS
) {
1363 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1364 tevent_req_error(req
, EINVAL
);
1365 return tevent_req_post(req
, ev
);
1368 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1369 if (ret
!= GNUTLS_E_SUCCESS
) {
1370 DBG_ERR("TLS %s - %s. Failed to set default priorities\n",
1371 __location__
, gnutls_strerror(ret
));
1372 tevent_req_error(req
, EINVAL
);
1373 return tevent_req_post(req
, ev
);
1376 if (strlen(tlsp
->tls_priority
) > 0) {
1377 ret
= gnutls_priority_set_direct(tlss
->tls_session
,
1380 if (ret
!= GNUTLS_E_SUCCESS
) {
1381 DEBUG(0,("TLS %s - %s. Check 'tls priority' option at '%s'\n",
1382 __location__
, gnutls_strerror(ret
), error_pos
));
1383 tevent_req_error(req
, EINVAL
);
1384 return tevent_req_post(req
, ev
);
1388 ret
= gnutls_credentials_set(tlss
->tls_session
, GNUTLS_CRD_CERTIFICATE
,
1390 if (ret
!= GNUTLS_E_SUCCESS
) {
1391 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1392 tevent_req_error(req
, EINVAL
);
1393 return tevent_req_post(req
, ev
);
1396 gnutls_certificate_server_set_request(tlss
->tls_session
,
1397 GNUTLS_CERT_REQUEST
);
1398 gnutls_dh_set_prime_bits(tlss
->tls_session
, DH_BITS
);
1400 gnutls_transport_set_ptr(tlss
->tls_session
,
1401 (gnutls_transport_ptr_t
)state
->tls_stream
);
1402 gnutls_transport_set_pull_function(tlss
->tls_session
,
1403 (gnutls_pull_func
)tstream_tls_pull_function
);
1404 gnutls_transport_set_push_function(tlss
->tls_session
,
1405 (gnutls_push_func
)tstream_tls_push_function
);
1407 tlss
->handshake
.req
= req
;
1408 tstream_tls_retry_handshake(state
->tls_stream
);
1409 if (!tevent_req_is_in_progress(req
)) {
1410 return tevent_req_post(req
, ev
);
1416 static void tstream_tls_retry_handshake(struct tstream_context
*stream
)
1418 struct tstream_tls
*tlss
=
1419 tstream_context_data(stream
,
1420 struct tstream_tls
);
1421 struct tevent_req
*req
= tlss
->handshake
.req
;
1424 if (tlss
->error
!= 0) {
1425 tevent_req_error(req
, tlss
->error
);
1429 ret
= gnutls_handshake(tlss
->tls_session
);
1430 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
1434 tlss
->handshake
.req
= NULL
;
1436 if (gnutls_error_is_fatal(ret
) != 0) {
1437 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1439 tevent_req_error(req
, tlss
->error
);
1443 if (ret
!= GNUTLS_E_SUCCESS
) {
1444 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1446 tevent_req_error(req
, tlss
->error
);
1450 if (tlss
->verify_peer
>= TLS_VERIFY_PEER_CA_ONLY
) {
1451 unsigned int status
= UINT32_MAX
;
1453 const char *hostname
= NULL
;
1455 if (tlss
->peer_name
!= NULL
) {
1456 ip
= is_ipaddress(tlss
->peer_name
);
1460 hostname
= tlss
->peer_name
;
1463 if (tlss
->verify_peer
== TLS_VERIFY_PEER_CA_ONLY
) {
1467 if (tlss
->verify_peer
>= TLS_VERIFY_PEER_CA_AND_NAME
) {
1468 if (hostname
== NULL
) {
1469 DEBUG(1,("TLS %s - no hostname available for "
1470 "verify_peer[%s] and peer_name[%s]\n",
1472 tls_verify_peer_string(tlss
->verify_peer
),
1474 tlss
->error
= EINVAL
;
1475 tevent_req_error(req
, tlss
->error
);
1480 ret
= gnutls_certificate_verify_peers3(tlss
->tls_session
,
1483 if (ret
!= GNUTLS_E_SUCCESS
) {
1484 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1486 tevent_req_error(req
, tlss
->error
);
1491 DEBUG(1,("TLS %s - check failed for "
1492 "verify_peer[%s] and peer_name[%s] "
1493 "status 0x%x (%s%s%s%s%s%s%s%s)\n",
1495 tls_verify_peer_string(tlss
->verify_peer
),
1498 status
& GNUTLS_CERT_INVALID
? "invalid " : "",
1499 status
& GNUTLS_CERT_REVOKED
? "revoked " : "",
1500 status
& GNUTLS_CERT_SIGNER_NOT_FOUND
?
1501 "signer_not_found " : "",
1502 status
& GNUTLS_CERT_SIGNER_NOT_CA
?
1503 "signer_not_ca " : "",
1504 status
& GNUTLS_CERT_INSECURE_ALGORITHM
?
1505 "insecure_algorithm " : "",
1506 status
& GNUTLS_CERT_NOT_ACTIVATED
?
1507 "not_activated " : "",
1508 status
& GNUTLS_CERT_EXPIRED
?
1510 status
& GNUTLS_CERT_UNEXPECTED_OWNER
?
1511 "unexpected_owner " : ""));
1512 tlss
->error
= EINVAL
;
1513 tevent_req_error(req
, tlss
->error
);
1518 if (tlss
->push
.subreq
!= NULL
|| tlss
->pull
.subreq
!= NULL
) {
1519 tlss
->waiting_flush
.mgmt_req
= req
;
1523 tevent_req_done(req
);
1526 int tstream_tls_accept_recv(struct tevent_req
*req
,
1528 TALLOC_CTX
*mem_ctx
,
1529 struct tstream_context
**tls_stream
)
1531 struct tstream_tls_accept_state
*state
=
1532 tevent_req_data(req
,
1533 struct tstream_tls_accept_state
);
1535 if (tevent_req_is_unix_error(req
, perrno
)) {
1536 tevent_req_received(req
);
1540 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1541 tevent_req_received(req
);