[gPXE-devel] [Patch] Fix tls handshake handling in gPXE

Stefan Hajnoczi stefanha at gmail.com
Wed Jun 23 15:18:23 EDT 2010


> From dcd0803f05a6c5e933da668d5ff48c7d248d9507 Mon Sep 17 00:00:00 2001
> From: tstack <tstack at tstack-dev2.(none)>

Oops, looks like the author git configuration option hasn't been configured.
Also, please sign off this patch by adding your name/email with a
Signed-off-by: line.

(See http://www.kernel.org/doc/Documentation/SubmittingPatches Section
12 "Sign your work" for details.)

> Date: Tue, 22 Jun 2010 10:22:29 -0700
> Subject: [PATCH] Fix tls handshake handling in gPXE
>
> The handshake record in TLS can contain multiple messages, however,
> gPXE was only expecting one message.  This seems to work fine with
> openssl, but the java ssl code seems to send multiple message blocks
> in a single record.  So, we need to iterate through them.
>
> For reference: http://en.wikipedia.org/wiki/Transport_Layer_Security
> ---
>  src/include/gpxe/tls.h |    7 ++++
>  src/net/tls.c          |   90 ++++++++++++++++++++++++++---------------------
>  2 files changed, 57 insertions(+), 40 deletions(-)
>
> diff --git a/src/include/gpxe/tls.h b/src/include/gpxe/tls.h
> index e2da046..5126bea 100644
> --- a/src/include/gpxe/tls.h
> +++ b/src/include/gpxe/tls.h
> @@ -52,6 +52,13 @@ struct tls_header {
>  /** Application data content type */
>  #define TLS_TYPE_DATA 23
>
> +/** Handshake message type */
> +struct tls_handshake_msg {
> +	uint8_t type;
> +	uint8_t length[3];
> +	uint8_t payload[0];
> +} __attribute__ (( packed ));
> +
>  /* Handshake message types */
>  #define TLS_HELLO_REQUEST 0
>  #define TLS_CLIENT_HELLO 1
> diff --git a/src/net/tls.c b/src/net/tls.c
> index a5b126e..ecc863f 100644
> --- a/src/net/tls.c
> +++ b/src/net/tls.c
> @@ -964,49 +964,59 @@ static int tls_new_finished ( struct tls_session *tls,
>   */
>  static int tls_new_handshake ( struct tls_session *tls,
>  			       void *data, size_t len ) {
> -	struct {
> -		uint8_t type;
> -		uint8_t length[3];
> -		uint8_t payload[0];
> -	} __attribute__ (( packed )) *handshake = data;
> -	void *payload = &handshake->payload;
> -	size_t payload_len = tls_uint24 ( handshake->length );
> -	void *end = ( payload + payload_len );
> -	int rc;
> +	void *data_end = ( data + len );
> +	int rc = 0;
> +
> +	while ( data < data_end ) {
> +		struct tls_handshake_msg *handshake = data;
> +		void *payload = &handshake->payload;
> +		size_t payload_len = tls_uint24 ( handshake->length );
> +
> +		DBGC ( tls, "TLS %p received Handshake %d %p %d\n",
> +		       tls,
> +		       handshake->type,
> +		       payload,
> +		       payload_len );

payload_len is size_t so its format specifier needs to be "%zu" (size_t
unsigned).  A similar issue recently came up and it results in a warning when
building in 64-bit mode.

At this point a sanity check is needed to ensure that payload + payload_len
(user input) is at most data_end.  Otherwise the functions called below would
try to use bogus/malicious payload_len values.

> +		
> +		switch ( handshake->type ) {
> +		case TLS_SERVER_HELLO:
> +			rc = tls_new_server_hello ( tls, payload, payload_len );
> +			break;
> +		case TLS_CERTIFICATE:
> +			rc = tls_new_certificate ( tls, payload, payload_len );
> +			break;
> +		case TLS_SERVER_HELLO_DONE:
> +			rc = tls_new_server_hello_done ( tls, payload, payload_len );
> +			break;
> +		case TLS_FINISHED:
> +			rc = tls_new_finished ( tls, payload, payload_len );
> +			break;
> +		default:
> +			DBGC ( tls, "TLS %p ignoring handshake type %d\n",
> +			       tls, handshake->type );
> +			rc = 0;
> +			break;
> +		}
> +		
> +		/* Add to handshake digest (except for Hello Requests, which
> +		 * are explicitly excluded).
> +		 */
> +		if ( handshake->type != TLS_HELLO_REQUEST )
> +			tls_add_handshake ( tls, data,
> +					    sizeof ( *handshake ) +
> +					    payload_len );
>
> -	/* Sanity check */
> -	if ( end != ( data + len ) ) {
> -		DBGC ( tls, "TLS %p received overlength Handshake\n", tls );
> -		DBGC_HD ( tls, data, len );
> -		return -EINVAL;
> +		data += sizeof ( *handshake ) + payload_len;
>  	}
>
> -	switch ( handshake->type ) {
> -	case TLS_SERVER_HELLO:
> -		rc = tls_new_server_hello ( tls, payload, payload_len );
> -		break;
> -	case TLS_CERTIFICATE:
> -		rc = tls_new_certificate ( tls, payload, payload_len );
> -		break;
> -	case TLS_SERVER_HELLO_DONE:
> -		rc = tls_new_server_hello_done ( tls, payload, payload_len );
> -		break;
> -	case TLS_FINISHED:
> -		rc = tls_new_finished ( tls, payload, payload_len );
> -		break;
> -	default:
> -		DBGC ( tls, "TLS %p ignoring handshake type %d\n",
> -		       tls, handshake->type );
> -		rc = 0;
> -		break;
> +	if ( data != data_end ) {
> +		DBGC ( tls, "TLS %p received overlength Handshake %p %p\n",
> +		       tls,
> +		       data,
> +		       data_end );
> +		DBGC_HD ( tls, data, len );
>  	}

This check is no longer needed here (see comment above).

> -
> -	/* Add to handshake digest (except for Hello Requests, which
> -	 * are explicitly excluded).
> -	 */
> -	if ( handshake->type != TLS_HELLO_REQUEST )
> -		tls_add_handshake ( tls, data, len );
> -
> +	
>  	return rc;
>  }
>
> --
> 1.6.3.3
>

Stefan


More information about the gPXE-devel mailing list