3d40fdafa08f5aabb79f29aabbf52163968f3dfd
[bbaumbach/samba-autobuild/.git] / source4 / lib / tls / tls.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    transport layer security handling code
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "lib/socket/socket.h"
26
27 #if HAVE_LIBGNUTLS
28 #include "gnutls/gnutls.h"
29
30 #define DH_BITS 1024
31
32 /* hold persistent tls data */
33 struct tls_params {
34         gnutls_certificate_credentials x509_cred;
35         gnutls_dh_params dh_params;
36         BOOL tls_enabled;
37 };
38
39 /* hold per connection tls data */
40 struct tls_context {
41         struct socket_context *socket;
42         struct fd_event *fde;
43         gnutls_session session;
44         BOOL done_handshake;
45         BOOL have_first_byte;
46         uint8_t first_byte;
47         BOOL tls_enabled;
48         BOOL tls_detect;
49         const char *plain_chars;
50         BOOL output_pending;
51         gnutls_certificate_credentials xcred;
52         BOOL interrupted;
53 };
54
55 #define TLSCHECK(call) do { \
56         ret = call; \
57         if (ret < 0) { \
58                 DEBUG(0,("TLS %s - %s\n", #call, gnutls_strerror(ret))); \
59                 goto failed; \
60         } \
61 } while (0)
62
63
64
65 /*
66   callback for reading from a socket
67 */
68 static ssize_t tls_pull(gnutls_transport_ptr ptr, void *buf, size_t size)
69 {
70         struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
71         NTSTATUS status;
72         size_t nread;
73         
74         if (tls->have_first_byte) {
75                 *(uint8_t *)buf = tls->first_byte;
76                 tls->have_first_byte = False;
77                 return 1;
78         }
79
80         status = socket_recv(tls->socket, buf, size, &nread, 0);
81         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
82                 return 0;
83         }
84         if (NT_STATUS_IS_ERR(status)) {
85                 EVENT_FD_NOT_READABLE(tls->fde);
86                 EVENT_FD_NOT_WRITEABLE(tls->fde);
87                 errno = EBADF;
88                 return -1;
89         }
90         if (!NT_STATUS_IS_OK(status)) {
91                 EVENT_FD_READABLE(tls->fde);
92                 errno = EAGAIN;
93                 return -1;
94         }
95         if (tls->output_pending) {
96                 EVENT_FD_WRITEABLE(tls->fde);
97         }
98         if (size != nread) {
99                 EVENT_FD_READABLE(tls->fde);
100         }
101         return nread;
102 }
103
104 /*
105   callback for writing to a socket
106 */
107 static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
108 {
109         struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
110         NTSTATUS status;
111         size_t nwritten;
112         DATA_BLOB b;
113
114         if (!tls->tls_enabled) {
115                 return size;
116         }
117
118         b.data = discard_const(buf);
119         b.length = size;
120
121         status = socket_send(tls->socket, &b, &nwritten, 0);
122         if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
123                 errno = EAGAIN;
124                 return -1;
125         }
126         if (!NT_STATUS_IS_OK(status)) {
127                 EVENT_FD_WRITEABLE(tls->fde);
128                 return -1;
129         }
130         if (size != nwritten) {
131                 EVENT_FD_WRITEABLE(tls->fde);
132         }
133         return nwritten;
134 }
135
136 /*
137   destroy a tls session
138  */
139 static int tls_destructor(void *ptr)
140 {
141         struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
142         int ret;
143         ret = gnutls_bye(tls->session, GNUTLS_SHUT_WR);
144         if (ret < 0) {
145                 DEBUG(0,("TLS gnutls_bye failed - %s\n", gnutls_strerror(ret)));
146         }
147         return 0;
148 }
149
150
151 /*
152   possibly continue the handshake process
153 */
154 static NTSTATUS tls_handshake(struct tls_context *tls)
155 {
156         int ret;
157
158         if (tls->done_handshake) {
159                 return NT_STATUS_OK;
160         }
161         
162         ret = gnutls_handshake(tls->session);
163         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
164                 if (gnutls_record_get_direction(tls->session) == 1) {
165                         EVENT_FD_WRITEABLE(tls->fde);
166                 }
167                 return STATUS_MORE_ENTRIES;
168         }
169         if (ret < 0) {
170                 DEBUG(0,("TLS gnutls_handshake failed - %s\n", gnutls_strerror(ret)));
171                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
172         }
173         tls->done_handshake = True;
174         return NT_STATUS_OK;
175 }
176
177 /*
178   possibly continue an interrupted operation
179 */
180 static NTSTATUS tls_interrupted(struct tls_context *tls)
181 {
182         int ret;
183
184         if (!tls->interrupted) {
185                 return NT_STATUS_OK;
186         }
187         if (gnutls_record_get_direction(tls->session) == 1) {
188                 ret = gnutls_record_send(tls->session, NULL, 0);
189         } else {
190                 ret = gnutls_record_recv(tls->session, NULL, 0);
191         }
192         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
193                 return STATUS_MORE_ENTRIES;
194         }
195         tls->interrupted = False;
196         return NT_STATUS_OK;
197 }
198
199 /*
200   see how many bytes are pending on the connection
201 */
202 NTSTATUS tls_socket_pending(struct tls_context *tls, size_t *npending)
203 {
204         if (!tls->tls_enabled || tls->tls_detect) {
205                 return socket_pending(tls->socket, npending);
206         }
207         *npending = gnutls_record_check_pending(tls->session);
208         if (*npending == 0) {
209                 NTSTATUS status = socket_pending(tls->socket, npending);
210                 if (*npending == 0) {
211                         /* seems to be a gnutls bug */
212                         (*npending) = 100;
213                 }
214                 return status;
215         }
216         return NT_STATUS_OK;
217 }
218
219 /*
220   receive data either by tls or normal socket_recv
221 */
222 NTSTATUS tls_socket_recv(struct tls_context *tls, void *buf, size_t wantlen, 
223                          size_t *nread)
224 {
225         int ret;
226         NTSTATUS status;
227         if (tls->tls_enabled && tls->tls_detect) {
228                 status = socket_recv(tls->socket, &tls->first_byte, 1, nread, 0);
229                 NT_STATUS_NOT_OK_RETURN(status);
230                 if (*nread == 0) return NT_STATUS_OK;
231                 tls->tls_detect = False;
232                 /* look for the first byte of a valid HTTP operation */
233                 if (strchr(tls->plain_chars, tls->first_byte)) {
234                         /* not a tls link */
235                         tls->tls_enabled = False;
236                         *(uint8_t *)buf = tls->first_byte;
237                         return NT_STATUS_OK;
238                 }
239                 tls->have_first_byte = True;
240         }
241
242         if (!tls->tls_enabled) {
243                 return socket_recv(tls->socket, buf, wantlen, nread, 0);
244         }
245
246         status = tls_handshake(tls);
247         NT_STATUS_NOT_OK_RETURN(status);
248
249         status = tls_interrupted(tls);
250         NT_STATUS_NOT_OK_RETURN(status);
251
252         ret = gnutls_record_recv(tls->session, buf, wantlen);
253         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
254                 if (gnutls_record_get_direction(tls->session) == 1) {
255                         EVENT_FD_WRITEABLE(tls->fde);
256                 }
257                 tls->interrupted = True;
258                 return STATUS_MORE_ENTRIES;
259         }
260         if (ret < 0) {
261                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
262         }
263         *nread = ret;
264         return NT_STATUS_OK;
265 }
266
267
268 /*
269   send data either by tls or normal socket_recv
270 */
271 NTSTATUS tls_socket_send(struct tls_context *tls, const DATA_BLOB *blob, size_t *sendlen)
272 {
273         NTSTATUS status;
274         int ret;
275
276         if (!tls->tls_enabled) {
277                 return socket_send(tls->socket, blob, sendlen, 0);
278         }
279
280         status = tls_handshake(tls);
281         NT_STATUS_NOT_OK_RETURN(status);
282
283         status = tls_interrupted(tls);
284         NT_STATUS_NOT_OK_RETURN(status);
285
286         ret = gnutls_record_send(tls->session, blob->data, blob->length);
287         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
288                 if (gnutls_record_get_direction(tls->session) == 1) {
289                         EVENT_FD_WRITEABLE(tls->fde);
290                 }
291                 tls->interrupted = True;
292                 return STATUS_MORE_ENTRIES;
293         }
294         if (ret < 0) {
295                 DEBUG(0,("gnutls_record_send of %d failed - %s\n", blob->length, gnutls_strerror(ret)));
296                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
297         }
298         *sendlen = ret;
299         tls->output_pending = (ret < blob->length);
300         return NT_STATUS_OK;
301 }
302
303
304 /*
305   initialise global tls state
306 */
307 struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
308 {
309         struct tls_params *params;
310         int ret;
311         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
312         const char *keyfile = private_path(tmp_ctx, lp_tls_keyfile());
313         const char *certfile = private_path(tmp_ctx, lp_tls_certfile());
314         const char *cafile = private_path(tmp_ctx, lp_tls_cafile());
315         const char *crlfile = private_path(tmp_ctx, lp_tls_crlfile());
316         void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *);
317
318         params = talloc(mem_ctx, struct tls_params);
319         if (params == NULL) {
320                 talloc_free(tmp_ctx);
321                 return NULL;
322         }
323
324         if (!lp_tls_enabled() || keyfile == NULL || *keyfile == 0) {
325                 params->tls_enabled = False;
326                 talloc_free(tmp_ctx);
327                 return params;
328         }
329
330         if (!file_exist(cafile)) {
331                 tls_cert_generate(params, keyfile, certfile, cafile);
332         }
333
334         ret = gnutls_global_init();
335         if (ret < 0) goto init_failed;
336
337         gnutls_certificate_allocate_credentials(&params->x509_cred);
338         if (ret < 0) goto init_failed;
339
340         if (cafile && *cafile) {
341                 ret = gnutls_certificate_set_x509_trust_file(params->x509_cred, cafile, 
342                                                              GNUTLS_X509_FMT_PEM);      
343                 if (ret < 0) {
344                         DEBUG(0,("TLS failed to initialise cafile %s\n", cafile));
345                         goto init_failed;
346                 }
347         }
348
349         if (crlfile && *crlfile) {
350                 ret = gnutls_certificate_set_x509_crl_file(params->x509_cred, 
351                                                            crlfile, 
352                                                            GNUTLS_X509_FMT_PEM);
353                 if (ret < 0) {
354                         DEBUG(0,("TLS failed to initialise crlfile %s\n", crlfile));
355                         goto init_failed;
356                 }
357         }
358         
359         ret = gnutls_certificate_set_x509_key_file(params->x509_cred, 
360                                                    certfile, keyfile,
361                                                    GNUTLS_X509_FMT_PEM);
362         if (ret < 0) {
363                 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s\n", 
364                          certfile, keyfile));
365                 goto init_failed;
366         }
367         
368         ret = gnutls_dh_params_init(&params->dh_params);
369         if (ret < 0) goto init_failed;
370
371         ret = gnutls_dh_params_generate2(params->dh_params, DH_BITS);
372         if (ret < 0) goto init_failed;
373
374         gnutls_certificate_set_dh_params(params->x509_cred, params->dh_params);
375
376         params->tls_enabled = True;
377
378         talloc_free(tmp_ctx);
379         return params;
380
381 init_failed:
382         DEBUG(0,("GNUTLS failed to initialise - %s\n", gnutls_strerror(ret)));
383         params->tls_enabled = False;
384         talloc_free(tmp_ctx);
385         return params;
386 }
387
388
389 /*
390   setup for a new connection
391 */
392 struct tls_context *tls_init_server(struct tls_params *params, 
393                                     struct socket_context *socket,
394                                     struct fd_event *fde, 
395                                     const char *plain_chars,
396                                     BOOL tls_enable)
397 {
398         struct tls_context *tls;
399         int ret;
400
401         tls = talloc(socket, struct tls_context);
402         if (tls == NULL) return NULL;
403
404         tls->socket          = socket;
405         tls->fde             = fde;
406
407         if (!params->tls_enabled || !tls_enable) {
408                 tls->tls_enabled = False;
409                 return tls;
410         }
411
412         TLSCHECK(gnutls_init(&tls->session, GNUTLS_SERVER));
413
414         talloc_set_destructor(tls, tls_destructor);
415
416         TLSCHECK(gnutls_set_default_priority(tls->session));
417         TLSCHECK(gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, 
418                                         params->x509_cred));
419         gnutls_certificate_server_set_request(tls->session, GNUTLS_CERT_REQUEST);
420         gnutls_dh_set_prime_bits(tls->session, DH_BITS);
421         gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
422         gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
423         gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
424         gnutls_transport_set_lowat(tls->session, 0);
425
426         tls->plain_chars = plain_chars;
427         if (plain_chars) {
428                 tls->tls_detect = True;
429         } else {
430                 tls->tls_detect = False;
431         }
432
433         tls->output_pending  = False;
434         tls->done_handshake  = False;
435         tls->have_first_byte = False;
436         tls->tls_enabled     = True;
437         tls->interrupted     = False;
438         
439         return tls;
440
441 failed:
442         DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
443         tls->tls_enabled = False;
444         params->tls_enabled = False;
445         return tls;
446 }
447
448
449 /*
450   setup for a new client connection
451 */
452 struct tls_context *tls_init_client(struct socket_context *socket,
453                                     struct fd_event *fde, 
454                                     BOOL tls_enable)
455 {
456         struct tls_context *tls;
457         int ret=0;
458         const int cert_type_priority[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
459         char *cafile;
460
461         tls = talloc(socket, struct tls_context);
462         if (tls == NULL) return NULL;
463
464         tls->socket          = socket;
465         tls->fde             = fde;
466         tls->tls_enabled     = tls_enable;
467
468         if (!tls->tls_enabled) {
469                 return tls;
470         }
471
472         cafile = private_path(tls, lp_tls_cafile());
473         if (!cafile || !*cafile) {
474                 goto failed;
475         }
476
477         gnutls_global_init();
478
479         gnutls_certificate_allocate_credentials(&tls->xcred);
480         gnutls_certificate_set_x509_trust_file(tls->xcred, cafile, GNUTLS_X509_FMT_PEM);
481         talloc_free(cafile);
482         TLSCHECK(gnutls_init(&tls->session, GNUTLS_CLIENT));
483         TLSCHECK(gnutls_set_default_priority(tls->session));
484         gnutls_certificate_type_set_priority(tls->session, cert_type_priority);
485         TLSCHECK(gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, tls->xcred));
486
487         talloc_set_destructor(tls, tls_destructor);
488
489         gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
490         gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
491         gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
492         gnutls_transport_set_lowat(tls->session, 0);
493         tls->tls_detect = False;
494
495         tls->output_pending  = False;
496         tls->done_handshake  = False;
497         tls->have_first_byte = False;
498         tls->tls_enabled     = True;
499         tls->interrupted     = False;
500         
501         return tls;
502
503 failed:
504         DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
505         tls->tls_enabled = False;
506         return tls;
507 }
508
509 BOOL tls_enabled(struct tls_context *tls)
510 {
511         return tls->tls_enabled;
512 }
513
514 BOOL tls_support(struct tls_params *params)
515 {
516         return params->tls_enabled;
517 }
518
519 #else
520
521 /* for systems without tls we just map the tls socket calls to the
522    normal socket calls */
523
524 struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
525 {
526         return talloc_new(mem_ctx);
527 }
528
529 struct tls_context *tls_init_server(struct tls_params *params, 
530                                     struct socket_context *sock, 
531                                     struct fd_event *fde,
532                                     const char *plain_chars,
533                                     BOOL tls_enable)
534 {
535         if (tls_enable && plain_chars == NULL) return NULL;
536         return (struct tls_context *)sock;
537 }
538
539 struct tls_context *tls_init_client(struct socket_context *sock, 
540                                     struct fd_event *fde,
541                                     BOOL tls_enable)
542 {
543         return (struct tls_context *)sock;
544 }
545
546
547 NTSTATUS tls_socket_recv(struct tls_context *tls, void *buf, size_t wantlen, 
548                          size_t *nread)
549 {
550         return socket_recv((struct socket_context *)tls, buf, wantlen, nread, 0);
551 }
552
553 NTSTATUS tls_socket_send(struct tls_context *tls, const DATA_BLOB *blob, size_t *sendlen)
554 {
555         return socket_send((struct socket_context *)tls, blob, sendlen, 0);
556 }
557
558 BOOL tls_enabled(struct tls_context *tls)
559 {
560         return False;
561 }
562
563 BOOL tls_support(struct tls_params *params)
564 {
565         return False;
566 }
567
568 NTSTATUS tls_socket_pending(struct tls_context *tls, size_t *npending)
569 {
570         return socket_pending((struct socket_context *)tls, npending);
571 }
572
573 #endif