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>
43 #include <sys/socket.h>
45 #include <sys/ioctl.h>
51 #include <netinet/in.h>
58 static SSL_CTX *tls_ctx = NULL;
59 static SSL *tls_conn = NULL;
62 static char *opt_cert_file = NULL, *opt_key_file = NULL;
63 static int opt_verify = 0;
66 tls_ssl_ctx_new (cert_file, key_file)
67 const char *cert_file, *key_file;
69 SSL_load_error_strings ();
70 SSLeay_add_ssl_algorithms ();
72 tls_ctx = SSL_CTX_new (TLSv1_client_method());
76 SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
80 if (SSL_CTX_use_certificate_file (tls_ctx, cert_file,
81 SSL_FILETYPE_PEM) <= 0)
85 if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file,
86 SSL_FILETYPE_PEM) <= 0)
88 if (!SSL_CTX_check_private_key (tls_ctx))
92 SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
102 SSL_SESSION *session;
106 tls_conn = (SSL *) SSL_new (ctx);
111 if (!SSL_set_fd (tls_conn, s))
114 SSL_set_connect_state (tls_conn);
116 if (SSL_connect (tls_conn) <= 0)
118 session = SSL_get_session (tls_conn);
120 SSL_CTX_remove_session (ctx, session);
130 tls_connect (hostname, service)
131 const char *hostname, *service;
133 int server, false = 0;
135 struct addrinfo *in, *in0, hints;
137 struct hostent *host;
138 struct servent *serv;
139 struct sockaddr_in sin;
143 memset (&hints, 0, sizeof (hints));
144 hints.ai_family = AF_UNSPEC;
145 hints.ai_socktype = SOCK_STREAM;
146 if (getaddrinfo (hostname, service, &hints, &in))
149 for (in = in0; in; in = in->ai_next)
151 server = socket (in->ai_family, in->ai_socktype, in->ai_protocol);
154 if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
166 memset (&sin, 0, sizeof (sin));
167 host = gethostbyname (hostname);
170 memcpy (&sin.sin_addr, host->h_addr, host->h_length);
171 serv = getservbyname (service, "tcp");
173 sin.sin_port = serv->s_port;
174 else if (isdigit (service[0]))
175 sin.sin_port = htons (atoi (service));
176 sin.sin_family = AF_INET;
177 server = socket (sin.sin_family, SOCK_STREAM, 0);
181 if (connect (server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
188 setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &false,
198 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
201 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
206 const char *progname;
208 printf ("%s (%s) %s\n"
209 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
210 "This program comes with ABSOLUTELY NO WARRANTY.\n"
211 "This is free software, and you are welcome to redistribute it\n"
212 "under certain conditions. See the file COPYING for details.\n\n"
213 "Usage: %s [options] host port\n\n"
215 " --cert-file [file] specify certificate file\n"
216 " --key-file [file] specify private key file\n"
217 " --verify [level] set verification level\n",
218 progname, PACKAGE, VERSION, progname);
226 int in = fileno (stdin), out = fileno (stdout),
229 struct pollfd readfds[2], writefds[1];
231 fd_set readfds, writefds;
233 char buffer[BUFSIZ], *retry;
234 struct sigaction act;
236 int this_option_optind = optind ? optind : 1;
237 int option_index = 0, c;
238 static struct option long_options[] =
240 {"cert-file", 1, 0, 'c'},
241 {"key-file", 1, 0, 'k'},
242 {"verify", 1, 0, 'v'},
248 c = getopt_long (argc, argv, "c:k:v:", long_options, &option_index);
255 opt_cert_file = optarg;
258 opt_key_file = optarg;
261 opt_verify = atoi (optarg);
264 usage (basename (argv[0]));
269 if (optind+2 != argc)
271 usage (basename (argv[0]));
275 tls_fd = tls_connect (argv[optind], argv[optind+1]);
278 perror ("tls_connect");
282 memset (&act, 0, sizeof (act));
283 act.sa_handler = tls_negotiate;
284 sigemptyset (&act.sa_mask);
285 act.sa_flags = SA_RESTART|SA_RESETHAND;
286 sigaction (SIGALRM, &act, NULL);
290 readfds[1].fd = tls_fd;
291 readfds[0].events = POLLIN;
292 readfds[1].events = POLLIN;
293 writefds[0].events = POLLOUT;
299 if (poll (readfds, 2, -1) == -1 && errno != EINTR)
302 FD_SET (tls_fd, &readfds);
303 FD_SET (in, &readfds);
304 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
312 if (readfds[0].revents & POLLIN)
314 if (FD_ISSET (in, &readfds))
317 nbuffer = read (in, buffer, sizeof buffer -1);
321 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
324 writefds[0].fd = tls_fd;
325 if (poll (writefds, 1, -1) == -1)
328 FD_SET (tls_fd, &writefds);
329 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
336 wrote = SSL_write (tls_conn, retry, nbuffer);
338 wrote = write (tls_fd, retry, nbuffer);
339 if (wrote < 0) goto finish;
343 if (readfds[1].revents & POLLIN)
345 if (FD_ISSET (tls_fd, &readfds))
349 nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
351 nbuffer = read (tls_fd, buffer, sizeof buffer -1);
354 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
357 writefds[0].fd = out;
358 if (poll (writefds, 1, -1) == -1)
361 FD_SET (out, &writefds);
362 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
368 wrote = write (out, retry, nbuffer);
369 if (wrote < 0) goto finish;