1 /* TLSv1 filter for STARTTLS extension.
3 Copyright (C) 1999, 2000 Daiki Ueno <ueno@unixuser.org>
5 Author: Daiki Ueno <ueno@unixuser.org>
9 This file is not part of any package.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with GNU Emacs; see the file COPYING. If not, write to the
23 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 Boston, MA 02111-1307, USA.
29 How to compile: (OpenSSL is required)
31 gcc -I/usr/local/ssl/include -o starttls starttls.c \
32 -L/usr/local/ssl/lib -lssl -lcrypto
36 #include <sys/types.h>
43 /* OpenSSL library. */
45 #include <openssl/lhash.h>
46 #include <openssl/bn.h>
47 #include <openssl/err.h>
48 #include <openssl/pem.h>
49 #include <openssl/x509.h>
50 #include <openssl/ssl.h>
56 #ifndef HAVE_GETADDRINFO
58 #endif /* !HAVE_GETADDRINFO */
61 #include <sys/socket.h>
63 #include <sys/ioctl.h>
69 #include <netinet/in.h>
73 static SSL_CTX *tls_ctx = NULL;
74 static SSL *tls_conn = NULL;
77 static char *opt_cert_file = NULL, *opt_key_file = NULL;
78 static int opt_verify = 0;
81 tls_ssl_ctx_new (cert_file, key_file)
82 const char *cert_file, *key_file;
84 SSL_load_error_strings ();
85 SSLeay_add_ssl_algorithms ();
87 tls_ctx = SSL_CTX_new (TLSv1_client_method());
91 SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
95 if (SSL_CTX_use_certificate_file (tls_ctx, cert_file,
96 SSL_FILETYPE_PEM) <= 0)
100 if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file,
101 SSL_FILETYPE_PEM) <= 0)
103 if (!SSL_CTX_check_private_key (tls_ctx))
107 SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
117 SSL_SESSION *session;
121 tls_conn = (SSL *) SSL_new (ctx);
126 if (!SSL_set_fd (tls_conn, s))
129 SSL_set_connect_state (tls_conn);
131 if (SSL_connect (tls_conn) <= 0)
133 session = SSL_get_session (tls_conn);
135 SSL_CTX_remove_session (ctx, session);
145 tls_connect (hostname, service)
146 const char *hostname, *service;
148 struct protoent *proto;
149 struct addrinfo *in, hints;
150 int server, false = 0;
152 proto = getprotobyname ("tcp");
156 memset (&hints, 0, sizeof (hints));
157 hints.ai_family = AF_UNSPEC;
158 hints.ai_socktype = SOCK_STREAM;
159 hints.ai_protocol = proto->p_proto;
161 if (getaddrinfo (hostname, service, &hints, &in) < 0)
164 server = socket (in->ai_family, in->ai_socktype, 0);
168 if (setsockopt (server, SOL_SOCKET, SO_KEEPALIVE,
169 (const char *) &false, sizeof (false)))
172 if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
185 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
188 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
193 const char *progname;
195 printf ("%s (%s) %s\n"
196 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
197 "This program comes with ABSOLUTELY NO WARRANTY.\n"
198 "This is free software, and you are welcome to redistribute it\n"
199 "under certain conditions. See the file COPYING for details.\n\n"
200 "Usage: %s [options] host port\n\n"
202 " --cert-file [file] specify certificate file\n"
203 " --key-file [file] specify private key file\n"
204 " --verify [level] set verification level\n",
205 progname, PACKAGE, VERSION, progname);
213 int in = fileno (stdin), out = fileno (stdout),
215 fd_set readfds, writefds;
216 char buffer[BUFSIZ], *retry;
217 struct sigaction act;
219 int this_option_optind = optind ? optind : 1;
220 int option_index = 0, c;
221 static struct option long_options[] =
223 {"cert-file", 1, 0, 'c'},
224 {"key-file", 1, 0, 'k'},
225 {"verify", 1, 0, 'v'},
231 c = getopt_long (argc, argv, "c:k:v:f", long_options, &option_index);
238 opt_cert_file = optarg;
241 opt_key_file = optarg;
244 opt_verify = atoi (optarg);
247 usage (basename (argv[0]));
252 if (optind+2 != argc)
254 usage (basename (argv[0]));
258 tls_fd = tls_connect (argv[optind], argv[optind+1]);
261 perror ("tls_connect");
265 memset (&act, 0, sizeof (act));
266 act.sa_handler = tls_negotiate;
267 sigemptyset (&act.sa_mask);
268 act.sa_flags = SA_RESTART|SA_RESETHAND;
269 sigaction (SIGALRM, &act, NULL);
273 FD_SET (tls_fd, &readfds);
274 FD_SET (in, &readfds);
275 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
281 if (FD_ISSET (in, &readfds))
283 nbuffer = read (in, buffer, sizeof buffer -1);
287 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
289 FD_SET (tls_fd, &writefds);
290 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
296 wrote = SSL_write (tls_conn, retry, nbuffer);
298 wrote = write (tls_fd, retry, nbuffer);
299 if (wrote < 0) goto finish;
302 if (FD_ISSET (tls_fd, &readfds))
305 nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
307 nbuffer = read (tls_fd, buffer, sizeof buffer -1);
310 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
312 FD_SET (out, &writefds);
313 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
318 wrote = write (out, retry, nbuffer);
319 if (wrote < 0) goto finish;