* starttls.c (do_tls_negotiate): New signal handler.
[elisp/starttls.git] / openssl.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netdb.h>
4
5 #include <openssl/lhash.h>
6 #include <openssl/bn.h>
7 #include <openssl/err.h>
8 #include <openssl/pem.h>
9 #include <openssl/x509.h>
10 #include <openssl/ssl.h>
11
12 static SSL_CTX *tls_ctx = NULL;
13 static SSL *tls_conn = NULL;
14
15 static int
16 tls_ssl_ctx_new (cert_file, key_file)
17   const char *cert_file, *key_file;
18 {
19   SSL_load_error_strings ();
20   SSLeay_add_ssl_algorithms ();
21
22   tls_ctx = SSL_CTX_new (TLSv1_client_method());
23   if (!tls_ctx)
24     return -1;
25
26   SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */); 
27
28   if (cert_file)
29     {
30       if (SSL_CTX_use_certificate_file (tls_ctx, cert_file, 
31                                         SSL_FILETYPE_PEM) <= 0)
32         return -1;
33       if (!key_file)
34         key_file = cert_file;
35       if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file, 
36                                        SSL_FILETYPE_PEM) <= 0)
37         return -1;
38       if (!SSL_CTX_check_private_key (tls_ctx))
39         return -1;
40     }
41
42   SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
43
44   return 0;
45 }
46
47 static int
48 tls_ssl_new(ctx, s)
49   SSL_CTX *ctx;
50   int s;
51 {
52   SSL_SESSION *session;
53   SSL_CIPHER *cipher;
54   X509   *peer;
55
56   tls_conn = (SSL *) SSL_new (ctx);
57   if (!tls_conn)
58     return -1;
59   SSL_clear(tls_conn);
60
61   if (!SSL_set_fd (tls_conn, s))
62     return -1;
63
64   SSL_set_connect_state (tls_conn);
65
66   if (SSL_connect (tls_conn) <= 0)
67     {
68       session = SSL_get_session (tls_conn);
69       if (session)
70         SSL_CTX_remove_session (ctx, session);
71       if (tls_conn!=NULL)
72         SSL_free (tls_conn);
73       return -1;
74     }
75
76   return 0;
77 }
78
79 int
80 tls_connect (hostname, service)
81      const char *hostname, *service;
82 {
83   int server, false = 0;
84 #ifdef HAVE_ADDRINFO
85   struct addrinfo *in, *in0, hints;
86 #else
87   struct hostent *host;
88   struct servent *serv;
89   struct sockaddr_in sin;
90 #endif
91
92 #ifdef HAVE_ADDRINFO
93   memset (&hints, 0, sizeof (hints));
94   hints.ai_family = AF_UNSPEC;
95   hints.ai_socktype = SOCK_STREAM;
96   if (getaddrinfo (hostname, service, &hints, &in0))
97     return -1;
98
99   for (in = in0; in; in = in->ai_next)
100     {
101       server = socket (in->ai_family, in->ai_socktype, in->ai_protocol);
102       if (server < 0)
103         continue;
104       if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
105         {
106           server = -1;
107           continue;
108         }
109       break;
110   }
111
112   if (server < 0)
113     return -1;
114 #else
115   memset (&sin, 0, sizeof (sin));
116   host = gethostbyname (hostname);
117   if (!host)
118     return -1;
119   memcpy (&sin.sin_addr, host->h_addr, host->h_length);
120   serv = getservbyname (service, "tcp");
121   if (serv)
122     sin.sin_port = serv->s_port;
123   else if (isdigit (service[0]))
124     sin.sin_port = htons (atoi (service));
125   sin.sin_family = AF_INET;
126   server = socket (sin.sin_family, SOCK_STREAM, 0);
127   if (server == -1)
128     return -1;
129
130   if (connect (server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
131     {
132       close (server);
133       return -1;
134     }
135 #endif
136
137   setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &false,
138               sizeof (false));
139
140   return server;
141 }
142
143 void
144 tls_negotiate (fd, cert_file, key_file)
145      int fd;
146 {
147   if (tls_ssl_ctx_new (cert_file, key_file) == -1)
148     return;
149
150   (void) tls_ssl_new (tls_ctx, fd); /* Negotiation has done. */
151 }
152
153 int
154 tls_write(fd, buf, num)
155      const char *buf;
156      int fd, num;
157 {
158   if (tls_conn) 
159     return SSL_write (tls_conn, buf, num);
160   return write (fd, buf, num);
161 }
162
163 int
164 tls_read(fd, buf, num)
165      char *buf;
166      int fd, num;
167 {
168   if (tls_conn)
169     return SSL_read (tls_conn, buf, num);
170   return read (fd, buf, num);
171 }
172
173 int
174 tls_pending()
175 {
176   return tls_conn && SSL_pending(tls_conn);
177 }