Merge branch 'session_tickets' into development

This commit is contained in:
Paul Bakker 2013-08-14 14:27:12 +02:00
commit 5994adc749
10 changed files with 1003 additions and 31 deletions

View file

@ -17,6 +17,7 @@ Features
* Support for truncated_hmac extension (RFC 6066) * Support for truncated_hmac extension (RFC 6066)
* Support for zeros-and-length (ANSI X.923) padding, one-and-zeros * Support for zeros-and-length (ANSI X.923) padding, one-and-zeros
(ISO/IEC 7816-4) padding and zero padding in the cipher layer (ISO/IEC 7816-4) padding and zero padding in the cipher layer
* Support for session tickets (RFC 5077)
Changes Changes
* Introduced separate SSL Ciphersuites module that is based on * Introduced separate SSL Ciphersuites module that is based on

View file

@ -528,6 +528,18 @@
*/ */
#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO #define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
/**
* \def POLARSSL_SSL_SESSION_TICKETS
*
* Enable support for RFC 5077 session tickets in SSL
*
* Requires: POLARSSL_AES_C
* POLARSSL_SHA256_C
*
* Comment this macro to disable support for SSL session tickets
*/
#define POLARSSL_SSL_SESSION_TICKETS
/** /**
* \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
* *

View file

@ -84,7 +84,7 @@
* ECP 4 4 (Started from top) * ECP 4 4 (Started from top)
* MD 5 4 * MD 5 4
* CIPHER 6 5 * CIPHER 6 5
* SSL 6 2 (Started from top) * SSL 6 4 (Started from top)
* SSL 7 31 * SSL 7 31
* *
* Module dependent error code (5 bits 0x.08.-0x.F8.) * Module dependent error code (5 bits 0x.08.-0x.F8.)

View file

@ -35,6 +35,7 @@
#include "sha1.h" #include "sha1.h"
#include "sha256.h" #include "sha256.h"
#include "sha512.h" #include "sha512.h"
#include "aes.h"
#include "ssl_ciphersuites.h" #include "ssl_ciphersuites.h"
@ -107,6 +108,8 @@
#define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */ #define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */
#define POLARSSL_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */ #define POLARSSL_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */
#define POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80 /**< Handshake protocol not within min/max boundaries */ #define POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80 /**< Handshake protocol not within min/max boundaries */
#define POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET -0x6E00 /**< Processing of the NewSessionTicket handshake message failed. */
/* /*
* Various constants * Various constants
@ -152,6 +155,9 @@
#define SSL_TRUNC_HMAC_ENABLED 1 #define SSL_TRUNC_HMAC_ENABLED 1
#define SSL_TRUNCATED_HMAC_LEN 10 /* 80 bits, rfc 6066 section 7 */ #define SSL_TRUNCATED_HMAC_LEN 10 /* 80 bits, rfc 6066 section 7 */
#define SSL_SESSION_TICKETS_DISABLED 0
#define SSL_SESSION_TICKETS_ENABLED 1
/* /*
* Size of the input / output buffer. * Size of the input / output buffer.
* Note: the RFC defines the default size of SSL / TLS messages. If you * Note: the RFC defines the default size of SSL / TLS messages. If you
@ -239,6 +245,7 @@
#define SSL_HS_HELLO_REQUEST 0 #define SSL_HS_HELLO_REQUEST 0
#define SSL_HS_CLIENT_HELLO 1 #define SSL_HS_CLIENT_HELLO 1
#define SSL_HS_SERVER_HELLO 2 #define SSL_HS_SERVER_HELLO 2
#define SSL_HS_NEW_SESSION_TICKET 4
#define SSL_HS_CERTIFICATE 11 #define SSL_HS_CERTIFICATE 11
#define SSL_HS_SERVER_KEY_EXCHANGE 12 #define SSL_HS_SERVER_KEY_EXCHANGE 12
#define SSL_HS_CERTIFICATE_REQUEST 13 #define SSL_HS_CERTIFICATE_REQUEST 13
@ -262,6 +269,8 @@
#define TLS_EXT_SIG_ALG 13 #define TLS_EXT_SIG_ALG 13
#define TLS_EXT_SESSION_TICKET 35
#define TLS_EXT_RENEGOTIATION_INFO 0xFF01 #define TLS_EXT_RENEGOTIATION_INFO 0xFF01
/* /*
@ -311,7 +320,8 @@ typedef enum
SSL_SERVER_FINISHED, SSL_SERVER_FINISHED,
SSL_FLUSH_BUFFERS, SSL_FLUSH_BUFFERS,
SSL_HANDSHAKE_WRAPUP, SSL_HANDSHAKE_WRAPUP,
SSL_HANDSHAKE_OVER SSL_HANDSHAKE_OVER,
SSL_SERVER_NEW_SESSION_TICKET,
} }
ssl_states; ssl_states;
@ -319,6 +329,9 @@ typedef struct _ssl_session ssl_session;
typedef struct _ssl_context ssl_context; typedef struct _ssl_context ssl_context;
typedef struct _ssl_transform ssl_transform; typedef struct _ssl_transform ssl_transform;
typedef struct _ssl_handshake_params ssl_handshake_params; typedef struct _ssl_handshake_params ssl_handshake_params;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
typedef struct _ssl_ticket_keys ssl_ticket_keys;
#endif
/* /*
* This structure is used for storing current session data. * This structure is used for storing current session data.
@ -338,6 +351,12 @@ struct _ssl_session
x509_cert *peer_cert; /*!< peer X.509 cert chain */ x509_cert *peer_cert; /*!< peer X.509 cert chain */
#endif /* POLARSSL_X509_PARSE_C */ #endif /* POLARSSL_X509_PARSE_C */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
unsigned char *ticket; /*!< RFC 5077 session ticket */
size_t ticket_len; /*!< session ticket length */
uint32_t ticket_lifetime; /*!< ticket lifetime hint */
#endif /* POLARSSL_SSL_SESSION_TICKETS */
unsigned char mfl_code; /*!< MaxFragmentLength negotiated by peer */ unsigned char mfl_code; /*!< MaxFragmentLength negotiated by peer */
int trunc_hmac; /*!< flag for truncated hmac activation */ int trunc_hmac; /*!< flag for truncated hmac activation */
}; };
@ -428,8 +447,25 @@ struct _ssl_handshake_params
int resume; /*!< session resume indicator*/ int resume; /*!< session resume indicator*/
int max_major_ver; /*!< max. major version client*/ int max_major_ver; /*!< max. major version client*/
int max_minor_ver; /*!< max. minor version client*/ int max_minor_ver; /*!< max. minor version client*/
#if defined(POLARSSL_SSL_SESSION_TICKETS)
int new_session_ticket; /*!< use NewSessionTicket? */
#endif /* POLARSSL_SSL_SESSION_TICKETS */
}; };
#if defined(POLARSSL_SSL_SESSION_TICKETS)
/*
* Parameters needed to secure session tickets
*/
struct _ssl_ticket_keys
{
unsigned char key_name[16]; /*!< name to quickly discard bad tickets */
aes_context enc; /*!< encryption context */
aes_context dec; /*!< decryption context */
unsigned char mac_key[16]; /*!< authentication key */
};
#endif /* POLARSSL_SSL_SESSION_TICKETS */
struct _ssl_context struct _ssl_context
{ {
/* /*
@ -538,6 +574,13 @@ struct _ssl_context
const char *peer_cn; /*!< expected peer CN */ const char *peer_cn; /*!< expected peer CN */
#endif /* POLARSSL_X509_PARSE_C */ #endif /* POLARSSL_X509_PARSE_C */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
/*
* Support for generating and checking session tickets
*/
ssl_ticket_keys *ticket_keys; /*!< keys for ticket encryption */
#endif /* POLARSSL_SSL_SESSION_TICKETS */
/* /*
* User settings * User settings
*/ */
@ -549,6 +592,7 @@ struct _ssl_context
int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ int allow_legacy_renegotiation; /*!< allow legacy renegotiation */
const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */ const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */
int trunc_hmac; /*!< negotiate truncated hmac? */ int trunc_hmac; /*!< negotiate truncated hmac? */
int session_tickets; /*!< use session tickets? */
#if defined(POLARSSL_DHM_C) #if defined(POLARSSL_DHM_C)
mpi dhm_P; /*!< prime modulus for DHM */ mpi dhm_P; /*!< prime modulus for DHM */
@ -655,6 +699,9 @@ int ssl_session_reset( ssl_context *ssl );
* *
* \param ssl SSL context * \param ssl SSL context
* \param endpoint must be SSL_IS_CLIENT or SSL_IS_SERVER * \param endpoint must be SSL_IS_CLIENT or SSL_IS_SERVER
*
* \note This function should be called right after ssl_init() since
* some other ssl_set_foo() functions depend on it.
*/ */
void ssl_set_endpoint( ssl_context *ssl, int endpoint ); void ssl_set_endpoint( ssl_context *ssl, int endpoint );
@ -774,15 +821,17 @@ void ssl_set_session_cache( ssl_context *ssl,
* \brief Request resumption of session (client-side only) * \brief Request resumption of session (client-side only)
* Session data is copied from presented session structure. * Session data is copied from presented session structure.
* *
* Warning: session.peer_cert is cleared by the SSL/TLS layer on
* connection shutdown, so do not cache the pointer! Either set
* it to NULL or make a full copy of the certificate when
* storing the session for use in this function.
*
* \param ssl SSL context * \param ssl SSL context
* \param session session context * \param session session context
*
* \return 0 if successful,
* POLARSSL_ERR_SSL_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_SSL_BAD_INPUT_DATA if used server-side or
* arguments are otherwise invalid
*
* \sa ssl_get_session()
*/ */
void ssl_set_session( ssl_context *ssl, const ssl_session *session ); int ssl_set_session( ssl_context *ssl, const ssl_session *session );
/** /**
* \brief Set the list of allowed ciphersuites * \brief Set the list of allowed ciphersuites
@ -998,6 +1047,26 @@ int ssl_set_max_frag_len( ssl_context *ssl, unsigned char mfl_code );
*/ */
int ssl_set_truncated_hmac( ssl_context *ssl, int truncate ); int ssl_set_truncated_hmac( ssl_context *ssl, int truncate );
#if defined(POLARSSL_SSL_SESSION_TICKETS)
/**
* \brief Enable / Disable session tickets
* (Default: SSL_SESSION_TICKETS_ENABLED on client,
* SSL_SESSION_TICKETS_DISABLED on server)
*
* \note On server, ssl_set_rng() must be called before this function
* to allow generating the ticket encryption and
* authentication keys.
*
* \param ssl SSL context
* \param use_tickets Enable or disable (SSL_SESSION_TICKETS_ENABLED or
* SSL_SESSION_TICKETS_DISABLED)
*
* \return O if successful,
* or a specific error code (server only).
*/
int ssl_set_session_tickets( ssl_context *ssl, int use_tickets );
#endif /* POLARSSL_SSL_SESSION_TICKETS */
/** /**
* \brief Enable / Disable renegotiation support for connection when * \brief Enable / Disable renegotiation support for connection when
* initiated by peer * initiated by peer
@ -1100,6 +1169,24 @@ const char *ssl_get_version( const ssl_context *ssl );
const x509_cert *ssl_get_peer_cert( const ssl_context *ssl ); const x509_cert *ssl_get_peer_cert( const ssl_context *ssl );
#endif /* POLARSSL_X509_PARSE_C */ #endif /* POLARSSL_X509_PARSE_C */
/**
* \brief Save session in order to resume it later (client-side only)
* Session data is copied to presented session structure.
*
* \warning Currently, peer certificate is lost in the operation.
*
* \param ssl SSL context
* \param session session context
*
* \return 0 if successful,
* POLARSSL_ERR_SSL_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_SSL_BAD_INPUT_DATA if used server-side or
* arguments are otherwise invalid
*
* \sa ssl_set_session()
*/
int ssl_get_session( const ssl_context *ssl, ssl_session *session );
/** /**
* \brief Perform the SSL handshake * \brief Perform the SSL handshake
* *

View file

@ -369,6 +369,8 @@ void polarssl_strerror( int ret, char *buf, size_t buflen )
snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" ); snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" );
if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION) ) if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION) )
snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" ); snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" );
if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) )
snprintf( buf, buflen, "SSL - Processing of the NewSessionTicket handshake message failed" );
#endif /* POLARSSL_SSL_TLS_C */ #endif /* POLARSSL_SSL_TLS_C */
#if defined(POLARSSL_X509_PARSE_C) #if defined(POLARSSL_X509_PARSE_C)

View file

@ -30,6 +30,13 @@
#include "polarssl/debug.h" #include "polarssl/debug.h"
#include "polarssl/ssl.h" #include "polarssl/ssl.h"
#if defined(POLARSSL_MEMORY_C)
#include "polarssl/memory.h"
#else
#define polarssl_malloc malloc
#define polarssl_free free
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -315,6 +322,43 @@ static void ssl_write_truncated_hmac_ext( ssl_context *ssl,
*olen = 4; *olen = 4;
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
static void ssl_write_session_ticket_ext( ssl_context *ssl,
unsigned char *buf, size_t *olen )
{
unsigned char *p = buf;
size_t tlen = ssl->session_negotiate->ticket_len;
if( ssl->session_tickets == SSL_SESSION_TICKETS_DISABLED )
{
*olen = 0;
return;
}
SSL_DEBUG_MSG( 3, ( "client hello, adding session ticket extension" ) );
*p++ = (unsigned char)( ( TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( TLS_EXT_SESSION_TICKET ) & 0xFF );
*p++ = (unsigned char)( ( tlen >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( tlen ) & 0xFF );
*olen = 4;
if( ssl->session_negotiate->ticket == NULL ||
ssl->session_negotiate->ticket_len == 0 )
{
return;
}
SSL_DEBUG_MSG( 3, ( "sending session ticket of length %d", tlen ) );
memcpy( p, ssl->session_negotiate->ticket, tlen );
*olen += tlen;
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
static int ssl_write_client_hello( ssl_context *ssl ) static int ssl_write_client_hello( ssl_context *ssl )
{ {
int ret; int ret;
@ -395,7 +439,27 @@ static int ssl_write_client_hello( ssl_context *ssl )
if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 || if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 ||
ssl->handshake->resume == 0 ) ssl->handshake->resume == 0 )
{
n = 0; n = 0;
}
#if defined(POLARSSL_SSL_SESSION_TICKETS)
/*
* RFC 5077 section 3.4: "When presenting a ticket, the client MAY
* generate and include a Session ID in the TLS ClientHello."
*/
if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE &&
ssl->session_negotiate->ticket != NULL &&
ssl->session_negotiate->ticket_len != 0 )
{
ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id, 32 );
if( ret != 0 )
return( ret );
ssl->session_negotiate->length = n = 32;
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
*p++ = (unsigned char) n; *p++ = (unsigned char) n;
@ -488,6 +552,11 @@ static int ssl_write_client_hello( ssl_context *ssl )
ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen );
ext_len += olen; ext_len += olen;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen );
ext_len += olen;
#endif
SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d",
ext_len ) ); ext_len ) );
@ -587,6 +656,25 @@ static int ssl_parse_truncated_hmac_ext( ssl_context *ssl,
return( 0 ); return( 0 );
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
static int ssl_parse_session_ticket_ext( ssl_context *ssl,
const unsigned char *buf,
size_t len )
{
if( ssl->session_tickets == SSL_SESSION_TICKETS_DISABLED ||
len != 0 )
{
return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO );
}
((void) buf);
ssl->handshake->new_session_ticket = 1;
return( 0 );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
static int ssl_parse_server_hello( ssl_context *ssl ) static int ssl_parse_server_hello( ssl_context *ssl )
{ {
uint32_t t; uint32_t t;
@ -825,6 +913,19 @@ static int ssl_parse_server_hello( ssl_context *ssl )
break; break;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
case TLS_EXT_SESSION_TICKET:
SSL_DEBUG_MSG( 3, ( "found session_ticket extension" ) );
if( ( ret = ssl_parse_session_ticket_ext( ssl,
ext + 4, ext_size ) ) != 0 )
{
return( ret );
}
break;
#endif /* POLARSSL_SSL_SESSION_TICKETS */
default: default:
SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
ext_id ) ); ext_id ) );
@ -1834,6 +1935,100 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
!POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED && !POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED &&
!POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ !POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
static int ssl_parse_new_session_ticket( ssl_context *ssl )
{
int ret;
uint32_t lifetime;
size_t ticket_len;
unsigned char *ticket;
SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) );
if( ( ret = ssl_read_record( ssl ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_read_record", ret );
return( ret );
}
if( ssl->in_msgtype != SSL_MSG_HANDSHAKE )
{
SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE );
}
/*
* struct {
* uint32 ticket_lifetime_hint;
* opaque ticket<0..2^16-1>;
* } NewSessionTicket;
*
* 0 . 0 handshake message type
* 1 . 3 handshake message length
* 4 . 7 ticket_lifetime_hint
* 8 . 9 ticket_len (n)
* 10 . 9+n ticket content
*/
if( ssl->in_msg[0] != SSL_HS_NEW_SESSION_TICKET ||
ssl->in_hslen < 10 )
{
SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
return( POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
}
lifetime = ( ssl->in_msg[4] << 24 ) | ( ssl->in_msg[5] << 16 ) |
( ssl->in_msg[6] << 8 ) | ( ssl->in_msg[7] );
ticket_len = ( ssl->in_msg[8] << 8 ) | ( ssl->in_msg[9] );
if( ticket_len + 10 != ssl->in_hslen )
{
SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
return( POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
}
SSL_DEBUG_MSG( 3, ( "ticket length: %d", ticket_len ) );
/* We're not waiting for a NewSessionTicket message any more */
ssl->handshake->new_session_ticket = 0;
/*
* Zero-length ticket means the server changed his mind and doesn't want
* to send a ticket after all, so just forget it
*/
if( ticket_len == 0)
return( 0 );
polarssl_free( ssl->session_negotiate->ticket );
ssl->session_negotiate->ticket = NULL;
ssl->session_negotiate->ticket_len = 0;
if( ( ticket = polarssl_malloc( ticket_len ) ) == NULL )
{
SSL_DEBUG_MSG( 1, ( "ticket malloc failed" ) );
return( POLARSSL_ERR_SSL_MALLOC_FAILED );
}
memcpy( ticket, ssl->in_msg + 10, ticket_len );
ssl->session_negotiate->ticket = ticket;
ssl->session_negotiate->ticket_len = ticket_len;
ssl->session_negotiate->ticket_lifetime = lifetime;
/*
* RFC 5077 section 3.4:
* "If the client receives a session ticket from the server, then it
* discards any Session ID that was sent in the ServerHello."
*/
SSL_DEBUG_MSG( 3, ( "ticket in use, discarding session id" ) );
ssl->session_negotiate->length = 0;
SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) );
return( 0 );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
/* /*
* SSL handshake -- client side -- single step * SSL handshake -- client side -- single step
*/ */
@ -1917,11 +2112,17 @@ int ssl_handshake_client_step( ssl_context *ssl )
break; break;
/* /*
* <== ChangeCipherSpec * <== ( NewSessionTicket )
* ChangeCipherSpec
* Finished * Finished
*/ */
case SSL_SERVER_CHANGE_CIPHER_SPEC: case SSL_SERVER_CHANGE_CIPHER_SPEC:
ret = ssl_parse_change_cipher_spec( ssl ); #if defined(POLARSSL_SSL_SESSION_TICKETS)
if( ssl->handshake->new_session_ticket != 0 )
ret = ssl_parse_new_session_ticket( ssl );
else
#endif
ret = ssl_parse_change_cipher_spec( ssl );
break; break;
case SSL_SERVER_FINISHED: case SSL_SERVER_FINISHED:

View file

@ -33,6 +33,13 @@
#include "polarssl/ecp.h" #include "polarssl/ecp.h"
#endif #endif
#if defined(POLARSSL_MEMORY_C)
#include "polarssl/memory.h"
#else
#define polarssl_malloc malloc
#define polarssl_free free
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -40,6 +47,262 @@
#include <time.h> #include <time.h>
#endif #endif
#if defined(POLARSSL_SSL_SESSION_TICKETS)
/*
* Serialize a session in the following format:
* 0 . n-1 session structure, n = sizeof(ssl_session)
* n . n+2 peer_cert length = m (0 if no certificate)
* n+3 . n+2+m peer cert ASN.1
*
* Assumes ticket is NULL (always true on server side).
*/
static void ssl_save_session( const ssl_session *session,
unsigned char *buf, size_t *olen )
{
unsigned char *p = buf;
#if defined(POLARSSL_X509_PARSE_C)
size_t cert_len;
#endif /* POLARSSL_X509_PARSE_C */
memcpy( p, session, sizeof( ssl_session ) );
p += sizeof( ssl_session );
#if defined(POLARSSL_X509_PARSE_C)
((ssl_session *) buf)->peer_cert = NULL;
if( session->peer_cert == NULL )
cert_len = 0;
else
cert_len = session->peer_cert->raw.len;
*p++ = (unsigned char)( cert_len >> 16 & 0xFF );
*p++ = (unsigned char)( cert_len >> 8 & 0xFF );
*p++ = (unsigned char)( cert_len & 0xFF );
if( session->peer_cert != NULL )
memcpy( p, session->peer_cert->raw.p, cert_len );
p += cert_len;
#endif /* POLARSSL_X509_PARSE_C */
*olen = p - buf;
}
/*
* Unserialise session, see ssl_save_session()
*/
static int ssl_load_session( ssl_session *session,
const unsigned char *buf, size_t len )
{
int ret;
const unsigned char *p = buf;
const unsigned char * const end = buf + len;
#if defined(POLARSSL_X509_PARSE_C)
size_t cert_len;
#endif /* POLARSSL_X509_PARSE_C */
if( p + sizeof( ssl_session ) > end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
memcpy( session, p, sizeof( ssl_session ) );
p += sizeof( ssl_session );
#if defined(POLARSSL_X509_PARSE_C)
if( p + 3 > end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
p += 3;
if( cert_len == 0 )
{
session->peer_cert = NULL;
}
else
{
if( p + cert_len > end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
session->peer_cert = polarssl_malloc( cert_len );
if( session->peer_cert == NULL )
return( POLARSSL_ERR_SSL_MALLOC_FAILED );
memset( session->peer_cert, 0, sizeof( x509_cert ) );
if( ( ret = x509parse_crt( session->peer_cert, p, cert_len ) ) != 0 )
{
polarssl_free( session->peer_cert );
free( session->peer_cert );
session->peer_cert = NULL;
return( ret );
}
p += cert_len;
}
#endif /* POLARSSL_X509_PARSE_C */
if( p != end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
return( 0 );
}
/*
* Create session ticket, secured as recommended in RFC 5077 section 4:
*
* struct {
* opaque key_name[16];
* opaque iv[16];
* opaque encrypted_state<0..2^16-1>;
* opaque mac[32];
* } ticket;
*
* (the internal state structure differs, however).
*/
static int ssl_write_ticket( ssl_context *ssl, size_t *tlen )
{
int ret;
unsigned char * const start = ssl->out_msg + 10;
unsigned char *p = start;
unsigned char *state;
unsigned char iv[16];
size_t clear_len, enc_len, pad_len, i;
if( ssl->ticket_keys == NULL )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
/* Write key name */
memcpy( p, ssl->ticket_keys->key_name, 16 );
p += 16;
/* Generate and write IV (with a copy for aes_crypt) */
if( ( ret = ssl->f_rng( ssl->p_rng, p, 16 ) ) != 0 )
return( ret );
memcpy( iv, p, 16 );
p += 16;
/* Dump session state */
state = p + 2;
ssl_save_session( ssl->session_negotiate, state, &clear_len );
SSL_DEBUG_BUF( 3, "session ticket cleartext", state, clear_len );
/* Apply PKCS padding */
pad_len = 16 - clear_len % 16;
enc_len = clear_len + pad_len;
for( i = clear_len; i < enc_len; i++ )
state[i] = (unsigned char) pad_len;
/* Encrypt */
if( ( ret = aes_crypt_cbc( &ssl->ticket_keys->enc, AES_ENCRYPT,
enc_len, iv, state, state ) ) != 0 )
{
return( ret );
}
/* Write length */
*p++ = (unsigned char)( ( enc_len >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( enc_len ) & 0xFF );
p = state + enc_len;
/* Compute and write MAC( key_name + iv + enc_state_len + enc_state ) */
sha256_hmac( ssl->ticket_keys->mac_key, 16, start, p - start, p, 0 );
p += 32;
*tlen = p - start;
SSL_DEBUG_BUF( 3, "session ticket structure", start, *tlen );
return( 0 );
}
/*
* Load session ticket (see ssl_write_ticket for structure)
*/
static int ssl_parse_ticket( ssl_context *ssl,
unsigned char *buf,
size_t len )
{
int ret;
ssl_session session;
unsigned char *key_name = buf;
unsigned char *iv = buf + 16;
unsigned char *enc_len_p = iv + 16;
unsigned char *ticket = enc_len_p + 2;
unsigned char *mac;
unsigned char computed_mac[16];
size_t enc_len, clear_len, i;
unsigned char pad_len;
SSL_DEBUG_BUF( 3, "session ticket structure", buf, len );
if( len < 34 || ssl->ticket_keys == NULL )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
mac = ticket + enc_len;
if( len != enc_len + 66 )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
/* Check name */
if( memcmp( key_name, ssl->ticket_keys->key_name, 16 ) != 0 )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
/* Check mac */
sha256_hmac( ssl->ticket_keys->mac_key, 16, buf, len - 32,
computed_mac, 0 );
ret = 0;
for( i = 0; i < 32; i++ )
if( mac[i] != computed_mac[i] )
ret = POLARSSL_ERR_SSL_INVALID_MAC;
if( ret != 0 )
return( ret );
/* Decrypt */
if( ( ret = aes_crypt_cbc( &ssl->ticket_keys->dec, AES_DECRYPT,
enc_len, iv, ticket, ticket ) ) != 0 )
{
return( ret );
}
/* Check PKCS padding */
pad_len = ticket[enc_len - 1];
ret = 0;
for( i = 2; i < pad_len; i++ )
if( ticket[enc_len - i] != pad_len )
ret = POLARSSL_ERR_SSL_BAD_INPUT_DATA;
if( ret != 0 )
return( ret );
clear_len = enc_len - pad_len;
SSL_DEBUG_BUF( 3, "session ticket cleartext", ticket, clear_len );
/* Actually load session */
if( ( ret = ssl_load_session( &session, ticket, clear_len ) ) != 0 )
{
SSL_DEBUG_MSG( 1, ( "failed to parse ticket content" ) );
memset( &session, 0, sizeof( ssl_session ) );
return( ret );
}
/*
* Keep the session ID sent by the client, since we MUST send it back to
* inform him we're accepting the ticket (RFC 5077 section 3.4)
*/
session.length = ssl->session_negotiate->length;
memcpy( &session.id, ssl->session_negotiate->id, session.length );
ssl_session_free( ssl->session_negotiate );
memcpy( ssl->session_negotiate, &session, sizeof( ssl_session ) );
memset( &session, 0, sizeof( ssl_session ) );
return( 0 );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
static int ssl_parse_servername_ext( ssl_context *ssl, static int ssl_parse_servername_ext( ssl_context *ssl,
const unsigned char *buf, const unsigned char *buf,
size_t len ) size_t len )
@ -323,6 +586,50 @@ static int ssl_parse_truncated_hmac_ext( ssl_context *ssl,
return( 0 ); return( 0 );
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
static int ssl_parse_session_ticket_ext( ssl_context *ssl,
unsigned char *buf,
size_t len )
{
int ret;
if( ssl->session_tickets == SSL_SESSION_TICKETS_DISABLED )
return( 0 );
/* Remember the client asked us to send a new ticket */
ssl->handshake->new_session_ticket = 1;
SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) );
if( len == 0 )
return( 0 );
if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE )
{
SSL_DEBUG_MSG( 3, ( "ticket rejected: renegotiating" ) );
return( 0 );
}
/*
* Failures are ok: just ignore the ticket and proceed.
*/
if( ( ret = ssl_parse_ticket( ssl, buf, len ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_parse_ticket", ret );
return( 0 );
}
SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) );
ssl->handshake->resume = 1;
/* Don't send a new ticket after all, this one is OK */
ssl->handshake->new_session_ticket = 0;
return( 0 );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) #if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
static int ssl_parse_client_hello_v2( ssl_context *ssl ) static int ssl_parse_client_hello_v2( ssl_context *ssl )
{ {
@ -610,7 +917,7 @@ static int ssl_parse_client_hello( ssl_context *ssl )
n = ( buf[3] << 8 ) | buf[4]; n = ( buf[3] << 8 ) | buf[4];
if( n < 45 || n > 512 ) if( n < 45 || n > 2048 )
{ {
SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
@ -873,6 +1180,16 @@ static int ssl_parse_client_hello( ssl_context *ssl )
return( ret ); return( ret );
break; break;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
case TLS_EXT_SESSION_TICKET:
SSL_DEBUG_MSG( 3, ( "found session ticket extension" ) );
ret = ssl_parse_session_ticket_ext( ssl, ext + 4, ext_size );
if( ret != 0 )
return( ret );
break;
#endif /* POLARSSL_SSL_SESSION_TICKETS */
default: default:
SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
ext_id ) ); ext_id ) );
@ -1005,6 +1322,31 @@ static void ssl_write_truncated_hmac_ext( ssl_context *ssl,
*olen = 4; *olen = 4;
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
static void ssl_write_session_ticket_ext( ssl_context *ssl,
unsigned char *buf,
size_t *olen )
{
unsigned char *p = buf;
if( ssl->handshake->new_session_ticket == 0 )
{
*olen = 0;
return;
}
SSL_DEBUG_MSG( 3, ( "server hello, adding session ticket extension" ) );
*p++ = (unsigned char)( ( TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( TLS_EXT_SESSION_TICKET ) & 0xFF );
*p++ = 0x00;
*p++ = 0x00;
*olen = 4;
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
static void ssl_write_renegotiation_ext( ssl_context *ssl, static void ssl_write_renegotiation_ext( ssl_context *ssl,
unsigned char *buf, unsigned char *buf,
size_t *olen ) size_t *olen )
@ -1111,36 +1453,52 @@ static int ssl_write_server_hello( ssl_context *ssl )
SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 );
/* /*
* 38 . 38 session id length * Resume is 0 by default, see ssl_handshake_init().
* 39 . 38+n session id * It may be already set to 1 by ssl_parse_session_ticket_ext().
* 39+n . 40+n chosen ciphersuite * If not, try looking up session ID in our cache.
* 41+n . 41+n chosen compression alg.
* 42+n . 43+n extensions length
* 44+n . 43+n+m extensions
*/ */
ssl->session_negotiate->length = n = 32; if( ssl->handshake->resume == 0 &&
*p++ = (unsigned char) ssl->session_negotiate->length; ssl->renegotiation == SSL_INITIAL_HANDSHAKE &&
ssl->session_negotiate->length != 0 &&
ssl->f_get_cache != NULL &&
ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) == 0 )
{
ssl->handshake->resume = 1;
}
if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || if( ssl->handshake->resume == 0 )
ssl->f_get_cache == NULL ||
ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) != 0 )
{ {
/* /*
* Not found, create a new session id * New session, create a new session id,
* unless we're about to issue a session ticket
*/ */
ssl->handshake->resume = 0;
ssl->state++; ssl->state++;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
if( ssl->handshake->new_session_ticket == 0 )
{
ssl->session_negotiate->length = n = 32;
if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id,
n ) ) != 0 )
return( ret );
}
else
{
ssl->session_negotiate->length = 0;
memset( ssl->session_negotiate->id, 0, 32 );
}
#else
ssl->session_negotiate->length = n = 32;
if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id, if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id,
n ) ) != 0 ) n ) ) != 0 )
return( ret ); return( ret );
#endif /* POLARSSL_SSL_SESSION_TICKETS */
} }
else else
{ {
/* /*
* Found a matching session, resuming it * Resuming a session
*/ */
ssl->handshake->resume = 1;
ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC; ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
if( ( ret = ssl_derive_keys( ssl ) ) != 0 ) if( ( ret = ssl_derive_keys( ssl ) ) != 0 )
@ -1150,6 +1508,15 @@ static int ssl_write_server_hello( ssl_context *ssl )
} }
} }
/*
* 38 . 38 session id length
* 39 . 38+n session id
* 39+n . 40+n chosen ciphersuite
* 41+n . 41+n chosen compression alg.
* 42+n . 43+n extensions length
* 44+n . 43+n+m extensions
*/
*p++ = (unsigned char) ssl->session_negotiate->length;
memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->length ); memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->length );
p += ssl->session_negotiate->length; p += ssl->session_negotiate->length;
@ -1179,6 +1546,11 @@ static int ssl_write_server_hello( ssl_context *ssl )
ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen );
ext_len += olen; ext_len += olen;
#if defined(POLARSSL_SSL_SESSION_TICKETS)
ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen );
ext_len += olen;
#endif
SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) );
*p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF );
@ -2114,6 +2486,58 @@ static int ssl_parse_certificate_verify( ssl_context *ssl )
!POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED && !POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED &&
!POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ !POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
static int ssl_write_new_session_ticket( ssl_context *ssl )
{
int ret;
size_t tlen;
SSL_DEBUG_MSG( 2, ( "=> write new session ticket" ) );
ssl->out_msgtype = SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = SSL_HS_NEW_SESSION_TICKET;
/*
* struct {
* uint32 ticket_lifetime_hint;
* opaque ticket<0..2^16-1>;
* } NewSessionTicket;
*
* 4 . 7 ticket_lifetime_hint (0 = unspecified)
* 8 . 9 ticket_len (n)
* 10 . 9+n ticket content
*/
ssl->out_msg[4] = 0x00;
ssl->out_msg[5] = 0x00;
ssl->out_msg[6] = 0x00;
ssl->out_msg[7] = 0x00;
if( ( ret = ssl_write_ticket( ssl, &tlen ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_write_ticket", ret );
tlen = 0;
}
ssl->out_msg[8] = (unsigned char)( ( tlen >> 8 ) & 0xFF );
ssl->out_msg[9] = (unsigned char)( ( tlen ) & 0xFF );
ssl->out_msglen = 10 + tlen;
if( ( ret = ssl_write_record( ssl ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_write_record", ret );
return( ret );
}
/* No need to remember writing a NewSessionTicket any more */
ssl->handshake->new_session_ticket = 0;
SSL_DEBUG_MSG( 2, ( "<= write new session ticket" ) );
return( 0 );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
/* /*
* SSL handshake -- server side -- single step * SSL handshake -- server side -- single step
*/ */
@ -2197,11 +2621,17 @@ int ssl_handshake_server_step( ssl_context *ssl )
break; break;
/* /*
* ==> ChangeCipherSpec * ==> ( NewSessionTicket )
* ChangeCipherSpec
* Finished * Finished
*/ */
case SSL_SERVER_CHANGE_CIPHER_SPEC: case SSL_SERVER_CHANGE_CIPHER_SPEC:
ret = ssl_write_change_cipher_spec( ssl ); #if defined(POLARSSL_SSL_SESSION_TICKETS)
if( ssl->handshake->new_session_ticket != 0 )
ret = ssl_write_new_session_ticket( ssl );
else
#endif
ret = ssl_write_change_cipher_spec( ssl );
break; break;
case SSL_SERVER_FINISHED: case SSL_SERVER_FINISHED:

View file

@ -76,6 +76,44 @@ static unsigned int mfl_code_to_length[SSL_MAX_FRAG_LEN_INVALID] =
4096, /* SSL_MAX_FRAG_LEN_4096 */ 4096, /* SSL_MAX_FRAG_LEN_4096 */
}; };
static int ssl_session_copy( ssl_session *dst, const ssl_session *src )
{
int ret;
ssl_session_free( dst );
memcpy( dst, src, sizeof( ssl_session ) );
#if defined(POLARSSL_X509_PARSE_C)
if( src->peer_cert != NULL )
{
if( ( dst->peer_cert = polarssl_malloc( sizeof(x509_cert) ) ) == NULL )
return( POLARSSL_ERR_SSL_MALLOC_FAILED );
memset( dst->peer_cert, 0, sizeof(x509_cert) );
if( ( ret = x509parse_crt( dst->peer_cert, src->peer_cert->raw.p,
src->peer_cert->raw.len ) != 0 ) )
{
polarssl_free( dst->peer_cert );
dst->peer_cert = NULL;
return( ret );
}
}
#endif /* POLARSSL_X509_PARSE_C */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
if( src->ticket != NULL )
{
if( ( dst->ticket = polarssl_malloc( src->ticket_len ) ) == NULL )
return( POLARSSL_ERR_SSL_MALLOC_FAILED );
memcpy( dst->ticket, src->ticket, src->ticket_len );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
return( 0 );
}
#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) #if defined(POLARSSL_SSL_HW_RECORD_ACCEL)
int (*ssl_hw_record_init)(ssl_context *ssl, int (*ssl_hw_record_init)(ssl_context *ssl,
const unsigned char *key_enc, const unsigned char *key_dec, const unsigned char *key_enc, const unsigned char *key_dec,
@ -2539,6 +2577,8 @@ static void ssl_calc_finished_tls_sha384(
void ssl_handshake_wrapup( ssl_context *ssl ) void ssl_handshake_wrapup( ssl_context *ssl )
{ {
int resume = ssl->handshake->resume;
SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
/* /*
@ -2570,9 +2610,13 @@ void ssl_handshake_wrapup( ssl_context *ssl )
/* /*
* Add cache entry * Add cache entry
*/ */
if( ssl->f_set_cache != NULL ) if( ssl->f_set_cache != NULL &&
ssl->session->length != 0 &&
resume == 0 )
{
if( ssl->f_set_cache( ssl->p_set_cache, ssl->session ) != 0 ) if( ssl->f_set_cache( ssl->p_set_cache, ssl->session ) != 0 )
SSL_DEBUG_MSG( 1, ( "cache did not store session" ) ); SSL_DEBUG_MSG( 1, ( "cache did not store session" ) );
}
ssl->state++; ssl->state++;
@ -2930,12 +2974,50 @@ int ssl_session_reset( ssl_context *ssl )
return( 0 ); return( 0 );
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
/*
* Allocate and initialize ticket keys
*/
static int ssl_ticket_keys_init( ssl_context *ssl )
{
int ret;
ssl_ticket_keys *tkeys;
unsigned char buf[16];
if( ssl->ticket_keys != NULL )
return( 0 );
if( ( tkeys = polarssl_malloc( sizeof( ssl_ticket_keys ) ) ) == NULL )
return( POLARSSL_ERR_SSL_MALLOC_FAILED );
if( ( ret = ssl->f_rng( ssl->p_rng, tkeys->key_name, 16 ) ) != 0 )
return( ret );
if( ( ret = ssl->f_rng( ssl->p_rng, buf, 16 ) ) != 0 ||
( ret = aes_setkey_enc( &tkeys->enc, buf, 128 ) ) != 0 ||
( ret = aes_setkey_dec( &tkeys->dec, buf, 128 ) ) != 0 )
{
return( ret );
}
if( ( ret = ssl->f_rng( ssl->p_rng, tkeys->mac_key, 16 ) ) != 0 )
return( ret );
ssl->ticket_keys = tkeys;
return( 0 );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
/* /*
* SSL set accessors * SSL set accessors
*/ */
void ssl_set_endpoint( ssl_context *ssl, int endpoint ) void ssl_set_endpoint( ssl_context *ssl, int endpoint )
{ {
ssl->endpoint = endpoint; ssl->endpoint = endpoint;
if( endpoint == SSL_IS_CLIENT )
ssl->session_tickets = SSL_SESSION_TICKETS_ENABLED;
} }
void ssl_set_authmode( ssl_context *ssl, int authmode ) void ssl_set_authmode( ssl_context *ssl, int authmode )
@ -2989,10 +3071,24 @@ void ssl_set_session_cache( ssl_context *ssl,
ssl->p_set_cache = p_set_cache; ssl->p_set_cache = p_set_cache;
} }
void ssl_set_session( ssl_context *ssl, const ssl_session *session ) int ssl_set_session( ssl_context *ssl, const ssl_session *session )
{ {
memcpy( ssl->session_negotiate, session, sizeof(ssl_session) ); int ret;
if( ssl == NULL ||
session == NULL ||
ssl->session_negotiate == NULL ||
ssl->endpoint != SSL_IS_CLIENT )
{
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
}
if( ( ret = ssl_session_copy( ssl->session_negotiate, session ) ) != 0 )
return( ret );
ssl->handshake->resume = 1; ssl->handshake->resume = 1;
return( 0 );
} }
void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites ) void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites )
@ -3169,6 +3265,21 @@ void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy )
ssl->allow_legacy_renegotiation = allow_legacy; ssl->allow_legacy_renegotiation = allow_legacy;
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
int ssl_set_session_tickets( ssl_context *ssl, int use_tickets )
{
ssl->session_tickets = use_tickets;
if( ssl->endpoint == SSL_IS_CLIENT )
return( 0 );
if( ssl->f_rng == NULL )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
return( ssl_ticket_keys_init( ssl ) );
}
#endif /* POLARSSL_SSL_SESSION_TICKETS */
/* /*
* SSL get accessors * SSL get accessors
*/ */
@ -3222,6 +3333,19 @@ const x509_cert *ssl_get_peer_cert( const ssl_context *ssl )
} }
#endif /* POLARSSL_X509_PARSE_C */ #endif /* POLARSSL_X509_PARSE_C */
int ssl_get_session( const ssl_context *ssl, ssl_session *dst )
{
if( ssl == NULL ||
dst == NULL ||
ssl->session == NULL ||
ssl->endpoint != SSL_IS_CLIENT )
{
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
}
return( ssl_session_copy( dst, ssl->session ) );
}
/* /*
* Perform a single step of the SSL handshake * Perform a single step of the SSL handshake
*/ */
@ -3540,6 +3664,10 @@ void ssl_session_free( ssl_session *session )
} }
#endif #endif
#if defined(POLARSSL_SSL_SESSION_TICKETS)
polarssl_free( session->ticket );
#endif
memset( session, 0, sizeof( ssl_session ) ); memset( session, 0, sizeof( ssl_session ) );
} }
@ -3590,6 +3718,10 @@ void ssl_free( ssl_context *ssl )
polarssl_free( ssl->session ); polarssl_free( ssl->session );
} }
#if defined(POLARSSL_SSL_SESSION_TICKETS)
polarssl_free( ssl->ticket_keys );
#endif
if ( ssl->hostname != NULL) if ( ssl->hostname != NULL)
{ {
memset( ssl->hostname, 0, ssl->hostname_len ); memset( ssl->hostname, 0, ssl->hostname_len );

View file

@ -59,6 +59,8 @@
#define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL #define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL
#define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE #define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE
#define DFL_TRUNC_HMAC 0 #define DFL_TRUNC_HMAC 0
#define DFL_RECONNECT 0
#define DFL_TICKETS SSL_SESSION_TICKETS_ENABLED
#define LONG_HEADER "User-agent: blah-blah-blah-blah-blah-blah-blah-blah-" \ #define LONG_HEADER "User-agent: blah-blah-blah-blah-blah-blah-blah-blah-" \
"-01--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ "-01--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \
@ -96,6 +98,8 @@ struct options
int auth_mode; /* verify mode for connection */ int auth_mode; /* verify mode for connection */
unsigned char mfl_code; /* code for maximum fragment length */ unsigned char mfl_code; /* code for maximum fragment length */
int trunc_hmac; /* negotiate truncated hmac or not */ int trunc_hmac; /* negotiate truncated hmac or not */
int reconnect; /* attempt to resume session */
int tickets; /* enable / disable session tickets */
} opt; } opt;
static void my_debug( void *ctx, int level, const char *str ) static void my_debug( void *ctx, int level, const char *str )
@ -174,6 +178,13 @@ static int my_verify( void *data, x509_cert *crt, int depth, int *flags )
#define USAGE_PSK "" #define USAGE_PSK ""
#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */ #endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
#define USAGE_TICKETS \
" tickets=%%d default: 1 (enabled)\n"
#else
#define USAGE_TICKETS ""
#endif /* POLARSSL_SSL_SESSION_TICKETS */
#define USAGE \ #define USAGE \
"\n usage: ssl_client2 param=<>...\n" \ "\n usage: ssl_client2 param=<>...\n" \
"\n acceptable parameters:\n" \ "\n acceptable parameters:\n" \
@ -184,6 +195,8 @@ static int my_verify( void *data, x509_cert *crt, int depth, int *flags )
" request_page=%%s default: \".\"\n" \ " request_page=%%s default: \".\"\n" \
" renegotiation=%%d default: 1 (enabled)\n" \ " renegotiation=%%d default: 1 (enabled)\n" \
" allow_legacy=%%d default: 0 (disabled)\n" \ " allow_legacy=%%d default: 0 (disabled)\n" \
" reconnect=%%d default: 0 (disabled)\n" \
USAGE_TICKETS \
"\n" \ "\n" \
" min_version=%%s default: \"\" (ssl3)\n" \ " min_version=%%s default: \"\" (ssl3)\n" \
" max_version=%%s default: \"\" (tls1_2)\n" \ " max_version=%%s default: \"\" (tls1_2)\n" \
@ -226,6 +239,7 @@ int main( int argc, char *argv[] )
entropy_context entropy; entropy_context entropy;
ctr_drbg_context ctr_drbg; ctr_drbg_context ctr_drbg;
ssl_context ssl; ssl_context ssl;
ssl_session saved_session;
#if defined(POLARSSL_X509_PARSE_C) #if defined(POLARSSL_X509_PARSE_C)
x509_cert cacert; x509_cert cacert;
x509_cert clicert; x509_cert clicert;
@ -239,6 +253,7 @@ int main( int argc, char *argv[] )
*/ */
server_fd = 0; server_fd = 0;
memset( &ssl, 0, sizeof( ssl_context ) ); memset( &ssl, 0, sizeof( ssl_context ) );
memset( &saved_session, 0, sizeof( ssl_session ) );
#if defined(POLARSSL_X509_PARSE_C) #if defined(POLARSSL_X509_PARSE_C)
memset( &cacert, 0, sizeof( x509_cert ) ); memset( &cacert, 0, sizeof( x509_cert ) );
memset( &clicert, 0, sizeof( x509_cert ) ); memset( &clicert, 0, sizeof( x509_cert ) );
@ -285,6 +300,8 @@ int main( int argc, char *argv[] )
opt.auth_mode = DFL_AUTH_MODE; opt.auth_mode = DFL_AUTH_MODE;
opt.mfl_code = DFL_MFL_CODE; opt.mfl_code = DFL_MFL_CODE;
opt.trunc_hmac = DFL_TRUNC_HMAC; opt.trunc_hmac = DFL_TRUNC_HMAC;
opt.reconnect = DFL_RECONNECT;
opt.tickets = DFL_TICKETS;
for( i = 1; i < argc; i++ ) for( i = 1; i < argc; i++ )
{ {
@ -345,6 +362,18 @@ int main( int argc, char *argv[] )
if( opt.allow_legacy < 0 || opt.allow_legacy > 1 ) if( opt.allow_legacy < 0 || opt.allow_legacy > 1 )
goto usage; goto usage;
} }
else if( strcmp( p, "reconnect" ) == 0 )
{
opt.reconnect = atoi( q );
if( opt.reconnect < 0 || opt.reconnect > 2 )
goto usage;
}
else if( strcmp( p, "tickets" ) == 0 )
{
opt.tickets = atoi( q );
if( opt.tickets < 0 || opt.tickets > 2 )
goto usage;
}
else if( strcmp( p, "min_version" ) == 0 ) else if( strcmp( p, "min_version" ) == 0 )
{ {
if( strcmp( q, "ssl3" ) == 0 ) if( strcmp( q, "ssl3" ) == 0 )
@ -652,6 +681,10 @@ int main( int argc, char *argv[] )
ssl_set_bio( &ssl, net_recv, &server_fd, ssl_set_bio( &ssl, net_recv, &server_fd,
net_send, &server_fd ); net_send, &server_fd );
#if defined(POLARSSL_SSL_SESSION_TICKETS)
ssl_set_session_tickets( &ssl, opt.tickets );
#endif
if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER ) if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
ssl_set_ciphersuites( &ssl, opt.force_ciphersuite ); ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
@ -693,6 +726,20 @@ int main( int argc, char *argv[] )
printf( " ok\n [ Ciphersuite is %s ]\n", printf( " ok\n [ Ciphersuite is %s ]\n",
ssl_get_ciphersuite( &ssl ) ); ssl_get_ciphersuite( &ssl ) );
if( opt.reconnect != 0 )
{
printf(" . Saving session for reuse..." );
fflush( stdout );
if( ( ret = ssl_get_session( &ssl, &saved_session ) ) != 0 )
{
printf( " failed\n ! ssl_get_session returned -0x%x\n\n", -ret );
goto exit;
}
printf( " ok\n" );
}
#if defined(POLARSSL_X509_PARSE_C) #if defined(POLARSSL_X509_PARSE_C)
/* /*
* 5. Verify the server certificate * 5. Verify the server certificate
@ -732,6 +779,7 @@ int main( int argc, char *argv[] )
/* /*
* 6. Write the GET request * 6. Write the GET request
*/ */
send_request:
printf( " > Write to server:" ); printf( " > Write to server:" );
fflush( stdout ); fflush( stdout );
@ -789,6 +837,43 @@ int main( int argc, char *argv[] )
ssl_close_notify( &ssl ); ssl_close_notify( &ssl );
if( opt.reconnect != 0 )
{
--opt.reconnect;
printf( " . Reconnecting with saved session..." );
fflush( stdout );
if( ( ret = ssl_session_reset( &ssl ) ) != 0 )
{
printf( " failed\n ! ssl_session_reset returned -0x%x\n\n", -ret );
goto exit;
}
ssl_set_session( &ssl, &saved_session );
if( ( ret = net_connect( &server_fd, opt.server_name,
opt.server_port ) ) != 0 )
{
printf( " failed\n ! net_connect returned -0x%x\n\n", -ret );
goto exit;
}
while( ( ret = ssl_handshake( &ssl ) ) != 0 )
{
if( ret != POLARSSL_ERR_NET_WANT_READ &&
ret != POLARSSL_ERR_NET_WANT_WRITE )
{
printf( " failed\n ! ssl_handshake returned -0x%x\n\n", -ret );
goto exit;
}
}
printf( " ok\n" );
goto send_request;
}
exit: exit:
#ifdef POLARSSL_ERROR_C #ifdef POLARSSL_ERROR_C
@ -807,6 +892,7 @@ exit:
x509_free( &cacert ); x509_free( &cacert );
rsa_free( &rsa ); rsa_free( &rsa );
#endif #endif
ssl_session_free( &saved_session );
ssl_free( &ssl ); ssl_free( &ssl );
memset( &ssl, 0, sizeof( ssl ) ); memset( &ssl, 0, sizeof( ssl ) );

View file

@ -69,6 +69,7 @@
#define DFL_MAX_VERSION -1 #define DFL_MAX_VERSION -1
#define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL #define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL
#define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE #define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE
#define DFL_TICKETS SSL_SESSION_TICKETS_ENABLED
#define LONG_RESPONSE "<p>01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ #define LONG_RESPONSE "<p>01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
"02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
@ -105,6 +106,7 @@ struct options
int max_version; /* maximum protocol version accepted */ int max_version; /* maximum protocol version accepted */
int auth_mode; /* verify mode for connection */ int auth_mode; /* verify mode for connection */
unsigned char mfl_code; /* code for maximum fragment length */ unsigned char mfl_code; /* code for maximum fragment length */
int tickets; /* enable / disable session tickets */
} opt; } opt;
static void my_debug( void *ctx, int level, const char *str ) static void my_debug( void *ctx, int level, const char *str )
@ -144,6 +146,13 @@ static void my_debug( void *ctx, int level, const char *str )
#define USAGE_PSK "" #define USAGE_PSK ""
#endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */ #endif /* POLARSSL_KEY_EXCHANGE_PSK_ENABLED */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
#define USAGE_TICKETS \
" tickets=%%d default: 1 (enabled)\n"
#else
#define USAGE_TICKETS ""
#endif /* POLARSSL_SSL_SESSION_TICKETS */
#define USAGE \ #define USAGE \
"\n usage: ssl_server2 param=<>...\n" \ "\n usage: ssl_server2 param=<>...\n" \
"\n acceptable parameters:\n" \ "\n acceptable parameters:\n" \
@ -152,6 +161,7 @@ static void my_debug( void *ctx, int level, const char *str )
USAGE_IO \ USAGE_IO \
" request_page=%%s default: \".\"\n" \ " request_page=%%s default: \".\"\n" \
" renegotiation=%%d default: 1 (enabled)\n" \ " renegotiation=%%d default: 1 (enabled)\n" \
USAGE_TICKETS \
" allow_legacy=%%d default: 0 (disabled)\n" \ " allow_legacy=%%d default: 0 (disabled)\n" \
" min_version=%%s default: \"ssl3\"\n" \ " min_version=%%s default: \"ssl3\"\n" \
" max_version=%%s default: \"tls1_2\"\n" \ " max_version=%%s default: \"tls1_2\"\n" \
@ -265,6 +275,7 @@ int main( int argc, char *argv[] )
opt.max_version = DFL_MAX_VERSION; opt.max_version = DFL_MAX_VERSION;
opt.auth_mode = DFL_AUTH_MODE; opt.auth_mode = DFL_AUTH_MODE;
opt.mfl_code = DFL_MFL_CODE; opt.mfl_code = DFL_MFL_CODE;
opt.tickets = DFL_TICKETS;
for( i = 1; i < argc; i++ ) for( i = 1; i < argc; i++ )
{ {
@ -396,6 +407,12 @@ int main( int argc, char *argv[] )
else else
goto usage; goto usage;
} }
else if( strcmp( p, "tickets" ) == 0 )
{
opt.tickets = atoi( q );
if( opt.tickets < 0 || opt.tickets > 1 )
goto usage;
}
else else
goto usage; goto usage;
} }
@ -611,6 +628,10 @@ int main( int argc, char *argv[] )
ssl_cache_set, &cache ); ssl_cache_set, &cache );
#endif #endif
#if defined(POLARSSL_SSL_SESSION_TICKETS)
ssl_set_session_tickets( &ssl, opt.tickets );
#endif
if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER ) if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
ssl_set_ciphersuites( &ssl, opt.force_ciphersuite ); ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );