4a0a1bac465238440e905d667e7d72d613e7ad87
[users/heiko/exim.git] / test / src / client.c
1 /* A little hacked up program that makes a TCP/IP call and reads a script to
2 drive it, for testing Exim server code running as a daemon. It's got a bit
3 messy with the addition of support for either OpenSSL or GnuTLS. The code for
4 those was hacked out of Exim itself, then code for OpenSSL OCSP stapling was
5 ripped from the openssl ocsp and s_client utilities. */
6
7 /* ANSI C standard includes */
8
9 #include <ctype.h>
10 #include <signal.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17
18 /* Unix includes */
19
20 #include <errno.h>
21 #include <dirent.h>
22 #include <sys/types.h>
23
24 #include <netinet/in_systm.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
27 #include <netinet/tcp.h>
28
29 #include <netdb.h>
30 #include <arpa/inet.h>
31 #include <sys/time.h>
32 #include <sys/resource.h>
33 #include <sys/socket.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <utime.h>
38
39 #ifdef AF_INET6
40 #define HAVE_IPV6 1
41 #endif
42
43 #ifndef S_ADDR_TYPE
44 #define S_ADDR_TYPE u_long
45 #endif
46
47 typedef unsigned char uschar;
48
49 #define CS   (char *)
50 #define US   (unsigned char *)
51
52 #define FALSE         0
53 #define TRUE          1
54
55
56
57 static int sigalrm_seen = 0;
58
59
60 /* TLS support can be optionally included, either for OpenSSL or GnuTLS. The
61 latter needs a whole pile of tables. */
62 #ifdef HAVE_OPENSSL
63 # define HAVE_TLS
64 # include <openssl/crypto.h>
65 # include <openssl/x509.h>
66 # include <openssl/pem.h>
67 # include <openssl/ssl.h>
68 # include <openssl/err.h>
69 # include <openssl/rand.h>
70
71 # if OPENSSL_VERSION_NUMBER < 0x0090806fL && !defined(DISABLE_OCSP) && !defined(OPENSSL_NO_TLSEXT)
72 #  warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
73 #  define DISABLE_OCSP
74 # endif
75 # ifndef DISABLE_OCSP
76 #  include <openssl/ocsp.h>
77 # endif
78 #endif
79
80
81 #ifdef HAVE_GNUTLS
82 # define HAVE_TLS
83 # include <gnutls/gnutls.h>
84 # include <gnutls/x509.h>
85 # if GNUTLS_VERSION_NUMBER >= 0x030103
86 #  define HAVE_OCSP
87 #  include <gnutls/ocsp.h>
88 # endif
89 # ifndef GNUTLS_NO_EXTENSIONS
90 #  define GNUTLS_NO_EXTENSIONS 0
91 # endif
92
93 # define DH_BITS      768
94
95 /* Local static variables for GNUTLS */
96
97 static gnutls_dh_params_t dh_params = NULL;
98
99 static gnutls_certificate_credentials_t x509_cred = NULL;
100 static gnutls_session_t tls_session = NULL;
101
102 static int  ssl_session_timeout = 200;
103
104 /* Priorities for TLS algorithms to use. */
105
106 #if GNUTLS_VERSION_NUMBER < 0x030400
107 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
108
109 static const int kx_priority[16] = {
110   GNUTLS_KX_RSA,
111   GNUTLS_KX_DHE_DSS,
112   GNUTLS_KX_DHE_RSA,
113   0 };
114
115 static int default_cipher_priority[16] = {
116   GNUTLS_CIPHER_AES_256_CBC,
117   GNUTLS_CIPHER_AES_128_CBC,
118   GNUTLS_CIPHER_3DES_CBC,
119   GNUTLS_CIPHER_ARCFOUR_128,
120   0 };
121
122 static const int mac_priority[16] = {
123   GNUTLS_MAC_SHA,
124   GNUTLS_MAC_MD5,
125   0 };
126
127 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
128 #endif
129
130 #endif  /*HAVE_GNUTLS*/
131
132
133
134 #ifdef HAVE_TLS
135 char * ocsp_stapling = NULL;
136 #endif
137
138
139 /*************************************************
140 *            SIGALRM handler - crash out         *
141 *************************************************/
142
143 static void
144 sigalrm_handler_crash(int sig)
145 {
146 sig = sig;    /* Keep picky compilers happy */
147 printf("\nClient timed out\n");
148 exit(99);
149 }
150
151
152 /*************************************************
153 *            SIGALRM handler - set flag          *
154 *************************************************/
155
156 static void
157 sigalrm_handler_flag(int sig)
158 {
159 sig = sig;    /* Keep picky compilers happy */
160 sigalrm_seen = 1;
161 }
162
163
164
165 /****************************************************************************/
166 /****************************************************************************/
167
168 #ifdef HAVE_OPENSSL
169 # ifndef DISABLE_OCSP
170
171 static STACK_OF(X509) *
172 chain_from_pem_file(const uschar * file)
173 {
174 BIO * bp;
175 X509 * x;
176 STACK_OF(X509) * sk;
177
178 if (!(sk = sk_X509_new_null())) return NULL;
179 if (!(bp = BIO_new_file(CS file, "r"))) return NULL;
180 while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)))
181   sk_X509_push(sk, x);
182 BIO_free(bp);
183 return sk;
184 }
185
186
187
188 static void
189 cert_stack_free(STACK_OF(X509) * sk)
190 {
191 while (sk_X509_num(sk) > 0) (void) sk_X509_pop(sk);
192 sk_X509_free(sk);
193 }
194
195
196 static int
197 tls_client_stapling_cb(SSL *s, void *arg)
198 {
199 const unsigned char *p;
200 int len;
201 OCSP_RESPONSE *rsp;
202 OCSP_BASICRESP *bs;
203 STACK_OF(X509) * sk;
204 int ret = 1;
205
206 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
207 /*BIO_printf(arg, "OCSP response: ");*/
208 if (!p)
209         {
210         BIO_printf(arg, "no response received\n");
211         return 1;
212         }
213 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
214         {
215         BIO_printf(arg, "response parse error\n");
216         BIO_dump_indent(arg, (char *)p, len, 4);
217         return 0;
218         }
219 if(!(bs = OCSP_response_get1_basic(rsp)))
220   {
221   BIO_printf(arg, "error parsing response\n");
222   return 0;
223   }
224
225
226 if (!(sk = chain_from_pem_file(ocsp_stapling)))
227   {
228   BIO_printf(arg, "error in cert setup\n");
229   return 0;
230   }
231
232 /* OCSP_basic_verify takes a "store" arg, but does not
233 use it for the chain verification, which is all we do
234 when OCSP_NOVERIFY is set.  The content from the wire
235 (in "bs") and a cert-stack "sk" are all that is used. */
236
237 if(OCSP_basic_verify(bs, sk, NULL, OCSP_NOVERIFY) <= 0)
238   {
239   BIO_printf(arg, "Response Verify Failure\n");
240   ERR_print_errors(arg);
241   ret = 0;
242   }
243 else
244   BIO_printf(arg, "Response verify OK\n");
245
246 cert_stack_free(sk);
247 return ret;
248 }
249 # endif /*DISABLE_OCSP*/
250
251
252 /*************************************************
253 *         Start an OpenSSL TLS session           *
254 *************************************************/
255
256 int
257 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
258 {
259 int rc;
260 static const unsigned char *sid_ctx = US"exim";
261
262 RAND_load_file("client.c", -1);   /* Not *very* random! */
263
264 *ssl = SSL_new (ctx);
265 SSL_set_session_id_context(*ssl, sid_ctx, strlen(CS sid_ctx));
266 SSL_set_fd (*ssl, sock);
267 SSL_set_connect_state(*ssl);
268
269 #ifndef DISABLE_OCSP
270 if (ocsp_stapling)
271   {
272   SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
273   SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
274   SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
275   }
276 #endif
277
278 signal(SIGALRM, sigalrm_handler_flag);
279 sigalrm_seen = 0;
280 alarm(5);
281 rc = SSL_connect (*ssl);
282 alarm(0);
283
284 if (sigalrm_seen)
285   {
286   printf("SSL_connect timed out\n");
287   return 0;
288   }
289
290 if (rc <= 0)
291   {
292   ERR_print_errors_fp(stdout);
293   return 0;
294   }
295
296 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
297 return 1;
298 }
299
300
301 /*************************************************
302 *           SSL Information callback             *
303 *************************************************/
304
305 static void
306 info_callback(SSL *s, int where, int ret)
307 {
308 where = where;
309 ret = ret;
310 printf("SSL info: %s\n", SSL_state_string_long(s));
311 }
312 #endif
313
314
315 /****************************************************************************/
316 /****************************************************************************/
317
318
319 #ifdef HAVE_GNUTLS
320 /*************************************************
321 *            Handle GnuTLS error                 *
322 *************************************************/
323
324 /* Called from lots of places when errors occur before actually starting to do
325 the TLS handshake, that is, while the session is still in clear.
326
327 Argument:
328   prefix    prefix text
329   err       a GnuTLS error number, or 0 if local error
330
331 Returns:    doesn't - it dies
332 */
333
334 static void
335 gnutls_error(uschar *prefix, int err)
336 {
337 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
338 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
339 fprintf(stderr, "\n");
340 exit(98);
341 }
342
343
344
345 /*************************************************
346 *             Setup up DH parameters             *
347 *************************************************/
348
349 /* For the test suite, the parameters should always be available in the spool
350 directory. */
351
352 static void
353 init_dh(void)
354 {
355 int fd;
356 int ret;
357 gnutls_datum_t m;
358 uschar filename[200];
359 struct stat statbuf;
360
361 /* Initialize the data structures for holding the parameters */
362
363 ret = gnutls_dh_params_init(&dh_params);
364 if (ret < 0) gnutls_error(US"init dh_params", ret);
365
366 /* Open the cache file for reading and if successful, read it and set up the
367 parameters. */
368
369 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
370 if (fd < 0)
371   {
372   fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
373   exit(97);
374   }
375
376 if (fstat(fd, &statbuf) < 0)
377   {
378   (void)close(fd);
379   return gnutls_error(US"TLS cache stat failed", 0);
380   }
381
382 m.size = statbuf.st_size;
383 m.data = malloc(m.size);
384 if (m.data == NULL)
385   return gnutls_error(US"memory allocation failed", 0);
386 if (read(fd, m.data, m.size) != m.size)
387   return gnutls_error(US"TLS cache read failed", 0);
388 (void)close(fd);
389
390 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
391 if (ret < 0) return gnutls_error(US"DH params import", ret);
392 free(m.data);
393 }
394
395
396
397
398 /*************************************************
399 *            Initialize for GnuTLS               *
400 *************************************************/
401
402 /*
403 Arguments:
404   certificate     certificate file
405   privatekey      private key file
406 */
407
408 static void
409 tls_init(uschar *certificate, uschar *privatekey)
410 {
411 int rc;
412
413 rc = gnutls_global_init();
414 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
415
416 /* Read D-H parameters from the cache file. */
417
418 init_dh();
419
420 /* Create the credentials structure */
421
422 rc = gnutls_certificate_allocate_credentials(&x509_cred);
423 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
424
425 /* Set the certificate and private keys */
426
427 if (certificate != NULL)
428   {
429   rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
430     CS privatekey, GNUTLS_X509_FMT_PEM);
431   if (rc < 0) gnutls_error("gnutls_certificate", rc);
432   }
433
434 /* Associate the parameters with the x509 credentials structure. */
435
436 gnutls_certificate_set_dh_params(x509_cred, dh_params);
437
438 /* set the CA info for server-cert verify */
439 if (ocsp_stapling)
440   gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
441         GNUTLS_X509_FMT_PEM);
442 }
443
444
445
446 /*************************************************
447 *        Initialize a single GNUTLS session      *
448 *************************************************/
449
450 static gnutls_session_t
451 tls_session_init(void)
452 {
453 gnutls_session_t session;
454
455 gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_NO_EXTENSIONS);
456
457 #if GNUTLS_VERSION_NUMBER < 0x030400
458 gnutls_cipher_set_priority(session, default_cipher_priority);
459 gnutls_compression_set_priority(session, comp_priority);
460 gnutls_kx_set_priority(session, kx_priority);
461 gnutls_protocol_set_priority(session, protocol_priority);
462 gnutls_mac_set_priority(session, mac_priority);
463
464 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
465 #else
466 gnutls_set_default_priority(session);
467 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
468 #endif
469
470 gnutls_dh_set_prime_bits(session, DH_BITS);
471 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
472
473 return session;
474 }
475 #endif
476
477
478 /****************************************************************************/
479 /****************************************************************************/
480
481
482
483
484 /*************************************************
485 *                 Main Program                   *
486 *************************************************/
487
488 const char * const HELP_MESSAGE = "\n\
489 Usage: client\n"
490 #ifdef HAVE_TLS
491 "\
492           [-tls-on-connect]\n\
493           [-ocsp]\n"
494 #endif
495 "\
496           [-tn] n seconds timeout\n\
497           <IP address>\n\
498           <port>\n\
499           [<outgoing interface>]\n\
500           [<cert file>]\n\
501           [<key file>]\n\
502 \n";
503
504 int main(int argc, char **argv)
505 {
506 struct sockaddr *s_ptr;
507 struct sockaddr_in s_in4;
508 char *interface = NULL;
509 char *address = NULL;
510 char *certfile = NULL;
511 char *keyfile = NULL;
512 char *end = NULL;
513 int argi = 1;
514 int host_af, port, s_len, rc, sock, save_errno;
515 int timeout = 5;
516 int tls_active = 0;
517 int sent_starttls = 0;
518 int tls_on_connect = 0;
519 long tmplong;
520
521 #if HAVE_IPV6
522 struct sockaddr_in6 s_in6;
523 #endif
524
525 #ifdef HAVE_OPENSSL
526 SSL_CTX* ctx;
527 SSL*     ssl;
528 #endif
529
530 unsigned char outbuffer[10240];
531 unsigned char inbuffer[10240];
532 unsigned char *inptr = inbuffer;
533
534 *inptr = 0;   /* Buffer empty */
535
536 /* Options */
537
538 while (argc >= argi + 1 && argv[argi][0] == '-')
539   {
540   if (strcmp(argv[argi], "-help") == 0 ||
541       strcmp(argv[argi], "--help") == 0 ||
542       strcmp(argv[argi], "-h") == 0)
543     {
544     puts(HELP_MESSAGE);
545     exit(0);
546     }
547   if (strcmp(argv[argi], "-tls-on-connect") == 0)
548     {
549     tls_on_connect = 1;
550     argi++;
551     }
552 #ifdef HAVE_TLS
553   else if (strcmp(argv[argi], "-ocsp") == 0)
554     {
555     if (argc < ++argi + 1)
556       {
557       fprintf(stderr, "Missing required certificate file for ocsp option\n");
558       exit(96);
559       }
560     ocsp_stapling = argv[argi++];
561     }
562
563 #endif
564   else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
565     {
566     tmplong = strtol(argv[argi]+2, &end, 10);
567     if (end == argv[argi]+2 || *end)
568       {
569       fprintf(stderr, "Failed to parse seconds from option <%s>\n",
570         argv[argi]);
571       exit(95);
572       }
573     if (tmplong > 10000L)
574       {
575       fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
576         tmplong);
577       exit(94);
578       }
579     if (tmplong < 0L)
580       {
581       fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
582       exit(93);
583       }
584     timeout = (int) tmplong;
585     argi++;
586     }
587   else
588     {
589     fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
590     exit(92);
591     }
592   }
593
594 /* Mandatory 1st arg is IP address */
595
596 if (argc < argi+1)
597   {
598   fprintf(stderr, "No IP address given\n");
599   exit(91);
600   }
601
602 address = argv[argi++];
603 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
604
605 /* Mandatory 2nd arg is port */
606
607 if (argc < argi+1)
608   {
609   fprintf(stderr, "No port number given\n");
610   exit(90);
611   }
612
613 port = atoi(argv[argi++]);
614
615 /* Optional next arg is interface */
616
617 if (argc > argi &&
618   (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
619     interface = argv[argi++];
620
621 /* Any more arguments are the name of a certificate file and key file */
622
623 if (argc > argi) certfile = argv[argi++];
624 if (argc > argi) keyfile = argv[argi++];
625
626
627 #if HAVE_IPV6
628 /* For an IPv6 address, use an IPv6 sockaddr structure. */
629
630 if (host_af == AF_INET6)
631   {
632   s_ptr = (struct sockaddr *)&s_in6;
633   s_len = sizeof(s_in6);
634   }
635 else
636 #endif
637
638 /* For an IPv4 address, use an IPv4 sockaddr structure,
639 even on an IPv6 system. */
640
641   {
642   s_ptr = (struct sockaddr *)&s_in4;
643   s_len = sizeof(s_in4);
644   }
645
646 printf("Connecting to %s port %d ... ", address, port);
647
648 sock = socket(host_af, SOCK_STREAM, 0);
649 if (sock < 0)
650   {
651   printf("socket creation failed: %s\n", strerror(errno));
652   exit(89);
653   }
654
655 /* Bind to a specific interface if requested. On an IPv6 system, this has
656 to be of the same family as the address we are calling. On an IPv4 system the
657 test is redundant, but it keeps the code tidier. */
658
659 if (interface != NULL)
660   {
661   int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
662
663   if (interface_af == host_af)
664     {
665     #if HAVE_IPV6
666
667     /* Set up for IPv6 binding */
668
669     if (host_af == AF_INET6)
670       {
671       memset(&s_in6, 0, sizeof(s_in6));
672       s_in6.sin6_family = AF_INET6;
673       s_in6.sin6_port = 0;
674       if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
675         {
676         printf("Unable to parse \"%s\"", interface);
677         exit(88);
678         }
679       }
680     else
681     #endif
682
683     /* Set up for IPv4 binding */
684
685       {
686       memset(&s_in4, 0, sizeof(s_in4));
687       s_in4.sin_family = AF_INET;
688       s_in4.sin_port = 0;
689       s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
690       }
691
692     /* Bind */
693
694     if (bind(sock, s_ptr, s_len) < 0)
695       {
696       printf("Unable to bind outgoing SMTP call to %s: %s",
697         interface, strerror(errno));
698       exit(87);
699       }
700     }
701   }
702
703 /* Set up a remote IPv6 address */
704
705 #if HAVE_IPV6
706 if (host_af == AF_INET6)
707   {
708   memset(&s_in6, 0, sizeof(s_in6));
709   s_in6.sin6_family = AF_INET6;
710   s_in6.sin6_port = htons(port);
711   if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
712     {
713     printf("Unable to parse \"%s\"", address);
714     exit(86);
715     }
716   }
717 else
718 #endif
719
720 /* Set up a remote IPv4 address */
721
722   {
723   memset(&s_in4, 0, sizeof(s_in4));
724   s_in4.sin_family = AF_INET;
725   s_in4.sin_port = htons(port);
726   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
727   }
728
729 /* SIGALRM handler crashes out */
730
731 signal(SIGALRM, sigalrm_handler_crash);
732 alarm(timeout);
733 rc = connect(sock, s_ptr, s_len);
734 save_errno = errno;
735 alarm(0);
736
737 /* A failure whose error code is "Interrupted system call" is in fact
738 an externally applied timeout if the signal handler has been run. */
739
740 if (rc < 0)
741   {
742   close(sock);
743   printf("connect failed: %s\n", strerror(save_errno));
744   exit(85);
745   }
746
747 printf("connected\n");
748
749
750 /* --------------- Set up for OpenSSL --------------- */
751
752 #ifdef HAVE_OPENSSL
753 SSL_library_init();
754 SSL_load_error_strings();
755
756 ctx = SSL_CTX_new(SSLv23_method());
757 if (ctx == NULL)
758   {
759   printf ("SSL_CTX_new failed\n");
760   exit(84);
761   }
762
763 if (certfile != NULL)
764   {
765   if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
766     {
767     printf("SSL_CTX_use_certificate_file failed\n");
768     exit(83);
769     }
770   printf("Certificate file = %s\n", certfile);
771   }
772
773 if (keyfile != NULL)
774   {
775   if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
776     {
777     printf("SSL_CTX_use_PrivateKey_file failed\n");
778     exit(82);
779     }
780   printf("Key file = %s\n", keyfile);
781   }
782
783 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
784 SSL_CTX_set_timeout(ctx, 200);
785 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
786 #endif
787
788
789 /* --------------- Set up for GnuTLS --------------- */
790
791 #ifdef HAVE_GNUTLS
792 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
793 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
794 tls_init(certfile, keyfile);
795 tls_session = tls_session_init();
796 #ifdef HAVE_OCSP
797 if (ocsp_stapling)
798   gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
799 #endif
800 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)sock);
801
802 /* When the server asks for a certificate and the client does not have one,
803 there is a SIGPIPE error in the gnutls_handshake() function for some reason
804 that is not understood. As luck would have it, this has never hit Exim itself
805 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
806 one wants. */
807
808 signal(SIGPIPE, SIG_IGN);
809 #endif
810
811 /* ---------------------------------------------- */
812
813
814 /* Start TLS session if configured to do so without STARTTLS */
815
816 #ifdef HAVE_TLS
817 if (tls_on_connect)
818   {
819   printf("Attempting to start TLS\n");
820
821 #ifdef HAVE_OPENSSL
822   tls_active = tls_start(sock, &ssl, ctx);
823 #endif
824
825 #ifdef HAVE_GNUTLS
826   {
827   int rc;
828   sigalrm_seen = FALSE;
829   alarm(timeout);
830   do {
831     rc = gnutls_handshake(tls_session);
832   } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
833   tls_active = rc >= 0;
834   alarm(0);
835
836   if (!tls_active) printf("%s\n", gnutls_strerror(rc));
837   }
838 #endif
839
840   if (!tls_active)
841     printf("Failed to start TLS\n");
842 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
843   else if (  ocsp_stapling
844           && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
845     printf("Failed to verify certificate status\n");
846 #endif
847   else
848     printf("Succeeded in starting TLS\n");
849   }
850 #endif
851
852 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
853   {
854   int n = (int)strlen(CS outbuffer);
855
856   /* Strip trailing newline */
857   if (outbuffer[n-1] == '\n') outbuffer[--n] = 0;
858
859   /* Expect incoming */
860
861   if (  strncmp(CS outbuffer, "???", 3) == 0
862      && (outbuffer[3] == ' ' || outbuffer[3] == '*')
863      )
864     {
865     unsigned char *lineptr;
866     unsigned exp_eof = outbuffer[3] == '*';
867
868     printf("%s\n", outbuffer);
869
870     if (*inptr == 0)   /* Refill input buffer */
871       {
872       if (tls_active)
873         {
874         #ifdef HAVE_OPENSSL
875         rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
876         #endif
877         #ifdef HAVE_GNUTLS
878         rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
879         #endif
880         }
881       else
882         {
883         alarm(timeout);
884         rc = read(sock, inbuffer, sizeof(inbuffer));
885         alarm(0);
886         }
887
888       if (rc < 0)
889         {
890         printf("Read error %s\n", strerror(errno));
891         exit(81);
892         }
893       else if (rc == 0)
894         if (exp_eof)
895           {
896           printf("Expected EOF read\n");
897           continue;
898           }
899         else
900           {
901           printf("Enexpected EOF read\n");
902           close(sock);
903           exit(80);
904           }
905       else if (exp_eof)
906         {
907         printf("Expected EOF not read\n");
908         close(sock);
909         exit(74);
910         }
911       else
912         {
913         inbuffer[rc] = 0;
914         inptr = inbuffer;
915         }
916       }
917
918     lineptr = inptr;
919     while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
920     if (*inptr != 0)
921       {
922       *inptr++ = 0;
923       if (*inptr == '\n') inptr++;
924       }
925
926     printf("<<< %s\n", lineptr);
927     if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
928       {
929       printf("\n******** Input mismatch ********\n");
930       exit(79);
931       }
932
933     #ifdef HAVE_TLS
934     if (sent_starttls)
935       {
936       if (lineptr[0] == '2')
937         {
938 int rc;
939         unsigned int verify;
940
941         printf("Attempting to start TLS\n");
942         fflush(stdout);
943
944         #ifdef HAVE_OPENSSL
945         tls_active = tls_start(sock, &ssl, ctx);
946         #endif
947
948         #ifdef HAVE_GNUTLS
949           {
950           int rc;
951           sigalrm_seen = FALSE;
952           alarm(timeout);
953           do {
954             rc = gnutls_handshake(tls_session);
955           } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
956           tls_active = rc >= 0;
957           alarm(0);
958
959           if (!tls_active) printf("%s\n", gnutls_strerror(rc));
960           }
961         #endif
962
963         if (!tls_active)
964           {
965           printf("Failed to start TLS\n");
966           fflush(stdout);
967           }
968         #ifdef HAVE_GNUTLS
969         else if (ocsp_stapling)
970           {
971           if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
972             {
973             printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
974             fflush(stdout);
975             }
976           else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
977             {
978             printf("Bad certificate\n");
979             fflush(stdout);
980             }
981           #ifdef HAVE_OCSP
982           else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
983             {
984             printf("Failed to verify certificate status\n");
985               {
986               gnutls_datum_t stapling;
987               gnutls_ocsp_resp_t resp;
988               gnutls_datum_t printed;
989               if (  (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
990                  && (rc= gnutls_ocsp_resp_init(&resp)) == 0
991                  && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
992                  && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
993                  )
994                 {
995                 fprintf(stderr, "%.4096s", printed.data);
996                 gnutls_free(printed.data);
997                 }
998               else
999                 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
1000               }
1001             fflush(stdout);
1002             }
1003           #endif
1004           }
1005         #endif
1006         else
1007           printf("Succeeded in starting TLS\n");
1008         }
1009       else printf("Abandoning TLS start attempt\n");
1010       }
1011     sent_starttls = 0;
1012     #endif
1013     }
1014
1015   /* Wait for a bit before proceeding */
1016
1017   else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
1018     {
1019     printf("%s\n", outbuffer);
1020     sleep(atoi(CS outbuffer + 4));
1021     }
1022
1023   /* Send outgoing, but barf if unconsumed incoming */
1024
1025   else
1026     {
1027     unsigned char *escape;
1028
1029     if (*inptr != 0)
1030       {
1031       printf("Unconsumed input: %s", inptr);
1032       printf("   About to send: %s\n", outbuffer);
1033       exit(78);
1034       }
1035
1036     #ifdef HAVE_TLS
1037
1038     /* Shutdown TLS */
1039
1040     if (strcmp(CS outbuffer, "stoptls") == 0 ||
1041         strcmp(CS outbuffer, "STOPTLS") == 0)
1042       {
1043       if (!tls_active)
1044         {
1045         printf("STOPTLS read when TLS not active\n");
1046         exit(77);
1047         }
1048       printf("Shutting down TLS encryption\n");
1049
1050       #ifdef HAVE_OPENSSL
1051       SSL_shutdown(ssl);
1052       SSL_free(ssl);
1053       #endif
1054
1055       #ifdef HAVE_GNUTLS
1056       gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1057       gnutls_deinit(tls_session);
1058       tls_session = NULL;
1059       gnutls_global_deinit();
1060       #endif
1061
1062       tls_active = 0;
1063       continue;
1064       }
1065
1066     /* Remember that we sent STARTTLS */
1067
1068     sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1069                      strcmp(CS outbuffer, "STARTTLS") == 0);
1070
1071     /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1072     but we haven't set the flag, so that there is no negotiation. This is for
1073     testing the server's timeout. */
1074
1075     if (strcmp(CS outbuffer, "starttls_wait") == 0)
1076       {
1077       outbuffer[8] = 0;
1078       n = 8;
1079       }
1080     #endif
1081
1082     printf(">>> %s\n", outbuffer);
1083     strcpy(CS outbuffer + n, "\r\n");
1084
1085     /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1086
1087     while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1088       {
1089       *escape = '\r';
1090       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
1091       n--;
1092       }
1093
1094     while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
1095       {
1096       *escape = '\n';
1097       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
1098       n--;
1099       }
1100
1101     /* OK, do it */
1102
1103     alarm(timeout);
1104     if (tls_active)
1105       {
1106       #ifdef HAVE_OPENSSL
1107         rc = SSL_write (ssl, outbuffer, n + 2);
1108       #endif
1109       #ifdef HAVE_GNUTLS
1110         rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1111         if (rc < 0)
1112           {
1113           printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1114           exit(76);
1115           }
1116       #endif
1117       }
1118     else
1119       {
1120       rc = write(sock, outbuffer, n + 2);
1121       }
1122     alarm(0);
1123
1124     if (rc < 0)
1125       {
1126       printf("Write error: %s\n", strerror(errno));
1127       exit(75);
1128       }
1129     }
1130   }
1131
1132 printf("End of script\n");
1133 shutdown(sock, SHUT_WR);
1134 while ((rc = read(sock, inbuffer, sizeof(inbuffer))) > 0) ;
1135 close(sock);
1136
1137 exit(0);
1138 }
1139
1140 /* End of client.c */