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>
42 #ifdef NEED_ADDRINFO_H
47 #include <sys/socket.h>
49 #include <sys/ioctl.h>
55 #include <netinet/in.h>
62 static SSL_CTX *tls_ctx = NULL;
63 static SSL *tls_conn = NULL;
66 static char *opt_cert_file = NULL, *opt_key_file = NULL;
67 static int opt_verify = 0;
70 tls_ssl_ctx_new (cert_file, key_file)
71 const char *cert_file, *key_file;
73 SSL_load_error_strings ();
74 SSLeay_add_ssl_algorithms ();
76 tls_ctx = SSL_CTX_new (TLSv1_client_method());
80 SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
84 if (SSL_CTX_use_certificate_file (tls_ctx, cert_file,
85 SSL_FILETYPE_PEM) <= 0)
89 if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file,
90 SSL_FILETYPE_PEM) <= 0)
92 if (!SSL_CTX_check_private_key (tls_ctx))
96 SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
106 SSL_SESSION *session;
110 tls_conn = (SSL *) SSL_new (ctx);
115 if (!SSL_set_fd (tls_conn, s))
118 SSL_set_connect_state (tls_conn);
120 if (SSL_connect (tls_conn) <= 0)
122 session = SSL_get_session (tls_conn);
124 SSL_CTX_remove_session (ctx, session);
134 tls_connect (hostname, service)
135 const char *hostname, *service;
137 struct protoent *proto;
138 struct addrinfo *in, hints;
139 int server, false = 0;
141 proto = getprotobyname ("tcp");
145 memset (&hints, 0, sizeof (hints));
146 hints.ai_family = AF_UNSPEC;
147 hints.ai_socktype = SOCK_STREAM;
148 hints.ai_protocol = proto->p_proto;
150 if (getaddrinfo (hostname, service, &hints, &in) < 0)
153 server = socket (in->ai_family, in->ai_socktype, 0);
157 if (setsockopt (server, SOL_SOCKET, SO_KEEPALIVE,
158 (const char *) &false, sizeof (false)))
161 if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
174 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
177 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
182 const char *progname;
184 printf ("%s (%s) %s\n"
185 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
186 "This program comes with ABSOLUTELY NO WARRANTY.\n"
187 "This is free software, and you are welcome to redistribute it\n"
188 "under certain conditions. See the file COPYING for details.\n\n"
189 "Usage: %s [options] host port\n\n"
191 " --cert-file [file] specify certificate file\n"
192 " --key-file [file] specify private key file\n"
193 " --verify [level] set verification level\n",
194 progname, PACKAGE, VERSION, progname);
202 int in = fileno (stdin), out = fileno (stdout),
205 struct pollfd readfds[2], writefds[1];
207 fd_set readfds, writefds;
209 char buffer[BUFSIZ], *retry;
210 struct sigaction act;
212 int this_option_optind = optind ? optind : 1;
213 int option_index = 0, c;
214 static struct option long_options[] =
216 {"cert-file", 1, 0, 'c'},
217 {"key-file", 1, 0, 'k'},
218 {"verify", 1, 0, 'v'},
224 c = getopt_long (argc, argv, "c:k:v:f", long_options, &option_index);
231 opt_cert_file = optarg;
234 opt_key_file = optarg;
237 opt_verify = atoi (optarg);
240 usage (basename (argv[0]));
245 if (optind+2 != argc)
247 usage (basename (argv[0]));
251 tls_fd = tls_connect (argv[optind], argv[optind+1]);
254 perror ("tls_connect");
258 memset (&act, 0, sizeof (act));
259 act.sa_handler = tls_negotiate;
260 sigemptyset (&act.sa_mask);
261 act.sa_flags = SA_RESTART|SA_RESETHAND;
262 sigaction (SIGALRM, &act, NULL);
266 readfds[1].fd = tls_fd;
267 readfds[0].events = POLLIN;
268 readfds[1].events = POLLIN;
269 writefds[0].events = POLLOUT;
275 if (poll (readfds, 2, -1) == -1 && errno != EINTR)
278 FD_SET (tls_fd, &readfds);
279 FD_SET (in, &readfds);
280 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
288 if (readfds[0].revents & POLLIN)
290 if (FD_ISSET (in, &readfds))
293 nbuffer = read (in, buffer, sizeof buffer -1);
297 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
300 writefds[0].fd = tls_fd;
301 if (poll (writefds, 1, -1) == -1)
304 FD_SET (tls_fd, &writefds);
305 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
312 wrote = SSL_write (tls_conn, retry, nbuffer);
314 wrote = write (tls_fd, retry, nbuffer);
315 if (wrote < 0) goto finish;
319 if (readfds[1].revents & POLLIN)
321 if (FD_ISSET (tls_fd, &readfds))
325 nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
327 nbuffer = read (tls_fd, buffer, sizeof buffer -1);
330 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
333 writefds[0].fd = out;
334 if (poll (writefds, 1, -1) == -1)
337 FD_SET (out, &writefds);
338 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
344 wrote = write (out, retry, nbuffer);
345 if (wrote < 0) goto finish;