diff options
| author | jsing <> | 2015-02-07 04:33:51 +0000 |
|---|---|---|
| committer | jsing <> | 2015-02-07 04:33:51 +0000 |
| commit | e7d2eaafd57f353d8d6754ac5f5253f1eada3342 (patch) | |
| tree | c652a4e26e0da1299668d77d878a3043b7d00689 /src/lib/libtls/tls.c | |
| parent | 5b4d499cb662ae06634b9b393174cb3f6233ac02 (diff) | |
| download | openbsd-e7d2eaafd57f353d8d6754ac5f5253f1eada3342.tar.gz openbsd-e7d2eaafd57f353d8d6754ac5f5253f1eada3342.tar.bz2 openbsd-e7d2eaafd57f353d8d6754ac5f5253f1eada3342.zip | |
Attempt to implement the OpenSSL error dance so that TLS read/write
failures return something that is actually useful to the caller.
ok reyk@
Diffstat (limited to '')
| -rw-r--r-- | src/lib/libtls/tls.c | 90 |
1 files changed, 61 insertions, 29 deletions
diff --git a/src/lib/libtls/tls.c b/src/lib/libtls/tls.c index 2ca5336260..696c35b459 100644 --- a/src/lib/libtls/tls.c +++ b/src/lib/libtls/tls.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: tls.c,v 1.5 2015/02/06 01:37:11 reyk Exp $ */ | 1 | /* $OpenBSD: tls.c,v 1.6 2015/02/07 04:33:51 jsing Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
| 4 | * | 4 | * |
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <unistd.h> | 23 | #include <unistd.h> |
| 24 | 24 | ||
| 25 | #include <openssl/bio.h> | 25 | #include <openssl/bio.h> |
| 26 | #include <openssl/err.h> | ||
| 26 | #include <openssl/evp.h> | 27 | #include <openssl/evp.h> |
| 27 | #include <openssl/pem.h> | 28 | #include <openssl/pem.h> |
| 28 | #include <openssl/x509.h> | 29 | #include <openssl/x509.h> |
| @@ -235,60 +236,91 @@ tls_reset(struct tls *ctx) | |||
| 235 | ctx->errmsg = NULL; | 236 | ctx->errmsg = NULL; |
| 236 | } | 237 | } |
| 237 | 238 | ||
| 238 | int | 239 | static int |
| 239 | tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen) | 240 | tls_ssl_error(struct tls *ctx, int ssl_ret, const char *prefix) |
| 240 | { | 241 | { |
| 241 | int ret, ssl_err; | 242 | const char *errstr = "unknown error"; |
| 242 | 243 | unsigned long err; | |
| 243 | if (buflen > INT_MAX) { | 244 | int ssl_err; |
| 244 | tls_set_error(ctx, "buflen too long"); | ||
| 245 | return (-1); | ||
| 246 | } | ||
| 247 | 245 | ||
| 248 | ret = SSL_read(ctx->ssl_conn, buf, buflen); | 246 | ssl_err = SSL_get_error(ctx->ssl_conn, ssl_ret); |
| 249 | if (ret > 0) { | 247 | switch (ssl_err) { |
| 250 | *outlen = (size_t)ret; | 248 | case SSL_ERROR_NONE: |
| 251 | return (0); | 249 | return (0); |
| 252 | } | ||
| 253 | 250 | ||
| 254 | ssl_err = SSL_get_error(ctx->ssl_conn, ret); | 251 | case SSL_ERROR_ZERO_RETURN: |
| 255 | switch (ssl_err) { | 252 | tls_set_error(ctx, "%s failed: TLS connection closed", prefix); |
| 253 | return (-1); | ||
| 254 | |||
| 256 | case SSL_ERROR_WANT_READ: | 255 | case SSL_ERROR_WANT_READ: |
| 257 | return (TLS_READ_AGAIN); | 256 | return (TLS_READ_AGAIN); |
| 257 | |||
| 258 | case SSL_ERROR_WANT_WRITE: | 258 | case SSL_ERROR_WANT_WRITE: |
| 259 | return (TLS_WRITE_AGAIN); | 259 | return (TLS_WRITE_AGAIN); |
| 260 | |||
| 261 | case SSL_ERROR_SYSCALL: | ||
| 262 | if ((err = ERR_peek_error()) != 0) { | ||
| 263 | errstr = ERR_error_string(err, NULL); | ||
| 264 | } else if (ssl_ret == 0) { | ||
| 265 | errstr = "EOF"; | ||
| 266 | } else if (ssl_ret == -1) { | ||
| 267 | errstr = strerror(errno); | ||
| 268 | } | ||
| 269 | tls_set_error(ctx, "%s failed: %s", prefix, errstr); | ||
| 270 | return (-1); | ||
| 271 | |||
| 272 | case SSL_ERROR_SSL: | ||
| 273 | if ((err = ERR_peek_error()) != 0) { | ||
| 274 | errstr = ERR_error_string(err, NULL); | ||
| 275 | } | ||
| 276 | tls_set_error(ctx, "%s failed: %s", prefix, errstr); | ||
| 277 | return (-1); | ||
| 278 | |||
| 279 | case SSL_ERROR_WANT_CONNECT: | ||
| 280 | case SSL_ERROR_WANT_ACCEPT: | ||
| 281 | case SSL_ERROR_WANT_X509_LOOKUP: | ||
| 260 | default: | 282 | default: |
| 261 | tls_set_error(ctx, "read failed (%i)", ssl_err); | 283 | tls_set_error(ctx, "%s failed (%i)", prefix, ssl_err); |
| 262 | return (-1); | 284 | return (-1); |
| 263 | } | 285 | } |
| 264 | } | 286 | } |
| 265 | 287 | ||
| 266 | int | 288 | int |
| 267 | tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen) | 289 | tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen) |
| 268 | { | 290 | { |
| 269 | int ret, ssl_err; | 291 | int ssl_ret; |
| 270 | 292 | ||
| 271 | if (buflen > INT_MAX) { | 293 | if (buflen > INT_MAX) { |
| 272 | tls_set_error(ctx, "buflen too long"); | 294 | tls_set_error(ctx, "buflen too long"); |
| 273 | return (-1); | 295 | return (-1); |
| 274 | } | 296 | } |
| 275 | 297 | ||
| 276 | ret = SSL_write(ctx->ssl_conn, buf, buflen); | 298 | ssl_ret = SSL_read(ctx->ssl_conn, buf, buflen); |
| 277 | if (ret > 0) { | 299 | if (ssl_ret > 0) { |
| 278 | *outlen = (size_t)ret; | 300 | *outlen = (size_t)ssl_ret; |
| 279 | return (0); | 301 | return (0); |
| 280 | } | 302 | } |
| 281 | 303 | ||
| 282 | ssl_err = SSL_get_error(ctx->ssl_conn, ret); | 304 | return tls_ssl_error(ctx, ssl_ret, "read"); |
| 283 | switch (ssl_err) { | 305 | } |
| 284 | case SSL_ERROR_WANT_READ: | 306 | |
| 285 | return (TLS_READ_AGAIN); | 307 | int |
| 286 | case SSL_ERROR_WANT_WRITE: | 308 | tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen) |
| 287 | return (TLS_WRITE_AGAIN); | 309 | { |
| 288 | default: | 310 | int ssl_ret; |
| 289 | tls_set_error(ctx, "write failed (%i)", ssl_err); | 311 | |
| 312 | if (buflen > INT_MAX) { | ||
| 313 | tls_set_error(ctx, "buflen too long"); | ||
| 290 | return (-1); | 314 | return (-1); |
| 291 | } | 315 | } |
| 316 | |||
| 317 | ssl_ret = SSL_write(ctx->ssl_conn, buf, buflen); | ||
| 318 | if (ssl_ret > 0) { | ||
| 319 | *outlen = (size_t)ssl_ret; | ||
| 320 | return (0); | ||
| 321 | } | ||
| 322 | |||
| 323 | return tls_ssl_error(ctx, ssl_ret, "write"); | ||
| 292 | } | 324 | } |
| 293 | 325 | ||
| 294 | int | 326 | int |
