Commit 7ada98e7 7ada98e754453cdae3198321b5c1b2f4e55538e4 by Sergey Poznyakoff

Implemented client TLS stream

1 parent d1ce780d
Showing 1 changed file with 203 additions and 10 deletions
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
32 #include <mailutils/nls.h> 32 #include <mailutils/nls.h>
33 #include <mailutils/stream.h> 33 #include <mailutils/stream.h>
34 34
35 #include <lbuf.h>
36
35 #ifdef WITH_TLS 37 #ifdef WITH_TLS
36 38
37 #include <gnutls/gnutls.h> 39 #include <gnutls/gnutls.h>
...@@ -44,9 +46,10 @@ static char *ssl_cert = NULL; ...@@ -44,9 +46,10 @@ static char *ssl_cert = NULL;
44 static char *ssl_key = NULL; 46 static char *ssl_key = NULL;
45 static char *ssl_cafile = NULL; 47 static char *ssl_cafile = NULL;
46 48
47 #define ARG_SSL_CERT 1 49 #define ARG_TLS 1
48 #define ARG_SSL_KEY 2 50 #define ARG_SSL_CERT 2
49 #define ARG_SSL_CAFILE 3 51 #define ARG_SSL_KEY 3
52 #define ARG_SSL_CAFILE 4
50 53
51 static struct argp_option _tls_argp_options[] = { 54 static struct argp_option _tls_argp_options[] = {
52 {NULL, 0, NULL, 0, N_("Encryption options"), 0}, 55 {NULL, 0, NULL, 0, N_("Encryption options"), 0},
...@@ -62,8 +65,17 @@ static struct argp_option _tls_argp_options[] = { ...@@ -62,8 +65,17 @@ static struct argp_option _tls_argp_options[] = {
62 static error_t 65 static error_t
63 _tls_argp_parser (int key, char *arg, struct argp_state *state) 66 _tls_argp_parser (int key, char *arg, struct argp_state *state)
64 { 67 {
68 static int tls_enable = 1;
69
65 switch (key) 70 switch (key)
66 { 71 {
72 case ARG_TLS:
73 if (!arg || strcasecmp (arg, "yes") == 0)
74 tls_enable = 1;
75 else if (strcasecmp (arg, "no") == 0)
76 tls_enable = 0;
77 break;
78
67 case ARG_SSL_CERT: 79 case ARG_SSL_CERT:
68 ssl_cert = arg; 80 ssl_cert = arg;
69 break; 81 break;
...@@ -76,6 +88,11 @@ _tls_argp_parser (int key, char *arg, struct argp_state *state) ...@@ -76,6 +88,11 @@ _tls_argp_parser (int key, char *arg, struct argp_state *state)
76 ssl_cafile = arg; 88 ssl_cafile = arg;
77 break; 89 break;
78 90
91 case ARGP_KEY_FINI:
92 if (tls_enable)
93 mu_init_tls_libs ();
94 break;
95
79 default: 96 default:
80 return ARGP_ERR_UNKNOWN; 97 return ARGP_ERR_UNKNOWN;
81 } 98 }
...@@ -104,6 +121,34 @@ mu_tls_init_argp () ...@@ -104,6 +121,34 @@ mu_tls_init_argp ()
104 } 121 }
105 } 122 }
106 123
124 static struct argp_option _tls_argp_client_options[] = {
125 {"tls", ARG_TLS, N_("BOOL"), OPTION_ARG_OPTIONAL,
126 N_("Enable TLS support") },
127 {NULL, 0, NULL, 0, NULL, 0}
128 };
129
130 static struct argp _tls_client_argp = {
131 _tls_argp_client_options,
132 _tls_argp_parser
133 };
134
135 static struct argp_child _tls_argp_client_child = {
136 &_tls_client_argp,
137 0,
138 NULL,
139 0
140 };
141
142 void
143 mu_tls_init_client_argp ()
144 {
145 if (mu_register_capa ("tls", &_tls_argp_client_child))
146 {
147 mu_error (_("INTERNAL ERROR: cannot register argp capability tls"));
148 abort ();
149 }
150 }
151
107 int 152 int
108 mu_check_tls_environment (void) 153 mu_check_tls_environment (void)
109 { 154 {
...@@ -142,16 +187,22 @@ mu_check_tls_environment (void) ...@@ -142,16 +187,22 @@ mu_check_tls_environment (void)
142 return 1; 187 return 1;
143 } 188 }
144 189
190 int mu_tls_enable = 0;
191
145 int 192 int
146 mu_init_tls_libs (void) 193 mu_init_tls_libs (void)
147 { 194 {
148 return !gnutls_global_init (); /* Returns 1 on success */ 195 if (!mu_tls_enable)
196 mu_tls_enable = !gnutls_global_init (); /* Returns 1 on success */
197 return mu_tls_enable;
149 } 198 }
150 199
151 void 200 void
152 mu_deinit_tls_libs (void) 201 mu_deinit_tls_libs (void)
153 { 202 {
203 if (mu_tls_enable)
154 gnutls_global_deinit (); 204 gnutls_global_deinit ();
205 mu_tls_enable = 0;
155 } 206 }
156 207
157 static void 208 static void
...@@ -194,8 +245,10 @@ struct _tls_stream { ...@@ -194,8 +245,10 @@ struct _tls_stream {
194 int ifd; 245 int ifd;
195 int ofd; 246 int ofd;
196 int last_err; 247 int last_err;
248 struct _line_buffer *lb;
197 enum tls_stream_state state; 249 enum tls_stream_state state;
198 gnutls_session session; 250 gnutls_session session;
251 stream_t tcp_str;
199 }; 252 };
200 253
201 254
...@@ -203,11 +256,16 @@ static void ...@@ -203,11 +256,16 @@ static void
203 _tls_destroy (stream_t stream) 256 _tls_destroy (stream_t stream)
204 { 257 {
205 struct _tls_stream *s = stream_get_owner (stream); 258 struct _tls_stream *s = stream_get_owner (stream);
259 if (x509_cred)
260 gnutls_certificate_free_credentials (x509_cred);
206 if (s->session && s->state == state_closed) 261 if (s->session && s->state == state_closed)
207 { 262 {
208 gnutls_deinit (s->session); 263 gnutls_deinit (s->session);
209 s->state = state_destroyed; 264 s->state = state_destroyed;
210 } 265 }
266 if (s->tcp_str)
267 stream_destroy (&s->tcp_str, stream_get_owner (s->tcp_str));
268 _auth_lb_destroy (&s->lb);
211 free (s); 269 free (s);
212 } 270 }
213 271
...@@ -242,7 +300,8 @@ _tls_readline (stream_t stream, char *optr, size_t osize, ...@@ -242,7 +300,8 @@ _tls_readline (stream_t stream, char *optr, size_t osize,
242 if (!stream || s->state != state_open || osize < 2) 300 if (!stream || s->state != state_open || osize < 2)
243 return EINVAL; 301 return EINVAL;
244 302
245 osize--; /* Allow for terminating zero */ 303 if (_auth_lb_level (s->lb) == 0)
304 {
246 ptr = optr; 305 ptr = optr;
247 rdsize = 0; 306 rdsize = 0;
248 do 307 do
...@@ -257,11 +316,14 @@ _tls_readline (stream_t stream, char *optr, size_t osize, ...@@ -257,11 +316,14 @@ _tls_readline (stream_t stream, char *optr, size_t osize,
257 } 316 }
258 while (osize > rdsize && rc > 0 && ptr[rdsize-1] != '\n'); 317 while (osize > rdsize && rc > 0 && ptr[rdsize-1] != '\n');
259 318
260 ptr[rdsize] = 0; 319 _auth_lb_grow (s->lb, ptr, rdsize);
320 }
261 321
322 osize--; /* Allow for terminating zero */
323 rdsize = _auth_lb_readline (s->lb, optr, osize);
324 optr[rdsize] = 0;
262 if (nbytes) 325 if (nbytes)
263 *nbytes = rdsize; 326 *nbytes = rdsize;
264
265 return 0; 327 return 0;
266 } 328 }
267 329
...@@ -359,6 +421,81 @@ _tls_open (stream_t stream) ...@@ -359,6 +421,81 @@ _tls_open (stream_t stream)
359 return 0; 421 return 0;
360 } 422 }
361 423
424 static int
425 prepare_client_session (struct _tls_stream *s)
426 {
427 int rc;
428 static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0};
429 static int kx_priority[] = {GNUTLS_KX_RSA, 0};
430 static int cipher_priority[] = {GNUTLS_CIPHER_3DES_CBC,
431 GNUTLS_CIPHER_ARCFOUR_128,
432 0};
433 static int comp_priority[] = {GNUTLS_COMP_NULL, 0};
434 static int mac_priority[] = {GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0};
435
436 gnutls_init (&s->session, GNUTLS_CLIENT);
437 gnutls_protocol_set_priority (s->session, protocol_priority);
438 gnutls_cipher_set_priority (s->session, cipher_priority);
439 gnutls_compression_set_priority (s->session, comp_priority);
440 gnutls_kx_set_priority (s->session, kx_priority);
441 gnutls_mac_set_priority (s->session, mac_priority);
442
443 gnutls_certificate_allocate_credentials (&x509_cred);
444 if (ssl_cafile)
445 {
446 rc = gnutls_certificate_set_x509_trust_file (x509_cred,
447 ssl_cafile,
448 GNUTLS_X509_FMT_PEM);
449 if (rc < 0)
450 {
451 s->last_err = rc;
452 return -1;
453 }
454 }
455
456 gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, x509_cred);
457
458 gnutls_transport_set_ptr2 (s->session, (gnutls_transport_ptr) s->ifd,
459 (gnutls_transport_ptr) s->ofd);
460
461 return 0;
462 }
463
464 static int
465 _tls_open_client (stream_t stream)
466 {
467 struct _tls_stream *s = stream_get_owner (stream);
468 int rc = 0;
469
470 switch (s->state)
471 {
472 case state_closed:
473 gnutls_certificate_free_credentials (x509_cred);
474 if (s->session)
475 gnutls_deinit (s->session);
476 /* FALLTHROUGH */
477
478 case state_init:
479 prepare_client_session (s);
480 rc = gnutls_handshake (s->session);
481 if (rc < 0)
482 {
483 s->last_err = rc;
484 gnutls_deinit (s->session);
485 s->state = state_init;
486 return -1;
487 }
488 break;
489
490 default:
491 return -1;
492 }
493
494 /* FIXME: if (ssl_cafile) verify_certificate (s->session); */
495 s->state = state_open;
496 return 0;
497 }
498
362 int 499 int
363 _tls_strerror (stream_t stream, char **pstr) 500 _tls_strerror (stream_t stream, char **pstr)
364 { 501 {
...@@ -367,12 +504,12 @@ _tls_strerror (stream_t stream, char **pstr) ...@@ -367,12 +504,12 @@ _tls_strerror (stream_t stream, char **pstr)
367 return 0; 504 return 0;
368 } 505 }
369 506
370 /* FIXME: It returns only input fd */
371 int 507 int
372 _tls_get_fd (stream_t stream, int *pfd) 508 _tls_get_fd (stream_t stream, int *pfd1, int *pfd2)
373 { 509 {
374 struct _tls_stream *s = stream_get_owner (stream); 510 struct _tls_stream *s = stream_get_owner (stream);
375 *pfd = s->ifd; 511 *pfd1 = s->ifd;
512 *pfd2 = s->ofd;
376 return 0; 513 return 0;
377 } 514 }
378 515
...@@ -408,11 +545,67 @@ tls_stream_create (stream_t *stream, int in_fd, int out_fd, int flags) ...@@ -408,11 +545,67 @@ tls_stream_create (stream_t *stream, int in_fd, int out_fd, int flags)
408 stream_set_destroy (*stream, _tls_destroy, s); 545 stream_set_destroy (*stream, _tls_destroy, s);
409 stream_set_strerror (*stream, _tls_strerror, s); 546 stream_set_strerror (*stream, _tls_strerror, s);
410 stream_set_fd (*stream, _tls_get_fd, s); 547 stream_set_fd (*stream, _tls_get_fd, s);
548 _auth_lb_create (&s->lb);
549
550 s->state = state_init;
551 return 0;
552 }
553
554 int
555 tls_stream_create_client (stream_t *stream, int in_fd, int out_fd, int flags)
556 {
557 struct _tls_stream *s;
558 int rc;
559
560 if (stream == NULL)
561 return EINVAL;
562
563 s = calloc (1, sizeof (*s));
564 if (s == NULL)
565 return ENOMEM;
566
567 s->ifd = in_fd;
568 s->ofd = out_fd;
569
570 rc = stream_create (stream, flags|MU_STREAM_NO_CHECK, s);
571 if (rc)
572 {
573 free (s);
574 return rc;
575 }
576
577 stream_set_open (*stream, _tls_open_client, s);
578 stream_set_close (*stream, _tls_close, s);
579 stream_set_read (*stream, _tls_read, s);
580 stream_set_readline (*stream, _tls_readline, s);
581 stream_set_write (*stream, _tls_write, s);
582 stream_set_flush (*stream, _tls_flush, s);
583 stream_set_destroy (*stream, _tls_destroy, s);
584 stream_set_strerror (*stream, _tls_strerror, s);
585 stream_set_fd (*stream, _tls_get_fd, s);
586 _auth_lb_create (&s->lb);
411 587
412 s->state = state_init; 588 s->state = state_init;
413 return 0; 589 return 0;
414 } 590 }
415 591
592 int
593 tls_stream_create_client_from_tcp (stream_t *stream, stream_t tcp_str,
594 int flags)
595 {
596 int rc, fd;
597
598 stream_get_fd (tcp_str, &fd);
599 rc = tls_stream_create_client (stream, fd, fd, flags);
600 if (rc == 0)
601 {
602 struct _tls_stream *s = stream_get_owner (*stream);
603 s->tcp_str = tcp_str;
604 }
605 return rc;
606 }
607
608
416 #endif /* WITH_TLS */ 609 #endif /* WITH_TLS */
417 610
418 /* EOF */ 611 /* EOF */
......