2015-09-28 09:43:08 +00:00
/*
* Lightweight mbedTLS - based implementation of the schannel ( SSL / TLS ) provider .
*
* Copyright 2015 Peter Hater
* Copyright 2015 Ismael Ferreras Morezuelas < swyterzone + ros @ gmail . com >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
*/
# include "config.h"
# include "wine/port.h"
# ifdef __REACTOS__
# include "precomp.h"
# else
# include <stdarg.h>
# include <errno.h>
# include "windef.h"
# include "winbase.h"
# include "sspi.h"
# include "schannel.h"
# include "wine/debug.h"
# include "wine/library.h"
# endif
2018-03-23 11:20:45 +00:00
WINE_DEFAULT_DEBUG_CHANNEL ( schannel ) ;
2015-09-28 09:43:08 +00:00
# if defined(SONAME_LIBMBEDTLS) && !defined(HAVE_SECURITY_SECURITY_H) && !defined(SONAME_LIBGNUTLS)
2015-10-04 17:08:38 +00:00
# include <mbedtls/ssl.h>
2017-02-26 15:53:13 +00:00
# include <mbedtls/net_sockets.h>
2015-10-04 17:08:38 +00:00
# include <mbedtls/entropy.h>
# include <mbedtls/ctr_drbg.h>
# include <mbedtls/md_internal.h>
# include <mbedtls/ssl_internal.h>
2015-09-28 09:43:08 +00:00
2016-05-22 10:53:23 +00:00
# define ROS_SCHAN_IS_BLOCKING(read_len) ((read_len & 0xFFF00000) == 0xCCC00000)
# define ROS_SCHAN_IS_BLOCKING_MARSHALL(read_len) ((read_len & 0x000FFFFF) | 0xCCC00000)
# define ROS_SCHAN_IS_BLOCKING_RETRIEVE(read_len) (read_len & 0x000FFFFF)
2015-09-28 09:43:08 +00:00
# ifndef __REACTOS__
/* WINE defines the back-end glue in here */
# include "secur32_priv.h"
/* in ReactOS we use schannel instead of secur32 */
WINE_DEFAULT_DEBUG_CHANNEL ( secur32 ) ;
/* WINE prefers to keep it optional, disable this to link explicitly */
# include "schannel_mbedtls_lazyload.h"
/* WINE does not define this standard win32 macro for some reason */
# ifndef _countof
# define _countof(a) (sizeof(a) / sizeof(*(a)))
# endif
# endif
typedef struct
{
2015-10-04 17:08:38 +00:00
mbedtls_ssl_context ssl ;
mbedtls_ssl_config conf ;
mbedtls_entropy_context entropy ;
mbedtls_ctr_drbg_context ctr_drbg ;
struct schan_transport * transport ;
} MBEDTLS_SESSION , * PMBEDTLS_SESSION ;
/* custom `net_recv` callback adapter, mbedTLS uses it in mbedtls_ssl_read for
2015-09-28 09:43:08 +00:00
pulling data from the underlying win32 net stack */
static int schan_pull_adapter ( void * session , unsigned char * buff , size_t buff_len )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = session ;
2015-09-28 09:43:08 +00:00
size_t requested = buff_len ;
int status ;
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_pull_adapter: (%p/%p, %p, %u) \n " , s , s - > transport , buff , buff_len ) ;
2015-09-28 09:43:08 +00:00
status = schan_pull ( s - > transport , buff , & buff_len ) ;
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_pull_adapter: (%p/%p, %p, %u) status: %#x \n " , s , s - > transport , buff , buff_len , status ) ;
2015-09-28 09:43:08 +00:00
if ( status = = NO_ERROR )
{
/* great, no more data left */
if ( buff_len = = 0 )
{
TRACE ( " Connection closed \n " ) ;
return 0 ;
}
/* there's still some bytes that need pulling */
else if ( buff_len < requested )
{
TRACE ( " Pulled %u bytes before would block \n " , buff_len ) ;
return ROS_SCHAN_IS_BLOCKING_MARSHALL ( buff_len ) ;
}
else
{
TRACE ( " Pulled %u bytes \n " , buff_len ) ;
return buff_len ;
}
}
else if ( status = = EAGAIN )
{
TRACE ( " Would block before being able to pull anything, passing buff_len=%u \n " , buff_len ) ;
return ROS_SCHAN_IS_BLOCKING_MARSHALL ( buff_len ) ;
}
else
{
ERR ( " Unknown status code from schan_pull: %d \n " , status ) ;
2015-10-04 17:08:38 +00:00
return MBEDTLS_ERR_NET_RECV_FAILED ;
2015-09-28 09:43:08 +00:00
}
/* this should be unreachable */
2015-10-04 17:08:38 +00:00
return MBEDTLS_ERR_NET_CONNECT_FAILED ;
2015-09-28 09:43:08 +00:00
}
2015-10-04 17:08:38 +00:00
/* custom `net_send` callback adapter, mbedTLS uses it in mbedtls_ssl_write for
2015-09-28 09:43:08 +00:00
pushing data to the underlying win32 net stack */
static int schan_push_adapter ( void * session , const unsigned char * buff , size_t buff_len )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = session ;
2015-09-28 09:43:08 +00:00
int status ;
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_push_adapter: (%p/%p, %p, %u) \n " , s , s - > transport , buff , buff_len ) ;
2015-09-28 09:43:08 +00:00
status = schan_push ( s - > transport , buff , & buff_len ) ;
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_push_adapter: (%p/%p, %p, %u) status: %#x \n " , s , s - > transport , buff , buff_len , status ) ;
2015-09-28 09:43:08 +00:00
if ( status = = NO_ERROR )
{
TRACE ( " Pushed %u bytes \n " , buff_len ) ;
return buff_len ;
}
else if ( status = = EAGAIN )
{
TRACE ( " Would block before being able to push anything. passing %u \n " , buff_len ) ;
return ROS_SCHAN_IS_BLOCKING_MARSHALL ( buff_len ) ;
}
else
{
ERR ( " Unknown status code from schan_push: %d \n " , status ) ;
2015-10-04 17:08:38 +00:00
return MBEDTLS_ERR_NET_SEND_FAILED ;
2015-09-28 09:43:08 +00:00
}
/* this should be unreachable */
2015-10-04 17:08:38 +00:00
return MBEDTLS_ERR_NET_CONNECT_FAILED ;
2015-09-28 09:43:08 +00:00
}
DWORD schan_imp_enabled_protocols ( void )
{
/* NOTE: No support for SSL 2.0 */
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_enabled_protocols() \n " ) ;
2015-09-28 09:43:08 +00:00
return 0
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_SSL_PROTO_SSL3
2015-09-28 09:43:08 +00:00
| SP_PROT_SSL3_CLIENT | SP_PROT_SSL3_SERVER
# endif
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_SSL_PROTO_TLS1
2015-09-28 09:43:08 +00:00
| SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER
# endif
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_SSL_PROTO_TLS1_1
2015-09-28 09:43:08 +00:00
| SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER
# endif
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_SSL_PROTO_TLS1_2
2015-09-28 09:43:08 +00:00
| SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER
# endif
;
}
2015-10-04 17:08:38 +00:00
static void schan_imp_debug ( void * ctx , int level , const char * file , int line , const char * str )
2015-09-28 09:43:08 +00:00
{
2015-10-04 17:08:38 +00:00
WARN ( " MBEDTLS schan_imp_debug: %s:%04d: %s \n " , file , line , str ) ;
}
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
BOOL schan_imp_create_session ( schan_imp_session * session , schan_credentials * cred )
{
MBEDTLS_SESSION * s = HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , sizeof ( MBEDTLS_SESSION ) ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
WARN ( " MBEDTLS schan_imp_create_session: %p %p %p \n " , session , * session , cred ) ;
2015-09-28 09:43:08 +00:00
if ( ! ( * session = ( schan_imp_session ) s ) )
{
ERR ( " Not enough memory to create session \n " ) ;
return FALSE ;
}
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS init entropy \n " ) ;
mbedtls_entropy_init ( & s - > entropy ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS init random - change static entropy private data \n " ) ;
mbedtls_ctr_drbg_init ( & s - > ctr_drbg ) ;
mbedtls_ctr_drbg_seed ( & s - > ctr_drbg , mbedtls_entropy_func , & s - > entropy , NULL , 0 ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
WARN ( " MBEDTLS init ssl \n " ) ;
mbedtls_ssl_init ( & s - > ssl ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
WARN ( " MBEDTLS init conf \n " ) ;
mbedtls_ssl_config_init ( & s - > conf ) ;
mbedtls_ssl_config_defaults ( & s - > conf , MBEDTLS_SSL_IS_CLIENT ,
MBEDTLS_SSL_TRANSPORT_STREAM , MBEDTLS_SSL_PRESET_DEFAULT ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS set BIO callbacks \n " ) ;
mbedtls_ssl_set_bio ( & s - > ssl , s , schan_push_adapter , schan_pull_adapter , NULL ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS set endpoint to %s \n " , ( cred - > credential_use & SECPKG_CRED_INBOUND ) ? " server " : " client " ) ;
mbedtls_ssl_conf_endpoint ( & s - > conf , ( cred - > credential_use & SECPKG_CRED_INBOUND ) ? MBEDTLS_SSL_IS_SERVER :
MBEDTLS_SSL_IS_CLIENT ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS set authmode \n " ) ;
mbedtls_ssl_conf_authmode ( & s - > conf , MBEDTLS_SSL_VERIFY_NONE ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS set rng \n " ) ;
mbedtls_ssl_conf_rng ( & s - > conf , mbedtls_ctr_drbg_random , & s - > ctr_drbg ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS set dbg \n " ) ;
mbedtls_ssl_conf_dbg ( & s - > conf , schan_imp_debug , stdout ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS setup \n " ) ;
mbedtls_ssl_setup ( & s - > ssl , & s - > conf ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_create_session END! \n " ) ;
2015-09-28 09:43:08 +00:00
return TRUE ;
}
void schan_imp_dispose_session ( schan_imp_session session )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
WARN ( " MBEDTLS schan_imp_dispose_session: %p \n " , session ) ;
2015-09-28 09:43:08 +00:00
/* tell the other peer (a server) that we are going away */
//ssl_close_notify(&s->ssl);
2015-10-04 17:08:38 +00:00
mbedtls_ssl_free ( & s - > ssl ) ;
mbedtls_ctr_drbg_free ( & s - > ctr_drbg ) ;
mbedtls_entropy_free ( & s - > entropy ) ;
2016-05-20 17:09:56 +00:00
mbedtls_ssl_config_free ( & s - > conf ) ;
2015-09-28 09:43:08 +00:00
/* safely overwrite the freed context with zeroes */
HeapFree ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , s ) ;
}
void schan_imp_set_session_transport ( schan_imp_session session ,
struct schan_transport * t )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_set_session_transport: %p %p \n " , session , t ) ;
2015-09-28 09:43:08 +00:00
s - > transport = t ;
}
void schan_imp_set_session_target ( schan_imp_session session , const char * target )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
TRACE ( " MBEDTLS schan_imp_set_session_target: sess: %p hostname: %s \n " , session , target ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
/* FIXME: WINE tests do not pass when we set the hostname because in the test cases
* contacting ' www . winehq . org ' the hostname is defined as ' localhost ' so the server
* sends a non - fatal alert which preemptively forces mbedTLS to close connection . */
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
mbedtls_ssl_set_hostname ( & s - > ssl , target ) ;
2015-09-28 09:43:08 +00:00
}
SECURITY_STATUS schan_imp_handshake ( schan_imp_session session )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
int err = mbedtls_ssl_handshake ( & s - > ssl ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_handshake: %p err: %#x \n " , session , err ) ;
2015-09-28 09:43:08 +00:00
2016-05-22 10:53:23 +00:00
if ( ROS_SCHAN_IS_BLOCKING ( err ) )
2015-09-28 09:43:08 +00:00
{
TRACE ( " Received ERR_NET_WANT_READ/WRITE... let's try again! \n " ) ;
return SEC_I_CONTINUE_NEEDED ;
}
2015-10-04 17:08:38 +00:00
else if ( err = = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE )
2015-09-28 09:43:08 +00:00
{
ERR ( " schan_imp_handshake: SSL Feature unavailable... \n " ) ;
return SEC_E_UNSUPPORTED_FUNCTION ;
}
else if ( err ! = 0 )
{
2015-10-04 17:08:38 +00:00
ERR ( " schan_imp_handshake: Oops! mbedtls_ssl_handshake returned the following error code: -%#x... \n " , - err ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_INTERNAL_ERROR ;
}
WARN ( " schan_imp_handshake: Handshake completed! \n " ) ;
2015-10-04 17:08:38 +00:00
WARN ( " schan_imp_handshake: Protocol is %s, Cipher suite is %s \n " , mbedtls_ssl_get_version ( & s - > ssl ) ,
mbedtls_ssl_get_ciphersuite ( & s - > ssl ) ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_OK ;
}
static unsigned int schannel_get_cipher_key_size ( int ciphersuite_id )
{
2015-10-04 17:08:38 +00:00
const mbedtls_ssl_ciphersuite_t * ssl_cipher_suite = mbedtls_ssl_ciphersuite_from_id ( ciphersuite_id ) ;
const mbedtls_cipher_info_t * cipher_info = mbedtls_cipher_info_from_type ( ssl_cipher_suite - > cipher ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
unsigned int key_bitlen = cipher_info - > key_bitlen ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schannel_get_cipher_key_size: Unknown cipher %#x, returning %u \n " , ciphersuite_id , key_bitlen ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
return key_bitlen ;
2015-09-28 09:43:08 +00:00
}
static unsigned int schannel_get_mac_key_size ( int ciphersuite_id )
{
2015-10-04 17:08:38 +00:00
const mbedtls_ssl_ciphersuite_t * ssl_cipher_suite = mbedtls_ssl_ciphersuite_from_id ( ciphersuite_id ) ;
const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type ( ssl_cipher_suite - > mac ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
int md_size = md_info - > size * CHAR_BIT ; /* return the size in bits, as the secur32:schannel winetest shows */
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schannel_get_mac_key_size: returning %i \n " , md_size ) ;
return md_size ;
2015-09-28 09:43:08 +00:00
}
2015-10-04 17:08:38 +00:00
static unsigned int schannel_get_kx_key_size ( const mbedtls_ssl_context * ssl , const mbedtls_ssl_config * conf , int ciphersuite_id )
2015-09-28 09:43:08 +00:00
{
2015-10-04 17:08:38 +00:00
const mbedtls_ssl_ciphersuite_t * ssl_ciphersuite = mbedtls_ssl_ciphersuite_from_id ( ciphersuite_id ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
/* if we are the server take ca_chain, if we are the client take the proper x509 peer certificate */
const mbedtls_x509_crt * server_cert = ( conf - > endpoint = = MBEDTLS_SSL_IS_SERVER ) ? conf - > ca_chain : mbedtls_ssl_get_peer_cert ( ssl ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
if ( ssl_ciphersuite - > key_exchange ! = MBEDTLS_KEY_EXCHANGE_NONE )
return mbedtls_pk_get_len ( & ( server_cert - > pk ) ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schannel_get_kx_key_size: Unknown kx %#x, returning 0 \n " , ssl_ciphersuite - > key_exchange ) ;
2015-09-28 09:43:08 +00:00
return 0 ;
}
2015-10-04 17:08:38 +00:00
static DWORD schannel_get_protocol ( const mbedtls_ssl_context * ssl , const mbedtls_ssl_config * conf )
2015-09-28 09:43:08 +00:00
{
/* FIXME: currently schannel only implements client connections, but
* there ' s no reason it couldn ' t be used for servers as well . The
* context doesn ' t tell us which it is , so decide based on ssl endpoint value . */
switch ( ssl - > minor_ver )
{
2015-10-04 17:08:38 +00:00
case MBEDTLS_SSL_MINOR_VERSION_0 :
return ( conf - > endpoint = = MBEDTLS_SSL_IS_CLIENT ) ? SP_PROT_SSL3_CLIENT :
SP_PROT_SSL3_SERVER ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
case MBEDTLS_SSL_MINOR_VERSION_1 :
return ( conf - > endpoint = = MBEDTLS_SSL_IS_CLIENT ) ? SP_PROT_TLS1_0_CLIENT :
SP_PROT_TLS1_0_SERVER ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
case MBEDTLS_SSL_MINOR_VERSION_2 :
return ( conf - > endpoint = = MBEDTLS_SSL_IS_CLIENT ) ? SP_PROT_TLS1_1_CLIENT :
SP_PROT_TLS1_1_SERVER ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
case MBEDTLS_SSL_MINOR_VERSION_3 :
return ( conf - > endpoint = = MBEDTLS_SSL_IS_CLIENT ) ? SP_PROT_TLS1_2_CLIENT :
SP_PROT_TLS1_2_SERVER ;
2015-09-28 09:43:08 +00:00
default :
{
2015-10-04 17:08:38 +00:00
FIXME ( " MBEDTLS schannel_get_protocol: unknown protocol %d \n " , ssl - > minor_ver ) ;
2015-09-28 09:43:08 +00:00
return 0 ;
}
}
}
static ALG_ID schannel_get_cipher_algid ( int ciphersuite_id )
{
2015-10-04 17:08:38 +00:00
const mbedtls_ssl_ciphersuite_t * cipher_suite = mbedtls_ssl_ciphersuite_from_id ( ciphersuite_id ) ;
2015-09-28 09:43:08 +00:00
switch ( cipher_suite - > cipher )
{
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_NONE :
case MBEDTLS_CIPHER_NULL :
2015-09-28 09:43:08 +00:00
return 0 ;
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_ARC4_C
2015-09-28 09:43:08 +00:00
/* ARC4 */
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_ARC4_128 :
2015-09-28 09:43:08 +00:00
return CALG_RC4 ;
# endif
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_DES_C
2015-09-28 09:43:08 +00:00
/* DES */
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_DES_ECB :
case MBEDTLS_CIPHER_DES_CBC :
case MBEDTLS_CIPHER_DES_EDE_ECB :
case MBEDTLS_CIPHER_DES_EDE_CBC :
2015-09-28 09:43:08 +00:00
return CALG_DES ;
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_DES_EDE3_ECB :
case MBEDTLS_CIPHER_DES_EDE3_CBC :
2015-09-28 09:43:08 +00:00
return CALG_3DES ;
# endif
2015-10-04 17:08:38 +00:00
# ifdef MBEDTLS_BLOWFISH_C
/* BLOWFISH */
case MBEDTLS_CIPHER_BLOWFISH_ECB :
case MBEDTLS_CIPHER_BLOWFISH_CBC :
case MBEDTLS_CIPHER_BLOWFISH_CFB64 :
case MBEDTLS_CIPHER_BLOWFISH_CTR :
return CALG_RC4 ; // (as schannel does not support it fake it as RC4, which has a
// similar profile of low footprint and medium-high security) CALG_BLOWFISH;
# endif
# ifdef MBEDTLS_CAMELLIA_C
/* CAMELLIA */
case MBEDTLS_CIPHER_CAMELLIA_128_ECB :
case MBEDTLS_CIPHER_CAMELLIA_192_ECB :
case MBEDTLS_CIPHER_CAMELLIA_256_ECB :
case MBEDTLS_CIPHER_CAMELLIA_128_CBC :
case MBEDTLS_CIPHER_CAMELLIA_192_CBC :
case MBEDTLS_CIPHER_CAMELLIA_256_CBC :
case MBEDTLS_CIPHER_CAMELLIA_128_CFB128 :
case MBEDTLS_CIPHER_CAMELLIA_192_CFB128 :
case MBEDTLS_CIPHER_CAMELLIA_256_CFB128 :
case MBEDTLS_CIPHER_CAMELLIA_128_CTR :
case MBEDTLS_CIPHER_CAMELLIA_192_CTR :
case MBEDTLS_CIPHER_CAMELLIA_256_CTR :
case MBEDTLS_CIPHER_CAMELLIA_128_GCM :
case MBEDTLS_CIPHER_CAMELLIA_192_GCM :
case MBEDTLS_CIPHER_CAMELLIA_256_GCM :
return CALG_AES_256 ; // (as schannel does not support it fake it as AES, which has a
// similar profile, offering modern high security) CALG_CAMELLIA;
# endif
# ifdef MBEDTLS_AES_C
2015-09-28 09:43:08 +00:00
/* AES 128 */
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_AES_128_ECB :
case MBEDTLS_CIPHER_AES_128_CBC :
case MBEDTLS_CIPHER_AES_128_CFB128 :
case MBEDTLS_CIPHER_AES_128_CTR :
case MBEDTLS_CIPHER_AES_128_GCM :
# ifdef MBEDTLS_CCM_C
case MBEDTLS_CIPHER_AES_128_CCM :
2015-09-28 09:43:08 +00:00
# endif
return CALG_AES_128 ;
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_AES_192_ECB :
case MBEDTLS_CIPHER_AES_192_CBC :
case MBEDTLS_CIPHER_AES_192_CFB128 :
case MBEDTLS_CIPHER_AES_192_CTR :
case MBEDTLS_CIPHER_AES_192_GCM :
# ifdef MBEDTLS_CCM_C
case MBEDTLS_CIPHER_AES_192_CCM :
2015-09-28 09:43:08 +00:00
# endif
return CALG_AES_192 ;
2015-10-04 17:08:38 +00:00
case MBEDTLS_CIPHER_AES_256_ECB :
case MBEDTLS_CIPHER_AES_256_CBC :
case MBEDTLS_CIPHER_AES_256_CFB128 :
case MBEDTLS_CIPHER_AES_256_CTR :
case MBEDTLS_CIPHER_AES_256_GCM :
# ifdef MBEDTLS_CCM_C
case MBEDTLS_CIPHER_AES_256_CCM :
2015-09-28 09:43:08 +00:00
# endif
return CALG_AES_256 ;
# endif
/* nothing to show? fall through */
default :
{
2015-10-04 17:08:38 +00:00
FIXME ( " MBEDTLS schannel_get_cipher_algid: unknown algorithm %d \n " , ciphersuite_id ) ;
2015-09-28 09:43:08 +00:00
return 0 ;
}
}
}
static ALG_ID schannel_get_mac_algid ( int ciphersuite_id )
{
2015-10-04 17:08:38 +00:00
const mbedtls_ssl_ciphersuite_t * cipher_suite = mbedtls_ssl_ciphersuite_from_id ( ciphersuite_id ) ;
2015-09-28 09:43:08 +00:00
switch ( cipher_suite - > mac )
{
2015-10-04 17:08:38 +00:00
case MBEDTLS_MD_NONE : return 0 ;
case MBEDTLS_MD_MD2 : return CALG_MD2 ;
case MBEDTLS_MD_MD4 : return CALG_MD4 ;
case MBEDTLS_MD_MD5 : return CALG_MD5 ;
case MBEDTLS_MD_SHA1 : return CALG_SHA1 ;
case MBEDTLS_MD_SHA224 : return CALG_SHA ;
case MBEDTLS_MD_SHA256 : return CALG_SHA_256 ;
case MBEDTLS_MD_SHA384 : return CALG_SHA_384 ;
case MBEDTLS_MD_SHA512 : return CALG_SHA_512 ;
case MBEDTLS_MD_RIPEMD160 : return ( ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_RIPEMD160 ) ; /* there's no CALG_RIPEMD or CALG_RIPEMD160 defined in <wincrypt.h> yet */
2015-09-28 09:43:08 +00:00
default :
{
2015-10-04 17:08:38 +00:00
FIXME ( " MBEDTLS schannel_get_mac_algid: unknown algorithm %d \n " , cipher_suite - > mac ) ;
2015-09-28 09:43:08 +00:00
return 0 ;
}
}
}
static ALG_ID schannel_get_kx_algid ( int ciphersuite_id )
{
2015-10-04 17:08:38 +00:00
const mbedtls_ssl_ciphersuite_t * cipher_suite = mbedtls_ssl_ciphersuite_from_id ( ciphersuite_id ) ;
2015-09-28 09:43:08 +00:00
switch ( cipher_suite - > key_exchange )
{
2015-10-04 17:08:38 +00:00
case MBEDTLS_KEY_EXCHANGE_NONE :
case MBEDTLS_KEY_EXCHANGE_PSK : /* the original implementation does not support */
return 0 ; /* any PSK, and does not define any `CALG_PSK` :) */
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
case MBEDTLS_KEY_EXCHANGE_RSA :
case MBEDTLS_KEY_EXCHANGE_RSA_PSK :
2015-09-28 09:43:08 +00:00
return CALG_RSA_KEYX ;
2015-10-04 17:08:38 +00:00
case MBEDTLS_KEY_EXCHANGE_DHE_RSA :
case MBEDTLS_KEY_EXCHANGE_DHE_PSK :
2015-09-28 09:43:08 +00:00
return CALG_DH_EPHEM ;
2015-10-04 17:08:38 +00:00
case MBEDTLS_KEY_EXCHANGE_ECDH_RSA :
case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA :
return CALG_ECDH ;
case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA :
case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA :
case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK :
return CALG_ECDH_EPHEM ;
2015-09-28 09:43:08 +00:00
default :
{
2015-10-04 17:08:38 +00:00
FIXME ( " MBEDTLS schannel_get_kx_algid: unknown algorithm %d \n " , cipher_suite - > key_exchange ) ;
2015-09-28 09:43:08 +00:00
return 0 ;
}
}
}
unsigned int schan_imp_get_session_cipher_block_size ( schan_imp_session session )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
unsigned int cipher_block_size = mbedtls_cipher_get_block_size ( & s - > ssl . transform - > cipher_ctx_enc ) ;
TRACE ( " MBEDTLS schan_imp_get_session_cipher_block_size %p returning %u. \n " , session , cipher_block_size ) ;
return cipher_block_size ;
2015-09-28 09:43:08 +00:00
}
unsigned int schan_imp_get_max_message_size ( schan_imp_session session )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
unsigned int max_frag_len = mbedtls_ssl_get_max_frag_len ( & s - > ssl ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_get_max_message_size %p returning %u. \n " , session , max_frag_len ) ;
return max_frag_len ;
2015-09-28 09:43:08 +00:00
}
SECURITY_STATUS schan_imp_get_connection_info ( schan_imp_session session ,
SecPkgContext_ConnectionInfo * info )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
int ciphersuite_id = mbedtls_ssl_get_ciphersuite_id ( mbedtls_ssl_get_ciphersuite ( & s - > ssl ) ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_get_connection_info %p %p. \n " , session , info ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
info - > dwProtocol = schannel_get_protocol ( & s - > ssl , & s - > conf ) ;
2015-09-28 09:43:08 +00:00
info - > aiCipher = schannel_get_cipher_algid ( ciphersuite_id ) ;
info - > dwCipherStrength = schannel_get_cipher_key_size ( ciphersuite_id ) ;
info - > aiHash = schannel_get_mac_algid ( ciphersuite_id ) ;
info - > dwHashStrength = schannel_get_mac_key_size ( ciphersuite_id ) ;
info - > aiExch = schannel_get_kx_algid ( ciphersuite_id ) ;
2015-10-04 17:08:38 +00:00
info - > dwExchStrength = schannel_get_kx_key_size ( & s - > ssl , & s - > conf , ciphersuite_id ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_OK ;
}
SECURITY_STATUS schan_imp_get_session_peer_certificate ( schan_imp_session session , HCERTSTORE store ,
PCCERT_CONTEXT * ret )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
2015-09-28 09:43:08 +00:00
PCCERT_CONTEXT cert_context = NULL ;
2015-10-04 17:08:38 +00:00
const mbedtls_x509_crt * next_cert ;
const mbedtls_x509_crt * peer_cert = mbedtls_ssl_get_peer_cert ( & s - > ssl ) ;
TRACE ( " MBEDTLS schan_imp_get_session_peer_certificate %p %p %p %p. \n " , session , store , ret , ret ! = NULL ? * ret : NULL ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
if ( ! peer_cert )
2015-09-28 09:43:08 +00:00
return SEC_E_INTERNAL_ERROR ;
2015-10-04 17:08:38 +00:00
for ( next_cert = peer_cert ; next_cert ! = NULL ; next_cert = next_cert - > next )
2015-09-28 09:43:08 +00:00
{
if ( ! CertAddEncodedCertificateToStore ( store , X509_ASN_ENCODING , next_cert - > raw . p , next_cert - > raw . len ,
2015-10-04 17:08:38 +00:00
CERT_STORE_ADD_REPLACE_EXISTING , ( next_cert ! = peer_cert ) ? NULL : & cert_context ) )
2015-09-28 09:43:08 +00:00
{
2015-10-04 17:08:38 +00:00
if ( next_cert ! = peer_cert )
2015-09-28 09:43:08 +00:00
CertFreeCertificateContext ( cert_context ) ;
return GetLastError ( ) ;
}
}
* ret = cert_context ;
return SEC_E_OK ;
}
SECURITY_STATUS schan_imp_send ( schan_imp_session session , const void * buffer ,
SIZE_T * length )
{
2015-10-04 17:08:38 +00:00
MBEDTLS_SESSION * s = ( MBEDTLS_SESSION * ) session ;
2015-09-28 09:43:08 +00:00
int ret ;
2015-10-04 17:08:38 +00:00
ret = mbedtls_ssl_write ( & s - > ssl , ( unsigned char * ) buffer , * length ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_send: (%p, %p, %p/%lu) \n " , s , buffer , length , * length ) ;
2015-09-28 09:43:08 +00:00
if ( ret > = 0 )
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_send: ret=%i. \n " , ret ) ;
2015-09-28 09:43:08 +00:00
* length = ret ;
}
2016-05-22 10:53:23 +00:00
else if ( ROS_SCHAN_IS_BLOCKING ( ret ) )
2015-09-28 09:43:08 +00:00
{
* length = ROS_SCHAN_IS_BLOCKING_RETRIEVE ( ret ) ;
if ( ! * length )
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_I_CONTINUE_NEEDED; len=%lu " , * length ) ;
2015-09-28 09:43:08 +00:00
return SEC_I_CONTINUE_NEEDED ;
}
else
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu " , * length ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_OK ;
}
}
else
{
2015-10-04 17:08:38 +00:00
ERR ( " MBEDTLS schan_imp_send: mbedtls_ssl_write failed with -%x \n " , - ret ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_INTERNAL_ERROR ;
}
return SEC_E_OK ;
}
SECURITY_STATUS schan_imp_recv ( schan_imp_session session , void * buffer ,
SIZE_T * length )
{
2015-10-04 17:08:38 +00:00
PMBEDTLS_SESSION s = ( PMBEDTLS_SESSION ) session ;
2015-09-28 09:43:08 +00:00
int ret ;
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_recv: (%p, %p, %p/%lu) \n " , s , buffer , length , * length ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
ret = mbedtls_ssl_read ( & s - > ssl , ( unsigned char * ) buffer , * length ) ;
2015-09-28 09:43:08 +00:00
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_recv: (%p, %p, %p/%lu) ret= %#x \n " , s , buffer , length , * length , ret ) ;
2015-09-28 09:43:08 +00:00
if ( ret > = 0 )
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_recv: ret == %i. \n " , ret ) ;
2015-09-28 09:43:08 +00:00
* length = ret ;
}
2016-05-22 10:53:23 +00:00
else if ( ROS_SCHAN_IS_BLOCKING ( ret ) )
2015-09-28 09:43:08 +00:00
{
* length = ROS_SCHAN_IS_BLOCKING_RETRIEVE ( ret ) ;
if ( ! * length )
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_I_CONTINUE_NEEDED; len=%lu " , * length ) ;
2015-09-28 09:43:08 +00:00
return SEC_I_CONTINUE_NEEDED ;
}
else
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu " , * length ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_OK ;
}
}
2015-10-04 17:08:38 +00:00
else if ( ret = = MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY )
2015-09-28 09:43:08 +00:00
{
2016-05-22 10:56:22 +00:00
* length = 0 ;
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_recv: ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -> SEC_E_OK \n " ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_OK ;
}
else
{
2015-10-04 17:08:38 +00:00
ERR ( " MBEDTLS schan_imp_recv: mbedtls_ssl_read failed with -%x \n " , - ret ) ;
2015-09-28 09:43:08 +00:00
return SEC_E_INTERNAL_ERROR ;
}
return SEC_E_OK ;
}
BOOL schan_imp_allocate_certificate_credentials ( schan_credentials * c )
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_allocate_certificate_credentials %p %p %d \n " , c , c - > credentials , c - > credential_use ) ;
2015-09-28 09:43:08 +00:00
/* in our case credentials aren't really used for anything, so just stub them */
c - > credentials = NULL ;
return TRUE ;
}
void schan_imp_free_certificate_credentials ( schan_credentials * c )
{
2015-10-04 17:08:38 +00:00
TRACE ( " MBEDTLS schan_imp_free_certificate_credentials %p %p %d \n " , c , c - > credentials , c - > credential_use ) ;
2015-09-28 09:43:08 +00:00
}
BOOL schan_imp_init ( void )
{
2015-10-04 17:08:38 +00:00
TRACE ( " Schannel MBEDTLS schan_imp_init \n " ) ;
2015-09-28 09:43:08 +00:00
return TRUE ;
}
void schan_imp_deinit ( void )
{
2015-10-04 17:08:38 +00:00
WARN ( " Schannel MBEDTLS schan_imp_deinit \n " ) ;
2015-09-28 09:43:08 +00:00
}
# endif /* SONAME_LIBMBEDTLS && !HAVE_SECURITY_SECURITY_H && !SONAME_LIBGNUTLS */