mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-12-23 18:15:35 +00:00
Merge branch 'session_tickets' into development
This commit is contained in:
commit
5994adc749
|
@ -17,6 +17,7 @@ Features
|
|||
* Support for truncated_hmac extension (RFC 6066)
|
||||
* Support for zeros-and-length (ANSI X.923) padding, one-and-zeros
|
||||
(ISO/IEC 7816-4) padding and zero padding in the cipher layer
|
||||
* Support for session tickets (RFC 5077)
|
||||
|
||||
Changes
|
||||
* Introduced separate SSL Ciphersuites module that is based on
|
||||
|
|
|
@ -528,6 +528,18 @@
|
|||
*/
|
||||
#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
|
||||
*
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
* ECP 4 4 (Started from top)
|
||||
* MD 5 4
|
||||
* CIPHER 6 5
|
||||
* SSL 6 2 (Started from top)
|
||||
* SSL 6 4 (Started from top)
|
||||
* SSL 7 31
|
||||
*
|
||||
* Module dependent error code (5 bits 0x.08.-0x.F8.)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "sha512.h"
|
||||
#include "aes.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_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_NEW_SESSION_TICKET -0x6E00 /**< Processing of the NewSessionTicket handshake message failed. */
|
||||
|
||||
|
||||
/*
|
||||
* Various constants
|
||||
|
@ -152,6 +155,9 @@
|
|||
#define SSL_TRUNC_HMAC_ENABLED 1
|
||||
#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.
|
||||
* 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_CLIENT_HELLO 1
|
||||
#define SSL_HS_SERVER_HELLO 2
|
||||
#define SSL_HS_NEW_SESSION_TICKET 4
|
||||
#define SSL_HS_CERTIFICATE 11
|
||||
#define SSL_HS_SERVER_KEY_EXCHANGE 12
|
||||
#define SSL_HS_CERTIFICATE_REQUEST 13
|
||||
|
@ -262,6 +269,8 @@
|
|||
|
||||
#define TLS_EXT_SIG_ALG 13
|
||||
|
||||
#define TLS_EXT_SESSION_TICKET 35
|
||||
|
||||
#define TLS_EXT_RENEGOTIATION_INFO 0xFF01
|
||||
|
||||
/*
|
||||
|
@ -311,7 +320,8 @@ typedef enum
|
|||
SSL_SERVER_FINISHED,
|
||||
SSL_FLUSH_BUFFERS,
|
||||
SSL_HANDSHAKE_WRAPUP,
|
||||
SSL_HANDSHAKE_OVER
|
||||
SSL_HANDSHAKE_OVER,
|
||||
SSL_SERVER_NEW_SESSION_TICKET,
|
||||
}
|
||||
ssl_states;
|
||||
|
||||
|
@ -319,6 +329,9 @@ typedef struct _ssl_session ssl_session;
|
|||
typedef struct _ssl_context ssl_context;
|
||||
typedef struct _ssl_transform ssl_transform;
|
||||
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.
|
||||
|
@ -338,6 +351,12 @@ struct _ssl_session
|
|||
x509_cert *peer_cert; /*!< peer X.509 cert chain */
|
||||
#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 */
|
||||
int trunc_hmac; /*!< flag for truncated hmac activation */
|
||||
};
|
||||
|
@ -428,8 +447,25 @@ struct _ssl_handshake_params
|
|||
int resume; /*!< session resume indicator*/
|
||||
int max_major_ver; /*!< max. major 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
|
||||
{
|
||||
/*
|
||||
|
@ -538,6 +574,13 @@ struct _ssl_context
|
|||
const char *peer_cn; /*!< expected peer CN */
|
||||
#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
|
||||
*/
|
||||
|
@ -549,6 +592,7 @@ struct _ssl_context
|
|||
int allow_legacy_renegotiation; /*!< allow legacy renegotiation */
|
||||
const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */
|
||||
int trunc_hmac; /*!< negotiate truncated hmac? */
|
||||
int session_tickets; /*!< use session tickets? */
|
||||
|
||||
#if defined(POLARSSL_DHM_C)
|
||||
mpi dhm_P; /*!< prime modulus for DHM */
|
||||
|
@ -655,6 +699,9 @@ int ssl_session_reset( ssl_context *ssl );
|
|||
*
|
||||
* \param ssl SSL context
|
||||
* \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 );
|
||||
|
||||
|
@ -774,15 +821,17 @@ void ssl_set_session_cache( ssl_context *ssl,
|
|||
* \brief Request resumption of session (client-side only)
|
||||
* 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 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
|
||||
|
@ -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 );
|
||||
|
||||
#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
|
||||
* 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 );
|
||||
#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
|
||||
*
|
||||
|
|
|
@ -369,6 +369,8 @@ void polarssl_strerror( int ret, char *buf, size_t buflen )
|
|||
snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" );
|
||||
if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION) )
|
||||
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 */
|
||||
|
||||
#if defined(POLARSSL_X509_PARSE_C)
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
#include "polarssl/debug.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 <stdio.h>
|
||||
|
||||
|
@ -315,6 +322,43 @@ static void ssl_write_truncated_hmac_ext( ssl_context *ssl,
|
|||
*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 )
|
||||
{
|
||||
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 ||
|
||||
ssl->handshake->resume == 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;
|
||||
|
||||
|
@ -488,6 +552,11 @@ static int ssl_write_client_hello( ssl_context *ssl )
|
|||
ssl_write_truncated_hmac_ext( ssl, p + 2 + 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",
|
||||
ext_len ) );
|
||||
|
||||
|
@ -587,6 +656,25 @@ static int ssl_parse_truncated_hmac_ext( ssl_context *ssl,
|
|||
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 )
|
||||
{
|
||||
uint32_t t;
|
||||
|
@ -825,6 +913,19 @@ static int ssl_parse_server_hello( ssl_context *ssl )
|
|||
|
||||
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:
|
||||
SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
|
||||
ext_id ) );
|
||||
|
@ -1834,6 +1935,100 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
|
|||
!POLARSSL_KEY_EXCHANGE_DHE_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
|
||||
*/
|
||||
|
@ -1917,10 +2112,16 @@ int ssl_handshake_client_step( ssl_context *ssl )
|
|||
break;
|
||||
|
||||
/*
|
||||
* <== ChangeCipherSpec
|
||||
* <== ( NewSessionTicket )
|
||||
* ChangeCipherSpec
|
||||
* Finished
|
||||
*/
|
||||
case SSL_SERVER_CHANGE_CIPHER_SPEC:
|
||||
#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;
|
||||
|
||||
|
|
|
@ -33,6 +33,13 @@
|
|||
#include "polarssl/ecp.h"
|
||||
#endif
|
||||
|
||||
#if defined(POLARSSL_MEMORY_C)
|
||||
#include "polarssl/memory.h"
|
||||
#else
|
||||
#define polarssl_malloc malloc
|
||||
#define polarssl_free free
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -40,6 +47,262 @@
|
|||
#include <time.h>
|
||||
#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,
|
||||
const unsigned char *buf,
|
||||
size_t len )
|
||||
|
@ -323,6 +586,50 @@ static int ssl_parse_truncated_hmac_ext( ssl_context *ssl,
|
|||
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)
|
||||
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];
|
||||
|
||||
if( n < 45 || n > 512 )
|
||||
if( n < 45 || n > 2048 )
|
||||
{
|
||||
SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
|
||||
return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
|
||||
|
@ -873,6 +1180,16 @@ static int ssl_parse_client_hello( ssl_context *ssl )
|
|||
return( ret );
|
||||
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:
|
||||
SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
|
||||
ext_id ) );
|
||||
|
@ -1005,6 +1322,31 @@ static void ssl_write_truncated_hmac_ext( ssl_context *ssl,
|
|||
*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,
|
||||
unsigned char *buf,
|
||||
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 );
|
||||
|
||||
/*
|
||||
* 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
|
||||
* Resume is 0 by default, see ssl_handshake_init().
|
||||
* It may be already set to 1 by ssl_parse_session_ticket_ext().
|
||||
* If not, try looking up session ID in our cache.
|
||||
*/
|
||||
ssl->session_negotiate->length = n = 32;
|
||||
*p++ = (unsigned char) ssl->session_negotiate->length;
|
||||
if( ssl->handshake->resume == 0 &&
|
||||
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 ||
|
||||
ssl->f_get_cache == NULL ||
|
||||
ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) != 0 )
|
||||
if( ssl->handshake->resume == 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++;
|
||||
|
||||
#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,
|
||||
n ) ) != 0 )
|
||||
return( ret );
|
||||
#endif /* POLARSSL_SSL_SESSION_TICKETS */
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Found a matching session, resuming it
|
||||
* Resuming a session
|
||||
*/
|
||||
ssl->handshake->resume = 1;
|
||||
ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
|
||||
|
||||
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 );
|
||||
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 );
|
||||
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 ) );
|
||||
|
||||
*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_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
|
||||
*/
|
||||
|
@ -2197,10 +2621,16 @@ int ssl_handshake_server_step( ssl_context *ssl )
|
|||
break;
|
||||
|
||||
/*
|
||||
* ==> ChangeCipherSpec
|
||||
* ==> ( NewSessionTicket )
|
||||
* ChangeCipherSpec
|
||||
* Finished
|
||||
*/
|
||||
case SSL_SERVER_CHANGE_CIPHER_SPEC:
|
||||
#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;
|
||||
|
||||
|
|
|
@ -76,6 +76,44 @@ static unsigned int mfl_code_to_length[SSL_MAX_FRAG_LEN_INVALID] =
|
|||
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)
|
||||
int (*ssl_hw_record_init)(ssl_context *ssl,
|
||||
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 )
|
||||
{
|
||||
int resume = ssl->handshake->resume;
|
||||
|
||||
SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) );
|
||||
|
||||
/*
|
||||
|
@ -2570,9 +2610,13 @@ void ssl_handshake_wrapup( ssl_context *ssl )
|
|||
/*
|
||||
* 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 )
|
||||
SSL_DEBUG_MSG( 1, ( "cache did not store session" ) );
|
||||
}
|
||||
|
||||
ssl->state++;
|
||||
|
||||
|
@ -2930,12 +2974,50 @@ int ssl_session_reset( ssl_context *ssl )
|
|||
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
|
||||
*/
|
||||
void ssl_set_endpoint( ssl_context *ssl, int 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 )
|
||||
|
@ -2989,10 +3071,24 @@ void ssl_set_session_cache( ssl_context *ssl,
|
|||
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;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
*/
|
||||
|
@ -3222,6 +3333,19 @@ const x509_cert *ssl_get_peer_cert( const ssl_context *ssl )
|
|||
}
|
||||
#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
|
||||
*/
|
||||
|
@ -3540,6 +3664,10 @@ void ssl_session_free( ssl_session *session )
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(POLARSSL_SSL_SESSION_TICKETS)
|
||||
polarssl_free( session->ticket );
|
||||
#endif
|
||||
|
||||
memset( session, 0, sizeof( ssl_session ) );
|
||||
}
|
||||
|
||||
|
@ -3590,6 +3718,10 @@ void ssl_free( ssl_context *ssl )
|
|||
polarssl_free( ssl->session );
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_SSL_SESSION_TICKETS)
|
||||
polarssl_free( ssl->ticket_keys );
|
||||
#endif
|
||||
|
||||
if ( ssl->hostname != NULL)
|
||||
{
|
||||
memset( ssl->hostname, 0, ssl->hostname_len );
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL
|
||||
#define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE
|
||||
#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-" \
|
||||
"-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 */
|
||||
unsigned char mfl_code; /* code for maximum fragment length */
|
||||
int trunc_hmac; /* negotiate truncated hmac or not */
|
||||
int reconnect; /* attempt to resume session */
|
||||
int tickets; /* enable / disable session tickets */
|
||||
} opt;
|
||||
|
||||
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 ""
|
||||
#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 \
|
||||
"\n usage: ssl_client2 param=<>...\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" \
|
||||
" renegotiation=%%d default: 1 (enabled)\n" \
|
||||
" allow_legacy=%%d default: 0 (disabled)\n" \
|
||||
" reconnect=%%d default: 0 (disabled)\n" \
|
||||
USAGE_TICKETS \
|
||||
"\n" \
|
||||
" min_version=%%s default: \"\" (ssl3)\n" \
|
||||
" max_version=%%s default: \"\" (tls1_2)\n" \
|
||||
|
@ -226,6 +239,7 @@ int main( int argc, char *argv[] )
|
|||
entropy_context entropy;
|
||||
ctr_drbg_context ctr_drbg;
|
||||
ssl_context ssl;
|
||||
ssl_session saved_session;
|
||||
#if defined(POLARSSL_X509_PARSE_C)
|
||||
x509_cert cacert;
|
||||
x509_cert clicert;
|
||||
|
@ -239,6 +253,7 @@ int main( int argc, char *argv[] )
|
|||
*/
|
||||
server_fd = 0;
|
||||
memset( &ssl, 0, sizeof( ssl_context ) );
|
||||
memset( &saved_session, 0, sizeof( ssl_session ) );
|
||||
#if defined(POLARSSL_X509_PARSE_C)
|
||||
memset( &cacert, 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.mfl_code = DFL_MFL_CODE;
|
||||
opt.trunc_hmac = DFL_TRUNC_HMAC;
|
||||
opt.reconnect = DFL_RECONNECT;
|
||||
opt.tickets = DFL_TICKETS;
|
||||
|
||||
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 )
|
||||
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 )
|
||||
{
|
||||
if( strcmp( q, "ssl3" ) == 0 )
|
||||
|
@ -652,6 +681,10 @@ int main( int argc, char *argv[] )
|
|||
ssl_set_bio( &ssl, net_recv, &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 )
|
||||
ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
|
||||
|
||||
|
@ -693,6 +726,20 @@ int main( int argc, char *argv[] )
|
|||
printf( " ok\n [ Ciphersuite is %s ]\n",
|
||||
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)
|
||||
/*
|
||||
* 5. Verify the server certificate
|
||||
|
@ -732,6 +779,7 @@ int main( int argc, char *argv[] )
|
|||
/*
|
||||
* 6. Write the GET request
|
||||
*/
|
||||
send_request:
|
||||
printf( " > Write to server:" );
|
||||
fflush( stdout );
|
||||
|
||||
|
@ -789,6 +837,43 @@ int main( int argc, char *argv[] )
|
|||
|
||||
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:
|
||||
|
||||
#ifdef POLARSSL_ERROR_C
|
||||
|
@ -807,6 +892,7 @@ exit:
|
|||
x509_free( &cacert );
|
||||
rsa_free( &rsa );
|
||||
#endif
|
||||
ssl_session_free( &saved_session );
|
||||
ssl_free( &ssl );
|
||||
|
||||
memset( &ssl, 0, sizeof( ssl ) );
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#define DFL_MAX_VERSION -1
|
||||
#define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL
|
||||
#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" \
|
||||
"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 auth_mode; /* verify mode for connection */
|
||||
unsigned char mfl_code; /* code for maximum fragment length */
|
||||
int tickets; /* enable / disable session tickets */
|
||||
} opt;
|
||||
|
||||
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 ""
|
||||
#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 \
|
||||
"\n usage: ssl_server2 param=<>...\n" \
|
||||
"\n acceptable parameters:\n" \
|
||||
|
@ -152,6 +161,7 @@ static void my_debug( void *ctx, int level, const char *str )
|
|||
USAGE_IO \
|
||||
" request_page=%%s default: \".\"\n" \
|
||||
" renegotiation=%%d default: 1 (enabled)\n" \
|
||||
USAGE_TICKETS \
|
||||
" allow_legacy=%%d default: 0 (disabled)\n" \
|
||||
" min_version=%%s default: \"ssl3\"\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.auth_mode = DFL_AUTH_MODE;
|
||||
opt.mfl_code = DFL_MFL_CODE;
|
||||
opt.tickets = DFL_TICKETS;
|
||||
|
||||
for( i = 1; i < argc; i++ )
|
||||
{
|
||||
|
@ -396,6 +407,12 @@ int main( int argc, char *argv[] )
|
|||
else
|
||||
goto usage;
|
||||
}
|
||||
else if( strcmp( p, "tickets" ) == 0 )
|
||||
{
|
||||
opt.tickets = atoi( q );
|
||||
if( opt.tickets < 0 || opt.tickets > 1 )
|
||||
goto usage;
|
||||
}
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
|
@ -611,6 +628,10 @@ int main( int argc, char *argv[] )
|
|||
ssl_cache_set, &cache );
|
||||
#endif
|
||||
|
||||
#if defined(POLARSSL_SSL_SESSION_TICKETS)
|
||||
ssl_set_session_tickets( &ssl, opt.tickets );
|
||||
#endif
|
||||
|
||||
if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
|
||||
ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
|
||||
|
||||
|
|
Loading…
Reference in a new issue