From e22c01e212d75c296dee28c5dc09561128d4761a Mon Sep 17 00:00:00 2001 From: Jim Hague Date: Thu, 15 Nov 2018 14:28:04 +0000 Subject: [PATCH] tls_do_handshake: move handshake and check for new session into abstraction layer. --- src/openssl/tls.c | 38 ++++++++++++++++++++++++++++++++++++++ src/openssl/tls.h | 27 +++++++++++++++++++++++++++ src/stub.c | 15 ++++++--------- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/openssl/tls.c b/src/openssl/tls.c index c0e6338c..0e0e0f93 100644 --- a/src/openssl/tls.c +++ b/src/openssl/tls.c @@ -33,6 +33,7 @@ #include "config.h" +#include #include #include #include @@ -342,6 +343,43 @@ _getdns_tls_session* _getdns_tls_connection_get_session(_getdns_tls_connection* return res; } +getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn) +{ + int r; + int err; + + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + ERR_clear_error(); + r = SSL_do_handshake(conn->ssl); + if (r == 1) + return GETDNS_RETURN_GOOD; + err = SSL_get_error(conn->ssl, r); + switch(err) + { + case SSL_ERROR_WANT_READ: + return GETDNS_RETURN_TLS_WANT_READ; + + case SSL_ERROR_WANT_WRITE: + return GETDNS_RETURN_TLS_WANT_WRITE; + + default: + return GETDNS_RETURN_GENERIC_ERROR; + } +} + +getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (SSL_session_reused(conn->ssl)) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_TLS_CONNECTION_FRESH; +} + getdns_return_t _getdns_tls_session_free(_getdns_tls_session* s) { if (!s || !s->ssl) diff --git a/src/openssl/tls.h b/src/openssl/tls.h index 53430653..6dfc503d 100644 --- a/src/openssl/tls.h +++ b/src/openssl/tls.h @@ -47,6 +47,11 @@ #define HAVE_TLS_CONN_CURVES_LIST (HAVE_DECL_SSL_SET1_CURVES_LIST) #endif +/* Additional return codes required by TLS abstraction. Internal use only. */ +#define GETDNS_RETURN_TLS_WANT_READ ((getdns_return_t) 420) +#define GETDNS_RETURN_TLS_WANT_WRITE ((getdns_return_t) 421) +#define GETDNS_RETURN_TLS_CONNECTION_FRESH ((getdns_return_t) 422) + typedef struct _getdns_tls_context { SSL_CTX* ssl; } _getdns_tls_context; @@ -78,6 +83,28 @@ getdns_return_t _getdns_tls_connection_set_curves_list(_getdns_tls_connection* c getdns_return_t _getdns_tls_connection_set_session(_getdns_tls_connection* conn, _getdns_tls_session* s); _getdns_tls_session* _getdns_tls_connection_get_session(_getdns_tls_connection* conn); +/** + * Attempt TLS handshake. + * + * @param conn the connection. + * @return GETDNS_RETURN_GOOD if handshake is complete. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_WANT_READ if handshake needs to read to proceed. + * @return GETDNS_RETURN_TLS_WANT_WRITE if handshake needs to write to proceed. + * @return GETDNS_RETURN_GENERIC_ERROR if handshake failed. + */ +getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn); + +/** + * See whether the connection is reusing a session. + * + * @param conn the connection. + * @return GETDNS_RETURN_GOOD if connection is being reused. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_CONNECTION_FRESH if connection is not being reused. + */ +getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn); + getdns_return_t _getdns_tls_session_free(_getdns_tls_session* s); getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict); diff --git a/src/stub.c b/src/stub.c index 16b49060..3acbb2ea 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1093,13 +1093,10 @@ tls_do_handshake(getdns_upstream *upstream) DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); int r; - int want; - ERR_clear_error(); - while ((r = SSL_do_handshake(upstream->tls_obj->ssl)) != 1) + while ((r = _getdns_tls_connection_do_handshake(upstream->tls_obj)) != GETDNS_RETURN_GOOD) { - want = SSL_get_error(upstream->tls_obj->ssl, r); - switch (want) { - case SSL_ERROR_WANT_READ: + switch (r) { + case GETDNS_RETURN_TLS_WANT_READ: GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = upstream_read_cb; upstream->event.write_cb = NULL; @@ -1107,7 +1104,7 @@ tls_do_handshake(getdns_upstream *upstream) upstream->fd, TIMEOUT_TLS, &upstream->event); upstream->tls_hs_state = GETDNS_HS_READ; return STUB_TCP_RETRY; - case SSL_ERROR_WANT_WRITE: + case GETDNS_RETURN_TLS_WANT_WRITE: GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = NULL; upstream->event.write_cb = upstream_write_cb; @@ -1123,7 +1120,7 @@ tls_do_handshake(getdns_upstream *upstream) } } /* A re-used session is not verified so need to fix up state in that case */ - if (SSL_session_reused(upstream->tls_obj->ssl)) + if (!_getdns_tls_connection_is_session_reused(upstream->tls_obj)) upstream->tls_auth_state = upstream->last_tls_auth_state; else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) { @@ -1232,7 +1229,7 @@ tls_do_handshake(getdns_upstream *upstream) DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded with auth state %s. Session is %s.\n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, _getdns_auth_str(upstream->tls_auth_state), - SSL_session_reused(upstream->tls_obj) ?"re-used":"new"); + _getdns_tls_connection_is_session_reused(upstream->tls_obj) ? "new" : "re-used"); upstream->tls_hs_state = GETDNS_HS_DONE; upstream->conn_state = GETDNS_CONN_OPEN; upstream->conn_completed++;