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