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