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. */
7 /* ANSI C standard includes */
22 #include <sys/types.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
29 #include <arpa/inet.h>
31 #include <sys/resource.h>
32 #include <sys/socket.h>
43 #define S_ADDR_TYPE u_long
46 typedef unsigned char uschar;
49 #define US (unsigned char *)
56 static int sigalrm_seen = 0;
59 /* TLS support can be optionally included, either for OpenSSL or GnuTLS. The
60 latter needs a whole pile of tables. */
63 # include <openssl/crypto.h>
64 # include <openssl/x509.h>
65 # include <openssl/pem.h>
66 # include <openssl/ssl.h>
67 # include <openssl/err.h>
68 # include <openssl/rand.h>
69 # if !defined(EXIM_HAVE_OPENSSL_TLSEXT) && !defined(DISABLE_OCSP)
70 # warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
74 # include <openssl/ocsp.h>
81 # include <gnutls/gnutls.h>
82 # include <gnutls/x509.h>
83 # if GNUTLS_VERSION_NUMBER >= 0x030103
85 # include <gnutls/ocsp.h>
90 /* Local static variables for GNUTLS */
92 static gnutls_dh_params dh_params = NULL;
94 static gnutls_certificate_credentials_t x509_cred = NULL;
95 static gnutls_session tls_session = NULL;
97 static int ssl_session_timeout = 200;
99 /* Priorities for TLS algorithms to use. */
101 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
103 static const int kx_priority[16] = {
109 static int default_cipher_priority[16] = {
110 GNUTLS_CIPHER_AES_256_CBC,
111 GNUTLS_CIPHER_AES_128_CBC,
112 GNUTLS_CIPHER_3DES_CBC,
113 GNUTLS_CIPHER_ARCFOUR_128,
116 static const int mac_priority[16] = {
121 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
122 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
124 #endif /*HAVE_GNUTLS*/
129 char * ocsp_stapling = NULL;
133 /*************************************************
134 * SIGALRM handler - crash out *
135 *************************************************/
138 sigalrm_handler_crash(int sig)
140 sig = sig; /* Keep picky compilers happy */
141 printf("\nClient timed out\n");
146 /*************************************************
147 * SIGALRM handler - set flag *
148 *************************************************/
151 sigalrm_handler_flag(int sig)
153 sig = sig; /* Keep picky compilers happy */
159 /****************************************************************************/
160 /****************************************************************************/
165 setup_verify(BIO *bp, char *CAfile, char *CApath)
169 if(!(store = X509_STORE_new())) goto end;
170 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
171 if (lookup == NULL) goto end;
173 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
174 BIO_printf(bp, "Error loading file %s\n", CAfile);
177 } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
179 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
180 if (lookup == NULL) goto end;
182 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
183 BIO_printf(bp, "Error loading directory %s\n", CApath);
186 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
191 X509_STORE_free(store);
198 tls_client_stapling_cb(SSL *s, void *arg)
200 const unsigned char *p;
205 X509_STORE *store = NULL;
208 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
209 /*BIO_printf(arg, "OCSP response: ");*/
212 BIO_printf(arg, "no response received\n");
215 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
217 BIO_printf(arg, "response parse error\n");
218 BIO_dump_indent(arg, (char *)p, len, 4);
221 if(!(bs = OCSP_response_get1_basic(rsp)))
223 BIO_printf(arg, "error parsing response\n");
227 CAfile = ocsp_stapling;
228 if(!(store = setup_verify(arg, CAfile, NULL)))
230 BIO_printf(arg, "error in cert setup\n");
234 /* No file of alternate certs, no options */
235 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
237 BIO_printf(arg, "Response Verify Failure\n");
238 ERR_print_errors(arg);
242 BIO_printf(arg, "Response verify OK\n");
244 X509_STORE_free(store);
250 /*************************************************
251 * Start an OpenSSL TLS session *
252 *************************************************/
255 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
258 static const unsigned char *sid_ctx = "exim";
260 RAND_load_file("client.c", -1); /* Not *very* random! */
262 *ssl = SSL_new (ctx);
263 SSL_set_session_id_context(*ssl, sid_ctx, strlen(sid_ctx));
264 SSL_set_fd (*ssl, sock);
265 SSL_set_connect_state(*ssl);
270 SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
271 SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
272 SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
276 signal(SIGALRM, sigalrm_handler_flag);
279 rc = SSL_connect (*ssl);
284 printf("SSL_connect timed out\n");
290 ERR_print_errors_fp(stdout);
294 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
299 /*************************************************
300 * SSL Information callback *
301 *************************************************/
304 info_callback(SSL *s, int where, int ret)
308 printf("SSL info: %s\n", SSL_state_string_long(s));
313 /****************************************************************************/
314 /****************************************************************************/
318 /*************************************************
319 * Handle GnuTLS error *
320 *************************************************/
322 /* Called from lots of places when errors occur before actually starting to do
323 the TLS handshake, that is, while the session is still in clear.
327 err a GnuTLS error number, or 0 if local error
329 Returns: doesn't - it dies
333 gnutls_error(uschar *prefix, int err)
335 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
336 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
337 fprintf(stderr, "\n");
343 /*************************************************
344 * Setup up DH parameters *
345 *************************************************/
347 /* For the test suite, the parameters should always be available in the spool
356 uschar filename[200];
359 /* Initialize the data structures for holding the parameters */
361 ret = gnutls_dh_params_init(&dh_params);
362 if (ret < 0) gnutls_error(US"init dh_params", ret);
364 /* Open the cache file for reading and if successful, read it and set up the
367 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
370 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
374 if (fstat(fd, &statbuf) < 0)
377 return gnutls_error(US"TLS cache stat failed", 0);
380 m.size = statbuf.st_size;
381 m.data = malloc(m.size);
383 return gnutls_error(US"memory allocation failed", 0);
384 if (read(fd, m.data, m.size) != m.size)
385 return gnutls_error(US"TLS cache read failed", 0);
388 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
389 if (ret < 0) return gnutls_error(US"DH params import", ret);
396 /*************************************************
397 * Initialize for GnuTLS *
398 *************************************************/
402 certificate certificate file
403 privatekey private key file
407 tls_init(uschar *certificate, uschar *privatekey)
411 rc = gnutls_global_init();
412 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
414 /* Read D-H parameters from the cache file. */
418 /* Create the credentials structure */
420 rc = gnutls_certificate_allocate_credentials(&x509_cred);
421 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
423 /* Set the certificate and private keys */
425 if (certificate != NULL)
427 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
428 CS privatekey, GNUTLS_X509_FMT_PEM);
429 if (rc < 0) gnutls_error("gnutls_certificate", rc);
432 /* Associate the parameters with the x509 credentials structure. */
434 gnutls_certificate_set_dh_params(x509_cred, dh_params);
436 /* set the CA info for server-cert verify */
438 gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
439 GNUTLS_X509_FMT_PEM);
444 /*************************************************
445 * Initialize a single GNUTLS session *
446 *************************************************/
448 static gnutls_session
449 tls_session_init(void)
451 gnutls_session session;
453 gnutls_init(&session, GNUTLS_CLIENT);
455 gnutls_cipher_set_priority(session, default_cipher_priority);
456 gnutls_compression_set_priority(session, comp_priority);
457 gnutls_kx_set_priority(session, kx_priority);
458 gnutls_protocol_set_priority(session, protocol_priority);
459 gnutls_mac_set_priority(session, mac_priority);
461 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
463 gnutls_dh_set_prime_bits(session, DH_BITS);
464 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
471 /****************************************************************************/
472 /****************************************************************************/
477 /*************************************************
479 *************************************************/
481 const char * const HELP_MESSAGE = "\n\
485 [<outgoing interface>]\n\
490 int main(int argc, char **argv)
492 struct sockaddr *s_ptr;
493 struct sockaddr_in s_in4;
494 char *interface = NULL;
495 char *address = NULL;
496 char *certfile = NULL;
497 char *keyfile = NULL;
500 int host_af, port, s_len, rc, sock, save_errno;
503 int sent_starttls = 0;
504 int tls_on_connect = 0;
508 struct sockaddr_in6 s_in6;
516 unsigned char outbuffer[10240];
517 unsigned char inbuffer[10240];
518 unsigned char *inptr = inbuffer;
520 *inptr = 0; /* Buffer empty */
524 while (argc >= argi + 1 && argv[argi][0] == '-')
526 if (strcmp(argv[argi], "-help") == 0 ||
527 strcmp(argv[argi], "--help") == 0 ||
528 strcmp(argv[argi], "-h") == 0)
533 if (strcmp(argv[argi], "-tls-on-connect") == 0)
539 else if (strcmp(argv[argi], "-ocsp") == 0)
541 if (argc < ++argi + 1)
543 fprintf(stderr, "Missing required certificate file for ocsp option\n");
546 ocsp_stapling = argv[argi++];
550 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
552 tmplong = strtol(argv[argi]+2, &end, 10);
553 if (end == argv[argi]+2 || *end)
555 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
559 if (tmplong > 10000L)
561 fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
567 fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
570 timeout = (int) tmplong;
575 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
580 /* Mandatory 1st arg is IP address */
584 fprintf(stderr, "No IP address given\n");
588 address = argv[argi++];
589 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
591 /* Mandatory 2nd arg is port */
595 fprintf(stderr, "No port number given\n");
599 port = atoi(argv[argi++]);
601 /* Optional next arg is interface */
604 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
605 interface = argv[argi++];
607 /* Any more arguments are the name of a certificate file and key file */
609 if (argc > argi) certfile = argv[argi++];
610 if (argc > argi) keyfile = argv[argi++];
614 /* For an IPv6 address, use an IPv6 sockaddr structure. */
616 if (host_af == AF_INET6)
618 s_ptr = (struct sockaddr *)&s_in6;
619 s_len = sizeof(s_in6);
624 /* For an IPv4 address, use an IPv4 sockaddr structure,
625 even on an IPv6 system. */
628 s_ptr = (struct sockaddr *)&s_in4;
629 s_len = sizeof(s_in4);
632 printf("Connecting to %s port %d ... ", address, port);
634 sock = socket(host_af, SOCK_STREAM, 0);
637 printf("socket creation failed: %s\n", strerror(errno));
641 /* Bind to a specific interface if requested. On an IPv6 system, this has
642 to be of the same family as the address we are calling. On an IPv4 system the
643 test is redundant, but it keeps the code tidier. */
645 if (interface != NULL)
647 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
649 if (interface_af == host_af)
653 /* Set up for IPv6 binding */
655 if (host_af == AF_INET6)
657 memset(&s_in6, 0, sizeof(s_in6));
658 s_in6.sin6_family = AF_INET6;
660 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
662 printf("Unable to parse \"%s\"", interface);
669 /* Set up for IPv4 binding */
672 memset(&s_in4, 0, sizeof(s_in4));
673 s_in4.sin_family = AF_INET;
675 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
680 if (bind(sock, s_ptr, s_len) < 0)
682 printf("Unable to bind outgoing SMTP call to %s: %s",
683 interface, strerror(errno));
689 /* Set up a remote IPv6 address */
692 if (host_af == AF_INET6)
694 memset(&s_in6, 0, sizeof(s_in6));
695 s_in6.sin6_family = AF_INET6;
696 s_in6.sin6_port = htons(port);
697 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
699 printf("Unable to parse \"%s\"", address);
706 /* Set up a remote IPv4 address */
709 memset(&s_in4, 0, sizeof(s_in4));
710 s_in4.sin_family = AF_INET;
711 s_in4.sin_port = htons(port);
712 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
715 /* SIGALRM handler crashes out */
717 signal(SIGALRM, sigalrm_handler_crash);
719 rc = connect(sock, s_ptr, s_len);
723 /* A failure whose error code is "Interrupted system call" is in fact
724 an externally applied timeout if the signal handler has been run. */
729 printf("connect failed: %s\n", strerror(save_errno));
733 printf("connected\n");
736 /* --------------- Set up for OpenSSL --------------- */
740 SSL_load_error_strings();
742 ctx = SSL_CTX_new(SSLv23_method());
745 printf ("SSL_CTX_new failed\n");
749 if (certfile != NULL)
751 if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
753 printf("SSL_CTX_use_certificate_file failed\n");
756 printf("Certificate file = %s\n", certfile);
761 if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
763 printf("SSL_CTX_use_PrivateKey_file failed\n");
766 printf("Key file = %s\n", keyfile);
769 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
770 SSL_CTX_set_timeout(ctx, 200);
771 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
775 /* --------------- Set up for GnuTLS --------------- */
778 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
779 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
780 tls_init(certfile, keyfile);
781 tls_session = tls_session_init();
784 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
786 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
788 /* When the server asks for a certificate and the client does not have one,
789 there is a SIGPIPE error in the gnutls_handshake() function for some reason
790 that is not understood. As luck would have it, this has never hit Exim itself
791 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
794 signal(SIGPIPE, SIG_IGN);
797 /* ---------------------------------------------- */
800 /* Start TLS session if configured to do so without STARTTLS */
805 printf("Attempting to start TLS\n");
808 tls_active = tls_start(sock, &ssl, ctx);
812 sigalrm_seen = FALSE;
814 tls_active = gnutls_handshake(tls_session) >= 0;
819 printf("Failed to start TLS\n");
820 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
821 else if ( ocsp_stapling
822 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
823 printf("Failed to verify certificate status\n");
826 printf("Succeeded in starting TLS\n");
830 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
832 int n = (int)strlen(CS outbuffer);
833 while (n > 0 && isspace(outbuffer[n-1])) n--;
836 /* Expect incoming */
838 if (strncmp(CS outbuffer, "??? ", 4) == 0)
840 unsigned char *lineptr;
841 printf("%s\n", outbuffer);
843 if (*inptr == 0) /* Refill input buffer */
848 rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
851 rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
857 rc = read(sock, inbuffer, sizeof(inbuffer));
863 printf("Read error %s\n", strerror(errno));
868 printf("Unexpected EOF read\n");
880 while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
884 if (*inptr == '\n') inptr++;
887 printf("<<< %s\n", lineptr);
888 if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
890 printf("\n******** Input mismatch ********\n");
897 if (lineptr[0] == '2')
902 printf("Attempting to start TLS\n");
906 tls_active = tls_start(sock, &ssl, ctx);
910 sigalrm_seen = FALSE;
912 tls_active = gnutls_handshake(tls_session) >= 0;
918 printf("Failed to start TLS\n");
922 else if (ocsp_stapling)
924 if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
926 printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
929 else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
931 printf("Bad certificate\n");
935 else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
937 printf("Failed to verify certificate status\n");
939 gnutls_datum_t stapling;
940 gnutls_ocsp_resp_t resp;
941 gnutls_datum_t printed;
942 if ( (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
943 && (rc= gnutls_ocsp_resp_init(&resp)) == 0
944 && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
945 && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
948 fprintf(stderr, "%.4096s", printed.data);
949 gnutls_free(printed.data);
952 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
960 printf("Succeeded in starting TLS\n");
962 else printf("Abandoning TLS start attempt\n");
968 /* Wait for a bit before proceeding */
970 else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
972 printf("%s\n", outbuffer);
973 sleep(atoi(CS outbuffer + 4));
976 /* Send outgoing, but barf if unconsumed incoming */
980 unsigned char *escape;
984 printf("Unconsumed input: %s", inptr);
985 printf(" About to send: %s\n", outbuffer);
993 if (strcmp(CS outbuffer, "stoptls") == 0 ||
994 strcmp(CS outbuffer, "STOPTLS") == 0)
998 printf("STOPTLS read when TLS not active\n");
1001 printf("Shutting down TLS encryption\n");
1009 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1010 gnutls_deinit(tls_session);
1012 gnutls_global_deinit();
1019 /* Remember that we sent STARTTLS */
1021 sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1022 strcmp(CS outbuffer, "STARTTLS") == 0);
1024 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1025 but we haven't set the flag, so that there is no negotiation. This is for
1026 testing the server's timeout. */
1028 if (strcmp(CS outbuffer, "starttls_wait") == 0)
1035 printf(">>> %s\n", outbuffer);
1036 strcpy(CS outbuffer + n, "\r\n");
1038 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1040 while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1043 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1047 while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
1050 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1060 rc = SSL_write (ssl, outbuffer, n + 2);
1063 rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1066 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1073 rc = write(sock, outbuffer, n + 2);
1079 printf("Write error: %s\n", strerror(errno));
1085 printf("End of script\n");
1091 /* End of client.c */