1 /* TLSv1 filter for STARTTLS extension.
3 Copyright (C) 1999 Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
5 Author: Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
9 This file is part of FLIM (Faithful Library about Internet Message).
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.
29 How to compile: (OpenSSL is required)
31 gcc -I/usr/local/ssl/include -o starttls starttls.c \
32 -L/usr/local/ssl/lib -lssl -lcrypto
36 #include <sys/types.h>
43 /* OpenSSL library. */
45 #include <openssl/lhash.h>
46 #include <openssl/bn.h>
47 #include <openssl/err.h>
48 #include <openssl/pem.h>
49 #include <openssl/x509.h>
50 #include <openssl/ssl.h>
57 #include <sys/socket.h>
59 #include <sys/ioctl.h>
66 #include <netinet/in.h>
69 static SSL *tls_conn = NULL;
73 tls_ssl_ctx_new (cert_file, key_file)
74 const char *cert_file, key_file;
78 SSL_load_error_strings ();
79 SSLeay_add_ssl_algorithms ();
81 if ((tls_ctx = SSL_CTX_new (TLSv1_client_method())) == NULL)
84 SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
87 if (SSL_CTX_use_certificate_file (tls_ctx, NULL, SSL_FILETYPE_PEM) <= 0)
89 if (SSL_CTX_use_PrivateKey_file (tls_ctx, NULL, SSL_FILETYPE_PEM) <= 0)
91 if (!SSL_CTX_check_private_key (tls_ctx))
95 SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
101 tls_ssl_new(tls_ctx, s)
105 SSL_SESSION *session;
109 if ((tls_conn = (SSL *) SSL_new (tls_ctx)) == NULL)
113 if (!SSL_set_fd (tls_conn, s))
116 SSL_set_connect_state (tls_conn);
118 if (SSL_connect (tls_conn) <= 0) {
119 session = SSL_get_session (tls_conn);
121 SSL_CTX_remove_session (tls_ctx, session);
132 tls_connect (hostname, service)
133 const char *hostname, *service;
135 struct protoent *proto;
136 struct addrinfo *in, hints;
137 int server, false = 0;
139 if ((proto = getprotobyname ("tcp")) == NULL)
142 memset (&hints, 0, sizeof (hints));
143 hints.ai_family = AF_UNSPEC;
144 hints.ai_socktype = SOCK_STREAM;
145 hints.ai_protocol = proto->p_proto;
146 if (getaddrinfo (hostname, service, &hints, &in) < 0)
149 if ((server = socket (in->ai_family, in->ai_socktype, 0)) < 0)
152 if (setsockopt (server, SOL_SOCKET, SO_KEEPALIVE,
153 (const char *) &false, sizeof (false)))
156 if (connect (server, in->ai_addr, in->ai_addrlen) < 0) {
170 if ((tls_ctx = tls_ssl_ctx_new (NULL, NULL)) == NULL)
173 tls_conn = tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
181 int in = fileno (stdin), out = fileno (stdout), nbuffer, wrote;
182 fd_set readfds, writefds;
183 char buffer[BUFSIZ], *retry;
184 struct sigaction act;
186 if ((tls_fd = tls_connect (argv[1], argv[2])) < 0) {
187 perror ("tls_connect");
191 memset (&act, 0, sizeof (act));
192 act.sa_handler = tls_negotiate;
193 sigemptyset (&act.sa_mask);
194 act.sa_flags = SA_RESTART|SA_RESETHAND;
195 sigaction (SIGALRM, &act, NULL);
198 FD_SET (tls_fd, &readfds);
199 FD_SET (in, &readfds);
200 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1 &&
205 if (FD_ISSET (in, &readfds)) {
206 nbuffer = read (in, buffer, sizeof buffer -1);
210 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote) {
211 FD_SET (tls_fd, &writefds);
212 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1) {
217 wrote = SSL_write (tls_conn, retry, nbuffer);
219 wrote = write (tls_fd, retry, nbuffer);
220 if (wrote < 0) goto finish;
223 if (FD_ISSET (tls_fd, &readfds)) {
225 nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
227 nbuffer = read (tls_fd, buffer, sizeof buffer -1);
230 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote) {
231 FD_SET (out, &writefds);
232 if (select (out+1, NULL, &writefds, NULL, NULL) == -1) {
236 wrote = write (out, retry, nbuffer);
237 if (wrote < 0) goto finish;