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>
88 # ifndef GNUTLS_NO_EXTENSIONS
89 # define GNUTLS_NO_EXTENSIONS 0
94 /* Local static variables for GNUTLS */
96 static gnutls_dh_params_t dh_params = NULL;
98 static gnutls_certificate_credentials_t x509_cred = NULL;
99 static gnutls_session_t tls_session = NULL;
101 static int ssl_session_timeout = 200;
103 /* Priorities for TLS algorithms to use. */
105 #if GNUTLS_VERSION_NUMBER < 0x030400
106 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
108 static const int kx_priority[16] = {
114 static int default_cipher_priority[16] = {
115 GNUTLS_CIPHER_AES_256_CBC,
116 GNUTLS_CIPHER_AES_128_CBC,
117 GNUTLS_CIPHER_3DES_CBC,
118 GNUTLS_CIPHER_ARCFOUR_128,
121 static const int mac_priority[16] = {
126 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
129 #endif /*HAVE_GNUTLS*/
134 char * ocsp_stapling = NULL;
138 /*************************************************
139 * SIGALRM handler - crash out *
140 *************************************************/
143 sigalrm_handler_crash(int sig)
145 sig = sig; /* Keep picky compilers happy */
146 printf("\nClient timed out\n");
151 /*************************************************
152 * SIGALRM handler - set flag *
153 *************************************************/
156 sigalrm_handler_flag(int sig)
158 sig = sig; /* Keep picky compilers happy */
164 /****************************************************************************/
165 /****************************************************************************/
170 setup_verify(BIO *bp, char *CAfile, char *CApath)
174 if(!(store = X509_STORE_new())) goto end;
175 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
176 if (lookup == NULL) goto end;
178 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
179 BIO_printf(bp, "Error loading file %s\n", CAfile);
182 } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
184 lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
185 if (lookup == NULL) goto end;
187 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
188 BIO_printf(bp, "Error loading directory %s\n", CApath);
191 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
196 X509_STORE_free(store);
203 tls_client_stapling_cb(SSL *s, void *arg)
205 const unsigned char *p;
210 X509_STORE *store = NULL;
213 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
214 /*BIO_printf(arg, "OCSP response: ");*/
217 BIO_printf(arg, "no response received\n");
220 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
222 BIO_printf(arg, "response parse error\n");
223 BIO_dump_indent(arg, (char *)p, len, 4);
226 if(!(bs = OCSP_response_get1_basic(rsp)))
228 BIO_printf(arg, "error parsing response\n");
232 CAfile = ocsp_stapling;
233 if(!(store = setup_verify(arg, CAfile, NULL)))
235 BIO_printf(arg, "error in cert setup\n");
239 /* No file of alternate certs, no options */
240 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
242 BIO_printf(arg, "Response Verify Failure\n");
243 ERR_print_errors(arg);
247 BIO_printf(arg, "Response verify OK\n");
249 X509_STORE_free(store);
255 /*************************************************
256 * Start an OpenSSL TLS session *
257 *************************************************/
260 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
263 static const unsigned char *sid_ctx = US"exim";
265 RAND_load_file("client.c", -1); /* Not *very* random! */
267 *ssl = SSL_new (ctx);
268 SSL_set_session_id_context(*ssl, sid_ctx, strlen(CS sid_ctx));
269 SSL_set_fd (*ssl, sock);
270 SSL_set_connect_state(*ssl);
275 SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
276 SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
277 SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
281 signal(SIGALRM, sigalrm_handler_flag);
284 rc = SSL_connect (*ssl);
289 printf("SSL_connect timed out\n");
295 ERR_print_errors_fp(stdout);
299 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
304 /*************************************************
305 * SSL Information callback *
306 *************************************************/
309 info_callback(SSL *s, int where, int ret)
313 printf("SSL info: %s\n", SSL_state_string_long(s));
318 /****************************************************************************/
319 /****************************************************************************/
323 /*************************************************
324 * Handle GnuTLS error *
325 *************************************************/
327 /* Called from lots of places when errors occur before actually starting to do
328 the TLS handshake, that is, while the session is still in clear.
332 err a GnuTLS error number, or 0 if local error
334 Returns: doesn't - it dies
338 gnutls_error(uschar *prefix, int err)
340 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
341 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
342 fprintf(stderr, "\n");
348 /*************************************************
349 * Setup up DH parameters *
350 *************************************************/
352 /* For the test suite, the parameters should always be available in the spool
361 uschar filename[200];
364 /* Initialize the data structures for holding the parameters */
366 ret = gnutls_dh_params_init(&dh_params);
367 if (ret < 0) gnutls_error(US"init dh_params", ret);
369 /* Open the cache file for reading and if successful, read it and set up the
372 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
375 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
379 if (fstat(fd, &statbuf) < 0)
382 return gnutls_error(US"TLS cache stat failed", 0);
385 m.size = statbuf.st_size;
386 m.data = malloc(m.size);
388 return gnutls_error(US"memory allocation failed", 0);
389 if (read(fd, m.data, m.size) != m.size)
390 return gnutls_error(US"TLS cache read failed", 0);
393 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
394 if (ret < 0) return gnutls_error(US"DH params import", ret);
401 /*************************************************
402 * Initialize for GnuTLS *
403 *************************************************/
407 certificate certificate file
408 privatekey private key file
412 tls_init(uschar *certificate, uschar *privatekey)
416 rc = gnutls_global_init();
417 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
419 /* Read D-H parameters from the cache file. */
423 /* Create the credentials structure */
425 rc = gnutls_certificate_allocate_credentials(&x509_cred);
426 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
428 /* Set the certificate and private keys */
430 if (certificate != NULL)
432 rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
433 CS privatekey, GNUTLS_X509_FMT_PEM);
434 if (rc < 0) gnutls_error("gnutls_certificate", rc);
437 /* Associate the parameters with the x509 credentials structure. */
439 gnutls_certificate_set_dh_params(x509_cred, dh_params);
441 /* set the CA info for server-cert verify */
443 gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
444 GNUTLS_X509_FMT_PEM);
449 /*************************************************
450 * Initialize a single GNUTLS session *
451 *************************************************/
453 static gnutls_session_t
454 tls_session_init(void)
456 gnutls_session_t session;
458 gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_NO_EXTENSIONS);
460 #if GNUTLS_VERSION_NUMBER < 0x030400
461 gnutls_cipher_set_priority(session, default_cipher_priority);
462 gnutls_compression_set_priority(session, comp_priority);
463 gnutls_kx_set_priority(session, kx_priority);
464 gnutls_protocol_set_priority(session, protocol_priority);
465 gnutls_mac_set_priority(session, mac_priority);
467 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
469 gnutls_set_default_priority(session);
470 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
473 gnutls_dh_set_prime_bits(session, DH_BITS);
474 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
481 /****************************************************************************/
482 /****************************************************************************/
487 /*************************************************
489 *************************************************/
491 const char * const HELP_MESSAGE = "\n\
499 [-tn] n seconds timeout\n\
502 [<outgoing interface>]\n\
507 int main(int argc, char **argv)
509 struct sockaddr *s_ptr;
510 struct sockaddr_in s_in4;
511 char *interface = NULL;
512 char *address = NULL;
513 char *certfile = NULL;
514 char *keyfile = NULL;
517 int host_af, port, s_len, rc, sock, save_errno;
520 int sent_starttls = 0;
521 int tls_on_connect = 0;
525 struct sockaddr_in6 s_in6;
533 unsigned char outbuffer[10240];
534 unsigned char inbuffer[10240];
535 unsigned char *inptr = inbuffer;
537 *inptr = 0; /* Buffer empty */
541 while (argc >= argi + 1 && argv[argi][0] == '-')
543 if (strcmp(argv[argi], "-help") == 0 ||
544 strcmp(argv[argi], "--help") == 0 ||
545 strcmp(argv[argi], "-h") == 0)
550 if (strcmp(argv[argi], "-tls-on-connect") == 0)
556 else if (strcmp(argv[argi], "-ocsp") == 0)
558 if (argc < ++argi + 1)
560 fprintf(stderr, "Missing required certificate file for ocsp option\n");
563 ocsp_stapling = argv[argi++];
567 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
569 tmplong = strtol(argv[argi]+2, &end, 10);
570 if (end == argv[argi]+2 || *end)
572 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
576 if (tmplong > 10000L)
578 fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
584 fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
587 timeout = (int) tmplong;
592 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
597 /* Mandatory 1st arg is IP address */
601 fprintf(stderr, "No IP address given\n");
605 address = argv[argi++];
606 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
608 /* Mandatory 2nd arg is port */
612 fprintf(stderr, "No port number given\n");
616 port = atoi(argv[argi++]);
618 /* Optional next arg is interface */
621 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
622 interface = argv[argi++];
624 /* Any more arguments are the name of a certificate file and key file */
626 if (argc > argi) certfile = argv[argi++];
627 if (argc > argi) keyfile = argv[argi++];
631 /* For an IPv6 address, use an IPv6 sockaddr structure. */
633 if (host_af == AF_INET6)
635 s_ptr = (struct sockaddr *)&s_in6;
636 s_len = sizeof(s_in6);
641 /* For an IPv4 address, use an IPv4 sockaddr structure,
642 even on an IPv6 system. */
645 s_ptr = (struct sockaddr *)&s_in4;
646 s_len = sizeof(s_in4);
649 printf("Connecting to %s port %d ... ", address, port);
651 sock = socket(host_af, SOCK_STREAM, 0);
654 printf("socket creation failed: %s\n", strerror(errno));
658 /* Bind to a specific interface if requested. On an IPv6 system, this has
659 to be of the same family as the address we are calling. On an IPv4 system the
660 test is redundant, but it keeps the code tidier. */
662 if (interface != NULL)
664 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
666 if (interface_af == host_af)
670 /* Set up for IPv6 binding */
672 if (host_af == AF_INET6)
674 memset(&s_in6, 0, sizeof(s_in6));
675 s_in6.sin6_family = AF_INET6;
677 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
679 printf("Unable to parse \"%s\"", interface);
686 /* Set up for IPv4 binding */
689 memset(&s_in4, 0, sizeof(s_in4));
690 s_in4.sin_family = AF_INET;
692 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
697 if (bind(sock, s_ptr, s_len) < 0)
699 printf("Unable to bind outgoing SMTP call to %s: %s",
700 interface, strerror(errno));
706 /* Set up a remote IPv6 address */
709 if (host_af == AF_INET6)
711 memset(&s_in6, 0, sizeof(s_in6));
712 s_in6.sin6_family = AF_INET6;
713 s_in6.sin6_port = htons(port);
714 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
716 printf("Unable to parse \"%s\"", address);
723 /* Set up a remote IPv4 address */
726 memset(&s_in4, 0, sizeof(s_in4));
727 s_in4.sin_family = AF_INET;
728 s_in4.sin_port = htons(port);
729 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
732 /* SIGALRM handler crashes out */
734 signal(SIGALRM, sigalrm_handler_crash);
736 rc = connect(sock, s_ptr, s_len);
740 /* A failure whose error code is "Interrupted system call" is in fact
741 an externally applied timeout if the signal handler has been run. */
746 printf("connect failed: %s\n", strerror(save_errno));
750 printf("connected\n");
753 /* --------------- Set up for OpenSSL --------------- */
757 SSL_load_error_strings();
759 ctx = SSL_CTX_new(SSLv23_method());
762 printf ("SSL_CTX_new failed\n");
766 if (certfile != NULL)
768 if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
770 printf("SSL_CTX_use_certificate_file failed\n");
773 printf("Certificate file = %s\n", certfile);
778 if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
780 printf("SSL_CTX_use_PrivateKey_file failed\n");
783 printf("Key file = %s\n", keyfile);
786 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
787 SSL_CTX_set_timeout(ctx, 200);
788 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
792 /* --------------- Set up for GnuTLS --------------- */
795 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
796 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
797 tls_init(certfile, keyfile);
798 tls_session = tls_session_init();
801 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
803 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)sock);
805 /* When the server asks for a certificate and the client does not have one,
806 there is a SIGPIPE error in the gnutls_handshake() function for some reason
807 that is not understood. As luck would have it, this has never hit Exim itself
808 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
811 signal(SIGPIPE, SIG_IGN);
814 /* ---------------------------------------------- */
817 /* Start TLS session if configured to do so without STARTTLS */
822 printf("Attempting to start TLS\n");
825 tls_active = tls_start(sock, &ssl, ctx);
831 sigalrm_seen = FALSE;
834 rc = gnutls_handshake(tls_session);
835 } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
836 tls_active = rc >= 0;
839 if (!tls_active) printf("%s\n", gnutls_strerror(rc));
844 printf("Failed to start TLS\n");
845 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
846 else if ( ocsp_stapling
847 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
848 printf("Failed to verify certificate status\n");
851 printf("Succeeded in starting TLS\n");
855 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
857 int n = (int)strlen(CS outbuffer);
859 /* Strip trailing newline */
860 if (outbuffer[n-1] == '\n') outbuffer[--n] = 0;
862 /* Expect incoming */
864 if (strncmp(CS outbuffer, "??? ", 4) == 0)
866 unsigned char *lineptr;
867 printf("%s\n", outbuffer);
869 if (*inptr == 0) /* Refill input buffer */
874 rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
877 rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
883 rc = read(sock, inbuffer, sizeof(inbuffer));
889 printf("Read error %s\n", strerror(errno));
894 printf("Unexpected EOF read\n");
906 while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
910 if (*inptr == '\n') inptr++;
913 printf("<<< %s\n", lineptr);
914 if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
916 printf("\n******** Input mismatch ********\n");
923 if (lineptr[0] == '2')
928 printf("Attempting to start TLS\n");
932 tls_active = tls_start(sock, &ssl, ctx);
938 sigalrm_seen = FALSE;
941 rc = gnutls_handshake(tls_session);
942 } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
943 tls_active = rc >= 0;
946 if (!tls_active) printf("%s\n", gnutls_strerror(rc));
952 printf("Failed to start TLS\n");
956 else if (ocsp_stapling)
958 if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
960 printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
963 else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
965 printf("Bad certificate\n");
969 else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
971 printf("Failed to verify certificate status\n");
973 gnutls_datum_t stapling;
974 gnutls_ocsp_resp_t resp;
975 gnutls_datum_t printed;
976 if ( (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
977 && (rc= gnutls_ocsp_resp_init(&resp)) == 0
978 && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
979 && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
982 fprintf(stderr, "%.4096s", printed.data);
983 gnutls_free(printed.data);
986 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
994 printf("Succeeded in starting TLS\n");
996 else printf("Abandoning TLS start attempt\n");
1002 /* Wait for a bit before proceeding */
1004 else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
1006 printf("%s\n", outbuffer);
1007 sleep(atoi(CS outbuffer + 4));
1010 /* Send outgoing, but barf if unconsumed incoming */
1014 unsigned char *escape;
1018 printf("Unconsumed input: %s", inptr);
1019 printf(" About to send: %s\n", outbuffer);
1027 if (strcmp(CS outbuffer, "stoptls") == 0 ||
1028 strcmp(CS outbuffer, "STOPTLS") == 0)
1032 printf("STOPTLS read when TLS not active\n");
1035 printf("Shutting down TLS encryption\n");
1043 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1044 gnutls_deinit(tls_session);
1046 gnutls_global_deinit();
1053 /* Remember that we sent STARTTLS */
1055 sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1056 strcmp(CS outbuffer, "STARTTLS") == 0);
1058 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1059 but we haven't set the flag, so that there is no negotiation. This is for
1060 testing the server's timeout. */
1062 if (strcmp(CS outbuffer, "starttls_wait") == 0)
1069 printf(">>> %s\n", outbuffer);
1070 strcpy(CS outbuffer + n, "\r\n");
1072 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1074 while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1077 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1081 while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
1084 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1094 rc = SSL_write (ssl, outbuffer, n + 2);
1097 rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1100 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1107 rc = write(sock, outbuffer, n + 2);
1113 printf("Write error: %s\n", strerror(errno));
1119 printf("End of script\n");
1120 shutdown(sock, SHUT_WR);
1121 while ((rc = read(sock, inbuffer, sizeof(inbuffer))) > 0) ;
1127 /* End of client.c */