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