tls_do_handshake: move handshake and check for new session into abstraction layer.

This commit is contained in:
Jim Hague 2018-11-15 14:28:04 +00:00
parent ffd1136e94
commit e22c01e212
3 changed files with 71 additions and 9 deletions

View File

@ -33,6 +33,7 @@
#include "config.h" #include "config.h"
#include <openssl/err.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/bio.h> #include <openssl/bio.h>
@ -342,6 +343,43 @@ _getdns_tls_session* _getdns_tls_connection_get_session(_getdns_tls_connection*
return res; 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) getdns_return_t _getdns_tls_session_free(_getdns_tls_session* s)
{ {
if (!s || !s->ssl) if (!s || !s->ssl)

View File

@ -47,6 +47,11 @@
#define HAVE_TLS_CONN_CURVES_LIST (HAVE_DECL_SSL_SET1_CURVES_LIST) #define HAVE_TLS_CONN_CURVES_LIST (HAVE_DECL_SSL_SET1_CURVES_LIST)
#endif #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 { typedef struct _getdns_tls_context {
SSL_CTX* ssl; SSL_CTX* ssl;
} _getdns_tls_context; } _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_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); _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_session_free(_getdns_tls_session* s);
getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict); getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict);

View File

@ -1093,13 +1093,10 @@ tls_do_handshake(getdns_upstream *upstream)
DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SETUP_TLS, DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SETUP_TLS,
__FUNC__, upstream->fd); __FUNC__, upstream->fd);
int r; int r;
int want; while ((r = _getdns_tls_connection_do_handshake(upstream->tls_obj)) != GETDNS_RETURN_GOOD)
ERR_clear_error();
while ((r = SSL_do_handshake(upstream->tls_obj->ssl)) != 1)
{ {
want = SSL_get_error(upstream->tls_obj->ssl, r); switch (r) {
switch (want) { case GETDNS_RETURN_TLS_WANT_READ:
case SSL_ERROR_WANT_READ:
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
upstream->event.read_cb = upstream_read_cb; upstream->event.read_cb = upstream_read_cb;
upstream->event.write_cb = NULL; upstream->event.write_cb = NULL;
@ -1107,7 +1104,7 @@ tls_do_handshake(getdns_upstream *upstream)
upstream->fd, TIMEOUT_TLS, &upstream->event); upstream->fd, TIMEOUT_TLS, &upstream->event);
upstream->tls_hs_state = GETDNS_HS_READ; upstream->tls_hs_state = GETDNS_HS_READ;
return STUB_TCP_RETRY; return STUB_TCP_RETRY;
case SSL_ERROR_WANT_WRITE: case GETDNS_RETURN_TLS_WANT_WRITE:
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
upstream->event.read_cb = NULL; upstream->event.read_cb = NULL;
upstream->event.write_cb = upstream_write_cb; 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 */ /* 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; upstream->tls_auth_state = upstream->last_tls_auth_state;
else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) { 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", DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded with auth state %s. Session is %s.\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd,
_getdns_auth_str(upstream->tls_auth_state), _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->tls_hs_state = GETDNS_HS_DONE;
upstream->conn_state = GETDNS_CONN_OPEN; upstream->conn_state = GETDNS_CONN_OPEN;
upstream->conn_completed++; upstream->conn_completed++;