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