Added ssl_handshake_step() to allow single stepping the handshake

process

Single stepping the handshake process allows for better support of
non-blocking network stacks and for getting information from specific
handshake messages if wanted.
This commit is contained in:
Paul Bakker 2013-01-25 14:49:24 +01:00
parent 9c94cddeae
commit 1961b709d8
5 changed files with 222 additions and 203 deletions

View File

@ -1,6 +1,9 @@
PolarSSL ChangeLog PolarSSL ChangeLog
= Version Master = Version Master
Changes
* Added ssl_handshake_step() to allow single stepping the handshake process
Bugfix Bugfix
* Memory leak when using RSA_PKCS_V21 operations fixed * Memory leak when using RSA_PKCS_V21 operations fixed
* Handle future version properly in ssl_write_certificate_request() * Handle future version properly in ssl_write_certificate_request()

View File

@ -970,6 +970,20 @@ const x509_cert *ssl_get_peer_cert( const ssl_context *ssl );
*/ */
int ssl_handshake( ssl_context *ssl ); int ssl_handshake( ssl_context *ssl );
/**
* \brief Perform a single step of the SSL handshake
*
* Note: the state of the context (ssl->state) will be at
* the following state after execution of this function.
* Do not call this function if state is SSL_HANDSHAKE_OVER.
*
* \param ssl SSL context
*
* \return 0 if successful, POLARSSL_ERR_NET_WANT_READ,
* POLARSSL_ERR_NET_WANT_WRITE, or a specific SSL error code.
*/
int ssl_handshake_step( ssl_context *ssl );
/** /**
* \brief Perform an SSL renegotiation on the running connection * \brief Perform an SSL renegotiation on the running connection
* *
@ -1061,8 +1075,8 @@ void ssl_handshake_free( ssl_handshake_params *handshake );
/* /*
* Internal functions (do not call directly) * Internal functions (do not call directly)
*/ */
int ssl_handshake_client( ssl_context *ssl ); int ssl_handshake_client_step( ssl_context *ssl );
int ssl_handshake_server( ssl_context *ssl ); int ssl_handshake_server_step( ssl_context *ssl );
void ssl_handshake_wrapup( ssl_context *ssl ); void ssl_handshake_wrapup( ssl_context *ssl );
int ssl_send_fatal_handshake_failure( ssl_context *ssl ); int ssl_send_fatal_handshake_failure( ssl_context *ssl );

View File

@ -1274,121 +1274,113 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
} }
/* /*
* SSL handshake -- client side * SSL handshake -- client side -- single step
*/ */
int ssl_handshake_client( ssl_context *ssl ) int ssl_handshake_client_step( ssl_context *ssl )
{ {
int ret = 0; int ret = 0;
SSL_DEBUG_MSG( 2, ( "=> handshake client" ) ); if( ssl->state == SSL_HANDSHAKE_OVER )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
while( ssl->state != SSL_HANDSHAKE_OVER ) SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );
if( ( ret = ssl_flush_output( ssl ) ) != 0 )
return( ret );
switch( ssl->state )
{ {
SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); case SSL_HELLO_REQUEST:
ssl->state = SSL_CLIENT_HELLO;
if( ( ret = ssl_flush_output( ssl ) ) != 0 )
break; break;
switch( ssl->state ) /*
{ * ==> ClientHello
case SSL_HELLO_REQUEST: */
ssl->state = SSL_CLIENT_HELLO; case SSL_CLIENT_HELLO:
break; ret = ssl_write_client_hello( ssl );
break;
/* /*
* ==> ClientHello * <== ServerHello
*/ * Certificate
case SSL_CLIENT_HELLO: * ( ServerKeyExchange )
ret = ssl_write_client_hello( ssl ); * ( CertificateRequest )
break; * ServerHelloDone
*/
case SSL_SERVER_HELLO:
ret = ssl_parse_server_hello( ssl );
break;
/* case SSL_SERVER_CERTIFICATE:
* <== ServerHello ret = ssl_parse_certificate( ssl );
* Certificate break;
* ( ServerKeyExchange )
* ( CertificateRequest )
* ServerHelloDone
*/
case SSL_SERVER_HELLO:
ret = ssl_parse_server_hello( ssl );
break;
case SSL_SERVER_CERTIFICATE: case SSL_SERVER_KEY_EXCHANGE:
ret = ssl_parse_certificate( ssl ); ret = ssl_parse_server_key_exchange( ssl );
break; break;
case SSL_SERVER_KEY_EXCHANGE: case SSL_CERTIFICATE_REQUEST:
ret = ssl_parse_server_key_exchange( ssl ); ret = ssl_parse_certificate_request( ssl );
break; break;
case SSL_CERTIFICATE_REQUEST: case SSL_SERVER_HELLO_DONE:
ret = ssl_parse_certificate_request( ssl ); ret = ssl_parse_server_hello_done( ssl );
break; break;
case SSL_SERVER_HELLO_DONE: /*
ret = ssl_parse_server_hello_done( ssl ); * ==> ( Certificate/Alert )
break; * ClientKeyExchange
* ( CertificateVerify )
* ChangeCipherSpec
* Finished
*/
case SSL_CLIENT_CERTIFICATE:
ret = ssl_write_certificate( ssl );
break;
/* case SSL_CLIENT_KEY_EXCHANGE:
* ==> ( Certificate/Alert ) ret = ssl_write_client_key_exchange( ssl );
* ClientKeyExchange break;
* ( CertificateVerify )
* ChangeCipherSpec
* Finished
*/
case SSL_CLIENT_CERTIFICATE:
ret = ssl_write_certificate( ssl );
break;
case SSL_CLIENT_KEY_EXCHANGE: case SSL_CERTIFICATE_VERIFY:
ret = ssl_write_client_key_exchange( ssl ); ret = ssl_write_certificate_verify( ssl );
break; break;
case SSL_CERTIFICATE_VERIFY: case SSL_CLIENT_CHANGE_CIPHER_SPEC:
ret = ssl_write_certificate_verify( ssl ); ret = ssl_write_change_cipher_spec( ssl );
break; break;
case SSL_CLIENT_CHANGE_CIPHER_SPEC: case SSL_CLIENT_FINISHED:
ret = ssl_write_change_cipher_spec( ssl ); ret = ssl_write_finished( ssl );
break; break;
case SSL_CLIENT_FINISHED: /*
ret = ssl_write_finished( ssl ); * <== ChangeCipherSpec
break; * Finished
*/
case SSL_SERVER_CHANGE_CIPHER_SPEC:
ret = ssl_parse_change_cipher_spec( ssl );
break;
/* case SSL_SERVER_FINISHED:
* <== ChangeCipherSpec ret = ssl_parse_finished( ssl );
* Finished break;
*/
case SSL_SERVER_CHANGE_CIPHER_SPEC:
ret = ssl_parse_change_cipher_spec( ssl );
break;
case SSL_SERVER_FINISHED: case SSL_FLUSH_BUFFERS:
ret = ssl_parse_finished( ssl ); SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
break; ssl->state = SSL_HANDSHAKE_WRAPUP;
break;
case SSL_FLUSH_BUFFERS: case SSL_HANDSHAKE_WRAPUP:
SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); ssl_handshake_wrapup( ssl );
ssl->state = SSL_HANDSHAKE_WRAPUP; break;
break;
case SSL_HANDSHAKE_WRAPUP: default:
ssl_handshake_wrapup( ssl ); SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
break; return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
}
default:
SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
}
if( ret != 0 )
break;
}
SSL_DEBUG_MSG( 2, ( "<= handshake client" ) );
return( ret ); return( ret );
} }
#endif #endif

View File

@ -1293,121 +1293,113 @@ static int ssl_parse_certificate_verify( ssl_context *ssl )
} }
/* /*
* SSL handshake -- server side * SSL handshake -- server side -- single step
*/ */
int ssl_handshake_server( ssl_context *ssl ) int ssl_handshake_server_step( ssl_context *ssl )
{ {
int ret = 0; int ret = 0;
SSL_DEBUG_MSG( 2, ( "=> handshake server" ) ); if( ssl->state == SSL_HANDSHAKE_OVER )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
while( ssl->state != SSL_HANDSHAKE_OVER ) SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) );
if( ( ret = ssl_flush_output( ssl ) ) != 0 )
return( ret );
switch( ssl->state )
{ {
SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); case SSL_HELLO_REQUEST:
ssl->state = SSL_CLIENT_HELLO;
if( ( ret = ssl_flush_output( ssl ) ) != 0 )
break; break;
switch( ssl->state ) /*
{ * <== ClientHello
case SSL_HELLO_REQUEST: */
ssl->state = SSL_CLIENT_HELLO; case SSL_CLIENT_HELLO:
break; ret = ssl_parse_client_hello( ssl );
/*
* <== ClientHello
*/
case SSL_CLIENT_HELLO:
ret = ssl_parse_client_hello( ssl );
break;
/*
* ==> ServerHello
* Certificate
* ( ServerKeyExchange )
* ( CertificateRequest )
* ServerHelloDone
*/
case SSL_SERVER_HELLO:
ret = ssl_write_server_hello( ssl );
break;
case SSL_SERVER_CERTIFICATE:
ret = ssl_write_certificate( ssl );
break;
case SSL_SERVER_KEY_EXCHANGE:
ret = ssl_write_server_key_exchange( ssl );
break;
case SSL_CERTIFICATE_REQUEST:
ret = ssl_write_certificate_request( ssl );
break;
case SSL_SERVER_HELLO_DONE:
ret = ssl_write_server_hello_done( ssl );
break;
/*
* <== ( Certificate/Alert )
* ClientKeyExchange
* ( CertificateVerify )
* ChangeCipherSpec
* Finished
*/
case SSL_CLIENT_CERTIFICATE:
ret = ssl_parse_certificate( ssl );
break;
case SSL_CLIENT_KEY_EXCHANGE:
ret = ssl_parse_client_key_exchange( ssl );
break;
case SSL_CERTIFICATE_VERIFY:
ret = ssl_parse_certificate_verify( ssl );
break;
case SSL_CLIENT_CHANGE_CIPHER_SPEC:
ret = ssl_parse_change_cipher_spec( ssl );
break;
case SSL_CLIENT_FINISHED:
ret = ssl_parse_finished( ssl );
break;
/*
* ==> ChangeCipherSpec
* Finished
*/
case SSL_SERVER_CHANGE_CIPHER_SPEC:
ret = ssl_write_change_cipher_spec( ssl );
break;
case SSL_SERVER_FINISHED:
ret = ssl_write_finished( ssl );
break;
case SSL_FLUSH_BUFFERS:
SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
ssl->state = SSL_HANDSHAKE_WRAPUP;
break;
case SSL_HANDSHAKE_WRAPUP:
ssl_handshake_wrapup( ssl );
break;
default:
SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
}
if( ret != 0 )
break; break;
/*
* ==> ServerHello
* Certificate
* ( ServerKeyExchange )
* ( CertificateRequest )
* ServerHelloDone
*/
case SSL_SERVER_HELLO:
ret = ssl_write_server_hello( ssl );
break;
case SSL_SERVER_CERTIFICATE:
ret = ssl_write_certificate( ssl );
break;
case SSL_SERVER_KEY_EXCHANGE:
ret = ssl_write_server_key_exchange( ssl );
break;
case SSL_CERTIFICATE_REQUEST:
ret = ssl_write_certificate_request( ssl );
break;
case SSL_SERVER_HELLO_DONE:
ret = ssl_write_server_hello_done( ssl );
break;
/*
* <== ( Certificate/Alert )
* ClientKeyExchange
* ( CertificateVerify )
* ChangeCipherSpec
* Finished
*/
case SSL_CLIENT_CERTIFICATE:
ret = ssl_parse_certificate( ssl );
break;
case SSL_CLIENT_KEY_EXCHANGE:
ret = ssl_parse_client_key_exchange( ssl );
break;
case SSL_CERTIFICATE_VERIFY:
ret = ssl_parse_certificate_verify( ssl );
break;
case SSL_CLIENT_CHANGE_CIPHER_SPEC:
ret = ssl_parse_change_cipher_spec( ssl );
break;
case SSL_CLIENT_FINISHED:
ret = ssl_parse_finished( ssl );
break;
/*
* ==> ChangeCipherSpec
* Finished
*/
case SSL_SERVER_CHANGE_CIPHER_SPEC:
ret = ssl_write_change_cipher_spec( ssl );
break;
case SSL_SERVER_FINISHED:
ret = ssl_write_finished( ssl );
break;
case SSL_FLUSH_BUFFERS:
SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
ssl->state = SSL_HANDSHAKE_WRAPUP;
break;
case SSL_HANDSHAKE_WRAPUP:
ssl_handshake_wrapup( ssl );
break;
default:
SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
} }
SSL_DEBUG_MSG( 2, ( "<= handshake server" ) );
return( ret ); return( ret );
} }
#endif #endif

View File

@ -3513,24 +3513,42 @@ const int ssl_default_ciphersuites[] =
}; };
/* /*
* Perform the SSL handshake * Perform a single step of the SSL handshake
*/ */
int ssl_handshake( ssl_context *ssl ) int ssl_handshake_step( ssl_context *ssl )
{ {
int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE; int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
SSL_DEBUG_MSG( 2, ( "=> handshake" ) );
#if defined(POLARSSL_SSL_CLI_C) #if defined(POLARSSL_SSL_CLI_C)
if( ssl->endpoint == SSL_IS_CLIENT ) if( ssl->endpoint == SSL_IS_CLIENT )
ret = ssl_handshake_client( ssl ); ret = ssl_handshake_client_step( ssl );
#endif #endif
#if defined(POLARSSL_SSL_SRV_C) #if defined(POLARSSL_SSL_SRV_C)
if( ssl->endpoint == SSL_IS_SERVER ) if( ssl->endpoint == SSL_IS_SERVER )
ret = ssl_handshake_server( ssl ); ret = ssl_handshake_server_step( ssl );
#endif #endif
return( ret );
}
/*
* Perform the SSL handshake
*/
int ssl_handshake( ssl_context *ssl )
{
int ret = 0;
SSL_DEBUG_MSG( 2, ( "=> handshake" ) );
while( ssl->state != SSL_HANDSHAKE_OVER )
{
ret = ssl_handshake_step( ssl );
if( ret != 0 )
break;
}
SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); SSL_DEBUG_MSG( 2, ( "<= handshake" ) );
return( ret ); return( ret );