2016-03-25 23:17:28 +03:00
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
# include <stdlib.h>
# include "openssl/ssl.h"
# include "openssl/err.h"
# include "openssl/crypto.h"
2016-06-03 11:20:28 +03:00
# include "openssl/opensslv.h"
2016-03-25 23:17:28 +03:00
# include <stdio.h>
# include <stdbool.h>
2016-09-15 09:09:13 +03:00
# include <stdint.h>
2016-06-03 11:20:28 +03:00
# include "azure_c_shared_utility/lock.h"
2016-04-06 06:50:09 +03:00
# include "azure_c_shared_utility/tlsio.h"
# include "azure_c_shared_utility/tlsio_openssl.h"
# include "azure_c_shared_utility/socketio.h"
2017-02-14 21:30:33 +03:00
# include "azure_c_shared_utility/optimize_size.h"
2016-06-20 19:55:56 +03:00
# include "azure_c_shared_utility/xlogging.h"
2016-05-05 03:08:08 +03:00
# include "azure_c_shared_utility/crt_abstractions.h"
2016-07-18 19:09:10 +03:00
# include "azure_c_shared_utility/x509_openssl.h"
2017-03-31 02:03:10 +03:00
# include "azure_c_shared_utility/shared_util_options.h"
2017-12-22 03:06:13 +03:00
# include "azure_c_shared_utility/gballoc.h"
2018-02-07 19:57:32 +03:00
# include "azure_c_shared_utility/const_defines.h"
2017-11-11 03:51:59 +03:00
2016-03-25 23:17:28 +03:00
typedef enum TLSIO_STATE_TAG
{
TLSIO_STATE_NOT_OPEN ,
TLSIO_STATE_OPENING_UNDERLYING_IO ,
TLSIO_STATE_IN_HANDSHAKE ,
2017-07-05 20:40:00 +03:00
// TLSIO_STATE_HANDSHAKE_FAILED is an ephemeral state signalling successful socket
// operation but with rejected handshake. The tlsio will never be in this state
// at the start of any of the API calls.
TLSIO_STATE_HANDSHAKE_FAILED ,
2016-03-25 23:17:28 +03:00
TLSIO_STATE_OPEN ,
TLSIO_STATE_CLOSING ,
TLSIO_STATE_ERROR
} TLSIO_STATE ;
2017-08-05 00:23:04 +03:00
typedef enum TLSIO_VERSION_TAG
{
VERSION_1_0 ,
VERSION_1_1 ,
VERSION_1_2 ,
} TLSIO_VERSION ;
2017-07-05 20:40:00 +03:00
static bool is_an_opening_state ( TLSIO_STATE state )
{
2018-09-07 01:34:57 +03:00
// TLSIO_STATE_HANDSHAKE_FAILED is deliberately not one of these states.
2017-07-05 20:40:00 +03:00
return state = = TLSIO_STATE_OPENING_UNDERLYING_IO | |
state = = TLSIO_STATE_IN_HANDSHAKE ;
}
2016-08-24 04:47:34 +03:00
typedef int ( * TLS_CERTIFICATE_VALIDATION_CALLBACK ) ( X509_STORE_CTX * , void * ) ;
2016-03-25 23:17:28 +03:00
typedef struct TLS_IO_INSTANCE_TAG
{
XIO_HANDLE underlying_io ;
ON_BYTES_RECEIVED on_bytes_received ;
ON_IO_OPEN_COMPLETE on_io_open_complete ;
ON_IO_CLOSE_COMPLETE on_io_close_complete ;
ON_IO_ERROR on_io_error ;
void * on_bytes_received_context ;
void * on_io_open_complete_context ;
void * on_io_close_complete_context ;
void * on_io_error_context ;
SSL * ssl ;
SSL_CTX * ssl_context ;
BIO * in_bio ;
BIO * out_bio ;
TLSIO_STATE tlsio_state ;
2016-05-05 03:08:08 +03:00
char * certificate ;
2018-04-30 22:39:06 +03:00
char * cipher_list ;
2018-03-24 04:18:14 +03:00
const char * x509_certificate ;
const char * x509_private_key ;
2017-08-05 00:23:04 +03:00
TLSIO_VERSION tls_version ;
2016-12-06 17:44:57 +03:00
TLS_CERTIFICATE_VALIDATION_CALLBACK tls_validation_callback ;
void * tls_validation_callback_data ;
2016-03-25 23:17:28 +03:00
} TLS_IO_INSTANCE ;
2017-07-05 20:40:00 +03:00
struct CRYPTO_dynlock_value
2016-06-03 11:20:28 +03:00
{
2017-07-05 20:40:00 +03:00
LOCK_HANDLE lock ;
2016-06-03 11:20:28 +03:00
} ;
2018-03-24 04:18:14 +03:00
static const char * const OPTION_UNDERLYING_IO_OPTIONS = " underlying_io_options " ;
2017-06-30 08:16:32 +03:00
# define SSL_DO_HANDSHAKE_SUCCESS 1
2017-05-11 23:36:01 +03:00
2016-07-21 04:47:38 +03:00
/*this function will clone an option given by name and value*/
static void * tlsio_openssl_CloneOption ( const char * name , const void * value )
{
void * result ;
2017-07-05 20:40:00 +03:00
if (
2016-07-21 04:47:38 +03:00
( name = = NULL ) | | ( value = = NULL )
2017-07-05 20:40:00 +03:00
)
2016-07-21 04:47:38 +03:00
{
LogError ( " invalid parameter detected: const char* name=%p, const void* value=%p " , name , value ) ;
result = NULL ;
}
else
{
2017-05-11 23:36:01 +03:00
if ( strcmp ( name , OPTION_UNDERLYING_IO_OPTIONS ) = = 0 )
2017-05-10 22:19:20 +03:00
{
result = ( void * ) value ;
}
2017-12-22 03:06:13 +03:00
else if ( strcmp ( name , OPTION_TRUSTED_CERT ) = = 0 )
2016-07-21 04:47:38 +03:00
{
2017-07-05 20:40:00 +03:00
if ( mallocAndStrcpy_s ( ( char * * ) & result , value ) ! = 0 )
2016-07-21 04:47:38 +03:00
{
LogError ( " unable to mallocAndStrcpy_s TrustedCerts value " ) ;
result = NULL ;
}
else
{
/*return as is*/
}
}
2018-06-08 02:25:41 +03:00
else if ( strcmp ( name , OPTION_OPENSSL_CIPHER_SUITE ) = = 0 )
2018-04-30 22:39:06 +03:00
{
if ( mallocAndStrcpy_s ( ( char * * ) & result , value ) ! = 0 )
{
LogError ( " unable to mallocAndStrcpy_s CipherSuite value " ) ;
result = NULL ;
}
else
{
/*return as is*/
}
}
2017-03-31 02:03:10 +03:00
else if ( strcmp ( name , SU_OPTION_X509_CERT ) = = 0 )
2016-07-21 04:47:38 +03:00
{
if ( mallocAndStrcpy_s ( ( char * * ) & result , value ) ! = 0 )
{
LogError ( " unable to mallocAndStrcpy_s x509certificate value " ) ;
result = NULL ;
}
else
{
/*return as is*/
}
}
2017-03-31 02:03:10 +03:00
else if ( strcmp ( name , SU_OPTION_X509_PRIVATE_KEY ) = = 0 )
2016-07-21 04:47:38 +03:00
{
if ( mallocAndStrcpy_s ( ( char * * ) & result , value ) ! = 0 )
{
LogError ( " unable to mallocAndStrcpy_s x509privatekey value " ) ;
result = NULL ;
}
else
{
/*return as is*/
}
}
2017-03-31 02:03:10 +03:00
else if ( strcmp ( name , OPTION_X509_ECC_CERT ) = = 0 )
{
if ( mallocAndStrcpy_s ( ( char * * ) & result , value ) ! = 0 )
{
LogError ( " unable to mallocAndStrcpy_s x509EccCertificate value " ) ;
result = NULL ;
}
else
{
/*return as is*/
}
}
else if ( strcmp ( name , OPTION_X509_ECC_KEY ) = = 0 )
{
if ( mallocAndStrcpy_s ( ( char * * ) & result , value ) ! = 0 )
{
LogError ( " unable to mallocAndStrcpy_s x509EccKey value " ) ;
result = NULL ;
}
else
{
/*return as is*/
}
}
2017-11-11 03:51:59 +03:00
else if ( strcmp ( name , OPTION_TLS_VERSION ) = = 0 )
{
2017-11-13 21:29:02 +03:00
int int_value ;
2018-09-07 01:34:57 +03:00
2017-11-13 21:29:02 +03:00
if ( * ( TLSIO_VERSION * ) value = = VERSION_1_0 )
{
int_value = 10 ;
}
else if ( * ( TLSIO_VERSION * ) value = = VERSION_1_1 )
{
int_value = 11 ;
}
else if ( * ( TLSIO_VERSION * ) value = = VERSION_1_2 )
{
int_value = 12 ;
}
else
{
LogError ( " Unexpected TLS version value (%d) " , * ( int * ) value ) ;
int_value = - 1 ;
}
2018-09-07 01:34:57 +03:00
2017-11-13 21:29:02 +03:00
if ( int_value < 0 )
2017-11-11 03:51:59 +03:00
{
result = NULL ;
}
else
{
2017-11-13 21:29:02 +03:00
int * value_clone ;
if ( ( value_clone = ( int * ) malloc ( sizeof ( int ) ) ) = = NULL )
2017-11-11 03:51:59 +03:00
{
2017-11-13 21:29:02 +03:00
LogError ( " Failed clonning tls_version option " ) ;
2017-11-11 03:51:59 +03:00
}
else
{
2017-11-13 21:29:02 +03:00
* value_clone = int_value ;
2017-11-11 03:51:59 +03:00
}
2018-09-07 01:34:57 +03:00
2017-11-11 03:51:59 +03:00
result = value_clone ;
}
}
2016-12-06 17:44:57 +03:00
else if (
( strcmp ( name , " tls_validation_callback " ) = = 0 ) | |
( strcmp ( name , " tls_validation_callback_data " ) = = 0 )
)
{
result = ( void * ) value ;
}
2016-07-21 04:47:38 +03:00
else
{
LogError ( " not handled option : %s " , name ) ;
result = NULL ;
}
}
return result ;
}
/*this function destroys an option previously created*/
static void tlsio_openssl_DestroyOption ( const char * name , const void * value )
{
/*since all options for this layer are actually string copies., disposing of one is just calling free*/
if (
( name = = NULL ) | | ( value = = NULL )
)
{
LogError ( " invalid parameter detected: const char* name=%p, const void* value=%p " , name , value ) ;
}
2016-12-06 17:44:57 +03:00
else
{
if (
2017-12-22 03:06:13 +03:00
( strcmp ( name , OPTION_TRUSTED_CERT ) = = 0 ) | |
2018-06-08 02:25:41 +03:00
( strcmp ( name , OPTION_OPENSSL_CIPHER_SUITE ) = = 0 ) | |
2017-03-31 02:03:10 +03:00
( strcmp ( name , SU_OPTION_X509_CERT ) = = 0 ) | |
( strcmp ( name , SU_OPTION_X509_PRIVATE_KEY ) = = 0 ) | |
( strcmp ( name , OPTION_X509_ECC_CERT ) = = 0 ) | |
2017-11-11 03:51:59 +03:00
( strcmp ( name , OPTION_X509_ECC_KEY ) = = 0 ) | |
( strcmp ( name , OPTION_TLS_VERSION ) = = 0 )
2016-12-06 17:44:57 +03:00
)
{
free ( ( void * ) value ) ;
}
else if (
( strcmp ( name , " tls_validation_callback " ) = = 0 ) | |
( strcmp ( name , " tls_validation_callback_data " ) = = 0 )
)
{
// nothing to free.
}
2017-05-11 23:36:01 +03:00
else if ( strcmp ( name , OPTION_UNDERLYING_IO_OPTIONS ) = = 0 )
2017-05-10 22:19:20 +03:00
{
OptionHandler_Destroy ( ( OPTIONHANDLER_HANDLE ) value ) ;
}
2016-07-21 04:47:38 +03:00
else
{
LogError ( " not handled option : %s " , name ) ;
}
}
}
static OPTIONHANDLER_HANDLE tlsio_openssl_retrieveoptions ( CONCRETE_IO_HANDLE handle )
{
OPTIONHANDLER_HANDLE result ;
2017-07-05 20:40:00 +03:00
if ( handle = = NULL )
2016-07-21 04:47:38 +03:00
{
LogError ( " invalid parameter detected: CONCRETE_IO_HANDLE handle=%p " , handle ) ;
result = NULL ;
}
else
{
result = OptionHandler_Create ( tlsio_openssl_CloneOption , tlsio_openssl_DestroyOption , tlsio_openssl_setoption ) ;
if ( result = = NULL )
{
LogError ( " unable to OptionHandler_Create " ) ;
/*return as is*/
}
else
{
/*this layer cares about the certificates and the x509 credentials*/
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) handle ;
2017-05-10 22:19:20 +03:00
OPTIONHANDLER_HANDLE underlying_io_options ;
2017-05-11 23:36:01 +03:00
if ( ( underlying_io_options = xio_retrieveoptions ( tls_io_instance - > underlying_io ) ) = = NULL | |
OptionHandler_AddOption ( result , OPTION_UNDERLYING_IO_OPTIONS , underlying_io_options ) ! = OPTIONHANDLER_OK )
2017-05-10 22:19:20 +03:00
{
LogError ( " unable to save underlying_io options " ) ;
OptionHandler_Destroy ( underlying_io_options ) ;
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
2017-07-05 20:40:00 +03:00
else if (
( tls_io_instance - > certificate ! = NULL ) & &
2017-12-22 03:06:13 +03:00
( OptionHandler_AddOption ( result , OPTION_TRUSTED_CERT , tls_io_instance - > certificate ) ! = OPTIONHANDLER_OK )
2017-07-05 20:40:00 +03:00
)
2016-07-21 04:47:38 +03:00
{
LogError ( " unable to save TrustedCerts option " ) ;
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
2018-04-30 22:39:06 +03:00
else if (
( tls_io_instance - > cipher_list ! = NULL ) & &
2018-06-08 02:25:41 +03:00
( OptionHandler_AddOption ( result , OPTION_OPENSSL_CIPHER_SUITE , tls_io_instance - > cipher_list ) ! = OPTIONHANDLER_OK )
2018-04-30 22:39:06 +03:00
)
{
LogError ( " unable to save CipherSuite option " ) ;
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
2018-03-24 04:18:14 +03:00
else if ( tls_io_instance - > x509_certificate ! = NULL & & ( OptionHandler_AddOption ( result , SU_OPTION_X509_CERT , tls_io_instance - > x509_certificate ) ! = OPTIONHANDLER_OK ) )
2016-07-21 04:47:38 +03:00
{
2018-03-24 04:18:14 +03:00
LogError ( " unable to save x509 certificate option " ) ;
2016-07-21 04:47:38 +03:00
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
2018-03-24 04:18:14 +03:00
else if ( tls_io_instance - > x509_private_key ! = NULL & & ( OptionHandler_AddOption ( result , SU_OPTION_X509_PRIVATE_KEY , tls_io_instance - > x509_private_key ) ! = OPTIONHANDLER_OK ) )
2016-07-21 04:47:38 +03:00
{
2018-03-24 04:18:14 +03:00
LogError ( " unable to save x509 privatekey option " ) ;
2017-03-31 02:03:10 +03:00
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
2016-12-06 17:44:57 +03:00
else if ( tls_io_instance - > tls_version ! = 0 )
{
2017-11-11 03:51:59 +03:00
if ( OptionHandler_AddOption ( result , OPTION_TLS_VERSION , & tls_io_instance - > tls_version ) ! = OPTIONHANDLER_OK )
2016-12-06 17:44:57 +03:00
{
LogError ( " unable to save tls_version option " ) ;
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
}
else if ( tls_io_instance - > tls_validation_callback ! = NULL )
{
2018-02-07 04:12:53 +03:00
# ifdef WIN32
2017-07-05 20:40:00 +03:00
# pragma warning(push)
# pragma warning(disable:4152)
2018-02-07 04:12:53 +03:00
# endif
2016-12-06 17:44:57 +03:00
void * ptr = tls_io_instance - > tls_validation_callback ;
2018-02-07 04:12:53 +03:00
# ifdef WIN32
2017-07-05 20:40:00 +03:00
# pragma warning(pop)
2018-02-07 04:12:53 +03:00
# endif
2017-05-11 23:36:01 +03:00
if ( OptionHandler_AddOption ( result , " tls_validation_callback " , ( const char * ) ptr ) ! = OPTIONHANDLER_OK )
2016-12-06 17:44:57 +03:00
{
LogError ( " unable to save tls_validation_callback option " ) ;
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
2017-05-11 23:36:01 +03:00
if ( OptionHandler_AddOption ( result , " tls_validation_callback_data " , ( const char * ) tls_io_instance - > tls_validation_callback_data ) ! = OPTIONHANDLER_OK )
2016-12-06 17:44:57 +03:00
{
LogError ( " unable to save tls_validation_callback_data option " ) ;
OptionHandler_Destroy ( result ) ;
result = NULL ;
}
}
2016-07-21 04:47:38 +03:00
else
{
/*all is fine, all interesting options have been saved*/
/*return as is*/
}
}
}
return result ;
}
2016-03-25 23:17:28 +03:00
static const IO_INTERFACE_DESCRIPTION tlsio_openssl_interface_description =
{
2016-07-21 04:47:38 +03:00
tlsio_openssl_retrieveoptions ,
2016-03-25 23:17:28 +03:00
tlsio_openssl_create ,
tlsio_openssl_destroy ,
tlsio_openssl_open ,
tlsio_openssl_close ,
tlsio_openssl_send ,
tlsio_openssl_dowork ,
tlsio_openssl_setoption
} ;
2016-06-03 11:20:28 +03:00
static LOCK_HANDLE * openssl_locks = NULL ;
static void openssl_lock_unlock_helper ( LOCK_HANDLE lock , int lock_mode , const char * file , int line )
{
2018-07-23 22:46:03 +03:00
# ifdef NO_LOGGING
// Avoid unused variable warning when logging not compiled in
( void ) file ;
( void ) line ;
# endif
2016-06-03 11:20:28 +03:00
if ( lock_mode & CRYPTO_LOCK )
{
if ( Lock ( lock ) ! = 0 )
{
LogError ( " Failed to lock openssl lock (%s:%d) " , file , line ) ;
}
}
else
{
if ( Unlock ( lock ) ! = 0 )
{
LogError ( " Failed to unlock openssl lock (%s:%d) " , file , line ) ;
}
}
}
static void log_ERR_get_error ( const char * message )
{
char buf [ 128 ] ;
2018-03-06 22:24:13 +03:00
AZURE_UNREFERENCED_PARAMETER ( buf ) ;
2016-06-03 11:20:28 +03:00
unsigned long error ;
2017-07-05 20:40:00 +03:00
int i ;
2016-06-03 11:20:28 +03:00
if ( message ! = NULL )
{
LogError ( " %s " , message ) ;
}
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
error = ERR_get_error ( ) ;
2017-07-05 20:40:00 +03:00
for ( i = 0 ; 0 ! = error ; i + + )
2016-06-03 11:20:28 +03:00
{
LogError ( " [%d] %s " , i , ERR_error_string ( error , buf ) ) ;
error = ERR_get_error ( ) ;
}
}
2018-06-13 03:04:57 +03:00
static STATIC_VAR_UNUSED struct CRYPTO_dynlock_value * openssl_dynamic_locks_create_cb ( const char * file , int line )
2016-06-03 11:20:28 +03:00
{
2018-07-23 22:46:03 +03:00
# ifdef NO_LOGGING
// Avoid unused variable warning when logging not compiled in
( void ) file ;
( void ) line ;
# endif
2016-06-03 11:20:28 +03:00
struct CRYPTO_dynlock_value * result ;
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
result = malloc ( sizeof ( struct CRYPTO_dynlock_value ) ) ;
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
if ( result = = NULL )
{
LogError ( " Failed to allocate lock! Out of memory (%s:%d). " , file , line ) ;
}
else
{
result - > lock = Lock_Init ( ) ;
if ( result - > lock = = NULL )
{
LogError ( " Failed to create lock for dynamic lock (%s:%d). " , file , line ) ;
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
free ( result ) ;
result = NULL ;
}
}
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
return result ;
}
2018-06-13 03:04:57 +03:00
static STATIC_VAR_UNUSED void openssl_dynamic_locks_lock_unlock_cb ( int lock_mode , struct CRYPTO_dynlock_value * dynlock_value , const char * file , int line )
2016-06-03 11:20:28 +03:00
{
openssl_lock_unlock_helper ( dynlock_value - > lock , lock_mode , file , line ) ;
}
2018-06-13 03:04:57 +03:00
static STATIC_VAR_UNUSED void openssl_dynamic_locks_destroy_cb ( struct CRYPTO_dynlock_value * dynlock_value , const char * file , int line )
2016-06-03 11:20:28 +03:00
{
2016-12-06 17:44:57 +03:00
( void ) file ;
( void ) line ;
2016-06-03 11:20:28 +03:00
Lock_Deinit ( dynlock_value - > lock ) ;
free ( dynlock_value ) ;
}
static void openssl_dynamic_locks_uninstall ( void )
{
# if (OPENSSL_VERSION_NUMBER >= 0x00906000)
CRYPTO_set_dynlock_create_callback ( NULL ) ;
CRYPTO_set_dynlock_lock_callback ( NULL ) ;
CRYPTO_set_dynlock_destroy_callback ( NULL ) ;
# endif
}
static void openssl_dynamic_locks_install ( void )
{
# if (OPENSSL_VERSION_NUMBER >= 0x00906000)
CRYPTO_set_dynlock_destroy_callback ( openssl_dynamic_locks_destroy_cb ) ;
CRYPTO_set_dynlock_lock_callback ( openssl_dynamic_locks_lock_unlock_cb ) ;
CRYPTO_set_dynlock_create_callback ( openssl_dynamic_locks_create_cb ) ;
# endif
}
2018-06-13 03:04:57 +03:00
static void STATIC_VAR_UNUSED openssl_static_locks_lock_unlock_cb ( int lock_mode , int lock_index , const char * file , int line )
2016-06-03 11:20:28 +03:00
{
if ( lock_index < 0 | | lock_index > = CRYPTO_num_locks ( ) )
{
LogError ( " Bad lock index %d passed (%s:%d) " , lock_index , file , line ) ;
}
else
{
openssl_lock_unlock_helper ( openssl_locks [ lock_index ] , lock_mode , file , line ) ;
}
}
static void openssl_static_locks_uninstall ( void )
{
if ( openssl_locks ! = NULL )
{
2017-07-05 20:40:00 +03:00
int i ;
2016-06-03 11:20:28 +03:00
CRYPTO_set_locking_callback ( NULL ) ;
2017-07-05 20:40:00 +03:00
for ( i = 0 ; i < CRYPTO_num_locks ( ) ; i + + )
2016-06-03 11:20:28 +03:00
{
if ( openssl_locks [ i ] ! = NULL )
{
Lock_Deinit ( openssl_locks [ i ] ) ;
}
}
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
free ( openssl_locks ) ;
openssl_locks = NULL ;
}
else
{
LogError ( " Locks already uninstalled " ) ;
}
}
static int openssl_static_locks_install ( void )
{
int result ;
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
if ( openssl_locks ! = NULL )
{
LogError ( " Locks already initialized " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-06-03 11:20:28 +03:00
}
else
{
openssl_locks = malloc ( CRYPTO_num_locks ( ) * sizeof ( LOCK_HANDLE ) ) ;
2017-07-05 20:40:00 +03:00
if ( openssl_locks = = NULL )
2016-06-03 11:20:28 +03:00
{
LogError ( " Failed to allocate locks " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-06-03 11:20:28 +03:00
}
else
{
int i ;
2017-07-05 20:40:00 +03:00
for ( i = 0 ; i < CRYPTO_num_locks ( ) ; i + + )
2016-06-03 11:20:28 +03:00
{
openssl_locks [ i ] = Lock_Init ( ) ;
if ( openssl_locks [ i ] = = NULL )
{
LogError ( " Failed to allocate lock %d " , i ) ;
break ;
}
}
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
if ( i ! = CRYPTO_num_locks ( ) )
{
2017-07-05 20:40:00 +03:00
int j ;
2017-05-30 07:39:08 +03:00
for ( j = 0 ; j < i ; j + + )
2016-06-03 11:20:28 +03:00
{
Lock_Deinit ( openssl_locks [ j ] ) ;
}
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-06-03 11:20:28 +03:00
}
else
{
CRYPTO_set_locking_callback ( openssl_static_locks_lock_unlock_cb ) ;
2017-07-05 20:40:00 +03:00
2016-06-03 11:20:28 +03:00
result = 0 ;
}
}
}
return result ;
}
2016-03-25 23:17:28 +03:00
static void indicate_error ( TLS_IO_INSTANCE * tls_io_instance )
{
if ( tls_io_instance - > on_io_error = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL on_io_error. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
tls_io_instance - > on_io_error ( tls_io_instance - > on_io_error_context ) ;
}
}
static void indicate_open_complete ( TLS_IO_INSTANCE * tls_io_instance , IO_OPEN_RESULT open_result )
{
if ( tls_io_instance - > on_io_open_complete = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL on_io_open_complete. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
tls_io_instance - > on_io_open_complete ( tls_io_instance - > on_io_open_complete_context , open_result ) ;
}
}
static int write_outgoing_bytes ( TLS_IO_INSTANCE * tls_io_instance , ON_SEND_COMPLETE on_send_complete , void * callback_context )
{
int result ;
2017-04-17 19:53:22 +03:00
size_t pending = BIO_ctrl_pending ( tls_io_instance - > out_bio ) ;
if ( pending = = 0 )
2016-03-25 23:17:28 +03:00
{
result = 0 ;
}
else
{
unsigned char * bytes_to_send = malloc ( pending ) ;
if ( bytes_to_send = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL bytes_to_send. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
2017-05-30 07:39:08 +03:00
if ( BIO_read ( tls_io_instance - > out_bio , bytes_to_send , ( int ) pending ) ! = ( int ) pending )
2016-03-25 23:17:28 +03:00
{
2016-06-03 11:20:28 +03:00
log_ERR_get_error ( " BIO_read not in pending state. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
if ( xio_send ( tls_io_instance - > underlying_io , bytes_to_send , pending , on_send_complete , callback_context ) ! = 0 )
{
2016-04-21 00:18:02 +03:00
LogError ( " Error in xio_send. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
result = 0 ;
}
}
free ( bytes_to_send ) ;
}
}
return result ;
}
2018-09-07 01:34:57 +03:00
// Non-NULL tls_io_instance is guaranteed by callers.
2017-07-05 20:40:00 +03:00
// We are in TLSIO_STATE_IN_HANDSHAKE when entering this method.
static void send_handshake_bytes ( TLS_IO_INSTANCE * tls_io_instance )
2016-03-25 23:17:28 +03:00
{
2017-07-05 20:40:00 +03:00
int hsret ;
// ERR_clear_error must be called before any call that might set an
// SSL_get_error result
ERR_clear_error ( ) ;
hsret = SSL_do_handshake ( tls_io_instance - > ssl ) ;
if ( hsret ! = SSL_DO_HANDSHAKE_SUCCESS )
2016-12-06 17:44:57 +03:00
{
2017-07-05 20:40:00 +03:00
int ssl_err = SSL_get_error ( tls_io_instance - > ssl , hsret ) ;
if ( ssl_err ! = SSL_ERROR_WANT_READ & & ssl_err ! = SSL_ERROR_WANT_WRITE )
2016-03-25 23:17:28 +03:00
{
2017-07-05 20:40:00 +03:00
if ( ssl_err = = SSL_ERROR_SSL )
2016-03-25 23:17:28 +03:00
{
2018-10-05 20:38:26 +03:00
LogError ( " %s " , ERR_error_string ( ERR_get_error ( ) , NULL ) ) ;
2016-03-25 23:17:28 +03:00
}
2017-07-05 20:40:00 +03:00
else
2016-03-25 23:17:28 +03:00
{
2018-04-23 19:54:27 +03:00
LogError ( " SSL handshake failed: %d " , ssl_err ) ;
2017-06-30 08:16:32 +03:00
}
2017-07-05 20:40:00 +03:00
tls_io_instance - > tlsio_state = TLSIO_STATE_HANDSHAKE_FAILED ;
}
else
{
if ( write_outgoing_bytes ( tls_io_instance , NULL , NULL ) ! = 0 )
2017-06-30 08:16:32 +03:00
{
2017-07-05 20:40:00 +03:00
LogError ( " Error in write_outgoing_bytes. " ) ;
tls_io_instance - > tlsio_state = TLSIO_STATE_HANDSHAKE_FAILED ;
2016-03-25 23:17:28 +03:00
}
}
}
2017-07-05 20:40:00 +03:00
else
{
tls_io_instance - > tlsio_state = TLSIO_STATE_OPEN ;
indicate_open_complete ( tls_io_instance , IO_OPEN_OK ) ;
}
2016-03-25 23:17:28 +03:00
}
2018-01-10 02:22:57 +03:00
static void close_openssl_instance ( TLS_IO_INSTANCE * tls_io_instance )
{
if ( tls_io_instance - > ssl ! = NULL )
{
SSL_free ( tls_io_instance - > ssl ) ;
tls_io_instance - > ssl = NULL ;
}
if ( tls_io_instance - > ssl_context ! = NULL )
{
SSL_CTX_free ( tls_io_instance - > ssl_context ) ;
tls_io_instance - > ssl_context = NULL ;
}
}
2016-03-25 23:17:28 +03:00
static void on_underlying_io_close_complete ( void * context )
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) context ;
switch ( tls_io_instance - > tlsio_state )
{
2017-07-05 20:40:00 +03:00
default :
case TLSIO_STATE_NOT_OPEN :
case TLSIO_STATE_OPEN :
case TLSIO_STATE_IN_HANDSHAKE :
case TLSIO_STATE_HANDSHAKE_FAILED :
case TLSIO_STATE_ERROR :
break ;
case TLSIO_STATE_OPENING_UNDERLYING_IO :
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
indicate_open_complete ( tls_io_instance , IO_OPEN_ERROR ) ;
break ;
case TLSIO_STATE_CLOSING :
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
if ( tls_io_instance - > on_io_close_complete ! = NULL )
{
tls_io_instance - > on_io_close_complete ( tls_io_instance - > on_io_close_complete_context ) ;
}
break ;
2016-03-25 23:17:28 +03:00
}
2018-01-10 02:22:57 +03:00
close_openssl_instance ( tls_io_instance ) ;
2016-03-25 23:17:28 +03:00
}
static void on_underlying_io_open_complete ( void * context , IO_OPEN_RESULT open_result )
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) context ;
if ( tls_io_instance - > tlsio_state = = TLSIO_STATE_OPENING_UNDERLYING_IO )
{
if ( open_result = = IO_OPEN_OK )
{
2016-05-05 03:08:08 +03:00
tls_io_instance - > tlsio_state = TLSIO_STATE_IN_HANDSHAKE ;
2017-07-05 20:40:00 +03:00
// Begin the handshake process here. It continues in on_underlying_io_bytes_received
send_handshake_bytes ( tls_io_instance ) ;
2016-03-25 23:17:28 +03:00
}
else
{
2016-12-06 17:44:57 +03:00
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
2016-03-25 23:17:28 +03:00
indicate_open_complete ( tls_io_instance , IO_OPEN_ERROR ) ;
2016-04-21 00:18:02 +03:00
LogError ( " Invalid tlsio_state. Expected state is TLSIO_STATE_OPENING_UNDERLYING_IO. " ) ;
2016-03-25 23:17:28 +03:00
}
}
}
static void on_underlying_io_error ( void * context )
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) context ;
switch ( tls_io_instance - > tlsio_state )
{
2017-07-05 20:40:00 +03:00
default :
break ;
2016-03-25 23:17:28 +03:00
2017-07-05 20:40:00 +03:00
case TLSIO_STATE_OPENING_UNDERLYING_IO :
case TLSIO_STATE_IN_HANDSHAKE :
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
indicate_open_complete ( tls_io_instance , IO_OPEN_ERROR ) ;
break ;
2016-03-25 23:17:28 +03:00
2017-07-05 20:40:00 +03:00
case TLSIO_STATE_OPEN :
indicate_error ( tls_io_instance ) ;
break ;
2016-03-25 23:17:28 +03:00
}
}
static int decode_ssl_received_bytes ( TLS_IO_INSTANCE * tls_io_instance )
{
int result = 0 ;
unsigned char buffer [ 64 ] ;
int rcv_bytes = 1 ;
2016-09-15 01:15:17 +03:00
2016-03-25 23:17:28 +03:00
while ( rcv_bytes > 0 )
{
2016-12-06 17:44:57 +03:00
if ( tls_io_instance - > ssl = = NULL )
{
LogError ( " SSL channel closed in decode_ssl_received_bytes. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-12-06 17:44:57 +03:00
return result ;
}
2016-09-15 01:15:17 +03:00
2016-03-25 23:17:28 +03:00
rcv_bytes = SSL_read ( tls_io_instance - > ssl , buffer , sizeof ( buffer ) ) ;
if ( rcv_bytes > 0 )
{
if ( tls_io_instance - > on_bytes_received = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL on_bytes_received. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
tls_io_instance - > on_bytes_received ( tls_io_instance - > on_bytes_received_context , buffer , rcv_bytes ) ;
}
}
}
return result ;
}
static void on_underlying_io_bytes_received ( void * context , const unsigned char * buffer , size_t size )
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) context ;
2017-04-17 19:53:22 +03:00
int written = BIO_write ( tls_io_instance - > in_bio , buffer , ( int ) size ) ;
2016-09-15 01:02:48 +03:00
if ( written ! = ( int ) size )
2016-03-25 23:17:28 +03:00
{
tls_io_instance - > tlsio_state = TLSIO_STATE_ERROR ;
indicate_error ( tls_io_instance ) ;
2016-06-03 11:20:28 +03:00
log_ERR_get_error ( " Error in BIO_write. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
switch ( tls_io_instance - > tlsio_state )
{
2017-07-05 20:40:00 +03:00
default :
break ;
2016-03-25 23:17:28 +03:00
2017-07-05 20:40:00 +03:00
case TLSIO_STATE_IN_HANDSHAKE :
send_handshake_bytes ( tls_io_instance ) ;
break ;
2016-05-05 03:08:08 +03:00
2017-07-05 20:40:00 +03:00
case TLSIO_STATE_OPEN :
if ( decode_ssl_received_bytes ( tls_io_instance ) ! = 0 )
{
tls_io_instance - > tlsio_state = TLSIO_STATE_ERROR ;
indicate_error ( tls_io_instance ) ;
LogError ( " Error in decode_ssl_received_bytes. " ) ;
}
break ;
2016-05-05 03:08:08 +03:00
}
}
}
static int add_certificate_to_store ( TLS_IO_INSTANCE * tls_io_instance , const char * certValue )
{
int result = 0 ;
if ( certValue ! = NULL )
{
X509_STORE * cert_store = SSL_CTX_get_cert_store ( tls_io_instance - > ssl_context ) ;
if ( cert_store = = NULL )
{
2017-03-09 01:44:32 +03:00
log_ERR_get_error ( " failure in SSL_CTX_get_cert_store. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
2017-07-07 13:56:34 +03:00
# if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && (OPENSSL_VERSION_NUMBER < 0x20000000L)
2017-07-07 11:23:25 +03:00
const BIO_METHOD * bio_method ;
# else
BIO_METHOD * bio_method ;
# endif
bio_method = BIO_s_mem ( ) ;
2017-03-09 01:44:32 +03:00
if ( bio_method = = NULL )
2016-03-25 23:17:28 +03:00
{
2017-03-09 01:44:32 +03:00
log_ERR_get_error ( " failure in BIO_s_mem " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
2017-03-09 01:44:32 +03:00
BIO * cert_memory_bio = BIO_new ( bio_method ) ;
if ( cert_memory_bio = = NULL )
2016-03-25 23:17:28 +03:00
{
2017-03-09 01:44:32 +03:00
log_ERR_get_error ( " failure in BIO_new " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
2016-05-05 03:08:08 +03:00
else
{
2017-03-09 01:44:32 +03:00
int puts_result = BIO_puts ( cert_memory_bio , certValue ) ;
if ( puts_result < 0 )
2016-05-05 03:08:08 +03:00
{
2017-03-09 01:44:32 +03:00
log_ERR_get_error ( " failure in BIO_puts " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
2017-03-09 01:44:32 +03:00
if ( ( size_t ) puts_result ! = strlen ( certValue ) )
{
log_ERR_get_error ( " mismatching legths " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2017-03-09 01:44:32 +03:00
}
else
{
X509 * certificate ;
while ( ( certificate = PEM_read_bio_X509 ( cert_memory_bio , NULL , NULL , NULL ) ) ! = NULL )
{
if ( ! X509_STORE_add_cert ( cert_store , certificate ) )
{
X509_free ( certificate ) ;
log_ERR_get_error ( " failure in X509_STORE_add_cert " ) ;
break ;
}
X509_free ( certificate ) ;
}
if ( certificate = = NULL )
{
result = 0 ; /*all is fine*/
}
else
{
/*previous while loop terminated unfortunately*/
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2017-03-09 01:44:32 +03:00
}
}
2016-05-05 03:08:08 +03:00
}
2017-03-09 01:44:32 +03:00
BIO_free ( cert_memory_bio ) ;
2016-05-05 03:08:08 +03:00
}
2016-03-25 23:17:28 +03:00
}
2016-05-05 03:08:08 +03:00
}
}
return result ;
}
2016-03-25 23:17:28 +03:00
2016-05-05 03:08:08 +03:00
static int create_openssl_instance ( TLS_IO_INSTANCE * tlsInstance )
{
int result ;
2017-07-07 11:23:25 +03:00
const SSL_METHOD * method = NULL ;
2016-08-24 04:47:34 +03:00
2017-07-07 13:56:34 +03:00
# if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (OPENSSL_VERSION_NUMBER >= 0x20000000L)
2017-08-05 00:23:04 +03:00
if ( tlsInstance - > tls_version = = VERSION_1_2 )
2016-12-06 17:44:57 +03:00
{
method = TLSv1_2_method ( ) ;
}
2017-08-05 00:23:04 +03:00
else if ( tlsInstance - > tls_version = = VERSION_1_1 )
2016-12-06 17:44:57 +03:00
{
method = TLSv1_1_method ( ) ;
}
2017-07-07 11:23:25 +03:00
else
{
method = TLSv1_method ( ) ;
}
# else
2017-07-07 13:44:47 +03:00
{
2017-07-07 11:23:25 +03:00
method = TLS_method ( ) ;
2017-07-07 13:44:47 +03:00
}
2017-07-07 11:23:25 +03:00
# endif
2016-08-24 04:47:34 +03:00
tlsInstance - > ssl_context = SSL_CTX_new ( method ) ;
2016-05-05 03:08:08 +03:00
if ( tlsInstance - > ssl_context = = NULL )
{
2016-06-03 11:20:28 +03:00
log_ERR_get_error ( " Failed allocating OpenSSL context. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
2018-04-30 22:39:06 +03:00
else if ( ( tlsInstance - > cipher_list ! = NULL ) & &
( SSL_CTX_set_cipher_list ( tlsInstance - > ssl_context , tlsInstance - > cipher_list ) ) ! = 1 )
{
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
tlsInstance - > ssl_context = NULL ;
log_ERR_get_error ( " unable to set cipher list. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2018-04-30 22:39:06 +03:00
}
2016-05-05 03:08:08 +03:00
else if ( add_certificate_to_store ( tlsInstance , tlsInstance - > certificate ) ! = 0 )
{
2016-07-19 02:39:57 +03:00
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
2016-12-06 17:44:57 +03:00
tlsInstance - > ssl_context = NULL ;
2016-07-19 02:39:57 +03:00
log_ERR_get_error ( " unable to add_certificate_to_store. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
2016-07-18 19:09:10 +03:00
/*x509 authentication can only be build before underlying connection is realized*/
2017-07-05 20:40:00 +03:00
else if (
2018-03-24 04:18:14 +03:00
( tlsInstance - > x509_certificate ! = NULL ) & &
( tlsInstance - > x509_private_key ! = NULL ) & &
( x509_openssl_add_credentials ( tlsInstance - > ssl_context , tlsInstance - > x509_certificate , tlsInstance - > x509_private_key ) ! = 0 )
2016-07-18 19:09:10 +03:00
)
2017-03-31 02:03:10 +03:00
{
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
tlsInstance - > ssl_context = NULL ;
log_ERR_get_error ( " unable to use x509 authentication " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2017-03-31 02:03:10 +03:00
}
2016-05-05 03:08:08 +03:00
else
{
2016-12-06 17:44:57 +03:00
SSL_CTX_set_cert_verify_callback ( tlsInstance - > ssl_context , tlsInstance - > tls_validation_callback , tlsInstance - > tls_validation_callback_data ) ;
2016-08-24 04:47:34 +03:00
2016-05-05 03:08:08 +03:00
tlsInstance - > in_bio = BIO_new ( BIO_s_mem ( ) ) ;
if ( tlsInstance - > in_bio = = NULL )
{
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
2016-12-06 17:44:57 +03:00
tlsInstance - > ssl_context = NULL ;
2016-06-03 11:20:28 +03:00
log_ERR_get_error ( " Failed BIO_new for in BIO. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
tlsInstance - > out_bio = BIO_new ( BIO_s_mem ( ) ) ;
if ( tlsInstance - > out_bio = = NULL )
2016-03-25 23:17:28 +03:00
{
2016-05-05 03:08:08 +03:00
( void ) BIO_free ( tlsInstance - > in_bio ) ;
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
2016-12-06 17:44:57 +03:00
tlsInstance - > ssl_context = NULL ;
2016-06-03 11:20:28 +03:00
log_ERR_get_error ( " Failed BIO_new for out BIO. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
2017-01-17 12:45:23 +03:00
if ( ( BIO_set_mem_eof_return ( tlsInstance - > in_bio , - 1 ) < = 0 ) | |
( BIO_set_mem_eof_return ( tlsInstance - > out_bio , - 1 ) < = 0 ) )
2016-05-05 03:08:08 +03:00
{
( void ) BIO_free ( tlsInstance - > in_bio ) ;
( void ) BIO_free ( tlsInstance - > out_bio ) ;
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
2016-12-06 17:44:57 +03:00
tlsInstance - > ssl_context = NULL ;
2017-01-17 12:45:23 +03:00
LogError ( " Failed BIO_set_mem_eof_return. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
2017-01-17 12:45:23 +03:00
SSL_CTX_set_verify ( tlsInstance - > ssl_context , SSL_VERIFY_PEER , NULL ) ;
// Specifies that the default locations for which CA certificates are loaded should be used.
if ( SSL_CTX_set_default_verify_paths ( tlsInstance - > ssl_context ) ! = 1 )
{
// This is only a warning to the user. They can still specify the certificate via SetOption.
LogInfo ( " WARNING: Unable to specify the default location for CA certificates on this platform. " ) ;
}
tlsInstance - > ssl = SSL_new ( tlsInstance - > ssl_context ) ;
if ( tlsInstance - > ssl = = NULL )
2016-05-05 03:08:08 +03:00
{
( void ) BIO_free ( tlsInstance - > in_bio ) ;
( void ) BIO_free ( tlsInstance - > out_bio ) ;
SSL_CTX_free ( tlsInstance - > ssl_context ) ;
2016-12-06 17:44:57 +03:00
tlsInstance - > ssl_context = NULL ;
2017-02-14 21:30:33 +03:00
log_ERR_get_error ( " Failed creating OpenSSL instance. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
else
{
2017-01-25 10:25:15 +03:00
SSL_set_bio ( tlsInstance - > ssl , tlsInstance - > in_bio , tlsInstance - > out_bio ) ;
SSL_set_connect_state ( tlsInstance - > ssl ) ;
result = 0 ;
2016-05-05 03:08:08 +03:00
}
}
2016-03-25 23:17:28 +03:00
}
}
}
2016-05-05 03:08:08 +03:00
return result ;
2016-03-25 23:17:28 +03:00
}
int tlsio_openssl_init ( void )
{
( void ) SSL_library_init ( ) ;
2016-06-03 11:20:28 +03:00
2016-03-25 23:17:28 +03:00
SSL_load_error_strings ( ) ;
ERR_load_BIO_strings ( ) ;
OpenSSL_add_all_algorithms ( ) ;
2016-06-03 11:20:28 +03:00
if ( openssl_static_locks_install ( ) ! = 0 )
{
LogError ( " Failed to install static locks in OpenSSL! " ) ;
2019-02-22 21:28:19 +03:00
return MU_FAILURE ;
2016-06-03 11:20:28 +03:00
}
openssl_dynamic_locks_install ( ) ;
2016-03-25 23:17:28 +03:00
return 0 ;
}
void tlsio_openssl_deinit ( void )
{
2016-06-03 11:20:28 +03:00
openssl_dynamic_locks_uninstall ( ) ;
openssl_static_locks_uninstall ( ) ;
2018-03-29 21:27:22 +03:00
# if (OPENSSL_VERSION_NUMBER >= 0x00907000L) && (OPENSSL_VERSION_NUMBER < 0x20000000L) && (FIPS_mode_set)
2016-12-06 17:44:57 +03:00
FIPS_mode_set ( 0 ) ;
2017-01-17 12:48:35 +03:00
# endif
2016-12-06 17:44:57 +03:00
CRYPTO_set_locking_callback ( NULL ) ;
CRYPTO_set_id_callback ( NULL ) ;
2016-06-03 11:20:28 +03:00
ERR_free_strings ( ) ;
2016-12-06 17:44:57 +03:00
EVP_cleanup ( ) ;
2017-07-07 11:23:25 +03:00
2017-07-07 13:44:47 +03:00
# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
2016-12-06 17:44:57 +03:00
ERR_remove_state ( 0 ) ;
2017-07-07 13:56:34 +03:00
# elif (OPENSSL_VERSION_NUMBER < 0x10100000L) || (OPENSSL_VERSION_NUMBER >= 0x20000000L)
2017-07-07 11:23:25 +03:00
ERR_remove_thread_state ( NULL ) ;
# endif
2018-03-29 21:27:22 +03:00
# if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && (OPENSSL_VERSION_NUMBER < 0x10010000L) && (SSL_COMP_free_compression_methods)
2016-12-06 17:44:57 +03:00
SSL_COMP_free_compression_methods ( ) ;
2016-09-21 22:40:57 +03:00
# endif
2016-12-06 17:44:57 +03:00
CRYPTO_cleanup_all_ex_data ( ) ;
2016-03-25 23:17:28 +03:00
}
2016-06-20 19:55:56 +03:00
CONCRETE_IO_HANDLE tlsio_openssl_create ( void * io_create_parameters )
2016-03-25 23:17:28 +03:00
{
TLSIO_CONFIG * tls_io_config = io_create_parameters ;
TLS_IO_INSTANCE * result ;
if ( tls_io_config = = NULL )
{
result = NULL ;
2016-04-21 00:18:02 +03:00
LogError ( " NULL tls_io_config. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
result = malloc ( sizeof ( TLS_IO_INSTANCE ) ) ;
if ( result = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " Failed allocating TLSIO instance. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
2018-03-19 23:18:36 +03:00
SOCKETIO_CONFIG socketio_config ;
2017-03-02 07:46:19 +03:00
const IO_INTERFACE_DESCRIPTION * underlying_io_interface ;
void * io_interface_parameters ;
if ( tls_io_config - > underlying_io_interface ! = NULL )
2017-01-17 12:48:35 +03:00
{
2017-03-02 07:46:19 +03:00
underlying_io_interface = tls_io_config - > underlying_io_interface ;
io_interface_parameters = tls_io_config - > underlying_io_parameters ;
2017-01-17 12:48:35 +03:00
}
else
{
2017-03-02 07:46:19 +03:00
socketio_config . hostname = tls_io_config - > hostname ;
socketio_config . port = tls_io_config - > port ;
2017-01-17 12:48:35 +03:00
socketio_config . accepted_socket = NULL ;
2016-07-18 19:09:10 +03:00
2017-03-02 07:46:19 +03:00
underlying_io_interface = socketio_get_interface_description ( ) ;
io_interface_parameters = & socketio_config ;
}
if ( underlying_io_interface = = NULL )
{
free ( result ) ;
result = NULL ;
LogError ( " Failed getting socket IO interface description. " ) ;
}
else
{
result - > certificate = NULL ;
2018-04-30 22:39:06 +03:00
result - > cipher_list = NULL ;
2017-03-02 07:46:19 +03:00
result - > in_bio = NULL ;
result - > out_bio = NULL ;
result - > on_bytes_received = NULL ;
result - > on_bytes_received_context = NULL ;
result - > on_io_open_complete = NULL ;
result - > on_io_open_complete_context = NULL ;
result - > on_io_close_complete = NULL ;
result - > on_io_close_complete_context = NULL ;
result - > on_io_error = NULL ;
result - > on_io_error_context = NULL ;
result - > ssl = NULL ;
result - > ssl_context = NULL ;
result - > tls_validation_callback = NULL ;
result - > tls_validation_callback_data = NULL ;
2018-03-24 04:18:14 +03:00
result - > x509_certificate = NULL ;
result - > x509_private_key = NULL ;
2017-03-31 02:03:10 +03:00
2018-10-03 00:30:52 +03:00
result - > tls_version = VERSION_1_2 ;
2017-03-02 07:46:19 +03:00
result - > underlying_io = xio_create ( underlying_io_interface , io_interface_parameters ) ;
2017-01-17 12:48:35 +03:00
if ( result - > underlying_io = = NULL )
{
free ( result ) ;
result = NULL ;
LogError ( " Failed xio_create. " ) ;
}
else
{
result - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
}
}
2016-03-25 23:17:28 +03:00
}
2017-07-05 20:40:00 +03:00
}
2016-03-25 23:17:28 +03:00
return result ;
}
void tlsio_openssl_destroy ( CONCRETE_IO_HANDLE tls_io )
{
if ( tls_io = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL tls_io. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) tls_io ;
2016-05-05 03:08:08 +03:00
if ( tls_io_instance - > certificate ! = NULL )
{
free ( tls_io_instance - > certificate ) ;
tls_io_instance - > certificate = NULL ;
}
2018-04-30 22:39:06 +03:00
if ( tls_io_instance - > cipher_list ! = NULL )
{
free ( tls_io_instance - > cipher_list ) ;
tls_io_instance - > cipher_list = NULL ;
}
2018-03-24 04:18:14 +03:00
free ( ( void * ) tls_io_instance - > x509_certificate ) ;
free ( ( void * ) tls_io_instance - > x509_private_key ) ;
2017-01-28 01:42:12 +03:00
close_openssl_instance ( tls_io_instance ) ;
if ( tls_io_instance - > underlying_io ! = NULL )
{
xio_destroy ( tls_io_instance - > underlying_io ) ;
tls_io_instance - > underlying_io = NULL ;
}
2016-03-25 23:17:28 +03:00
free ( tls_io ) ;
}
}
int tlsio_openssl_open ( CONCRETE_IO_HANDLE tls_io , ON_IO_OPEN_COMPLETE on_io_open_complete , void * on_io_open_complete_context , ON_BYTES_RECEIVED on_bytes_received , void * on_bytes_received_context , ON_IO_ERROR on_io_error , void * on_io_error_context )
{
int result ;
if ( tls_io = = NULL )
{
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-04-21 00:18:02 +03:00
LogError ( " NULL tls_io. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) tls_io ;
if ( tls_io_instance - > tlsio_state ! = TLSIO_STATE_NOT_OPEN )
{
2016-04-21 00:18:02 +03:00
LogError ( " Invalid tlsio_state. Expected state is TLSIO_STATE_NOT_OPEN. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
tls_io_instance - > on_io_open_complete = on_io_open_complete ;
tls_io_instance - > on_io_open_complete_context = on_io_open_complete_context ;
tls_io_instance - > on_bytes_received = on_bytes_received ;
tls_io_instance - > on_bytes_received_context = on_bytes_received_context ;
tls_io_instance - > on_io_error = on_io_error ;
tls_io_instance - > on_io_error_context = on_io_error_context ;
tls_io_instance - > tlsio_state = TLSIO_STATE_OPENING_UNDERLYING_IO ;
2016-05-05 03:08:08 +03:00
if ( create_openssl_instance ( tls_io_instance ) ! = 0 )
{
2017-03-08 19:50:53 +03:00
LogError ( " Failed creating the OpenSSL instance. " ) ;
2016-10-18 22:08:27 +03:00
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-05-05 03:08:08 +03:00
}
2017-07-05 20:40:00 +03:00
else if ( xio_open ( tls_io_instance - > underlying_io , on_underlying_io_open_complete , tls_io_instance ,
on_underlying_io_bytes_received , tls_io_instance , on_underlying_io_error , tls_io_instance ) ! = 0 )
2016-03-25 23:17:28 +03:00
{
2017-03-08 19:50:53 +03:00
LogError ( " Failed opening the underlying I/O. " ) ;
close_openssl_instance ( tls_io_instance ) ;
2016-10-18 22:08:27 +03:00
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
result = 0 ;
}
}
}
return result ;
}
2017-07-05 20:40:00 +03:00
/* Codes_SRS_TLSIO_30_009: [ The phrase "enter TLSIO_STATE_EXT_CLOSING" means the adapter shall iterate through any unsent messages in the queue and shall delete each message after calling its on_send_complete with the associated callback_context and IO_SEND_CANCELLED. ]*/
/* Codes_SRS_TLSIO_30_006: [ The phrase "enter TLSIO_STATE_EXT_CLOSED" means the adapter shall forcibly close any existing connections then call the on_io_close_complete function and pass the on_io_close_complete_context that was supplied in tlsio_close_async. ]*/
/* Codes_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing, then the adapter shall enter TLSIO_STATE_EXT_CLOSED immediately after entering TLSIO_STATE_EX_CLOSING. ]*/
2016-03-25 23:17:28 +03:00
int tlsio_openssl_close ( CONCRETE_IO_HANDLE tls_io , ON_IO_CLOSE_COMPLETE on_io_close_complete , void * callback_context )
{
2017-07-05 20:40:00 +03:00
int result ;
2016-03-25 23:17:28 +03:00
2017-07-05 20:40:00 +03:00
/* Codes_SRS_TLSIO_30_050: [ If the tlsio_handle parameter is NULL, tlsio_close_async shall log an error and return _FAILURE_. ]*/
2016-03-25 23:17:28 +03:00
if ( tls_io = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL tls_io. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) tls_io ;
2017-07-05 20:40:00 +03:00
if ( tls_io_instance - > tlsio_state ! = TLSIO_STATE_ERROR & & tls_io_instance - > tlsio_state ! = TLSIO_STATE_OPEN )
2016-03-25 23:17:28 +03:00
{
2017-07-05 20:40:00 +03:00
/* Codes_RS_TLSIO_30_053: [ If the adapter is in any state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR then tlsio_close_async shall log that tlsio_close_async has been called and then continue normally. ]*/
// LogInfo rather than LogError because this is an unusual but not erroneous situation
LogInfo ( " Closing tlsio from a state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR " ) ;
2016-03-25 23:17:28 +03:00
}
2017-07-05 20:40:00 +03:00
if ( is_an_opening_state ( tls_io_instance - > tlsio_state ) )
2016-03-25 23:17:28 +03:00
{
2017-07-05 20:40:00 +03:00
/* Codes_SRS_TLSIO_30_057: [ On success, if the adapter is in TLSIO_STATE_EXT_OPENING, it shall call on_io_open_complete with the on_io_open_complete_context supplied in tlsio_open_async and IO_OPEN_CANCELLED. This callback shall be made before changing the internal state of the adapter. ]*/
tls_io_instance - > on_io_open_complete ( tls_io_instance - > on_io_open_complete_context , IO_OPEN_CANCELLED ) ;
}
if ( tls_io_instance - > tlsio_state = = TLSIO_STATE_OPEN )
{
// Attempt a graceful shutdown
/* Codes_SRS_TLSIO_30_056: [ On success the adapter shall enter TLSIO_STATE_EX_CLOSING. ]*/
2016-03-25 23:17:28 +03:00
tls_io_instance - > tlsio_state = TLSIO_STATE_CLOSING ;
tls_io_instance - > on_io_close_complete = on_io_close_complete ;
tls_io_instance - > on_io_close_complete_context = callback_context ;
2018-09-07 01:34:57 +03:00
// xio_close is guaranteed to succeed from the open state, and the callback completes the
2017-07-05 20:40:00 +03:00
// transition into TLSIO_STATE_NOT_OPEN
2018-01-10 02:22:57 +03:00
if ( xio_close ( tls_io_instance - > underlying_io , on_underlying_io_close_complete , tls_io_instance ) ! = 0 )
{
close_openssl_instance ( tls_io_instance ) ;
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
}
2016-03-25 23:17:28 +03:00
}
2017-07-05 20:40:00 +03:00
else
{
// Just force the shutdown
/* Codes_SRS_TLSIO_30_056: [ On success the adapter shall enter TLSIO_STATE_EX_CLOSING. ]*/
/* Codes_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing or if the adapter is not in TLSIO_STATE_EXT_OPEN, then the adapter shall enter TLSIO_STATE_EXT_CLOSED immediately after entering TLSIO_STATE_EXT_CLOSING. ]*/
// Current implementations of xio_close will fail if not in the open state, but we don't care
( void ) xio_close ( tls_io_instance - > underlying_io , NULL , NULL ) ;
close_openssl_instance ( tls_io_instance ) ;
tls_io_instance - > tlsio_state = TLSIO_STATE_NOT_OPEN ;
}
result = 0 ;
2016-03-25 23:17:28 +03:00
}
2017-07-05 20:40:00 +03:00
/* Codes_SRS_TLSIO_30_054: [ On failure, the adapter shall not call on_io_close_complete. ]*/
2016-03-25 23:17:28 +03:00
return result ;
}
int tlsio_openssl_send ( CONCRETE_IO_HANDLE tls_io , const void * buffer , size_t size , ON_SEND_COMPLETE on_send_complete , void * callback_context )
{
int result ;
if ( tls_io = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL tls_io. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) tls_io ;
if ( tls_io_instance - > tlsio_state ! = TLSIO_STATE_OPEN )
{
2016-04-21 00:18:02 +03:00
LogError ( " Invalid tlsio_state. Expected state is TLSIO_STATE_OPEN. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
2017-07-05 20:40:00 +03:00
int res ;
2016-12-06 17:44:57 +03:00
if ( tls_io_instance - > ssl = = NULL )
{
LogError ( " SSL channel closed in tlsio_openssl_send. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-12-06 17:44:57 +03:00
return result ;
}
2016-09-15 01:15:17 +03:00
2017-05-30 07:39:08 +03:00
res = SSL_write ( tls_io_instance - > ssl , buffer , ( int ) size ) ;
2016-09-15 01:02:48 +03:00
if ( res ! = ( int ) size )
2016-03-25 23:17:28 +03:00
{
2016-06-03 11:20:28 +03:00
log_ERR_get_error ( " SSL_write error. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
if ( write_outgoing_bytes ( tls_io_instance , on_send_complete , callback_context ) ! = 0 )
{
2016-04-21 00:18:02 +03:00
LogError ( " Error in write_outgoing_bytes. " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
result = 0 ;
}
}
}
}
return result ;
}
void tlsio_openssl_dowork ( CONCRETE_IO_HANDLE tls_io )
{
if ( tls_io = = NULL )
{
2016-04-21 00:18:02 +03:00
LogError ( " NULL tls_io. " ) ;
2016-03-25 23:17:28 +03:00
}
else
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) tls_io ;
2017-07-05 20:40:00 +03:00
switch ( tls_io_instance - > tlsio_state )
2016-03-25 23:17:28 +03:00
{
2017-07-05 20:40:00 +03:00
case TLSIO_STATE_OPENING_UNDERLYING_IO :
case TLSIO_STATE_IN_HANDSHAKE :
case TLSIO_STATE_OPEN :
2017-01-24 00:38:03 +03:00
/* this is needed in order to pump out bytes produces by OpenSSL for things like renegotiation */
write_outgoing_bytes ( tls_io_instance , NULL , NULL ) ;
2017-07-05 20:40:00 +03:00
break ;
case TLSIO_STATE_NOT_OPEN :
case TLSIO_STATE_HANDSHAKE_FAILED :
case TLSIO_STATE_CLOSING :
case TLSIO_STATE_ERROR :
default :
break ;
2016-03-25 23:17:28 +03:00
}
2017-02-06 10:21:34 +03:00
2017-07-05 20:40:00 +03:00
if ( tls_io_instance - > tlsio_state ! = TLSIO_STATE_NOT_OPEN )
{
/* Same behavior as schannel */
xio_dowork ( tls_io_instance - > underlying_io ) ;
if ( tls_io_instance - > tlsio_state = = TLSIO_STATE_HANDSHAKE_FAILED )
{
// The handshake failed so we need to close. The tlsio becomes aware of the
2018-09-07 01:34:57 +03:00
// handshake failure during an on_bytes_received while the underlying
2017-07-05 20:40:00 +03:00
// xio_dowork is pumping data out of the socket in a while loop. The tlsio can't
// close down during the callback because that would mean the xio_dowork would
// be trying to read from a closed socket. So instead, the tlsio sets its state
2018-09-07 01:34:57 +03:00
// to TLSIO_STATE_HANDSHAKE_FAILED during the on_bytes_received callback,
2017-07-05 20:40:00 +03:00
// can then gracefully shut things down here.
2018-09-07 01:34:57 +03:00
//
2017-07-05 20:40:00 +03:00
// Set the state to TLSIO_STATE_ERROR so close won't gripe about the state
tls_io_instance - > tlsio_state = TLSIO_STATE_ERROR ;
tlsio_openssl_close ( tls_io_instance , NULL , NULL ) ;
indicate_open_complete ( tls_io_instance , IO_OPEN_ERROR ) ;
}
}
2016-03-25 23:17:28 +03:00
}
}
int tlsio_openssl_setoption ( CONCRETE_IO_HANDLE tls_io , const char * optionName , const void * value )
{
int result ;
if ( tls_io = = NULL | | optionName = = NULL )
{
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-03-25 23:17:28 +03:00
}
else
{
TLS_IO_INSTANCE * tls_io_instance = ( TLS_IO_INSTANCE * ) tls_io ;
2016-04-05 02:34:45 +03:00
2017-12-22 03:06:13 +03:00
if ( strcmp ( OPTION_TRUSTED_CERT , optionName ) = = 0 )
2016-04-05 02:34:45 +03:00
{
2016-05-05 03:08:08 +03:00
const char * cert = ( const char * ) value ;
2017-07-05 20:40:00 +03:00
size_t len ;
2016-05-05 03:08:08 +03:00
if ( tls_io_instance - > certificate ! = NULL )
{
// Free the memory if it has been previously allocated
free ( tls_io_instance - > certificate ) ;
2018-12-11 21:54:31 +03:00
tls_io_instance - > certificate = NULL ;
2016-05-05 03:08:08 +03:00
}
// Store the certificate
2017-05-30 07:39:08 +03:00
len = strlen ( cert ) ;
2017-07-05 20:40:00 +03:00
tls_io_instance - > certificate = malloc ( len + 1 ) ;
2016-05-05 03:08:08 +03:00
if ( tls_io_instance - > certificate = = NULL )
2016-04-05 02:34:45 +03:00
{
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-04-05 02:34:45 +03:00
}
else
{
2016-05-05 03:08:08 +03:00
strcpy ( tls_io_instance - > certificate , cert ) ;
result = 0 ;
}
2016-04-05 02:34:45 +03:00
2016-05-05 03:08:08 +03:00
// If we're previously connected then add the cert to the context
if ( tls_io_instance - > ssl_context ! = NULL )
{
result = add_certificate_to_store ( tls_io_instance , cert ) ;
2016-04-05 02:34:45 +03:00
}
}
2018-06-08 02:25:41 +03:00
else if ( strcmp ( OPTION_OPENSSL_CIPHER_SUITE , optionName ) = = 0 )
2018-04-30 22:39:06 +03:00
{
if ( tls_io_instance - > cipher_list ! = NULL )
{
// Free the memory if it has been previously allocated
free ( tls_io_instance - > cipher_list ) ;
tls_io_instance - > cipher_list = NULL ;
}
// Store the cipher suites
2018-06-08 08:42:36 +03:00
if ( mallocAndStrcpy_s ( ( char * * ) & tls_io_instance - > cipher_list , value ) ! = 0 )
2018-04-30 22:39:06 +03:00
{
2018-06-08 08:42:36 +03:00
LogError ( " unable to mallocAndStrcpy_s %s " , optionName ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2018-04-30 22:39:06 +03:00
}
else
{
result = 0 ;
}
}
2018-03-24 04:18:14 +03:00
else if ( strcmp ( SU_OPTION_X509_CERT , optionName ) = = 0 | | strcmp ( OPTION_X509_ECC_CERT , optionName ) = = 0 )
2016-07-18 19:09:10 +03:00
{
2018-03-24 04:18:14 +03:00
if ( tls_io_instance - > x509_certificate ! = NULL )
2016-07-18 19:09:10 +03:00
{
LogError ( " unable to set x509 options more than once " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-07-18 19:09:10 +03:00
}
else
2017-07-05 20:40:00 +03:00
{
2016-07-21 04:47:38 +03:00
/*let's make a copy of this option*/
2018-03-24 04:18:14 +03:00
if ( mallocAndStrcpy_s ( ( char * * ) & tls_io_instance - > x509_certificate , value ) ! = 0 )
2016-07-21 04:47:38 +03:00
{
2018-06-08 08:42:36 +03:00
LogError ( " unable to mallocAndStrcpy_s %s " , optionName ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-07-21 04:47:38 +03:00
}
else
{
result = 0 ;
}
2016-07-18 19:09:10 +03:00
}
}
2018-03-24 04:18:14 +03:00
else if ( strcmp ( SU_OPTION_X509_PRIVATE_KEY , optionName ) = = 0 | | strcmp ( OPTION_X509_ECC_KEY , optionName ) = = 0 )
2016-07-18 19:09:10 +03:00
{
2018-03-24 04:18:14 +03:00
if ( tls_io_instance - > x509_private_key ! = NULL )
2016-07-18 19:09:10 +03:00
{
LogError ( " unable to set more than once x509 options " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2016-07-18 19:09:10 +03:00
}
else
{
2016-07-21 04:47:38 +03:00
/*let's make a copy of this option*/
2018-03-24 04:18:14 +03:00
if ( mallocAndStrcpy_s ( ( char * * ) & tls_io_instance - > x509_private_key , value ) ! = 0 )
2017-03-31 02:03:10 +03:00
{
2018-06-08 08:42:36 +03:00
LogError ( " unable to mallocAndStrcpy_s %s " , optionName ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2017-03-31 02:03:10 +03:00
}
else
{
result = 0 ;
}
}
}
2016-08-24 04:47:34 +03:00
else if ( strcmp ( " tls_validation_callback " , optionName ) = = 0 )
{
2018-02-07 04:12:53 +03:00
# ifdef WIN32
2017-07-05 20:40:00 +03:00
# pragma warning(push)
# pragma warning(disable:4055)
2018-02-07 04:12:53 +03:00
# endif // WIN32
2016-08-24 04:47:34 +03:00
tls_io_instance - > tls_validation_callback = ( TLS_CERTIFICATE_VALIDATION_CALLBACK ) value ;
2018-02-07 04:12:53 +03:00
# ifdef WIN32
2017-07-05 20:40:00 +03:00
# pragma warning(pop)
2018-02-07 04:12:53 +03:00
# endif // WIN32
2016-08-24 04:47:34 +03:00
if ( tls_io_instance - > ssl_context ! = NULL )
{
SSL_CTX_set_cert_verify_callback ( tls_io_instance - > ssl_context , tls_io_instance - > tls_validation_callback , tls_io_instance - > tls_validation_callback_data ) ;
}
result = 0 ;
}
else if ( strcmp ( " tls_validation_callback_data " , optionName ) = = 0 )
{
tls_io_instance - > tls_validation_callback_data = ( void * ) value ;
2016-07-18 19:09:10 +03:00
2016-08-24 04:47:34 +03:00
if ( tls_io_instance - > ssl_context ! = NULL )
{
SSL_CTX_set_cert_verify_callback ( tls_io_instance - > ssl_context , tls_io_instance - > tls_validation_callback , tls_io_instance - > tls_validation_callback_data ) ;
}
result = 0 ;
}
2017-11-11 03:51:59 +03:00
else if ( strcmp ( OPTION_TLS_VERSION , optionName ) = = 0 )
2016-12-06 17:44:57 +03:00
{
2017-08-05 00:23:04 +03:00
if ( tls_io_instance - > ssl_context ! = NULL )
{
LogError ( " Unable to set the tls version after the tls connection is established " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2017-08-05 00:23:04 +03:00
}
else
{
2017-11-13 21:29:02 +03:00
const int version_option = * ( const int * ) value ;
2017-11-11 03:51:59 +03:00
if ( version_option = = 0 | | version_option = = 10 )
2017-08-05 00:23:04 +03:00
{
tls_io_instance - > tls_version = VERSION_1_0 ;
}
2017-11-11 03:51:59 +03:00
else if ( version_option = = 11 )
2017-08-05 00:23:04 +03:00
{
tls_io_instance - > tls_version = VERSION_1_1 ;
}
2017-11-11 03:51:59 +03:00
else if ( version_option = = 12 )
2017-08-05 00:23:04 +03:00
{
tls_io_instance - > tls_version = VERSION_1_2 ;
}
else
{
2017-11-11 03:51:59 +03:00
LogInfo ( " Value of TLS version option %d is not found shall default to version 1.2 " , version_option ) ;
2017-08-05 00:23:04 +03:00
tls_io_instance - > tls_version = VERSION_1_2 ;
}
result = 0 ;
}
2016-12-06 17:44:57 +03:00
}
2017-05-11 23:36:01 +03:00
else if ( strcmp ( optionName , OPTION_UNDERLYING_IO_OPTIONS ) = = 0 )
2017-05-10 22:19:20 +03:00
{
if ( OptionHandler_FeedOptions ( ( OPTIONHANDLER_HANDLE ) value , ( void * ) tls_io_instance - > underlying_io ) ! = OPTIONHANDLER_OK )
{
LogError ( " failed feeding options to underlying I/O instance " ) ;
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
2017-05-10 22:19:20 +03:00
}
else
{
result = 0 ;
}
}
2017-07-26 19:02:15 +03:00
else if ( strcmp ( " ignore_server_name_check " , optionName ) = = 0 )
{
result = 0 ;
}
2016-04-05 02:34:45 +03:00
else
{
Condition fix, attempt 3, and schannel context cleanup
1. Condition_c11 should be waiting on milliseconds, not seconds timeouts. Current fix/impl uses 32 bit time, which is in seconds, so sub second waits are not working correctly. Use xtime to get correct time (as per cnd_timeout impl), which is 64 bit, both seconds and nanoseconds, and then add ms to it.
2. TLS Security context needs to be freed on close, also handle the case where bytes are left in the receive buffer after decrypt and hand shake init, by looping until the buffer is drained and more bytes are needed.
3. setoption should not pass NULL handles on to the underlying IO.
4. Remove iotlogging.h header include from tlsio_openssl header. Only concrete implementation should decide logging concern.
5. Remove logging buffers and protocol status in winhttp adapter, which is the concern of the caller, only log errors related to winhttp.
2016-04-12 11:55:20 +03:00
if ( tls_io_instance - > underlying_io = = NULL )
{
2019-02-22 21:28:19 +03:00
result = MU_FAILURE ;
Condition fix, attempt 3, and schannel context cleanup
1. Condition_c11 should be waiting on milliseconds, not seconds timeouts. Current fix/impl uses 32 bit time, which is in seconds, so sub second waits are not working correctly. Use xtime to get correct time (as per cnd_timeout impl), which is 64 bit, both seconds and nanoseconds, and then add ms to it.
2. TLS Security context needs to be freed on close, also handle the case where bytes are left in the receive buffer after decrypt and hand shake init, by looping until the buffer is drained and more bytes are needed.
3. setoption should not pass NULL handles on to the underlying IO.
4. Remove iotlogging.h header include from tlsio_openssl header. Only concrete implementation should decide logging concern.
5. Remove logging buffers and protocol status in winhttp adapter, which is the concern of the caller, only log errors related to winhttp.
2016-04-12 11:55:20 +03:00
}
else
{
result = xio_setoption ( tls_io_instance - > underlying_io , optionName , value ) ;
}
2016-04-05 02:34:45 +03:00
}
2016-03-25 23:17:28 +03:00
}
return result ;
}
const IO_INTERFACE_DESCRIPTION * tlsio_openssl_get_interface_description ( void )
{
return & tlsio_openssl_interface_description ;
}