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 OCSP stapling was ripped
5 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>
72 char * ocsp_stapling = NULL;
78 #include <gnutls/gnutls.h>
79 #include <gnutls/x509.h>
83 /* Local static variables for GNUTLS */
85 static gnutls_dh_params dh_params = NULL;
87 static gnutls_certificate_credentials_t x509_cred = NULL;
88 static gnutls_session tls_session = NULL;
90 static int ssl_session_timeout = 200;
92 /* Priorities for TLS algorithms to use. */
94 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
96 static const int kx_priority[16] = {
102 static int default_cipher_priority[16] = {
103 GNUTLS_CIPHER_AES_256_CBC,
104 GNUTLS_CIPHER_AES_128_CBC,
105 GNUTLS_CIPHER_3DES_CBC,
106 GNUTLS_CIPHER_ARCFOUR_128,
109 static const int mac_priority[16] = {
114 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
115 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
122 /*************************************************
123 * SIGALRM handler - crash out *
124 *************************************************/
127 sigalrm_handler_crash(int sig)
129 sig = sig; /* Keep picky compilers happy */
130 printf("\nClient timed out\n");
135 /*************************************************
136 * SIGALRM handler - set flag *
137 *************************************************/
140 sigalrm_handler_flag(int sig)
142 sig = sig; /* Keep picky compilers happy */
148 /****************************************************************************/
149 /****************************************************************************/
154 setup_verify(BIO *bp, char *CAfile, char *CApath)
158 if(!(store = X509_STORE_new())) goto end;
159 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
160 if (lookup == NULL) goto end;
162 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
163 BIO_printf(bp, "Error loading file %s\n", CAfile);
166 } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
168 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
169 if (lookup == NULL) goto end;
171 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
172 BIO_printf(bp, "Error loading directory %s\n", CApath);
175 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
180 X509_STORE_free(store);
186 tls_client_stapling_cb(SSL *s, void *arg)
188 const unsigned char *p;
193 X509_STORE *store = NULL;
196 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
197 /*BIO_printf(arg, "OCSP response: ");*/
200 BIO_printf(arg, "no response received\n");
203 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
205 BIO_printf(arg, "response parse error\n");
206 BIO_dump_indent(arg, (char *)p, len, 4);
209 if(!(bs = OCSP_response_get1_basic(rsp)))
211 BIO_printf(arg, "error parsing response\n");
215 CAfile = ocsp_stapling;
216 if(!(store = setup_verify(arg, CAfile, NULL)))
218 BIO_printf(arg, "error in cert setup\n");
222 /* No file of alternate certs, no options */
223 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
225 BIO_printf(arg, "Response Verify Failure\n");
226 ERR_print_errors(arg);
230 BIO_printf(arg, "Response verify OK\n");
232 X509_STORE_free(store);
237 /*************************************************
238 * Start an OpenSSL TLS session *
239 *************************************************/
241 int tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
244 static const char *sid_ctx = "exim";
246 RAND_load_file("client.c", -1); /* Not *very* random! */
248 *ssl = SSL_new (ctx);
249 SSL_set_session_id_context(*ssl, sid_ctx, strlen(sid_ctx));
250 SSL_set_fd (*ssl, sock);
251 SSL_set_connect_state(*ssl);
255 SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
256 SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
257 SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
260 signal(SIGALRM, sigalrm_handler_flag);
263 rc = SSL_connect (*ssl);
268 printf("SSL_connect timed out\n");
274 ERR_print_errors_fp(stdout);
278 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
283 /*************************************************
284 * SSL Information callback *
285 *************************************************/
288 info_callback(SSL *s, int where, int ret)
292 printf("SSL info: %s\n", SSL_state_string_long(s));
297 /****************************************************************************/
298 /****************************************************************************/
302 /*************************************************
303 * Handle GnuTLS error *
304 *************************************************/
306 /* Called from lots of places when errors occur before actually starting to do
307 the TLS handshake, that is, while the session is still in clear.
311 err a GnuTLS error number, or 0 if local error
313 Returns: doesn't - it dies
317 gnutls_error(uschar *prefix, int err)
319 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
320 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
321 fprintf(stderr, "\n");
327 /*************************************************
328 * Setup up DH parameters *
329 *************************************************/
331 /* For the test suite, the parameters should always be available in the spool
340 uschar filename[200];
343 /* Initialize the data structures for holding the parameters */
345 ret = gnutls_dh_params_init(&dh_params);
346 if (ret < 0) gnutls_error(US"init dh_params", ret);
348 /* Open the cache file for reading and if successful, read it and set up the
351 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
354 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
358 if (fstat(fd, &statbuf) < 0)
361 return gnutls_error(US"TLS cache stat failed", 0);
364 m.size = statbuf.st_size;
365 m.data = malloc(m.size);
367 return gnutls_error(US"memory allocation failed", 0);
368 if (read(fd, m.data, m.size) != m.size)
369 return gnutls_error(US"TLS cache read failed", 0);
372 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
373 if (ret < 0) return gnutls_error(US"DH params import", ret);
380 /*************************************************
381 * Initialize for GnuTLS *
382 *************************************************/
386 certificate certificate file
387 privatekey private key file
391 tls_init(uschar *certificate, uschar *privatekey)
395 rc = gnutls_global_init();
396 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
398 /* Read D-H parameters from the cache file. */
402 /* Create the credentials structure */
404 rc = gnutls_certificate_allocate_credentials(&x509_cred);
405 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
407 /* Set the certificate and private keys */
409 if (certificate != NULL)
411 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
412 CS privatekey, GNUTLS_X509_FMT_PEM);
413 if (rc < 0) gnutls_error("gnutls_certificate", rc);
416 /* Associate the parameters with the x509 credentials structure. */
418 gnutls_certificate_set_dh_params(x509_cred, dh_params);
423 /*************************************************
424 * Initialize a single GNUTLS session *
425 *************************************************/
427 static gnutls_session
428 tls_session_init(void)
430 gnutls_session session;
432 gnutls_init(&session, GNUTLS_CLIENT);
434 gnutls_cipher_set_priority(session, default_cipher_priority);
435 gnutls_compression_set_priority(session, comp_priority);
436 gnutls_kx_set_priority(session, kx_priority);
437 gnutls_protocol_set_priority(session, protocol_priority);
438 gnutls_mac_set_priority(session, mac_priority);
440 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
442 gnutls_dh_set_prime_bits(session, DH_BITS);
443 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
450 /****************************************************************************/
451 /****************************************************************************/
456 /*************************************************
458 *************************************************/
460 const char * const HELP_MESSAGE = "\n\
464 [<outgoing interface>]\n\
469 int main(int argc, char **argv)
471 struct sockaddr *s_ptr;
472 struct sockaddr_in s_in4;
473 char *interface = NULL;
474 char *address = NULL;
475 char *certfile = NULL;
476 char *keyfile = NULL;
479 int host_af, port, s_len, rc, sock, save_errno;
482 int sent_starttls = 0;
483 int tls_on_connect = 0;
487 struct sockaddr_in6 s_in6;
495 unsigned char outbuffer[10240];
496 unsigned char inbuffer[10240];
497 unsigned char *inptr = inbuffer;
499 *inptr = 0; /* Buffer empty */
503 while (argc >= argi + 1 && argv[argi][0] == '-')
505 if (strcmp(argv[argi], "-help") == 0 ||
506 strcmp(argv[argi], "--help") == 0 ||
507 strcmp(argv[argi], "-h") == 0)
509 printf(HELP_MESSAGE);
512 if (strcmp(argv[argi], "-tls-on-connect") == 0)
518 else if (strcmp(argv[argi], "-ocsp") == 0)
520 if (argc < ++argi + 1)
522 fprintf(stderr, "Missing required certificate file for ocsp option\n");
525 ocsp_stapling = argv[argi++];
528 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
530 tmplong = strtol(argv[argi]+2, &end, 10);
531 if (end == argv[argi]+2 || *end)
533 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
537 if (tmplong > 10000L)
539 fprintf(stderr, "Unreasonably long wait of %d seconds requested\n",
545 fprintf(stderr, "Timeout must not be negative (%d)\n", tmplong);
548 timeout = (int) tmplong;
553 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
558 /* Mandatory 1st arg is IP address */
562 fprintf(stderr, "No IP address given\n");
566 address = argv[argi++];
567 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
569 /* Mandatory 2nd arg is port */
573 fprintf(stderr, "No port number given\n");
577 port = atoi(argv[argi++]);
579 /* Optional next arg is interface */
582 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
583 interface = argv[argi++];
585 /* Any more arguments are the name of a certificate file and key file */
587 if (argc > argi) certfile = argv[argi++];
588 if (argc > argi) keyfile = argv[argi++];
592 /* For an IPv6 address, use an IPv6 sockaddr structure. */
594 if (host_af == AF_INET6)
596 s_ptr = (struct sockaddr *)&s_in6;
597 s_len = sizeof(s_in6);
602 /* For an IPv4 address, use an IPv4 sockaddr structure,
603 even on an IPv6 system. */
606 s_ptr = (struct sockaddr *)&s_in4;
607 s_len = sizeof(s_in4);
610 printf("Connecting to %s port %d ... ", address, port);
612 sock = socket(host_af, SOCK_STREAM, 0);
615 printf("socket creation failed: %s\n", strerror(errno));
619 /* Bind to a specific interface if requested. On an IPv6 system, this has
620 to be of the same family as the address we are calling. On an IPv4 system the
621 test is redundant, but it keeps the code tidier. */
623 if (interface != NULL)
625 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
627 if (interface_af == host_af)
631 /* Set up for IPv6 binding */
633 if (host_af == AF_INET6)
635 memset(&s_in6, 0, sizeof(s_in6));
636 s_in6.sin6_family = AF_INET6;
638 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
640 printf("Unable to parse \"%s\"", interface);
647 /* Set up for IPv4 binding */
650 memset(&s_in4, 0, sizeof(s_in4));
651 s_in4.sin_family = AF_INET;
653 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
658 if (bind(sock, s_ptr, s_len) < 0)
660 printf("Unable to bind outgoing SMTP call to %s: %s",
661 interface, strerror(errno));
667 /* Set up a remote IPv6 address */
670 if (host_af == AF_INET6)
672 memset(&s_in6, 0, sizeof(s_in6));
673 s_in6.sin6_family = AF_INET6;
674 s_in6.sin6_port = htons(port);
675 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
677 printf("Unable to parse \"%s\"", address);
684 /* Set up a remote IPv4 address */
687 memset(&s_in4, 0, sizeof(s_in4));
688 s_in4.sin_family = AF_INET;
689 s_in4.sin_port = htons(port);
690 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
693 /* SIGALRM handler crashes out */
695 signal(SIGALRM, sigalrm_handler_crash);
697 rc = connect(sock, s_ptr, s_len);
701 /* A failure whose error code is "Interrupted system call" is in fact
702 an externally applied timeout if the signal handler has been run. */
707 printf("failed: %s\n", strerror(save_errno));
711 printf("connected\n");
714 /* --------------- Set up for OpenSSL --------------- */
718 SSL_load_error_strings();
720 ctx = SSL_CTX_new(SSLv23_method());
723 printf ("SSL_CTX_new failed\n");
727 if (certfile != NULL)
729 if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
731 printf("SSL_CTX_use_certificate_file failed\n");
734 printf("Certificate file = %s\n", certfile);
739 if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
741 printf("SSL_CTX_use_PrivateKey_file failed\n");
744 printf("Key file = %s\n", keyfile);
747 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
748 SSL_CTX_set_timeout(ctx, 200);
749 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
753 /* --------------- Set up for GnuTLS --------------- */
756 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
757 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
758 tls_init(certfile, keyfile);
759 tls_session = tls_session_init();
760 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
762 /* When the server asks for a certificate and the client does not have one,
763 there is a SIGPIPE error in the gnutls_handshake() function for some reason
764 that is not understood. As luck would have it, this has never hit Exim itself
765 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
768 signal(SIGPIPE, SIG_IGN);
771 /* ---------------------------------------------- */
774 /* Start TLS session if configured to do so without STARTTLS */
779 printf("Attempting to start TLS\n");
782 tls_active = tls_start(sock, &ssl, ctx);
786 sigalrm_seen = FALSE;
788 tls_active = gnutls_handshake(tls_session) >= 0;
793 printf("Failed to start TLS\n");
795 printf("Succeeded in starting TLS\n");
799 while (fgets(outbuffer, sizeof(outbuffer), stdin) != NULL)
801 int n = (int)strlen(outbuffer);
802 while (n > 0 && isspace(outbuffer[n-1])) n--;
805 /* Expect incoming */
807 if (strncmp(outbuffer, "??? ", 4) == 0)
809 unsigned char *lineptr;
810 printf("%s\n", outbuffer);
812 if (*inptr == 0) /* Refill input buffer */
817 rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
820 rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
826 rc = read(sock, inbuffer, sizeof(inbuffer));
832 printf("Read error %s\n", strerror(errno));
837 printf("Unexpected EOF read\n");
849 while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
853 if (*inptr == '\n') inptr++;
856 printf("<<< %s\n", lineptr);
857 if (strncmp(lineptr, outbuffer + 4, (int)strlen(outbuffer) - 4) != 0)
859 printf("\n******** Input mismatch ********\n");
866 if (lineptr[0] == '2')
868 printf("Attempting to start TLS\n");
872 tls_active = tls_start(sock, &ssl, ctx);
876 sigalrm_seen = FALSE;
878 tls_active = gnutls_handshake(tls_session) >= 0;
884 printf("Failed to start TLS\n");
888 printf("Succeeded in starting TLS\n");
890 else printf("Abandoning TLS start attempt\n");
896 /* Wait for a bit before proceeding */
898 else if (strncmp(outbuffer, "+++ ", 4) == 0)
900 printf("%s\n", outbuffer);
901 sleep(atoi(outbuffer + 4));
904 /* Send outgoing, but barf if unconsumed incoming */
908 unsigned char *escape;
912 printf("Unconsumed input: %s", inptr);
913 printf(" About to send: %s\n", outbuffer);
921 if (strcmp(outbuffer, "stoptls") == 0 ||
922 strcmp(outbuffer, "STOPTLS") == 0)
926 printf("STOPTLS read when TLS not active\n");
929 printf("Shutting down TLS encryption\n");
937 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
938 gnutls_deinit(tls_session);
940 gnutls_global_deinit();
947 /* Remember that we sent STARTTLS */
949 sent_starttls = (strcmp(outbuffer, "starttls") == 0 ||
950 strcmp(outbuffer, "STARTTLS") == 0);
952 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
953 but we haven't set the flag, so that there is no negotiation. This is for
954 testing the server's timeout. */
956 if (strcmp(outbuffer, "starttls_wait") == 0)
963 printf(">>> %s\n", outbuffer);
964 strcpy(outbuffer + n, "\r\n");
966 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
968 while ((escape = strstr(outbuffer, "\\r")) != NULL)
971 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
975 while ((escape = strstr(outbuffer, "\\n")) != NULL)
978 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
988 rc = SSL_write (ssl, outbuffer, n + 2);
991 rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
994 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1001 rc = write(sock, outbuffer, n + 2);
1007 printf("Write error: %s\n", strerror(errno));
1013 printf("End of script\n");
1019 /* End of client.c */