xref: /openbsd-src/usr.sbin/relayd/ssl.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: ssl.c,v 1.13 2007/12/07 17:17:01 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 
23 #include <net/if.h>
24 #include <netinet/in.h>
25 
26 #include <limits.h>
27 #include <event.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 
34 #include <openssl/ssl.h>
35 #include <openssl/err.h>
36 #include <openssl/engine.h>
37 
38 #include "relayd.h"
39 
40 void	ssl_read(int, short, void *);
41 void	ssl_write(int, short, void *);
42 void	ssl_connect(int, short, void *);
43 void	ssl_cleanup(struct ctl_tcp_event *);
44 
45 void
46 ssl_read(int s, short event, void *arg)
47 {
48 	struct ctl_tcp_event	*cte = arg;
49 	int			 ret;
50 	int			 ssl_err;
51 	int			 retry_flag;
52 	char			 rbuf[SMALL_READ_BUF_SIZE];
53 
54 	if (event == EV_TIMEOUT) {
55 		cte->host->up = HOST_DOWN;
56 		ssl_cleanup(cte);
57 		hce_notify_done(cte->host, "ssl_read: timeout");
58 		return;
59 	}
60 
61 	bzero(rbuf, sizeof(rbuf));
62 	ssl_err = 0;
63 	retry_flag = EV_READ;
64 
65 	ret = SSL_read(cte->ssl, rbuf, sizeof(rbuf));
66 	if (ret <= 0) {
67 		ssl_err = SSL_get_error(cte->ssl, ret);
68 		switch (ssl_err) {
69 		case SSL_ERROR_WANT_READ:
70 			retry_flag = EV_READ;
71 			goto retry;
72 		case SSL_ERROR_WANT_WRITE:
73 			retry_flag = EV_WRITE;
74 			goto retry;
75 		case SSL_ERROR_ZERO_RETURN: /* FALLTHROUGH */
76 		case SSL_ERROR_SYSCALL:
77 			if (ret == 0) {
78 				cte->host->up = HOST_DOWN;
79 				(void)cte->validate_close(cte);
80 				ssl_cleanup(cte);
81 				if (cte->host->up == HOST_UP)
82 					hce_notify_done(cte->host,
83 					    "ssl_read: check succeeded");
84 				else
85 					hce_notify_done(cte->host,
86 					    "ssl_read: check failed");
87 				return;
88 			}
89 			/* FALLTHROUGH */
90 		default:
91 			cte->host->up = HOST_DOWN;
92 			ssl_error(cte->host->conf.name, "cannot read");
93 			ssl_cleanup(cte);
94 			hce_notify_done(cte->host, "ssl_read: SSL error");
95 			break;
96 		}
97 		return;
98 	}
99 	if (buf_add(cte->buf, rbuf, ret) == -1)
100 		fatal("ssl_read: buf_add error");
101 	if (cte->validate_read != NULL) {
102 		if (cte->validate_read(cte) != 0)
103 			goto retry;
104 
105 		ssl_cleanup(cte);
106 		if (cte->host->up == HOST_UP)
107 			hce_notify_done(cte->host, "ssl_read: check succeeded");
108 		else
109 			hce_notify_done(cte->host, "ssl_read: check failed");
110 		return;
111 	}
112 
113 retry:
114 	event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_read,
115 	    &cte->tv_start, &cte->table->conf.timeout, cte);
116 	return;
117 }
118 
119 void
120 ssl_write(int s, short event, void *arg)
121 {
122 	struct ctl_tcp_event	*cte = arg;
123 	int			 len;
124 	int			 ret;
125 	int			 ssl_err;
126 	int			 retry_flag;
127 
128 	if (event == EV_TIMEOUT) {
129 		cte->host->up = HOST_DOWN;
130 		ssl_cleanup(cte);
131 		hce_notify_done(cte->host, "ssl_write: timeout");
132 		return;
133 	}
134 
135 	len = strlen(cte->table->sendbuf);
136 	retry_flag = EV_WRITE;
137 
138 	ret = SSL_write(cte->ssl, cte->table->sendbuf, len);
139 	if (ret <= 0) {
140 		ssl_err = SSL_get_error(cte->ssl, ret);
141 		switch (ssl_err) {
142 		case SSL_ERROR_WANT_READ:
143 			retry_flag = EV_READ;
144 			goto retry;
145 		case SSL_ERROR_WANT_WRITE:
146 			retry_flag = EV_WRITE;
147 			goto retry;
148 		default:
149 			cte->host->up = HOST_DOWN;
150 			ssl_error(cte->host->conf.name, "cannot write");
151 			ssl_cleanup(cte);
152 			hce_notify_done(cte->host, "ssl_write: SSL error");
153 			return;
154 		}
155 	}
156 	if ((cte->buf = buf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
157 		fatalx("ssl_write: cannot create dynamic buffer");
158 
159 	event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, ssl_read,
160 	    &cte->tv_start, &cte->table->conf.timeout, cte);
161 	return;
162 retry:
163 	event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_write,
164 	    &cte->tv_start, &cte->table->conf.timeout, cte);
165 }
166 
167 void
168 ssl_connect(int s, short event, void *arg)
169 {
170 	struct ctl_tcp_event	*cte = arg;
171 	int			 ret;
172 	int			 ssl_err;
173 	int			 retry_flag;
174 
175 	if (event == EV_TIMEOUT) {
176 		cte->host->up = HOST_DOWN;
177 		hce_notify_done(cte->host, "ssl_connect: timeout");
178 		ssl_cleanup(cte);
179 		return;
180 	}
181 
182 	retry_flag = ssl_err = 0;
183 
184 	ret = SSL_connect(cte->ssl);
185 	if (ret <= 0) {
186 		ssl_err = SSL_get_error(cte->ssl, ret);
187 		switch (ssl_err) {
188 		case SSL_ERROR_WANT_READ:
189 			retry_flag = EV_READ;
190 			goto retry;
191 		case SSL_ERROR_WANT_WRITE:
192 			retry_flag = EV_WRITE;
193 			goto retry;
194 		default:
195 			cte->host->up = HOST_DOWN;
196 			ssl_error(cte->host->conf.name, "cannot connect");
197 			hce_notify_done(cte->host, "ssl_connect: SSL error");
198 			ssl_cleanup(cte);
199 			return;
200 		}
201 	}
202 
203 	if (cte->table->conf.check == CHECK_TCP) {
204 		cte->host->up = HOST_UP;
205 		hce_notify_done(cte->host, "ssl_connect: connect successful");
206 		ssl_cleanup(cte);
207 		return;
208 	}
209 	if (cte->table->sendbuf != NULL) {
210 		event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_write,
211 		    &cte->tv_start, &cte->table->conf.timeout, cte);
212 		return;
213 	}
214 
215 	if ((cte->buf = buf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
216 		fatalx("ssl_connect: cannot create dynamic buffer");
217 	event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, ssl_read,
218 	    &cte->tv_start, &cte->table->conf.timeout, cte);
219 	return;
220 
221 retry:
222 	event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_connect,
223 	    &cte->tv_start, &cte->table->conf.timeout, cte);
224 }
225 
226 void
227 ssl_cleanup(struct ctl_tcp_event *cte)
228 {
229 	close(cte->s);
230 	if (cte->ssl != NULL)
231 		SSL_free(cte->ssl);
232 	if (cte->buf != NULL)
233 		buf_free(cte->buf);
234 }
235 
236 void
237 ssl_error(const char *where, const char *what)
238 {
239 	unsigned long	 code;
240 	char		 errbuf[128];
241 	extern int	 debug;
242 
243 	if (!debug)
244 		return;
245 	for (; (code = ERR_get_error()) != 0 ;) {
246 		ERR_error_string_n(code, errbuf, sizeof(errbuf));
247 		log_debug("SSL library error: %s: %s: %s", where, what, errbuf);
248 	}
249 }
250 
251 void
252 ssl_init(struct relayd *env)
253 {
254 	SSL_library_init();
255 	SSL_load_error_strings();
256 
257 	/* Init hardware crypto engines. */
258 	ENGINE_load_builtin_engines();
259 	ENGINE_register_all_complete();
260 }
261 
262 void
263 ssl_transaction(struct ctl_tcp_event *cte)
264 {
265 	cte->ssl = SSL_new(cte->table->ssl_ctx);
266 	if (cte->ssl == NULL) {
267 		ssl_error(cte->host->conf.name, "cannot create object");
268 		fatal("cannot create SSL object");
269 	}
270 
271 	if (SSL_set_fd(cte->ssl, cte->s) == 0) {
272 		cte->host->up = HOST_UNKNOWN;
273 		ssl_error(cte->host->conf.name, "cannot set fd");
274 		ssl_cleanup(cte);
275 		hce_notify_done(cte->host,
276 		    "ssl_transaction: cannot set SSL fd");
277 		return;
278 	}
279 	SSL_set_connect_state(cte->ssl);
280 
281 	event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_connect,
282 	    &cte->tv_start, &cte->table->conf.timeout, cte);
283 }
284 
285 SSL_CTX *
286 ssl_ctx_create(struct relayd *env)
287 {
288 	SSL_CTX	*ctx;
289 
290 	ctx = SSL_CTX_new(SSLv23_client_method());
291 	if (ctx == NULL) {
292 		ssl_error("ssl_ctx_create", "cannot create context");
293 		fatal("could not create SSL context");
294 	}
295 	return (ctx);
296 }
297