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