diff options
| author | jsing <> | 2015-09-10 10:14:21 +0000 |
|---|---|---|
| committer | jsing <> | 2015-09-10 10:14:21 +0000 |
| commit | 801db6d0104e7b66f26bfc8d07ecb98601abc7ee (patch) | |
| tree | b1c4283700879b3793a5395cbab5ffd49e03f34f /src/lib/libtls/tls_client.c | |
| parent | 0dc5f09cfe416c2447e33a7ef2cbed7570956a15 (diff) | |
| download | openbsd-801db6d0104e7b66f26bfc8d07ecb98601abc7ee.tar.gz openbsd-801db6d0104e7b66f26bfc8d07ecb98601abc7ee.tar.bz2 openbsd-801db6d0104e7b66f26bfc8d07ecb98601abc7ee.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 '')
| -rw-r--r-- | src/lib/libtls/tls_client.c | 58 |
1 files changed, 37 insertions, 21 deletions
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 | } | 242 | int |
| 243 | tls_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 | } |
