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 #include <gnutls/ocsp.h>
82 /* Local static variables for GNUTLS */
84 static gnutls_dh_params dh_params = NULL;
86 static gnutls_certificate_credentials_t x509_cred = NULL;
87 static gnutls_session tls_session = NULL;
89 static int ssl_session_timeout = 200;
91 /* Priorities for TLS algorithms to use. */
93 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
95 static const int kx_priority[16] = {
101 static int default_cipher_priority[16] = {
102 GNUTLS_CIPHER_AES_256_CBC,
103 GNUTLS_CIPHER_AES_128_CBC,
104 GNUTLS_CIPHER_3DES_CBC,
105 GNUTLS_CIPHER_ARCFOUR_128,
108 static const int mac_priority[16] = {
113 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
114 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
121 char * ocsp_stapling = NULL;
125 /*************************************************
126 * SIGALRM handler - crash out *
127 *************************************************/
130 sigalrm_handler_crash(int sig)
132 sig = sig; /* Keep picky compilers happy */
133 printf("\nClient timed out\n");
138 /*************************************************
139 * SIGALRM handler - set flag *
140 *************************************************/
143 sigalrm_handler_flag(int sig)
145 sig = sig; /* Keep picky compilers happy */
151 /****************************************************************************/
152 /****************************************************************************/
157 setup_verify(BIO *bp, char *CAfile, char *CApath)
161 if(!(store = X509_STORE_new())) goto end;
162 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
163 if (lookup == NULL) goto end;
165 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
166 BIO_printf(bp, "Error loading file %s\n", CAfile);
169 } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
171 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
172 if (lookup == NULL) goto end;
174 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
175 BIO_printf(bp, "Error loading directory %s\n", CApath);
178 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
183 X509_STORE_free(store);
189 tls_client_stapling_cb(SSL *s, void *arg)
191 const unsigned char *p;
196 X509_STORE *store = NULL;
199 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
200 /*BIO_printf(arg, "OCSP response: ");*/
203 BIO_printf(arg, "no response received\n");
206 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
208 BIO_printf(arg, "response parse error\n");
209 BIO_dump_indent(arg, (char *)p, len, 4);
212 if(!(bs = OCSP_response_get1_basic(rsp)))
214 BIO_printf(arg, "error parsing response\n");
218 CAfile = ocsp_stapling;
219 if(!(store = setup_verify(arg, CAfile, NULL)))
221 BIO_printf(arg, "error in cert setup\n");
225 /* No file of alternate certs, no options */
226 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
228 BIO_printf(arg, "Response Verify Failure\n");
229 ERR_print_errors(arg);
233 BIO_printf(arg, "Response verify OK\n");
235 X509_STORE_free(store);
240 /*************************************************
241 * Start an OpenSSL TLS session *
242 *************************************************/
245 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
248 static const char *sid_ctx = "exim";
250 RAND_load_file("client.c", -1); /* Not *very* random! */
252 *ssl = SSL_new (ctx);
253 SSL_set_session_id_context(*ssl, sid_ctx, strlen(sid_ctx));
254 SSL_set_fd (*ssl, sock);
255 SSL_set_connect_state(*ssl);
259 SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
260 SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
261 SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
264 signal(SIGALRM, sigalrm_handler_flag);
267 rc = SSL_connect (*ssl);
272 printf("SSL_connect timed out\n");
278 ERR_print_errors_fp(stdout);
282 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
287 /*************************************************
288 * SSL Information callback *
289 *************************************************/
292 info_callback(SSL *s, int where, int ret)
296 printf("SSL info: %s\n", SSL_state_string_long(s));
301 /****************************************************************************/
302 /****************************************************************************/
306 /*************************************************
307 * Handle GnuTLS error *
308 *************************************************/
310 /* Called from lots of places when errors occur before actually starting to do
311 the TLS handshake, that is, while the session is still in clear.
315 err a GnuTLS error number, or 0 if local error
317 Returns: doesn't - it dies
321 gnutls_error(uschar *prefix, int err)
323 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
324 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
325 fprintf(stderr, "\n");
331 /*************************************************
332 * Setup up DH parameters *
333 *************************************************/
335 /* For the test suite, the parameters should always be available in the spool
344 uschar filename[200];
347 /* Initialize the data structures for holding the parameters */
349 ret = gnutls_dh_params_init(&dh_params);
350 if (ret < 0) gnutls_error(US"init dh_params", ret);
352 /* Open the cache file for reading and if successful, read it and set up the
355 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
358 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
362 if (fstat(fd, &statbuf) < 0)
365 return gnutls_error(US"TLS cache stat failed", 0);
368 m.size = statbuf.st_size;
369 m.data = malloc(m.size);
371 return gnutls_error(US"memory allocation failed", 0);
372 if (read(fd, m.data, m.size) != m.size)
373 return gnutls_error(US"TLS cache read failed", 0);
376 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
377 if (ret < 0) return gnutls_error(US"DH params import", ret);
384 /*************************************************
385 * Initialize for GnuTLS *
386 *************************************************/
390 certificate certificate file
391 privatekey private key file
395 tls_init(uschar *certificate, uschar *privatekey)
399 rc = gnutls_global_init();
400 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
402 /* Read D-H parameters from the cache file. */
406 /* Create the credentials structure */
408 rc = gnutls_certificate_allocate_credentials(&x509_cred);
409 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
411 /* Set the certificate and private keys */
413 if (certificate != NULL)
415 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
416 CS privatekey, GNUTLS_X509_FMT_PEM);
417 if (rc < 0) gnutls_error("gnutls_certificate", rc);
420 /* Associate the parameters with the x509 credentials structure. */
422 gnutls_certificate_set_dh_params(x509_cred, dh_params);
424 /* set the CA info for server-cert verify */
426 gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
427 GNUTLS_X509_FMT_PEM);
432 /*************************************************
433 * Initialize a single GNUTLS session *
434 *************************************************/
436 static gnutls_session
437 tls_session_init(void)
439 gnutls_session session;
441 gnutls_init(&session, GNUTLS_CLIENT);
443 gnutls_cipher_set_priority(session, default_cipher_priority);
444 gnutls_compression_set_priority(session, comp_priority);
445 gnutls_kx_set_priority(session, kx_priority);
446 gnutls_protocol_set_priority(session, protocol_priority);
447 gnutls_mac_set_priority(session, mac_priority);
449 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
451 gnutls_dh_set_prime_bits(session, DH_BITS);
452 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
459 /****************************************************************************/
460 /****************************************************************************/
465 /*************************************************
467 *************************************************/
469 const char * const HELP_MESSAGE = "\n\
473 [<outgoing interface>]\n\
478 int main(int argc, char **argv)
480 struct sockaddr *s_ptr;
481 struct sockaddr_in s_in4;
482 char *interface = NULL;
483 char *address = NULL;
484 char *certfile = NULL;
485 char *keyfile = NULL;
488 int host_af, port, s_len, rc, sock, save_errno;
491 int sent_starttls = 0;
492 int tls_on_connect = 0;
496 struct sockaddr_in6 s_in6;
504 unsigned char outbuffer[10240];
505 unsigned char inbuffer[10240];
506 unsigned char *inptr = inbuffer;
508 *inptr = 0; /* Buffer empty */
512 while (argc >= argi + 1 && argv[argi][0] == '-')
514 if (strcmp(argv[argi], "-help") == 0 ||
515 strcmp(argv[argi], "--help") == 0 ||
516 strcmp(argv[argi], "-h") == 0)
518 printf(HELP_MESSAGE);
521 if (strcmp(argv[argi], "-tls-on-connect") == 0)
527 else if (strcmp(argv[argi], "-ocsp") == 0)
529 if (argc < ++argi + 1)
531 fprintf(stderr, "Missing required certificate file for ocsp option\n");
534 ocsp_stapling = argv[argi++];
538 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
540 tmplong = strtol(argv[argi]+2, &end, 10);
541 if (end == argv[argi]+2 || *end)
543 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
547 if (tmplong > 10000L)
549 fprintf(stderr, "Unreasonably long wait of %d seconds requested\n",
555 fprintf(stderr, "Timeout must not be negative (%d)\n", tmplong);
558 timeout = (int) tmplong;
563 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
568 /* Mandatory 1st arg is IP address */
572 fprintf(stderr, "No IP address given\n");
576 address = argv[argi++];
577 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
579 /* Mandatory 2nd arg is port */
583 fprintf(stderr, "No port number given\n");
587 port = atoi(argv[argi++]);
589 /* Optional next arg is interface */
592 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
593 interface = argv[argi++];
595 /* Any more arguments are the name of a certificate file and key file */
597 if (argc > argi) certfile = argv[argi++];
598 if (argc > argi) keyfile = argv[argi++];
602 /* For an IPv6 address, use an IPv6 sockaddr structure. */
604 if (host_af == AF_INET6)
606 s_ptr = (struct sockaddr *)&s_in6;
607 s_len = sizeof(s_in6);
612 /* For an IPv4 address, use an IPv4 sockaddr structure,
613 even on an IPv6 system. */
616 s_ptr = (struct sockaddr *)&s_in4;
617 s_len = sizeof(s_in4);
620 printf("Connecting to %s port %d ... ", address, port);
622 sock = socket(host_af, SOCK_STREAM, 0);
625 printf("socket creation failed: %s\n", strerror(errno));
629 /* Bind to a specific interface if requested. On an IPv6 system, this has
630 to be of the same family as the address we are calling. On an IPv4 system the
631 test is redundant, but it keeps the code tidier. */
633 if (interface != NULL)
635 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
637 if (interface_af == host_af)
641 /* Set up for IPv6 binding */
643 if (host_af == AF_INET6)
645 memset(&s_in6, 0, sizeof(s_in6));
646 s_in6.sin6_family = AF_INET6;
648 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
650 printf("Unable to parse \"%s\"", interface);
657 /* Set up for IPv4 binding */
660 memset(&s_in4, 0, sizeof(s_in4));
661 s_in4.sin_family = AF_INET;
663 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
668 if (bind(sock, s_ptr, s_len) < 0)
670 printf("Unable to bind outgoing SMTP call to %s: %s",
671 interface, strerror(errno));
677 /* Set up a remote IPv6 address */
680 if (host_af == AF_INET6)
682 memset(&s_in6, 0, sizeof(s_in6));
683 s_in6.sin6_family = AF_INET6;
684 s_in6.sin6_port = htons(port);
685 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
687 printf("Unable to parse \"%s\"", address);
694 /* Set up a remote IPv4 address */
697 memset(&s_in4, 0, sizeof(s_in4));
698 s_in4.sin_family = AF_INET;
699 s_in4.sin_port = htons(port);
700 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
703 /* SIGALRM handler crashes out */
705 signal(SIGALRM, sigalrm_handler_crash);
707 rc = connect(sock, s_ptr, s_len);
711 /* A failure whose error code is "Interrupted system call" is in fact
712 an externally applied timeout if the signal handler has been run. */
717 printf("failed: %s\n", strerror(save_errno));
721 printf("connected\n");
724 /* --------------- Set up for OpenSSL --------------- */
728 SSL_load_error_strings();
730 ctx = SSL_CTX_new(SSLv23_method());
733 printf ("SSL_CTX_new failed\n");
737 if (certfile != NULL)
739 if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
741 printf("SSL_CTX_use_certificate_file failed\n");
744 printf("Certificate file = %s\n", certfile);
749 if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
751 printf("SSL_CTX_use_PrivateKey_file failed\n");
754 printf("Key file = %s\n", keyfile);
757 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
758 SSL_CTX_set_timeout(ctx, 200);
759 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
763 /* --------------- Set up for GnuTLS --------------- */
766 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
767 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
768 tls_init(certfile, keyfile);
769 tls_session = tls_session_init();
771 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
772 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
774 /* When the server asks for a certificate and the client does not have one,
775 there is a SIGPIPE error in the gnutls_handshake() function for some reason
776 that is not understood. As luck would have it, this has never hit Exim itself
777 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
780 signal(SIGPIPE, SIG_IGN);
783 /* ---------------------------------------------- */
786 /* Start TLS session if configured to do so without STARTTLS */
791 printf("Attempting to start TLS\n");
794 tls_active = tls_start(sock, &ssl, ctx);
798 sigalrm_seen = FALSE;
800 tls_active = gnutls_handshake(tls_session) >= 0;
805 printf("Failed to start TLS\n");
807 else if ( ocsp_stapling
808 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
809 printf("Failed to verify certificate status\n");
812 printf("Succeeded in starting TLS\n");
816 while (fgets(outbuffer, sizeof(outbuffer), stdin) != NULL)
818 int n = (int)strlen(outbuffer);
819 while (n > 0 && isspace(outbuffer[n-1])) n--;
822 /* Expect incoming */
824 if (strncmp(outbuffer, "??? ", 4) == 0)
826 unsigned char *lineptr;
827 printf("%s\n", outbuffer);
829 if (*inptr == 0) /* Refill input buffer */
834 rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
837 rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
843 rc = read(sock, inbuffer, sizeof(inbuffer));
849 printf("Read error %s\n", strerror(errno));
854 printf("Unexpected EOF read\n");
866 while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
870 if (*inptr == '\n') inptr++;
873 printf("<<< %s\n", lineptr);
874 if (strncmp(lineptr, outbuffer + 4, (int)strlen(outbuffer) - 4) != 0)
876 printf("\n******** Input mismatch ********\n");
883 if (lineptr[0] == '2')
888 printf("Attempting to start TLS\n");
892 tls_active = tls_start(sock, &ssl, ctx);
896 sigalrm_seen = FALSE;
898 tls_active = gnutls_handshake(tls_session) >= 0;
904 printf("Failed to start TLS\n");
908 else if (ocsp_stapling)
910 if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
912 printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
915 else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
917 printf("Bad certificate\n");
920 else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
922 printf("Failed to verify certificate status\n");
924 gnutls_datum_t stapling;
925 gnutls_ocsp_resp_t resp;
926 gnutls_datum_t printed;
927 if ( (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
928 && (rc= gnutls_ocsp_resp_init(&resp)) == 0
929 && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
930 && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
933 fprintf(stderr, "%.4096s", printed.data);
934 gnutls_free(printed.data);
937 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
944 printf("Succeeded in starting TLS\n");
946 else printf("Abandoning TLS start attempt\n");
952 /* Wait for a bit before proceeding */
954 else if (strncmp(outbuffer, "+++ ", 4) == 0)
956 printf("%s\n", outbuffer);
957 sleep(atoi(outbuffer + 4));
960 /* Send outgoing, but barf if unconsumed incoming */
964 unsigned char *escape;
968 printf("Unconsumed input: %s", inptr);
969 printf(" About to send: %s\n", outbuffer);
977 if (strcmp(outbuffer, "stoptls") == 0 ||
978 strcmp(outbuffer, "STOPTLS") == 0)
982 printf("STOPTLS read when TLS not active\n");
985 printf("Shutting down TLS encryption\n");
993 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
994 gnutls_deinit(tls_session);
996 gnutls_global_deinit();
1003 /* Remember that we sent STARTTLS */
1005 sent_starttls = (strcmp(outbuffer, "starttls") == 0 ||
1006 strcmp(outbuffer, "STARTTLS") == 0);
1008 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1009 but we haven't set the flag, so that there is no negotiation. This is for
1010 testing the server's timeout. */
1012 if (strcmp(outbuffer, "starttls_wait") == 0)
1019 printf(">>> %s\n", outbuffer);
1020 strcpy(outbuffer + n, "\r\n");
1022 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1024 while ((escape = strstr(outbuffer, "\\r")) != NULL)
1027 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1031 while ((escape = strstr(outbuffer, "\\n")) != NULL)
1034 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1044 rc = SSL_write (ssl, outbuffer, n + 2);
1047 rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1050 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1057 rc = write(sock, outbuffer, n + 2);
1063 printf("Write error: %s\n", strerror(errno));
1069 printf("End of script\n");
1075 /* End of client.c */