1 /* $OpenBSD: ssl.c,v 1.15 2009/06/04 13:46:07 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, HCE_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 hce_notify_done(cte->host, cte->host->he); 82 return; 83 } 84 /* FALLTHROUGH */ 85 default: 86 cte->host->up = HOST_DOWN; 87 ssl_error(cte->host->conf.name, "cannot read"); 88 ssl_cleanup(cte); 89 hce_notify_done(cte->host, HCE_SSL_READ_ERROR); 90 break; 91 } 92 return; 93 } 94 if (buf_add(cte->buf, rbuf, ret) == -1) 95 fatal("ssl_read: buf_add error"); 96 if (cte->validate_read != NULL) { 97 if (cte->validate_read(cte) != 0) 98 goto retry; 99 100 ssl_cleanup(cte); 101 hce_notify_done(cte->host, cte->host->he); 102 return; 103 } 104 105 retry: 106 event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_read, 107 &cte->tv_start, &cte->table->conf.timeout, cte); 108 return; 109 } 110 111 void 112 ssl_write(int s, short event, void *arg) 113 { 114 struct ctl_tcp_event *cte = arg; 115 int len; 116 int ret; 117 int ssl_err; 118 int retry_flag; 119 120 if (event == EV_TIMEOUT) { 121 cte->host->up = HOST_DOWN; 122 ssl_cleanup(cte); 123 hce_notify_done(cte->host, HCE_SSL_WRITE_TIMEOUT); 124 return; 125 } 126 127 len = strlen(cte->table->sendbuf); 128 retry_flag = EV_WRITE; 129 130 ret = SSL_write(cte->ssl, cte->table->sendbuf, len); 131 if (ret <= 0) { 132 ssl_err = SSL_get_error(cte->ssl, ret); 133 switch (ssl_err) { 134 case SSL_ERROR_WANT_READ: 135 retry_flag = EV_READ; 136 goto retry; 137 case SSL_ERROR_WANT_WRITE: 138 retry_flag = EV_WRITE; 139 goto retry; 140 default: 141 cte->host->up = HOST_DOWN; 142 ssl_error(cte->host->conf.name, "cannot write"); 143 ssl_cleanup(cte); 144 hce_notify_done(cte->host, HCE_SSL_WRITE_ERROR); 145 return; 146 } 147 } 148 if ((cte->buf = buf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL) 149 fatalx("ssl_write: cannot create dynamic buffer"); 150 151 event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, ssl_read, 152 &cte->tv_start, &cte->table->conf.timeout, cte); 153 return; 154 retry: 155 event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_write, 156 &cte->tv_start, &cte->table->conf.timeout, cte); 157 } 158 159 void 160 ssl_connect(int s, short event, void *arg) 161 { 162 struct ctl_tcp_event *cte = arg; 163 int ret; 164 int ssl_err; 165 int retry_flag; 166 167 if (event == EV_TIMEOUT) { 168 cte->host->up = HOST_DOWN; 169 hce_notify_done(cte->host, HCE_SSL_CONNECT_TIMEOUT); 170 ssl_cleanup(cte); 171 return; 172 } 173 174 retry_flag = ssl_err = 0; 175 176 ret = SSL_connect(cte->ssl); 177 if (ret <= 0) { 178 ssl_err = SSL_get_error(cte->ssl, ret); 179 switch (ssl_err) { 180 case SSL_ERROR_WANT_READ: 181 retry_flag = EV_READ; 182 goto retry; 183 case SSL_ERROR_WANT_WRITE: 184 retry_flag = EV_WRITE; 185 goto retry; 186 default: 187 cte->host->up = HOST_DOWN; 188 ssl_error(cte->host->conf.name, "cannot connect"); 189 hce_notify_done(cte->host, HCE_SSL_CONNECT_FAIL); 190 ssl_cleanup(cte); 191 return; 192 } 193 } 194 195 if (cte->table->conf.check == CHECK_TCP) { 196 cte->host->up = HOST_UP; 197 hce_notify_done(cte->host, HCE_SSL_CONNECT_OK); 198 ssl_cleanup(cte); 199 return; 200 } 201 if (cte->table->sendbuf != NULL) { 202 event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_write, 203 &cte->tv_start, &cte->table->conf.timeout, cte); 204 return; 205 } 206 207 if ((cte->buf = buf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL) 208 fatalx("ssl_connect: cannot create dynamic buffer"); 209 event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, ssl_read, 210 &cte->tv_start, &cte->table->conf.timeout, cte); 211 return; 212 213 retry: 214 event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_connect, 215 &cte->tv_start, &cte->table->conf.timeout, cte); 216 } 217 218 void 219 ssl_cleanup(struct ctl_tcp_event *cte) 220 { 221 close(cte->s); 222 if (cte->ssl != NULL) { 223 SSL_shutdown(cte->ssl); 224 SSL_clear(cte->ssl); 225 } 226 if (cte->buf != NULL) 227 buf_free(cte->buf); 228 } 229 230 void 231 ssl_error(const char *where, const char *what) 232 { 233 unsigned long code; 234 char errbuf[128]; 235 extern int debug; 236 237 if (!debug) 238 return; 239 for (; (code = ERR_get_error()) != 0 ;) { 240 ERR_error_string_n(code, errbuf, sizeof(errbuf)); 241 log_debug("SSL library error: %s: %s: %s", where, what, errbuf); 242 } 243 } 244 245 void 246 ssl_init(struct relayd *env) 247 { 248 SSL_library_init(); 249 SSL_load_error_strings(); 250 251 /* Init hardware crypto engines. */ 252 ENGINE_load_builtin_engines(); 253 ENGINE_register_all_complete(); 254 } 255 256 void 257 ssl_transaction(struct ctl_tcp_event *cte) 258 { 259 if (cte->ssl == NULL) { 260 cte->ssl = SSL_new(cte->table->ssl_ctx); 261 if (cte->ssl == NULL) { 262 ssl_error(cte->host->conf.name, "cannot create object"); 263 fatal("cannot create SSL object"); 264 } 265 } 266 267 if (SSL_set_fd(cte->ssl, cte->s) == 0) { 268 cte->host->up = HOST_UNKNOWN; 269 ssl_error(cte->host->conf.name, "cannot set fd"); 270 ssl_cleanup(cte); 271 hce_notify_done(cte->host, HCE_SSL_CONNECT_ERROR); 272 return; 273 } 274 SSL_set_connect_state(cte->ssl); 275 276 event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_connect, 277 &cte->tv_start, &cte->table->conf.timeout, cte); 278 } 279 280 SSL_CTX * 281 ssl_ctx_create(struct relayd *env) 282 { 283 SSL_CTX *ctx; 284 285 ctx = SSL_CTX_new(SSLv23_client_method()); 286 if (ctx == NULL) { 287 ssl_error("ssl_ctx_create", "cannot create context"); 288 fatal("could not create SSL context"); 289 } 290 return (ctx); 291 } 292