1 /* TLSv1 filter for STARTTLS extension.
3 Copyright (C) 1999, 2000 Daiki Ueno <ueno@unixuser.org>
5 Author: Daiki Ueno <ueno@unixuser.org>
6 Kenichi OKADA <okada@opaopa.org>
10 This file is not part of any package.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2, or (at your option)
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with GNU Emacs; see the file COPYING. If not, write to the
24 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 Boston, MA 02111-1307, USA.
30 How to compile: (OpenSSL is required)
32 gcc -I/usr/local/ssl/include -o starttls starttls.c \
33 -L/usr/local/ssl/lib -lssl -lcrypto
37 #include <sys/types.h>
44 /* OpenSSL library. */
46 #include <openssl/lhash.h>
47 #include <openssl/bn.h>
48 #include <openssl/err.h>
49 #include <openssl/pem.h>
50 #include <openssl/x509.h>
51 #include <openssl/ssl.h>
57 #ifndef HAVE_GETADDRINFO
58 #include "getaddrinfo.h"
59 #endif /* !HAVE_GETADDRINFO */
62 #include <sys/socket.h>
64 #include <sys/ioctl.h>
70 #include <netinet/in.h>
87 char *p = rindex((path), '/');
88 return p ? p + 1 : (path);
94 static SSL_CTX *tls_ctx = NULL;
95 static SSL *tls_conn = NULL;
98 static char *opt_cert_file = NULL, *opt_key_file = NULL;
99 static int opt_verify = 0;
100 static int opt_force;
103 tls_ssl_ctx_new (cert_file, key_file)
104 const char *cert_file, *key_file;
106 SSL_load_error_strings ();
107 SSLeay_add_ssl_algorithms ();
109 tls_ctx = SSL_CTX_new (TLSv1_client_method());
113 SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
117 if (SSL_CTX_use_certificate_file (tls_ctx, cert_file,
118 SSL_FILETYPE_PEM) <= 0)
121 key_file = cert_file;
122 if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file,
123 SSL_FILETYPE_PEM) <= 0)
125 if (!SSL_CTX_check_private_key (tls_ctx))
129 SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
139 SSL_SESSION *session;
143 tls_conn = (SSL *) SSL_new (ctx);
148 if (!SSL_set_fd (tls_conn, s))
151 SSL_set_connect_state (tls_conn);
153 if (SSL_connect (tls_conn) <= 0)
155 session = SSL_get_session (tls_conn);
157 SSL_CTX_remove_session (ctx, session);
167 tls_connect (hostname, service)
168 const char *hostname, *service;
170 struct protoent *proto;
171 struct addrinfo *in, hints;
172 int server, false = 0;
174 proto = getprotobyname ("tcp");
178 memset (&hints, 0, sizeof (hints));
179 hints.ai_family = AF_UNSPEC;
180 hints.ai_socktype = SOCK_STREAM;
181 hints.ai_protocol = proto->p_proto;
183 if (getaddrinfo (hostname, service, &hints, &in) < 0)
186 server = socket (in->ai_family, in->ai_socktype, 0);
190 if (setsockopt (server, SOL_SOCKET, SO_KEEPALIVE,
191 (const char *) &false, sizeof (false)))
194 if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
207 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
210 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
215 const char *progname;
217 printf ("%s (%s) %s\n"
218 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
219 "This program comes with ABSOLUTELY NO WARRANTY.\n"
220 "This is free software, and you are welcome to redistribute it\n"
221 "under certain conditions. See the file COPYING for details.\n\n"
222 "Usage: %s [options] host port\n\n"
224 " --cert-file [file] specify certificate file\n"
225 " --key-file [file] specify private key file\n"
226 " --verify [level] set verification level\n"
227 " --force force negotiate\n",
228 progname, PACKAGE, VERSION, progname);
236 int in = fileno (stdin), out = fileno (stdout),
238 fd_set readfds, writefds;
239 char buffer[BUFSIZ], *retry;
240 struct sigaction act;
242 int this_option_optind = optind ? optind : 1;
243 int option_index = 0, c;
244 static struct option long_options[] =
246 {"cert-file", 1, 0, 'c'},
247 {"key-file", 1, 0, 'k'},
248 {"verify", 1, 0, 'v'},
249 {"force", 0, 0, 'f'},
255 c = getopt_long (argc, argv, "c:k:v:f", long_options, &option_index);
262 opt_cert_file = optarg;
265 opt_key_file = optarg;
268 opt_verify = atoi (optarg);
274 usage (basename (argv[0]));
279 if (optind+2 != argc)
281 usage (basename (argv[0]));
285 tls_fd = tls_connect (argv[optind], argv[optind+1]);
288 perror ("tls_connect");
292 memset (&act, 0, sizeof (act));
293 act.sa_handler = tls_negotiate;
294 sigemptyset (&act.sa_mask);
295 act.sa_flags = SA_RESTART|SA_RESETHAND;
296 sigaction (SIGALRM, &act, NULL);
298 if (opt_force == true)
303 FD_SET (tls_fd, &readfds);
304 FD_SET (in, &readfds);
305 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
311 if (FD_ISSET (in, &readfds))
313 nbuffer = read (in, buffer, BUFSIZ/2);
317 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
319 FD_SET (tls_fd, &writefds);
320 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
326 wrote = SSL_write (tls_conn, retry, nbuffer);
328 wrote = write (tls_fd, retry, nbuffer);
329 if (wrote < 0) goto finish;
332 if (FD_ISSET (tls_fd, &readfds))
335 nbuffer = SSL_read (tls_conn, buffer, BUFSIZ/8);
337 nbuffer = read (tls_fd, buffer, BUFSIZ/2);
340 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
342 FD_SET (out, &writefds);
343 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
348 wrote = write (out, retry, nbuffer);
349 if (wrote < 0) goto finish;