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, &in0))
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)
165 memset (&sin, 0, sizeof (sin));
166 host = gethostbyname (hostname);
169 memcpy (&sin.sin_addr, host->h_addr, host->h_length);
170 serv = getservbyname (service, "tcp");
172 sin.sin_port = serv->s_port;
173 else if (isdigit (service[0]))
174 sin.sin_port = htons (atoi (service));
175 sin.sin_family = AF_INET;
176 server = socket (sin.sin_family, SOCK_STREAM, 0);
180 if (connect (server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
187 setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &false,
197 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
200 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
205 const char *progname;
207 printf ("%s (%s) %s\n"
208 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
209 "This program comes with ABSOLUTELY NO WARRANTY.\n"
210 "This is free software, and you are welcome to redistribute it\n"
211 "under certain conditions. See the file COPYING for details.\n\n"
212 "Usage: %s [options] host port\n\n"
214 " --cert-file [file] specify certificate file\n"
215 " --key-file [file] specify private key file\n"
216 " --verify [level] set verification level\n",
217 progname, PACKAGE, VERSION, progname);
225 int in = fileno (stdin), out = fileno (stdout),
228 struct pollfd readfds[2], writefds[1];
230 fd_set readfds, writefds;
232 char buffer[BUFSIZ], *retry;
233 struct sigaction act;
235 int this_option_optind = optind ? optind : 1;
236 int option_index = 0, c;
237 static struct option long_options[] =
239 {"cert-file", 1, 0, 'c'},
240 {"key-file", 1, 0, 'k'},
241 {"verify", 1, 0, 'v'},
247 c = getopt_long (argc, argv, "c:k:v:", long_options, &option_index);
254 opt_cert_file = optarg;
257 opt_key_file = optarg;
260 opt_verify = atoi (optarg);
263 usage (basename (argv[0]));
268 if (optind+2 != argc)
270 usage (basename (argv[0]));
274 tls_fd = tls_connect (argv[optind], argv[optind+1]);
277 perror ("tls_connect");
281 memset (&act, 0, sizeof (act));
282 act.sa_handler = tls_negotiate;
283 sigemptyset (&act.sa_mask);
284 act.sa_flags = SA_RESTART|SA_RESETHAND;
285 sigaction (SIGALRM, &act, NULL);
289 readfds[1].fd = tls_fd;
290 readfds[0].events = POLLIN;
291 readfds[1].events = POLLIN;
292 writefds[0].events = POLLOUT;
298 if (poll (readfds, 2, -1) == -1 && errno != EINTR)
301 FD_SET (tls_fd, &readfds);
302 FD_SET (in, &readfds);
303 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
311 if (readfds[0].revents & POLLIN)
313 if (FD_ISSET (in, &readfds))
316 nbuffer = read (in, buffer, sizeof buffer -1);
320 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
323 writefds[0].fd = tls_fd;
324 if (poll (writefds, 1, -1) == -1)
327 FD_SET (tls_fd, &writefds);
328 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
335 wrote = SSL_write (tls_conn, retry, nbuffer);
337 wrote = write (tls_fd, retry, nbuffer);
338 if (wrote < 0) goto finish;
342 if (readfds[1].revents & POLLIN)
344 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;
371 if (tls_conn && SSL_pending(tls_conn))