summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2015-09-10 10:14:21 +0000
committerjsing <>2015-09-10 10:14:21 +0000
commitf7415644a66ca9d04e5e06312a163e677032b695 (patch)
treeb1c4283700879b3793a5395cbab5ffd49e03f34f /src
parentfb8be3d22f2620af8ca6f69de96a1d4e5a8d153b (diff)
downloadopenbsd-f7415644a66ca9d04e5e06312a163e677032b695.tar.gz
openbsd-f7415644a66ca9d04e5e06312a163e677032b695.tar.bz2
openbsd-f7415644a66ca9d04e5e06312a163e677032b695.zip
Split tls_handshake() out from tls_accept/tls_connect. By doing this the
tls_accept/tls_connect functions can be guaranteed to succeed or fail and will no longer return TLS_READ_AGAIN/TLS_WRITE_AGAIN. This also resolves the semantics of tls_accept_*. The tls_handshake() function now does I/O and can return TLS_READ_AGAIN/TLS_WRITE_AGAIN. Calls to tls_read() and tls_write() will trigger the handshake if it has not already completed, meaning that in many cases existing code will continue to work. Discussed over many coffees at l2k15. ok beck@ bluhm@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libtls/tls.c35
-rw-r--r--src/lib/libtls/tls.h3
-rw-r--r--src/lib/libtls/tls_client.c58
-rw-r--r--src/lib/libtls/tls_internal.h7
-rw-r--r--src/lib/libtls/tls_server.c76
5 files changed, 120 insertions, 59 deletions
diff --git a/src/lib/libtls/tls.c b/src/lib/libtls/tls.c
index 6b9834565c..fe5bc964e2 100644
--- a/src/lib/libtls/tls.c
+++ b/src/lib/libtls/tls.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls.c,v 1.19 2015/09/09 19:49:07 jsing Exp $ */ 1/* $OpenBSD: tls.c,v 1.20 2015/09/10 10:14:20 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -315,6 +315,9 @@ tls_reset(struct tls *ctx)
315 ctx->socket = -1; 315 ctx->socket = -1;
316 ctx->state = 0; 316 ctx->state = 0;
317 317
318 free(ctx->servername);
319 ctx->servername = NULL;
320
318 free(ctx->errmsg); 321 free(ctx->errmsg);
319 ctx->errmsg = NULL; 322 ctx->errmsg = NULL;
320 ctx->errnum = 0; 323 ctx->errnum = 0;
@@ -367,6 +370,20 @@ tls_ssl_error(struct tls *ctx, SSL *ssl_conn, int ssl_ret, const char *prefix)
367} 370}
368 371
369int 372int
373tls_handshake(struct tls *ctx)
374{
375 int rv = -1;
376
377 if ((ctx->flags & TLS_CLIENT) != 0)
378 rv = tls_handshake_client(ctx);
379 else if ((ctx->flags & TLS_SERVER_CONN) != 0)
380 rv = tls_handshake_server(ctx);
381
382 errno = 0;
383 return (rv);
384}
385
386int
370tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen) 387tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen)
371{ 388{
372 int ssl_ret; 389 int ssl_ret;
@@ -374,13 +391,17 @@ tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen)
374 391
375 *outlen = 0; 392 *outlen = 0;
376 393
394 if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
395 if ((rv = tls_handshake(ctx)) != 0)
396 goto out;
397 }
398
377 if (buflen > INT_MAX) { 399 if (buflen > INT_MAX) {
378 tls_set_errorx(ctx, "buflen too long"); 400 tls_set_errorx(ctx, "buflen too long");
379 goto out; 401 goto out;
380 } 402 }
381 403
382 ssl_ret = SSL_read(ctx->ssl_conn, buf, buflen); 404 if ((ssl_ret = SSL_read(ctx->ssl_conn, buf, buflen)) > 0) {
383 if (ssl_ret > 0) {
384 *outlen = (size_t)ssl_ret; 405 *outlen = (size_t)ssl_ret;
385 rv = 0; 406 rv = 0;
386 goto out; 407 goto out;
@@ -400,13 +421,17 @@ tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen)
400 421
401 *outlen = 0; 422 *outlen = 0;
402 423
424 if ((ctx->state & TLS_HANDSHAKE_COMPLETE) == 0) {
425 if ((rv = tls_handshake(ctx)) != 0)
426 goto out;
427 }
428
403 if (buflen > INT_MAX) { 429 if (buflen > INT_MAX) {
404 tls_set_errorx(ctx, "buflen too long"); 430 tls_set_errorx(ctx, "buflen too long");
405 goto out; 431 goto out;
406 } 432 }
407 433
408 ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen); 434 if ((ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen)) > 0) {
409 if (ssl_ret > 0) {
410 *outlen = (size_t)ssl_ret; 435 *outlen = (size_t)ssl_ret;
411 rv = 0; 436 rv = 0;
412 goto out; 437 goto out;
diff --git a/src/lib/libtls/tls.h b/src/lib/libtls/tls.h
index 579a97798e..8548fe1d83 100644
--- a/src/lib/libtls/tls.h
+++ b/src/lib/libtls/tls.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls.h,v 1.15 2015/09/10 09:10:42 jsing Exp $ */ 1/* $OpenBSD: tls.h,v 1.16 2015/09/10 10:14:20 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -94,6 +94,7 @@ int tls_connect_fds(struct tls *_ctx, int _fd_read, int _fd_write,
94int tls_connect_servername(struct tls *_ctx, const char *_host, 94int tls_connect_servername(struct tls *_ctx, const char *_host,
95 const char *_port, const char *_servername); 95 const char *_port, const char *_servername);
96int tls_connect_socket(struct tls *_ctx, int _s, const char *_servername); 96int tls_connect_socket(struct tls *_ctx, int _s, const char *_servername);
97int tls_handshake(struct tls *_ctx);
97int tls_read(struct tls *_ctx, void *_buf, size_t _buflen, size_t *_outlen); 98int tls_read(struct tls *_ctx, void *_buf, size_t _buflen, size_t *_outlen);
98int tls_write(struct tls *_ctx, const void *_buf, size_t _buflen, 99int tls_write(struct tls *_ctx, const void *_buf, size_t _buflen,
99 size_t *_outlen); 100 size_t *_outlen);
diff --git a/src/lib/libtls/tls_client.c b/src/lib/libtls/tls_client.c
index 81e47da0e1..fb7f3a6f75 100644
--- a/src/lib/libtls/tls_client.c
+++ b/src/lib/libtls/tls_client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_client.c,v 1.25 2015/09/09 19:49:07 jsing Exp $ */ 1/* $OpenBSD: tls_client.c,v 1.26 2015/09/10 10:14:20 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -166,20 +166,23 @@ tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
166 const char *servername) 166 const char *servername)
167{ 167{
168 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; 168 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
169 X509 *cert = NULL; 169 int rv = -1;
170 int ret, err;
171 170
172 if ((ctx->flags & TLS_CLIENT) == 0) { 171 if ((ctx->flags & TLS_CLIENT) == 0) {
173 tls_set_errorx(ctx, "not a client context"); 172 tls_set_errorx(ctx, "not a client context");
174 goto err; 173 goto err;
175 } 174 }
176 175
177 if (ctx->state & TLS_STATE_CONNECTING)
178 goto connecting;
179
180 if (fd_read < 0 || fd_write < 0) { 176 if (fd_read < 0 || fd_write < 0) {
181 tls_set_errorx(ctx, "invalid file descriptors"); 177 tls_set_errorx(ctx, "invalid file descriptors");
182 return (-1); 178 goto err;
179 }
180
181 if (servername != NULL) {
182 if ((ctx->servername = strdup(servername)) == NULL) {
183 tls_set_errorx(ctx, "out of memory");
184 goto err;
185 }
183 } 186 }
184 187
185 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { 188 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
@@ -230,16 +233,28 @@ tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
230 } 233 }
231 } 234 }
232 235
233 connecting: 236 rv = 0;
234 if ((ret = SSL_connect(ctx->ssl_conn)) != 1) { 237
235 err = tls_ssl_error(ctx, ctx->ssl_conn, ret, "connect"); 238 err:
236 if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) { 239 return (rv);
237 ctx->state |= TLS_STATE_CONNECTING; 240}
238 return (err); 241
239 } 242int
243tls_handshake_client(struct tls *ctx)
244{
245 X509 *cert = NULL;
246 int ssl_ret;
247 int rv = -1;
248
249 if ((ctx->flags & TLS_CLIENT) == 0) {
250 tls_set_errorx(ctx, "not a client context");
251 goto err;
252 }
253
254 if ((ssl_ret = SSL_connect(ctx->ssl_conn)) != 1) {
255 rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "handshake");
240 goto err; 256 goto err;
241 } 257 }
242 ctx->state &= ~TLS_STATE_CONNECTING;
243 258
244 if (ctx->config->verify_name) { 259 if (ctx->config->verify_name) {
245 cert = SSL_get_peer_certificate(ctx->ssl_conn); 260 cert = SSL_get_peer_certificate(ctx->ssl_conn);
@@ -247,19 +262,20 @@ tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
247 tls_set_errorx(ctx, "no server certificate"); 262 tls_set_errorx(ctx, "no server certificate");
248 goto err; 263 goto err;
249 } 264 }
250 if ((ret = tls_check_servername(ctx, cert, servername)) != 0) { 265 if ((rv = tls_check_servername(ctx, cert,
251 if (ret != -2) 266 ctx->servername)) != 0) {
267 if (rv != -2)
252 tls_set_errorx(ctx, "name `%s' not present in" 268 tls_set_errorx(ctx, "name `%s' not present in"
253 " server certificate", servername); 269 " server certificate", ctx->servername);
254 goto err; 270 goto err;
255 } 271 }
256 X509_free(cert);
257 } 272 }
258 273
259 return (0); 274 ctx->state |= TLS_HANDSHAKE_COMPLETE;
275 rv = 0;
260 276
261 err: 277 err:
262 X509_free(cert); 278 X509_free(cert);
263 279
264 return (-1); 280 return (rv);
265} 281}
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h
index 78ae542cb6..a5399d5594 100644
--- a/src/lib/libtls/tls_internal.h
+++ b/src/lib/libtls/tls_internal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_internal.h,v 1.17 2015/09/10 09:10:42 jsing Exp $ */ 1/* $OpenBSD: tls_internal.h,v 1.18 2015/09/10 10:14:20 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> 3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
@@ -52,7 +52,7 @@ struct tls_config {
52#define TLS_SERVER (1 << 1) 52#define TLS_SERVER (1 << 1)
53#define TLS_SERVER_CONN (1 << 2) 53#define TLS_SERVER_CONN (1 << 2)
54 54
55#define TLS_STATE_CONNECTING (1 << 0) 55#define TLS_HANDSHAKE_COMPLETE (1 << 0)
56 56
57struct tls { 57struct tls {
58 struct tls_config *config; 58 struct tls_config *config;
@@ -62,6 +62,7 @@ struct tls {
62 char *errmsg; 62 char *errmsg;
63 int errnum; 63 int errnum;
64 64
65 char *servername;
65 int socket; 66 int socket;
66 67
67 SSL *ssl_conn; 68 SSL *ssl_conn;
@@ -76,6 +77,8 @@ int tls_configure_keypair(struct tls *ctx, int);
76int tls_configure_server(struct tls *ctx); 77int tls_configure_server(struct tls *ctx);
77int tls_configure_ssl(struct tls *ctx); 78int tls_configure_ssl(struct tls *ctx);
78int tls_configure_ssl_verify(struct tls *ctx, int verify); 79int tls_configure_ssl_verify(struct tls *ctx, int verify);
80int tls_handshake_client(struct tls *ctx);
81int tls_handshake_server(struct tls *ctx);
79int tls_host_port(const char *hostport, char **host, char **port); 82int tls_host_port(const char *hostport, char **host, char **port);
80int tls_set_error(struct tls *ctx, const char *fmt, ...) 83int tls_set_error(struct tls *ctx, const char *fmt, ...)
81 __attribute__((__format__ (printf, 2, 3))) 84 __attribute__((__format__ (printf, 2, 3)))
diff --git a/src/lib/libtls/tls_server.c b/src/lib/libtls/tls_server.c
index a3cee09596..3dfd29ac19 100644
--- a/src/lib/libtls/tls_server.c
+++ b/src/lib/libtls/tls_server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_server.c,v 1.14 2015/09/10 09:10:42 jsing Exp $ */ 1/* $OpenBSD: tls_server.c,v 1.15 2015/09/10 10:14:20 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -110,54 +110,70 @@ tls_configure_server(struct tls *ctx)
110} 110}
111 111
112int 112int
113tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket)
114{
115 return (tls_accept_fds(ctx, cctx, socket, socket));
116}
117
118int
113tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write) 119tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
114{ 120{
115 struct tls *conn_ctx = *cctx; 121 struct tls *conn_ctx = NULL;
116 int ret, err;
117 122
118 if ((ctx->flags & TLS_SERVER) == 0) { 123 if ((ctx->flags & TLS_SERVER) == 0) {
119 tls_set_errorx(ctx, "not a server context"); 124 tls_set_errorx(ctx, "not a server context");
120 goto err; 125 goto err;
121 } 126 }
122 127
123 if (conn_ctx == NULL) { 128 if ((conn_ctx = tls_server_conn(ctx)) == NULL) {
124 if ((conn_ctx = tls_server_conn(ctx)) == NULL) { 129 tls_set_errorx(ctx, "connection context failure");
125 tls_set_errorx(ctx, "connection context failure"); 130 goto err;
126 goto err;
127 }
128 *cctx = conn_ctx;
129
130 if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
131 tls_set_errorx(ctx, "ssl failure");
132 goto err;
133 }
134 if (SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx) != 1) {
135 tls_set_errorx(ctx, "ssl application data failure");
136 goto err;
137 }
138 if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
139 SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
140 tls_set_errorx(ctx, "ssl file descriptor failure");
141 goto err;
142 }
143 } 131 }
144 132
145 if ((ret = SSL_accept(conn_ctx->ssl_conn)) != 1) { 133 if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
146 err = tls_ssl_error(ctx, conn_ctx->ssl_conn, ret, "accept"); 134 tls_set_errorx(ctx, "ssl failure");
147 if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) { 135 goto err;
148 return (err); 136 }
149 } 137 if (SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx) != 1) {
138 tls_set_errorx(ctx, "ssl application data failure");
139 goto err;
140 }
141 if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
142 SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
143 tls_set_errorx(ctx, "ssl file descriptor failure");
150 goto err; 144 goto err;
151 } 145 }
152 146
147 *cctx = conn_ctx;
148
153 return (0); 149 return (0);
154 150
155 err: 151 err:
152 tls_free(conn_ctx);
153
154 *cctx = NULL;
155
156 return (-1); 156 return (-1);
157} 157}
158 158
159int 159int
160tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket) 160tls_handshake_server(struct tls *ctx)
161{ 161{
162 return (tls_accept_fds(ctx, cctx, socket, socket)); 162 int ssl_ret;
163 int rv = -1;
164
165 if ((ctx->flags & TLS_SERVER_CONN) == 0) {
166 tls_set_errorx(ctx, "not a server connection context");
167 goto err;
168 }
169
170 if ((ssl_ret = SSL_accept(ctx->ssl_conn)) != 1) {
171 rv = tls_ssl_error(ctx, ctx->ssl_conn, ssl_ret, "handshake");
172 goto err;
173 }
174
175 ctx->state |= TLS_HANDSHAKE_COMPLETE;
176
177 err:
178 return (rv);
163} 179}