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. */
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 # include <openssl/ocsp.h>
76 # include <gnutls/gnutls.h>
77 # include <gnutls/x509.h>
78 # if GNUTLS_VERSION_NUMBER >= 0x030103
80 # include <gnutls/ocsp.h>
85 /* Local static variables for GNUTLS */
87 static gnutls_dh_params dh_params = NULL;
89 static gnutls_certificate_credentials_t x509_cred = NULL;
90 static gnutls_session tls_session = NULL;
92 static int ssl_session_timeout = 200;
94 /* Priorities for TLS algorithms to use. */
96 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
98 static const int kx_priority[16] = {
104 static int default_cipher_priority[16] = {
105 GNUTLS_CIPHER_AES_256_CBC,
106 GNUTLS_CIPHER_AES_128_CBC,
107 GNUTLS_CIPHER_3DES_CBC,
108 GNUTLS_CIPHER_ARCFOUR_128,
111 static const int mac_priority[16] = {
116 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
117 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
119 #endif /*HAVE_GNUTLS*/
124 char * ocsp_stapling = NULL;
128 /*************************************************
129 * SIGALRM handler - crash out *
130 *************************************************/
133 sigalrm_handler_crash(int sig)
135 sig = sig; /* Keep picky compilers happy */
136 printf("\nClient timed out\n");
141 /*************************************************
142 * SIGALRM handler - set flag *
143 *************************************************/
146 sigalrm_handler_flag(int sig)
148 sig = sig; /* Keep picky compilers happy */
154 /****************************************************************************/
155 /****************************************************************************/
160 setup_verify(BIO *bp, char *CAfile, char *CApath)
164 if(!(store = X509_STORE_new())) goto end;
165 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
166 if (lookup == NULL) goto end;
168 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
169 BIO_printf(bp, "Error loading file %s\n", CAfile);
172 } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
174 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
175 if (lookup == NULL) goto end;
177 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
178 BIO_printf(bp, "Error loading directory %s\n", CApath);
181 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
186 X509_STORE_free(store);
192 tls_client_stapling_cb(SSL *s, void *arg)
194 const unsigned char *p;
199 X509_STORE *store = NULL;
202 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
203 /*BIO_printf(arg, "OCSP response: ");*/
206 BIO_printf(arg, "no response received\n");
209 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
211 BIO_printf(arg, "response parse error\n");
212 BIO_dump_indent(arg, (char *)p, len, 4);
215 if(!(bs = OCSP_response_get1_basic(rsp)))
217 BIO_printf(arg, "error parsing response\n");
221 CAfile = ocsp_stapling;
222 if(!(store = setup_verify(arg, CAfile, NULL)))
224 BIO_printf(arg, "error in cert setup\n");
228 /* No file of alternate certs, no options */
229 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
231 BIO_printf(arg, "Response Verify Failure\n");
232 ERR_print_errors(arg);
236 BIO_printf(arg, "Response verify OK\n");
238 X509_STORE_free(store);
243 /*************************************************
244 * Start an OpenSSL TLS session *
245 *************************************************/
248 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
251 static const char *sid_ctx = "exim";
253 RAND_load_file("client.c", -1); /* Not *very* random! */
255 *ssl = SSL_new (ctx);
256 SSL_set_session_id_context(*ssl, sid_ctx, strlen(sid_ctx));
257 SSL_set_fd (*ssl, sock);
258 SSL_set_connect_state(*ssl);
262 SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
263 SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
264 SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
267 signal(SIGALRM, sigalrm_handler_flag);
270 rc = SSL_connect (*ssl);
275 printf("SSL_connect timed out\n");
281 ERR_print_errors_fp(stdout);
285 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
290 /*************************************************
291 * SSL Information callback *
292 *************************************************/
295 info_callback(SSL *s, int where, int ret)
299 printf("SSL info: %s\n", SSL_state_string_long(s));
304 /****************************************************************************/
305 /****************************************************************************/
309 /*************************************************
310 * Handle GnuTLS error *
311 *************************************************/
313 /* Called from lots of places when errors occur before actually starting to do
314 the TLS handshake, that is, while the session is still in clear.
318 err a GnuTLS error number, or 0 if local error
320 Returns: doesn't - it dies
324 gnutls_error(uschar *prefix, int err)
326 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
327 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
328 fprintf(stderr, "\n");
334 /*************************************************
335 * Setup up DH parameters *
336 *************************************************/
338 /* For the test suite, the parameters should always be available in the spool
347 uschar filename[200];
350 /* Initialize the data structures for holding the parameters */
352 ret = gnutls_dh_params_init(&dh_params);
353 if (ret < 0) gnutls_error(US"init dh_params", ret);
355 /* Open the cache file for reading and if successful, read it and set up the
358 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
361 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
365 if (fstat(fd, &statbuf) < 0)
368 return gnutls_error(US"TLS cache stat failed", 0);
371 m.size = statbuf.st_size;
372 m.data = malloc(m.size);
374 return gnutls_error(US"memory allocation failed", 0);
375 if (read(fd, m.data, m.size) != m.size)
376 return gnutls_error(US"TLS cache read failed", 0);
379 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
380 if (ret < 0) return gnutls_error(US"DH params import", ret);
387 /*************************************************
388 * Initialize for GnuTLS *
389 *************************************************/
393 certificate certificate file
394 privatekey private key file
398 tls_init(uschar *certificate, uschar *privatekey)
402 rc = gnutls_global_init();
403 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
405 /* Read D-H parameters from the cache file. */
409 /* Create the credentials structure */
411 rc = gnutls_certificate_allocate_credentials(&x509_cred);
412 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
414 /* Set the certificate and private keys */
416 if (certificate != NULL)
418 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
419 CS privatekey, GNUTLS_X509_FMT_PEM);
420 if (rc < 0) gnutls_error("gnutls_certificate", rc);
423 /* Associate the parameters with the x509 credentials structure. */
425 gnutls_certificate_set_dh_params(x509_cred, dh_params);
427 /* set the CA info for server-cert verify */
429 gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
430 GNUTLS_X509_FMT_PEM);
435 /*************************************************
436 * Initialize a single GNUTLS session *
437 *************************************************/
439 static gnutls_session
440 tls_session_init(void)
442 gnutls_session session;
444 gnutls_init(&session, GNUTLS_CLIENT);
446 gnutls_cipher_set_priority(session, default_cipher_priority);
447 gnutls_compression_set_priority(session, comp_priority);
448 gnutls_kx_set_priority(session, kx_priority);
449 gnutls_protocol_set_priority(session, protocol_priority);
450 gnutls_mac_set_priority(session, mac_priority);
452 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
454 gnutls_dh_set_prime_bits(session, DH_BITS);
455 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
462 /****************************************************************************/
463 /****************************************************************************/
468 /*************************************************
470 *************************************************/
472 const char * const HELP_MESSAGE = "\n\
476 [<outgoing interface>]\n\
481 int main(int argc, char **argv)
483 struct sockaddr *s_ptr;
484 struct sockaddr_in s_in4;
485 char *interface = NULL;
486 char *address = NULL;
487 char *certfile = NULL;
488 char *keyfile = NULL;
491 int host_af, port, s_len, rc, sock, save_errno;
494 int sent_starttls = 0;
495 int tls_on_connect = 0;
499 struct sockaddr_in6 s_in6;
507 unsigned char outbuffer[10240];
508 unsigned char inbuffer[10240];
509 unsigned char *inptr = inbuffer;
511 *inptr = 0; /* Buffer empty */
515 while (argc >= argi + 1 && argv[argi][0] == '-')
517 if (strcmp(argv[argi], "-help") == 0 ||
518 strcmp(argv[argi], "--help") == 0 ||
519 strcmp(argv[argi], "-h") == 0)
524 if (strcmp(argv[argi], "-tls-on-connect") == 0)
530 else if (strcmp(argv[argi], "-ocsp") == 0)
532 if (argc < ++argi + 1)
534 fprintf(stderr, "Missing required certificate file for ocsp option\n");
537 ocsp_stapling = argv[argi++];
541 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
543 tmplong = strtol(argv[argi]+2, &end, 10);
544 if (end == argv[argi]+2 || *end)
546 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
550 if (tmplong > 10000L)
552 fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
558 fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
561 timeout = (int) tmplong;
566 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
571 /* Mandatory 1st arg is IP address */
575 fprintf(stderr, "No IP address given\n");
579 address = argv[argi++];
580 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
582 /* Mandatory 2nd arg is port */
586 fprintf(stderr, "No port number given\n");
590 port = atoi(argv[argi++]);
592 /* Optional next arg is interface */
595 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
596 interface = argv[argi++];
598 /* Any more arguments are the name of a certificate file and key file */
600 if (argc > argi) certfile = argv[argi++];
601 if (argc > argi) keyfile = argv[argi++];
605 /* For an IPv6 address, use an IPv6 sockaddr structure. */
607 if (host_af == AF_INET6)
609 s_ptr = (struct sockaddr *)&s_in6;
610 s_len = sizeof(s_in6);
615 /* For an IPv4 address, use an IPv4 sockaddr structure,
616 even on an IPv6 system. */
619 s_ptr = (struct sockaddr *)&s_in4;
620 s_len = sizeof(s_in4);
623 printf("Connecting to %s port %d ... ", address, port);
625 sock = socket(host_af, SOCK_STREAM, 0);
628 printf("socket creation failed: %s\n", strerror(errno));
632 /* Bind to a specific interface if requested. On an IPv6 system, this has
633 to be of the same family as the address we are calling. On an IPv4 system the
634 test is redundant, but it keeps the code tidier. */
636 if (interface != NULL)
638 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
640 if (interface_af == host_af)
644 /* Set up for IPv6 binding */
646 if (host_af == AF_INET6)
648 memset(&s_in6, 0, sizeof(s_in6));
649 s_in6.sin6_family = AF_INET6;
651 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
653 printf("Unable to parse \"%s\"", interface);
660 /* Set up for IPv4 binding */
663 memset(&s_in4, 0, sizeof(s_in4));
664 s_in4.sin_family = AF_INET;
666 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
671 if (bind(sock, s_ptr, s_len) < 0)
673 printf("Unable to bind outgoing SMTP call to %s: %s",
674 interface, strerror(errno));
680 /* Set up a remote IPv6 address */
683 if (host_af == AF_INET6)
685 memset(&s_in6, 0, sizeof(s_in6));
686 s_in6.sin6_family = AF_INET6;
687 s_in6.sin6_port = htons(port);
688 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
690 printf("Unable to parse \"%s\"", address);
697 /* Set up a remote IPv4 address */
700 memset(&s_in4, 0, sizeof(s_in4));
701 s_in4.sin_family = AF_INET;
702 s_in4.sin_port = htons(port);
703 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
706 /* SIGALRM handler crashes out */
708 signal(SIGALRM, sigalrm_handler_crash);
710 rc = connect(sock, s_ptr, s_len);
714 /* A failure whose error code is "Interrupted system call" is in fact
715 an externally applied timeout if the signal handler has been run. */
720 printf("failed: %s\n", strerror(save_errno));
724 printf("connected\n");
727 /* --------------- Set up for OpenSSL --------------- */
731 SSL_load_error_strings();
733 ctx = SSL_CTX_new(SSLv23_method());
736 printf ("SSL_CTX_new failed\n");
740 if (certfile != NULL)
742 if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
744 printf("SSL_CTX_use_certificate_file failed\n");
747 printf("Certificate file = %s\n", certfile);
752 if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
754 printf("SSL_CTX_use_PrivateKey_file failed\n");
757 printf("Key file = %s\n", keyfile);
760 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
761 SSL_CTX_set_timeout(ctx, 200);
762 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
766 /* --------------- Set up for GnuTLS --------------- */
769 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
770 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
771 tls_init(certfile, keyfile);
772 tls_session = tls_session_init();
775 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
777 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
779 /* When the server asks for a certificate and the client does not have one,
780 there is a SIGPIPE error in the gnutls_handshake() function for some reason
781 that is not understood. As luck would have it, this has never hit Exim itself
782 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
785 signal(SIGPIPE, SIG_IGN);
788 /* ---------------------------------------------- */
791 /* Start TLS session if configured to do so without STARTTLS */
796 printf("Attempting to start TLS\n");
799 tls_active = tls_start(sock, &ssl, ctx);
803 sigalrm_seen = FALSE;
805 tls_active = gnutls_handshake(tls_session) >= 0;
810 printf("Failed to start TLS\n");
811 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
812 else if ( ocsp_stapling
813 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
814 printf("Failed to verify certificate status\n");
817 printf("Succeeded in starting TLS\n");
821 while (fgets(outbuffer, sizeof(outbuffer), stdin) != NULL)
823 int n = (int)strlen(outbuffer);
824 while (n > 0 && isspace(outbuffer[n-1])) n--;
827 /* Expect incoming */
829 if (strncmp(outbuffer, "??? ", 4) == 0)
831 unsigned char *lineptr;
832 printf("%s\n", outbuffer);
834 if (*inptr == 0) /* Refill input buffer */
839 rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
842 rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
848 rc = read(sock, inbuffer, sizeof(inbuffer));
854 printf("Read error %s\n", strerror(errno));
859 printf("Unexpected EOF read\n");
871 while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
875 if (*inptr == '\n') inptr++;
878 printf("<<< %s\n", lineptr);
879 if (strncmp(lineptr, outbuffer + 4, (int)strlen(outbuffer) - 4) != 0)
881 printf("\n******** Input mismatch ********\n");
888 if (lineptr[0] == '2')
893 printf("Attempting to start TLS\n");
897 tls_active = tls_start(sock, &ssl, ctx);
901 sigalrm_seen = FALSE;
903 tls_active = gnutls_handshake(tls_session) >= 0;
909 printf("Failed to start TLS\n");
913 else if (ocsp_stapling)
915 if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
917 printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
920 else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
922 printf("Bad certificate\n");
926 else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
928 printf("Failed to verify certificate status\n");
930 gnutls_datum_t stapling;
931 gnutls_ocsp_resp_t resp;
932 gnutls_datum_t printed;
933 if ( (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
934 && (rc= gnutls_ocsp_resp_init(&resp)) == 0
935 && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
936 && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
939 fprintf(stderr, "%.4096s", printed.data);
940 gnutls_free(printed.data);
943 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
951 printf("Succeeded in starting TLS\n");
953 else printf("Abandoning TLS start attempt\n");
959 /* Wait for a bit before proceeding */
961 else if (strncmp(outbuffer, "+++ ", 4) == 0)
963 printf("%s\n", outbuffer);
964 sleep(atoi(outbuffer + 4));
967 /* Send outgoing, but barf if unconsumed incoming */
971 unsigned char *escape;
975 printf("Unconsumed input: %s", inptr);
976 printf(" About to send: %s\n", outbuffer);
984 if (strcmp(outbuffer, "stoptls") == 0 ||
985 strcmp(outbuffer, "STOPTLS") == 0)
989 printf("STOPTLS read when TLS not active\n");
992 printf("Shutting down TLS encryption\n");
1000 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1001 gnutls_deinit(tls_session);
1003 gnutls_global_deinit();
1010 /* Remember that we sent STARTTLS */
1012 sent_starttls = (strcmp(outbuffer, "starttls") == 0 ||
1013 strcmp(outbuffer, "STARTTLS") == 0);
1015 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1016 but we haven't set the flag, so that there is no negotiation. This is for
1017 testing the server's timeout. */
1019 if (strcmp(outbuffer, "starttls_wait") == 0)
1026 printf(">>> %s\n", outbuffer);
1027 strcpy(outbuffer + n, "\r\n");
1029 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1031 while ((escape = strstr(outbuffer, "\\r")) != NULL)
1034 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1038 while ((escape = strstr(outbuffer, "\\n")) != NULL)
1041 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1051 rc = SSL_write (ssl, outbuffer, n + 2);
1054 rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1057 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1064 rc = write(sock, outbuffer, n + 2);
1070 printf("Write error: %s\n", strerror(errno));
1076 printf("End of script\n");
1082 /* End of client.c */