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