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