diff options
author | jsing <> | 2015-02-07 04:33:51 +0000 |
---|---|---|
committer | jsing <> | 2015-02-07 04:33:51 +0000 |
commit | be7bacd2cbd3fc2572c636ac04282b2ca64f7272 (patch) | |
tree | c652a4e26e0da1299668d77d878a3043b7d00689 /src | |
parent | 8be6550862be7d914bef6a13291d7b523db088da (diff) | |
download | openbsd-be7bacd2cbd3fc2572c636ac04282b2ca64f7272.tar.gz openbsd-be7bacd2cbd3fc2572c636ac04282b2ca64f7272.tar.bz2 openbsd-be7bacd2cbd3fc2572c636ac04282b2ca64f7272.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 'src')
-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 |