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 struct protoent *proto;
134 int server, false = 0, family, socktype;
135 struct sockaddr *addr;
136 struct sockaddr_in sin;
137 size_t addrlen; /* socklen_t addrlen */
139 struct addrinfo *in, hints;
141 struct hostent *host;
142 struct servent *serv;
145 proto = getprotobyname ("tcp");
150 memset (&hints, 0, sizeof (hints));
151 hints.ai_family = AF_UNSPEC;
152 hints.ai_socktype = SOCK_STREAM;
153 hints.ai_protocol = proto->p_proto;
155 if (getaddrinfo (hostname, service, &hints, &in) < 0)
158 family = in->ai_family;
159 socktype = in->ai_socktype;
161 addrlen = in->ai_addrlen;
164 memset (&sin, 0, sizeof (sin));
165 host = gethostbyname (hostname);
168 memcpy (&sin.sin_addr, host->h_addr, host->h_length);
169 serv = getservbyname (service, proto->p_name);
171 sin.sin_port = htons (serv->s_port);
172 else if (isdigit (service[0]))
173 sin.sin_port = htons (atoi (service));
174 family = sin.sin_family = AF_INET;
175 socktype = SOCK_STREAM;
176 addr = (struct sockaddr *)&sin;
177 addrlen = sizeof (sin);
180 server = socket (family, socktype, 0);
184 setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &false,
187 if (connect (server, addr, addrlen) < 0)
200 if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
203 (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
208 const char *progname;
210 printf ("%s (%s) %s\n"
211 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
212 "This program comes with ABSOLUTELY NO WARRANTY.\n"
213 "This is free software, and you are welcome to redistribute it\n"
214 "under certain conditions. See the file COPYING for details.\n\n"
215 "Usage: %s [options] host port\n\n"
217 " --cert-file [file] specify certificate file\n"
218 " --key-file [file] specify private key file\n"
219 " --verify [level] set verification level\n",
220 progname, PACKAGE, VERSION, progname);
228 int in = fileno (stdin), out = fileno (stdout),
231 struct pollfd readfds[2], writefds[1];
233 fd_set readfds, writefds;
235 char buffer[BUFSIZ], *retry;
236 struct sigaction act;
238 int this_option_optind = optind ? optind : 1;
239 int option_index = 0, c;
240 static struct option long_options[] =
242 {"cert-file", 1, 0, 'c'},
243 {"key-file", 1, 0, 'k'},
244 {"verify", 1, 0, 'v'},
250 c = getopt_long (argc, argv, "c:k:v:", long_options, &option_index);
257 opt_cert_file = optarg;
260 opt_key_file = optarg;
263 opt_verify = atoi (optarg);
266 usage (basename (argv[0]));
271 if (optind+2 != argc)
273 usage (basename (argv[0]));
277 tls_fd = tls_connect (argv[optind], argv[optind+1]);
280 perror ("tls_connect");
284 memset (&act, 0, sizeof (act));
285 act.sa_handler = tls_negotiate;
286 sigemptyset (&act.sa_mask);
287 act.sa_flags = SA_RESTART|SA_RESETHAND;
288 sigaction (SIGALRM, &act, NULL);
292 readfds[1].fd = tls_fd;
293 readfds[0].events = POLLIN;
294 readfds[1].events = POLLIN;
295 writefds[0].events = POLLOUT;
301 if (poll (readfds, 2, -1) == -1 && errno != EINTR)
304 FD_SET (tls_fd, &readfds);
305 FD_SET (in, &readfds);
306 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
314 if (readfds[0].revents & POLLIN)
316 if (FD_ISSET (in, &readfds))
319 nbuffer = read (in, buffer, sizeof buffer -1);
323 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
326 writefds[0].fd = tls_fd;
327 if (poll (writefds, 1, -1) == -1)
330 FD_SET (tls_fd, &writefds);
331 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
338 wrote = SSL_write (tls_conn, retry, nbuffer);
340 wrote = write (tls_fd, retry, nbuffer);
341 if (wrote < 0) goto finish;
345 if (readfds[1].revents & POLLIN)
347 if (FD_ISSET (tls_fd, &readfds))
351 nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
353 nbuffer = read (tls_fd, buffer, sizeof buffer -1);
356 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
359 writefds[0].fd = out;
360 if (poll (writefds, 1, -1) == -1)
363 FD_SET (out, &writefds);
364 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
370 wrote = write (out, retry, nbuffer);
371 if (wrote < 0) goto finish;