1 /* simple wrapper program for STARTTLS
3 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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.
28 #include <sys/types.h>
35 #include <openssl/lhash.h>
36 #include <openssl/bn.h>
37 #include <openssl/err.h>
38 #include <openssl/pem.h>
39 #include <openssl/x509.h>
40 #include <openssl/ssl.h>
46 #ifdef NEED_ADDRINFO_H
51 #include <sys/socket.h>
53 #include <sys/ioctl.h>
59 #include <netinet/in.h>
66 static SSL_CTX *tls_ctx = NULL;
67 static SSL *tls_conn = NULL;
70 static char *opt_cert_file = NULL, *opt_key_file = NULL;
71 static int opt_verify = 0;
74 tls_ssl_ctx_new (cert_file, key_file)
75 const char *cert_file, *key_file;
77 SSL_load_error_strings ();
78 SSLeay_add_ssl_algorithms ();
80 tls_ctx = SSL_CTX_new (TLSv1_client_method());
84 SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
88 if (SSL_CTX_use_certificate_file (tls_ctx, cert_file,
89 SSL_FILETYPE_PEM) <= 0)
93 if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file,
94 SSL_FILETYPE_PEM) <= 0)
96 if (!SSL_CTX_check_private_key (tls_ctx))
100 SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
110 SSL_SESSION *session;
114 tls_conn = (SSL *) SSL_new (ctx);
119 if (!SSL_set_fd (tls_conn, s))
122 SSL_set_connect_state (tls_conn);
124 if (SSL_connect (tls_conn) <= 0)
126 session = SSL_get_session (tls_conn);
128 SSL_CTX_remove_session (ctx, session);
138 tls_connect (hostname, service)
139 const char *hostname, *service;
141 struct protoent *proto;
142 struct addrinfo *in, hints;
143 int server, false = 0;
145 proto = getprotobyname ("tcp");
149 memset (&hints, 0, sizeof (hints));
150 hints.ai_family = AF_UNSPEC;
151 hints.ai_socktype = SOCK_STREAM;
152 hints.ai_protocol = proto->p_proto;
154 if (getaddrinfo (hostname, service, &hints, &in) < 0)
157 server = socket (in->ai_family, in->ai_socktype, 0);
161 if (setsockopt (server, SOL_SOCKET, SO_KEEPALIVE,
162 (const char *) &false, sizeof (false)))
165 if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
178 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
181 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
186 const char *progname;
188 printf ("%s (%s) %s\n"
189 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
190 "This program comes with ABSOLUTELY NO WARRANTY.\n"
191 "This is free software, and you are welcome to redistribute it\n"
192 "under certain conditions. See the file COPYING for details.\n\n"
193 "Usage: %s [options] host port\n\n"
195 " --cert-file [file] specify certificate file\n"
196 " --key-file [file] specify private key file\n"
197 " --verify [level] set verification level\n",
198 progname, PACKAGE, VERSION, progname);
206 int in = fileno (stdin), out = fileno (stdout),
209 struct pollfd readfds[2], writefds[1];
211 fd_set readfds, writefds;
213 char buffer[BUFSIZ], *retry;
214 struct sigaction act;
216 int this_option_optind = optind ? optind : 1;
217 int option_index = 0, c;
218 static struct option long_options[] =
220 {"cert-file", 1, 0, 'c'},
221 {"key-file", 1, 0, 'k'},
222 {"verify", 1, 0, 'v'},
228 c = getopt_long (argc, argv, "c:k:v:f", long_options, &option_index);
235 opt_cert_file = optarg;
238 opt_key_file = optarg;
241 opt_verify = atoi (optarg);
244 usage (basename (argv[0]));
249 if (optind+2 != argc)
251 usage (basename (argv[0]));
255 tls_fd = tls_connect (argv[optind], argv[optind+1]);
258 perror ("tls_connect");
262 memset (&act, 0, sizeof (act));
263 act.sa_handler = tls_negotiate;
264 sigemptyset (&act.sa_mask);
265 act.sa_flags = SA_RESTART|SA_RESETHAND;
266 sigaction (SIGALRM, &act, NULL);
270 readfds[1].fd = tls_fd;
271 readfds[0].events = POLLIN;
272 readfds[1].events = POLLIN;
273 writefds[0].events = POLLOUT;
279 if (poll (readfds, 2, -1) == -1 && errno != EINTR)
282 FD_SET (tls_fd, &readfds);
283 FD_SET (in, &readfds);
284 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
292 if (readfds[0].revents & POLLIN)
294 if (FD_ISSET (in, &readfds))
297 nbuffer = read (in, buffer, sizeof buffer -1);
301 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
304 writefds[0].fd = tls_fd;
305 if (poll (writefds, 1, -1) == -1)
308 FD_SET (tls_fd, &writefds);
309 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
316 wrote = SSL_write (tls_conn, retry, nbuffer);
318 wrote = write (tls_fd, retry, nbuffer);
319 if (wrote < 0) goto finish;
323 if (readfds[1].revents & POLLIN)
325 if (FD_ISSET (tls_fd, &readfds))
329 nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
331 nbuffer = read (tls_fd, buffer, sizeof buffer -1);
334 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
337 writefds[0].fd = out;
338 if (poll (writefds, 1, -1) == -1)
341 FD_SET (out, &writefds);
342 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
348 wrote = write (out, retry, nbuffer);
349 if (wrote < 0) goto finish;