@ -54,6 +54,10 @@
# define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
# define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
# ifndef TSI_OPENSSL_ALPN_SUPPORT
# define TSI_OPENSSL_ALPN_SUPPORT 1
# endif
/* TODO(jboeuf): I have not found a way to get this number dynamically from the
* SSL structure . This is what we would ultimately want though . . . */
# define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
@ -70,6 +74,8 @@ struct tsi_ssl_handshaker_factory {
typedef struct {
tsi_ssl_handshaker_factory base ;
SSL_CTX * ssl_context ;
unsigned char * alpn_protocol_list ;
size_t alpn_protocol_list_length ;
} tsi_ssl_client_handshaker_factory ;
typedef struct {
@ -841,7 +847,7 @@ static tsi_result ssl_handshaker_process_bytes_from_peer(
static tsi_result ssl_handshaker_extract_peer ( tsi_handshaker * self ,
tsi_peer * peer ) {
tsi_result result = TSI_OK ;
const unsigned char * alpn_selected ;
const unsigned char * alpn_selected = NULL ;
unsigned int alpn_selected_len ;
tsi_ssl_handshaker * impl = ( tsi_ssl_handshaker * ) self ;
X509 * peer_cert = SSL_get_peer_certificate ( impl - > ssl ) ;
@ -850,7 +856,14 @@ static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
X509_free ( peer_cert ) ;
if ( result ! = TSI_OK ) return result ;
}
# if TSI_OPENSSL_ALPN_SUPPORT
SSL_get0_alpn_selected ( impl - > ssl , & alpn_selected , & alpn_selected_len ) ;
# endif /* TSI_OPENSSL_ALPN_SUPPORT */
if ( alpn_selected = = NULL ) {
/* Try npn. */
SSL_get0_next_proto_negotiated ( impl - > ssl , & alpn_selected ,
& alpn_selected_len ) ;
}
if ( alpn_selected ! = NULL ) {
size_t i ;
tsi_peer_property * new_properties =
@ -1012,6 +1025,32 @@ static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
return TSI_OK ;
}
static int select_protocol_list ( const unsigned char * * out ,
unsigned char * outlen ,
const unsigned char * client_list ,
unsigned int client_list_len ,
const unsigned char * server_list ,
unsigned int server_list_len ) {
const unsigned char * client_current = client_list ;
while ( ( unsigned int ) ( client_current - client_list ) < client_list_len ) {
unsigned char client_current_len = * ( client_current + + ) ;
const unsigned char * server_current = server_list ;
while ( ( server_current > = server_list ) & &
( gpr_uintptr ) ( server_current - server_list ) < server_list_len ) {
unsigned char server_current_len = * ( server_current + + ) ;
if ( ( client_current_len = = server_current_len ) & &
! memcmp ( client_current , server_current , server_current_len ) ) {
* out = server_current ;
* outlen = server_current_len ;
return SSL_TLSEXT_ERR_OK ;
}
server_current + = server_current_len ;
}
client_current + = client_current_len ;
}
return SSL_TLSEXT_ERR_NOACK ;
}
/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
static tsi_result ssl_client_handshaker_factory_create_handshaker (
@ -1027,10 +1066,21 @@ static void ssl_client_handshaker_factory_destroy(
tsi_ssl_handshaker_factory * self ) {
tsi_ssl_client_handshaker_factory * impl =
( tsi_ssl_client_handshaker_factory * ) self ;
SSL_CTX_free ( impl - > ssl_context ) ;
if ( impl - > ssl_context ! = NULL ) SSL_CTX_free ( impl - > ssl_context ) ;
if ( impl - > alpn_protocol_list ! = NULL ) free ( impl - > alpn_protocol_list ) ;
free ( impl ) ;
}
static int client_handshaker_factory_npn_callback (
SSL * ssl , unsigned char * * out , unsigned char * outlen ,
const unsigned char * in , unsigned int inlen , void * arg ) {
tsi_ssl_client_handshaker_factory * factory =
( tsi_ssl_client_handshaker_factory * ) arg ;
return select_protocol_list ( ( const unsigned char * * ) out , outlen ,
factory - > alpn_protocol_list ,
factory - > alpn_protocol_list_length , in , inlen ) ;
}
/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
static tsi_result ssl_server_handshaker_factory_create_handshaker (
@ -1134,30 +1184,25 @@ static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap,
return SSL_TLSEXT_ERR_ALERT_WARNING ;
}
# if TSI_OPENSSL_ALPN_SUPPORT
static int server_handshaker_factory_alpn_callback (
SSL * ssl , const unsigned char * * out , unsigned char * outlen ,
const unsigned char * in , unsigned int inlen , void * arg ) {
tsi_ssl_server_handshaker_factory * factory =
( tsi_ssl_server_handshaker_factory * ) arg ;
const unsigned char * client_current = in ;
while ( ( unsigned int ) ( client_current - in ) < inlen ) {
unsigned char client_current_len = * ( client_current + + ) ;
const unsigned char * server_current = factory - > alpn_protocol_list ;
while ( ( server_current > = factory - > alpn_protocol_list ) & &
( gpr_uintptr ) ( server_current - factory - > alpn_protocol_list ) <
factory - > alpn_protocol_list_length ) {
unsigned char server_current_len = * ( server_current + + ) ;
if ( ( client_current_len = = server_current_len ) & &
! memcmp ( client_current , server_current , server_current_len ) ) {
* out = server_current ;
* outlen = server_current_len ;
return SSL_TLSEXT_ERR_OK ;
}
server_current + = server_current_len ;
}
client_current + = client_current_len ;
}
return SSL_TLSEXT_ERR_NOACK ;
return select_protocol_list ( out , outlen , in , inlen ,
factory - > alpn_protocol_list ,
factory - > alpn_protocol_list_length ) ;
}
# endif /* TSI_OPENSSL_ALPN_SUPPORT */
static int server_handshaker_factory_npn_advertised_callback (
SSL * ssl , const unsigned char * * out , unsigned int * outlen , void * arg ) {
tsi_ssl_server_handshaker_factory * factory =
( tsi_ssl_server_handshaker_factory * ) arg ;
* out = factory - > alpn_protocol_list ;
* outlen = factory - > alpn_protocol_list_length ;
return SSL_TLSEXT_ERR_OK ;
}
/* --- tsi_ssl_handshaker_factory constructors. --- */
@ -1184,6 +1229,14 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
gpr_log ( GPR_ERROR , " Could not create ssl context. " ) ;
return TSI_INVALID_ARGUMENT ;
}
impl = calloc ( 1 , sizeof ( tsi_ssl_client_handshaker_factory ) ) ;
if ( impl = = NULL ) {
SSL_CTX_free ( ssl_context ) ;
return TSI_OUT_OF_RESOURCES ;
}
impl - > ssl_context = ssl_context ;
do {
result =
populate_ssl_context ( ssl_context , pem_private_key , pem_private_key_size ,
@ -1197,41 +1250,33 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
}
if ( num_alpn_protocols ! = 0 ) {
unsigned char * alpn_protocol_list = NULL ;
size_t alpn_protocol_list_length = 0 ;
int ssl_failed ;
result = build_alpn_protocol_name_list (
alpn_protocols , alpn_protocols_lengths , num_alpn_protocols ,
& alpn_protocol_list , & alpn_protocol_list_length ) ;
& impl - > alpn_protocol_list , & impl - > alpn_protocol_list_length ) ;
if ( result ! = TSI_OK ) {
gpr_log ( GPR_ERROR , " Building alpn list failed with error %s. " ,
tsi_result_to_string ( result ) ) ;
free ( alpn_protocol_list ) ;
break ;
}
ssl_failed = SSL_CTX_set_alpn_protos ( ssl_context , alpn_protocol_list ,
alpn_protocol_list_length ) ;
free ( alpn_protocol_list ) ;
if ( ssl_failed ) {
# if TSI_OPENSSL_ALPN_SUPPORT
if ( SSL_CTX_set_alpn_protos ( ssl_context , impl - > alpn_protocol_list ,
impl - > alpn_protocol_list_length ) ) {
gpr_log ( GPR_ERROR , " Could not set alpn protocol list to context. " ) ;
result = TSI_INVALID_ARGUMENT ;
break ;
}
# endif /* TSI_OPENSSL_ALPN_SUPPORT */
SSL_CTX_set_next_proto_select_cb (
ssl_context , client_handshaker_factory_npn_callback , impl ) ;
}
} while ( 0 ) ;
if ( result ! = TSI_OK ) {
SSL_CTX_free ( ssl_context ) ;
ssl_client_handshaker_factory_destroy ( & impl - > base ) ;
return result ;
}
SSL_CTX_set_verify ( ssl_context , SSL_VERIFY_PEER , NULL ) ;
/* TODO(jboeuf): Add revocation verification. */
impl = calloc ( 1 , sizeof ( tsi_ssl_client_handshaker_factory ) ) ;
if ( impl = = NULL ) {
SSL_CTX_free ( ssl_context ) ;
return TSI_OUT_OF_RESOURCES ;
}
impl - > ssl_context = ssl_context ;
impl - > base . create_handshaker =
ssl_client_handshaker_factory_create_handshaker ;
impl - > base . destroy = ssl_client_handshaker_factory_destroy ;
@ -1322,8 +1367,13 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
impl - > ssl_contexts [ i ] ,
ssl_server_handshaker_factory_servername_callback ) ;
SSL_CTX_set_tlsext_servername_arg ( impl - > ssl_contexts [ i ] , impl ) ;
# if TSI_OPENSSL_ALPN_SUPPORT
SSL_CTX_set_alpn_select_cb ( impl - > ssl_contexts [ i ] ,
server_handshaker_factory_alpn_callback , impl ) ;
# endif /* TSI_OPENSSL_ALPN_SUPPORT */
SSL_CTX_set_next_protos_advertised_cb (
impl - > ssl_contexts [ i ] ,
server_handshaker_factory_npn_advertised_callback , impl ) ;
} while ( 0 ) ;
if ( result ! = TSI_OK ) {