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>
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"
75 # include <openssl/ocsp.h>
82 # include <gnutls/gnutls.h>
83 # include <gnutls/x509.h>
84 # if GNUTLS_VERSION_NUMBER >= 0x030103
86 # include <gnutls/ocsp.h>
91 /* Local static variables for GNUTLS */
93 static gnutls_dh_params dh_params = NULL;
95 static gnutls_certificate_credentials_t x509_cred = NULL;
96 static gnutls_session tls_session = NULL;
98 static int ssl_session_timeout = 200;
100 /* Priorities for TLS algorithms to use. */
102 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
104 static const int kx_priority[16] = {
110 static int default_cipher_priority[16] = {
111 GNUTLS_CIPHER_AES_256_CBC,
112 GNUTLS_CIPHER_AES_128_CBC,
113 GNUTLS_CIPHER_3DES_CBC,
114 GNUTLS_CIPHER_ARCFOUR_128,
117 static const int mac_priority[16] = {
122 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
123 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
125 #endif /*HAVE_GNUTLS*/
130 char * ocsp_stapling = NULL;
134 /*************************************************
135 * SIGALRM handler - crash out *
136 *************************************************/
139 sigalrm_handler_crash(int sig)
141 sig = sig; /* Keep picky compilers happy */
142 printf("\nClient timed out\n");
147 /*************************************************
148 * SIGALRM handler - set flag *
149 *************************************************/
152 sigalrm_handler_flag(int sig)
154 sig = sig; /* Keep picky compilers happy */
160 /****************************************************************************/
161 /****************************************************************************/
166 setup_verify(BIO *bp, char *CAfile, char *CApath)
170 if(!(store = X509_STORE_new())) goto end;
171 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
172 if (lookup == NULL) goto end;
174 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
175 BIO_printf(bp, "Error loading file %s\n", CAfile);
178 } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
180 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
181 if (lookup == NULL) goto end;
183 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
184 BIO_printf(bp, "Error loading directory %s\n", CApath);
187 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
192 X509_STORE_free(store);
199 tls_client_stapling_cb(SSL *s, void *arg)
201 const unsigned char *p;
206 X509_STORE *store = NULL;
209 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
210 /*BIO_printf(arg, "OCSP response: ");*/
213 BIO_printf(arg, "no response received\n");
216 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
218 BIO_printf(arg, "response parse error\n");
219 BIO_dump_indent(arg, (char *)p, len, 4);
222 if(!(bs = OCSP_response_get1_basic(rsp)))
224 BIO_printf(arg, "error parsing response\n");
228 CAfile = ocsp_stapling;
229 if(!(store = setup_verify(arg, CAfile, NULL)))
231 BIO_printf(arg, "error in cert setup\n");
235 /* No file of alternate certs, no options */
236 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
238 BIO_printf(arg, "Response Verify Failure\n");
239 ERR_print_errors(arg);
243 BIO_printf(arg, "Response verify OK\n");
245 X509_STORE_free(store);
251 /*************************************************
252 * Start an OpenSSL TLS session *
253 *************************************************/
256 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
259 static const unsigned char *sid_ctx = US"exim";
261 RAND_load_file("client.c", -1); /* Not *very* random! */
263 *ssl = SSL_new (ctx);
264 SSL_set_session_id_context(*ssl, sid_ctx, strlen(CS sid_ctx));
265 SSL_set_fd (*ssl, sock);
266 SSL_set_connect_state(*ssl);
271 SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
272 SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
273 SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
277 signal(SIGALRM, sigalrm_handler_flag);
280 rc = SSL_connect (*ssl);
285 printf("SSL_connect timed out\n");
291 ERR_print_errors_fp(stdout);
295 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
300 /*************************************************
301 * SSL Information callback *
302 *************************************************/
305 info_callback(SSL *s, int where, int ret)
309 printf("SSL info: %s\n", SSL_state_string_long(s));
314 /****************************************************************************/
315 /****************************************************************************/
319 /*************************************************
320 * Handle GnuTLS error *
321 *************************************************/
323 /* Called from lots of places when errors occur before actually starting to do
324 the TLS handshake, that is, while the session is still in clear.
328 err a GnuTLS error number, or 0 if local error
330 Returns: doesn't - it dies
334 gnutls_error(uschar *prefix, int err)
336 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
337 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
338 fprintf(stderr, "\n");
344 /*************************************************
345 * Setup up DH parameters *
346 *************************************************/
348 /* For the test suite, the parameters should always be available in the spool
357 uschar filename[200];
360 /* Initialize the data structures for holding the parameters */
362 ret = gnutls_dh_params_init(&dh_params);
363 if (ret < 0) gnutls_error(US"init dh_params", ret);
365 /* Open the cache file for reading and if successful, read it and set up the
368 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
371 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
375 if (fstat(fd, &statbuf) < 0)
378 return gnutls_error(US"TLS cache stat failed", 0);
381 m.size = statbuf.st_size;
382 m.data = malloc(m.size);
384 return gnutls_error(US"memory allocation failed", 0);
385 if (read(fd, m.data, m.size) != m.size)
386 return gnutls_error(US"TLS cache read failed", 0);
389 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
390 if (ret < 0) return gnutls_error(US"DH params import", ret);
397 /*************************************************
398 * Initialize for GnuTLS *
399 *************************************************/
403 certificate certificate file
404 privatekey private key file
408 tls_init(uschar *certificate, uschar *privatekey)
412 rc = gnutls_global_init();
413 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
415 /* Read D-H parameters from the cache file. */
419 /* Create the credentials structure */
421 rc = gnutls_certificate_allocate_credentials(&x509_cred);
422 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
424 /* Set the certificate and private keys */
426 if (certificate != NULL)
428 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
429 CS privatekey, GNUTLS_X509_FMT_PEM);
430 if (rc < 0) gnutls_error("gnutls_certificate", rc);
433 /* Associate the parameters with the x509 credentials structure. */
435 gnutls_certificate_set_dh_params(x509_cred, dh_params);
437 /* set the CA info for server-cert verify */
439 gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
440 GNUTLS_X509_FMT_PEM);
445 /*************************************************
446 * Initialize a single GNUTLS session *
447 *************************************************/
449 static gnutls_session
450 tls_session_init(void)
452 gnutls_session session;
454 gnutls_init(&session, GNUTLS_CLIENT);
456 gnutls_cipher_set_priority(session, default_cipher_priority);
457 gnutls_compression_set_priority(session, comp_priority);
458 gnutls_kx_set_priority(session, kx_priority);
459 gnutls_protocol_set_priority(session, protocol_priority);
460 gnutls_mac_set_priority(session, mac_priority);
462 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
464 gnutls_dh_set_prime_bits(session, DH_BITS);
465 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
472 /****************************************************************************/
473 /****************************************************************************/
478 /*************************************************
480 *************************************************/
482 const char * const HELP_MESSAGE = "\n\
490 [-tn] n seconds timeout\n\
493 [<outgoing interface>]\n\
498 int main(int argc, char **argv)
500 struct sockaddr *s_ptr;
501 struct sockaddr_in s_in4;
502 char *interface = NULL;
503 char *address = NULL;
504 char *certfile = NULL;
505 char *keyfile = NULL;
508 int host_af, port, s_len, rc, sock, save_errno;
511 int sent_starttls = 0;
512 int tls_on_connect = 0;
516 struct sockaddr_in6 s_in6;
524 unsigned char outbuffer[10240];
525 unsigned char inbuffer[10240];
526 unsigned char *inptr = inbuffer;
528 *inptr = 0; /* Buffer empty */
532 while (argc >= argi + 1 && argv[argi][0] == '-')
534 if (strcmp(argv[argi], "-help") == 0 ||
535 strcmp(argv[argi], "--help") == 0 ||
536 strcmp(argv[argi], "-h") == 0)
541 if (strcmp(argv[argi], "-tls-on-connect") == 0)
547 else if (strcmp(argv[argi], "-ocsp") == 0)
549 if (argc < ++argi + 1)
551 fprintf(stderr, "Missing required certificate file for ocsp option\n");
554 ocsp_stapling = argv[argi++];
558 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
560 tmplong = strtol(argv[argi]+2, &end, 10);
561 if (end == argv[argi]+2 || *end)
563 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
567 if (tmplong > 10000L)
569 fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
575 fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
578 timeout = (int) tmplong;
583 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
588 /* Mandatory 1st arg is IP address */
592 fprintf(stderr, "No IP address given\n");
596 address = argv[argi++];
597 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
599 /* Mandatory 2nd arg is port */
603 fprintf(stderr, "No port number given\n");
607 port = atoi(argv[argi++]);
609 /* Optional next arg is interface */
612 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
613 interface = argv[argi++];
615 /* Any more arguments are the name of a certificate file and key file */
617 if (argc > argi) certfile = argv[argi++];
618 if (argc > argi) keyfile = argv[argi++];
622 /* For an IPv6 address, use an IPv6 sockaddr structure. */
624 if (host_af == AF_INET6)
626 s_ptr = (struct sockaddr *)&s_in6;
627 s_len = sizeof(s_in6);
632 /* For an IPv4 address, use an IPv4 sockaddr structure,
633 even on an IPv6 system. */
636 s_ptr = (struct sockaddr *)&s_in4;
637 s_len = sizeof(s_in4);
640 printf("Connecting to %s port %d ... ", address, port);
642 sock = socket(host_af, SOCK_STREAM, 0);
645 printf("socket creation failed: %s\n", strerror(errno));
649 /* Bind to a specific interface if requested. On an IPv6 system, this has
650 to be of the same family as the address we are calling. On an IPv4 system the
651 test is redundant, but it keeps the code tidier. */
653 if (interface != NULL)
655 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
657 if (interface_af == host_af)
661 /* Set up for IPv6 binding */
663 if (host_af == AF_INET6)
665 memset(&s_in6, 0, sizeof(s_in6));
666 s_in6.sin6_family = AF_INET6;
668 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
670 printf("Unable to parse \"%s\"", interface);
677 /* Set up for IPv4 binding */
680 memset(&s_in4, 0, sizeof(s_in4));
681 s_in4.sin_family = AF_INET;
683 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
688 if (bind(sock, s_ptr, s_len) < 0)
690 printf("Unable to bind outgoing SMTP call to %s: %s",
691 interface, strerror(errno));
697 /* Set up a remote IPv6 address */
700 if (host_af == AF_INET6)
702 memset(&s_in6, 0, sizeof(s_in6));
703 s_in6.sin6_family = AF_INET6;
704 s_in6.sin6_port = htons(port);
705 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
707 printf("Unable to parse \"%s\"", address);
714 /* Set up a remote IPv4 address */
717 memset(&s_in4, 0, sizeof(s_in4));
718 s_in4.sin_family = AF_INET;
719 s_in4.sin_port = htons(port);
720 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
723 /* SIGALRM handler crashes out */
725 signal(SIGALRM, sigalrm_handler_crash);
727 rc = connect(sock, s_ptr, s_len);
731 /* A failure whose error code is "Interrupted system call" is in fact
732 an externally applied timeout if the signal handler has been run. */
737 printf("connect failed: %s\n", strerror(save_errno));
741 printf("connected\n");
744 /* --------------- Set up for OpenSSL --------------- */
748 SSL_load_error_strings();
750 ctx = SSL_CTX_new(SSLv23_method());
753 printf ("SSL_CTX_new failed\n");
757 if (certfile != NULL)
759 if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
761 printf("SSL_CTX_use_certificate_file failed\n");
764 printf("Certificate file = %s\n", certfile);
769 if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
771 printf("SSL_CTX_use_PrivateKey_file failed\n");
774 printf("Key file = %s\n", keyfile);
777 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
778 SSL_CTX_set_timeout(ctx, 200);
779 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
783 /* --------------- Set up for GnuTLS --------------- */
786 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
787 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
788 tls_init(certfile, keyfile);
789 tls_session = tls_session_init();
792 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
794 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
796 /* When the server asks for a certificate and the client does not have one,
797 there is a SIGPIPE error in the gnutls_handshake() function for some reason
798 that is not understood. As luck would have it, this has never hit Exim itself
799 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
802 signal(SIGPIPE, SIG_IGN);
805 /* ---------------------------------------------- */
808 /* Start TLS session if configured to do so without STARTTLS */
813 printf("Attempting to start TLS\n");
816 tls_active = tls_start(sock, &ssl, ctx);
820 sigalrm_seen = FALSE;
822 tls_active = gnutls_handshake(tls_session) >= 0;
827 printf("Failed to start TLS\n");
828 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
829 else if ( ocsp_stapling
830 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
831 printf("Failed to verify certificate status\n");
834 printf("Succeeded in starting TLS\n");
838 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
840 int n = (int)strlen(CS outbuffer);
841 while (n > 0 && isspace(outbuffer[n-1])) n--;
844 /* Expect incoming */
846 if (strncmp(CS outbuffer, "??? ", 4) == 0)
848 unsigned char *lineptr;
849 printf("%s\n", outbuffer);
851 if (*inptr == 0) /* Refill input buffer */
856 rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
859 rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
865 rc = read(sock, inbuffer, sizeof(inbuffer));
871 printf("Read error %s\n", strerror(errno));
876 printf("Unexpected EOF read\n");
888 while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
892 if (*inptr == '\n') inptr++;
895 printf("<<< %s\n", lineptr);
896 if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
898 printf("\n******** Input mismatch ********\n");
905 if (lineptr[0] == '2')
910 printf("Attempting to start TLS\n");
914 tls_active = tls_start(sock, &ssl, ctx);
918 sigalrm_seen = FALSE;
920 tls_active = gnutls_handshake(tls_session) >= 0;
926 printf("Failed to start TLS\n");
930 else if (ocsp_stapling)
932 if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
934 printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
937 else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
939 printf("Bad certificate\n");
943 else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
945 printf("Failed to verify certificate status\n");
947 gnutls_datum_t stapling;
948 gnutls_ocsp_resp_t resp;
949 gnutls_datum_t printed;
950 if ( (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
951 && (rc= gnutls_ocsp_resp_init(&resp)) == 0
952 && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
953 && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
956 fprintf(stderr, "%.4096s", printed.data);
957 gnutls_free(printed.data);
960 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
968 printf("Succeeded in starting TLS\n");
970 else printf("Abandoning TLS start attempt\n");
976 /* Wait for a bit before proceeding */
978 else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
980 printf("%s\n", outbuffer);
981 sleep(atoi(CS outbuffer + 4));
984 /* Send outgoing, but barf if unconsumed incoming */
988 unsigned char *escape;
992 printf("Unconsumed input: %s", inptr);
993 printf(" About to send: %s\n", outbuffer);
1001 if (strcmp(CS outbuffer, "stoptls") == 0 ||
1002 strcmp(CS outbuffer, "STOPTLS") == 0)
1006 printf("STOPTLS read when TLS not active\n");
1009 printf("Shutting down TLS encryption\n");
1017 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1018 gnutls_deinit(tls_session);
1020 gnutls_global_deinit();
1027 /* Remember that we sent STARTTLS */
1029 sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1030 strcmp(CS outbuffer, "STARTTLS") == 0);
1032 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1033 but we haven't set the flag, so that there is no negotiation. This is for
1034 testing the server's timeout. */
1036 if (strcmp(CS outbuffer, "starttls_wait") == 0)
1043 printf(">>> %s\n", outbuffer);
1044 strcpy(CS outbuffer + n, "\r\n");
1046 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1048 while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1051 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1055 while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
1058 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1068 rc = SSL_write (ssl, outbuffer, n + 2);
1071 rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1074 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1081 rc = write(sock, outbuffer, n + 2);
1087 printf("Write error: %s\n", strerror(errno));
1093 printf("End of script\n");
1099 /* End of client.c */