This is an automated email from the ASF dual-hosted git repository. jensg pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/thrift.git
commit 47f6317336b2d8fbd1249a1a49aa561ee052719f Author: Jens Geyer <je...@apache.org> AuthorDate: Thu Jun 6 22:42:58 2019 +0200 THRIFT-4881 Allow TLS1.1 and TLS1.2 even when not configured as systemwide default Client: Delphi Patch: Jens Geyer --- lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas | 13 ++ lib/delphi/src/Thrift.Transport.WinHTTP.pas | 42 ++++++ lib/delphi/src/Thrift.Transport.pas | 14 +- lib/delphi/src/Thrift.WinHTTP.pas | 177 +++++++++++++++++++++++++- lib/delphi/test/TestClient.pas | 7 +- 5 files changed, 249 insertions(+), 4 deletions(-) diff --git a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas index cdfb541..620beba 100644 --- a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas +++ b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas @@ -68,9 +68,12 @@ type function GetSendTimeout: Integer; procedure SetReadTimeout(const Value: Integer); function GetReadTimeout: Integer; + function GetSecureProtocols : TSecureProtocols; + procedure SetSecureProtocols( const value : TSecureProtocols); function GetCustomHeaders: IThriftDictionary<string,string>; procedure SendRequest; + property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout; property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout; property SendTimeout: Integer read GetSendTimeout write SetSendTimeout; @@ -173,6 +176,16 @@ begin FReadTimeout := Value; end; +function TMsxmlHTTPClientImpl.GetSecureProtocols : TSecureProtocols; +begin + Result := []; +end; + +procedure TMsxmlHTTPClientImpl.SetSecureProtocols( const value : TSecureProtocols); +begin + raise TTransportExceptionBadArgs.Create('SetSecureProtocols: Not supported with '+ClassName); +end; + function TMsxmlHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>; begin Result := FCustomHeaders; diff --git a/lib/delphi/src/Thrift.Transport.WinHTTP.pas b/lib/delphi/src/Thrift.Transport.WinHTTP.pas index aac2aea..8b4a7bc 100644 --- a/lib/delphi/src/Thrift.Transport.WinHTTP.pas +++ b/lib/delphi/src/Thrift.Transport.WinHTTP.pas @@ -46,8 +46,10 @@ type FSendTimeout : Integer; FReadTimeout : Integer; FCustomHeaders : IThriftDictionary<string,string>; + FSecureProtocols : TSecureProtocols; function CreateRequest: IWinHTTPRequest; + function SecureProtocolsAsWinHTTPFlags : Cardinal; private type THTTPResponseStream = class( TThriftStreamImpl) @@ -82,9 +84,12 @@ type function GetSendTimeout: Integer; procedure SetReadTimeout(const Value: Integer); function GetReadTimeout: Integer; + function GetSecureProtocols : TSecureProtocols; + procedure SetSecureProtocols( const value : TSecureProtocols); function GetCustomHeaders: IThriftDictionary<string,string>; procedure SendRequest; + property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout; property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout; property SendTimeout: Integer read GetSendTimeout write SetSendTimeout; @@ -111,6 +116,8 @@ begin FSendTimeout := 30 * 1000; FReadTimeout := 30 * 1000; + FSecureProtocols := DEFAULT_THRIFT_SECUREPROTOCOLS; + FCustomHeaders := TThriftDictionaryImpl<string,string>.Create; FOutputMemoryStream := TMemoryStream.Create; end; @@ -133,6 +140,8 @@ begin url := TWinHTTPUrlImpl.Create( FUri); session := TWinHTTPSessionImpl.Create('Apache Thrift Delphi Client'); + session.EnableSecureProtocols( SecureProtocolsAsWinHTTPFlags); + connect := session.Connect( url.HostName, url.Port); sPath := url.UrlPath + url.ExtraInfo; @@ -148,6 +157,29 @@ begin end; end; + +function TWinHTTPClientImpl.SecureProtocolsAsWinHTTPFlags : Cardinal; +const + PROTOCOL_MAPPING : array[TSecureProtocol] of Cardinal = ( + WINHTTP_FLAG_SECURE_PROTOCOL_SSL2, + WINHTTP_FLAG_SECURE_PROTOCOL_SSL3, + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1, + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1, + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 + ); +var + prot : TSecureProtocol; + protos : TSecureProtocols; +begin + result := 0; + protos := GetSecureProtocols; + for prot := Low(TSecureProtocol) to High(TSecureProtocol) do begin + if prot in protos + then result := result or PROTOCOL_MAPPING[prot]; + end; +end; + + function TWinHTTPClientImpl.GetDnsResolveTimeout: Integer; begin Result := FDnsResolveTimeout; @@ -188,6 +220,16 @@ begin FReadTimeout := Value; end; +function TWinHTTPClientImpl.GetSecureProtocols : TSecureProtocols; +begin + Result := FSecureProtocols; +end; + +procedure TWinHTTPClientImpl.SetSecureProtocols( const value : TSecureProtocols); +begin + FSecureProtocols := Value; +end; + function TWinHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>; begin Result := FCustomHeaders; diff --git a/lib/delphi/src/Thrift.Transport.pas b/lib/delphi/src/Thrift.Transport.pas index 1f8fdb0..c2071df 100644 --- a/lib/delphi/src/Thrift.Transport.pas +++ b/lib/delphi/src/Thrift.Transport.pas @@ -118,8 +118,15 @@ type TTransportExceptionBadArgs = class (TTransportExceptionSpecialized); TTransportExceptionInterrupted = class (TTransportExceptionSpecialized); + TSecureProtocol = ( + SSL_2, SSL_3, TLS_1, // outdated, for compatibilty only + TLS_1_1, TLS_1_2 // secure (as of today) + ); + + TSecureProtocols = set of TSecureProtocol; + IHTTPClient = interface( ITransport ) - ['{BA142D12-8AE6-4B50-9E33-6B7843B21D73}'] + ['{7BF615DD-8680-4004-A5B2-88947BA3BA3D}'] procedure SetDnsResolveTimeout(const Value: Integer); function GetDnsResolveTimeout: Integer; procedure SetConnectionTimeout(const Value: Integer); @@ -130,12 +137,15 @@ type function GetReadTimeout: Integer; function GetCustomHeaders: IThriftDictionary<string,string>; procedure SendRequest; + function GetSecureProtocols : TSecureProtocols; + procedure SetSecureProtocols( const value : TSecureProtocols); property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout; property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout; property SendTimeout: Integer read GetSendTimeout write SetSendTimeout; property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout; property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders; + property SecureProtocols : TSecureProtocols read GetSecureProtocols write SetSecureProtocols; end; IServerTransport = interface @@ -373,6 +383,8 @@ procedure TFramedTransportImpl_Initialize; const DEFAULT_THRIFT_TIMEOUT = 5 * 1000; // ms + DEFAULT_THRIFT_SECUREPROTOCOLS = [ TSecureProtocol.TLS_1_1, TSecureProtocol.TLS_1_2]; + implementation diff --git a/lib/delphi/src/Thrift.WinHTTP.pas b/lib/delphi/src/Thrift.WinHTTP.pas index 6ad8400..4b98f69 100644 --- a/lib/delphi/src/Thrift.WinHTTP.pas +++ b/lib/delphi/src/Thrift.WinHTTP.pas @@ -84,6 +84,16 @@ function WinHttpOpenRequest( const hConnect : HINTERNET; const dwFlags : DWORD ) : HINTERNET; stdcall; +function WinHttpQueryOption( const hInternet : HINTERNET; + const dwOption : DWORD; + const pBuffer : Pointer; + var dwBufferLength : DWORD) : BOOL; stdcall; + +function WinHttpSetOption( const hInternet : HINTERNET; + const dwOption : DWORD; + const pBuffer : Pointer; + const dwBufferLength : DWORD) : BOOL; stdcall; + function WinHttpSetTimeouts( const hRequestOrSession : HINTERNET; const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32 ) : BOOL; stdcall; @@ -193,6 +203,157 @@ const INTERNET_SCHEME_HTTP = INTERNET_SCHEME(1); INTERNET_SCHEME_HTTPS = INTERNET_SCHEME(2); + WINHTTP_NO_CLIENT_CERT_CONTEXT = nil; + + // options manifests for WinHttp{Query|Set}Option + WINHTTP_OPTION_CALLBACK = 1; + WINHTTP_OPTION_RESOLVE_TIMEOUT = 2; + WINHTTP_OPTION_CONNECT_TIMEOUT = 3; + WINHTTP_OPTION_CONNECT_RETRIES = 4; + WINHTTP_OPTION_SEND_TIMEOUT = 5; + WINHTTP_OPTION_RECEIVE_TIMEOUT = 6; + WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT = 7; + WINHTTP_OPTION_HANDLE_TYPE = 9; + WINHTTP_OPTION_READ_BUFFER_SIZE = 12; + WINHTTP_OPTION_WRITE_BUFFER_SIZE = 13; + WINHTTP_OPTION_PARENT_HANDLE = 21; + WINHTTP_OPTION_EXTENDED_ERROR = 24; + WINHTTP_OPTION_SECURITY_FLAGS = 31; + WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT = 32; + WINHTTP_OPTION_URL = 34; + WINHTTP_OPTION_SECURITY_KEY_BITNESS = 36; + WINHTTP_OPTION_PROXY = 38; + WINHTTP_OPTION_USER_AGENT = 41; + WINHTTP_OPTION_CONTEXT_VALUE = 45; + WINHTTP_OPTION_CLIENT_CERT_CONTEXT = 47; + WINHTTP_OPTION_REQUEST_PRIORITY = 58; + WINHTTP_OPTION_HTTP_VERSION = 59; + WINHTTP_OPTION_DISABLE_FEATURE = 63; + WINHTTP_OPTION_CODEPAGE = 68; + WINHTTP_OPTION_MAX_CONNS_PER_SERVER = 73; + WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER = 74; + WINHTTP_OPTION_AUTOLOGON_POLICY = 77; + WINHTTP_OPTION_SERVER_CERT_CONTEXT = 78; + WINHTTP_OPTION_ENABLE_FEATURE = 79; + WINHTTP_OPTION_WORKER_THREAD_COUNT = 80; + WINHTTP_OPTION_PASSPORT_COBRANDING_TEXT = 81; + WINHTTP_OPTION_PASSPORT_COBRANDING_URL = 82; + WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH = 83; + WINHTTP_OPTION_SECURE_PROTOCOLS = 84; + WINHTTP_OPTION_ENABLETRACING = 85; + WINHTTP_OPTION_PASSPORT_SIGN_OUT = 86; + WINHTTP_OPTION_PASSPORT_RETURN_URL = 87; + WINHTTP_OPTION_REDIRECT_POLICY = 88; + WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS = 89; + WINHTTP_OPTION_MAX_HTTP_STATUS_CONTINUE = 90; + WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE = 91; + WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE = 92; + WINHTTP_OPTION_CONNECTION_INFO = 93; + WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST = 94; + WINHTTP_OPTION_SPN = 96; + WINHTTP_OPTION_GLOBAL_PROXY_CREDS = 97; + WINHTTP_OPTION_GLOBAL_SERVER_CREDS = 98; + WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT = 99; + WINHTTP_OPTION_REJECT_USERPWD_IN_URL = 100; + WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS = 101; + WINHTTP_OPTION_RECEIVE_PROXY_CONNECT_RESPONSE = 103; + WINHTTP_OPTION_IS_PROXY_CONNECT_RESPONSE = 104; + WINHTTP_OPTION_SERVER_SPN_USED = 106; + WINHTTP_OPTION_PROXY_SPN_USED = 107; + WINHTTP_OPTION_SERVER_CBT = 108; + // + WINHTTP_FIRST_OPTION = WINHTTP_OPTION_CALLBACK; + WINHTTP_LAST_OPTION = WINHTTP_OPTION_SERVER_CBT; + + WINHTTP_OPTION_USERNAME = $1000; + WINHTTP_OPTION_PASSWORD = $1001; + WINHTTP_OPTION_PROXY_USERNAME = $1002; + WINHTTP_OPTION_PROXY_PASSWORD = $1003; + + // manifest value for WINHTTP_OPTION_MAX_CONNS_PER_SERVER and WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER + WINHTTP_CONNS_PER_SERVER_UNLIMITED = $FFFFFFFF; + + // values for WINHTTP_OPTION_AUTOLOGON_POLICY + WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM = 0; + WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW = 1; + WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH = 2; + + WINHTTP_AUTOLOGON_SECURITY_LEVEL_DEFAULT = WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM; + + // values for WINHTTP_OPTION_REDIRECT_POLICY + WINHTTP_OPTION_REDIRECT_POLICY_NEVER = 0; + WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP = 1; + WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS = 2; + + WINHTTP_OPTION_REDIRECT_POLICY_LAST = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS; + WINHTTP_OPTION_REDIRECT_POLICY_DEFAULT = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP; + + WINHTTP_DISABLE_PASSPORT_AUTH = $00000000; + WINHTTP_ENABLE_PASSPORT_AUTH = $10000000; + WINHTTP_DISABLE_PASSPORT_KEYRING = $20000000; + WINHTTP_ENABLE_PASSPORT_KEYRING = $40000000; + + // values for WINHTTP_OPTION_DISABLE_FEATURE + WINHTTP_DISABLE_COOKIES = $00000001; + WINHTTP_DISABLE_REDIRECTS = $00000002; + WINHTTP_DISABLE_AUTHENTICATION = $00000004; + WINHTTP_DISABLE_KEEP_ALIVE = $00000008; + + // values for WINHTTP_OPTION_ENABLE_FEATURE + WINHTTP_ENABLE_SSL_REVOCATION = $00000001; + WINHTTP_ENABLE_SSL_REVERT_IMPERSONATION = $00000002; + + // values for WINHTTP_OPTION_SPN + WINHTTP_DISABLE_SPN_SERVER_PORT = $00000000; + WINHTTP_ENABLE_SPN_SERVER_PORT = $00000001; + WINHTTP_OPTION_SPN_MASK = WINHTTP_ENABLE_SPN_SERVER_PORT; + + // winhttp handle types + WINHTTP_HANDLE_TYPE_SESSION = 1; + WINHTTP_HANDLE_TYPE_CONNECT = 2; + WINHTTP_HANDLE_TYPE_REQUEST = 3; + + // values for auth schemes + WINHTTP_AUTH_SCHEME_BASIC = $00000001; + WINHTTP_AUTH_SCHEME_NTLM = $00000002; + WINHTTP_AUTH_SCHEME_PASSPORT = $00000004; + WINHTTP_AUTH_SCHEME_DIGEST = $00000008; + WINHTTP_AUTH_SCHEME_NEGOTIATE = $00000010; + + // WinHttp supported Authentication Targets + WINHTTP_AUTH_TARGET_SERVER = $00000000; + WINHTTP_AUTH_TARGET_PROXY = $00000001; + + // values for WINHTTP_OPTION_SECURITY_FLAGS + + // query only + SECURITY_FLAG_SECURE = $00000001; // can query only + SECURITY_FLAG_STRENGTH_WEAK = $10000000; + SECURITY_FLAG_STRENGTH_MEDIUM = $40000000; + SECURITY_FLAG_STRENGTH_STRONG = $20000000; + + // Secure connection error status flags + WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED = $00000001; + WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT = $00000002; + WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED = $00000004; + WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA = $00000008; + WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID = $00000010; + WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID = $00000020; + WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE = $00000040; + WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR = $80000000; + + WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 = $00000008; + WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 = $00000020; + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 = $00000080; + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 = $00000200; + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 = $00000800; + + // Note: SECURE_PROTOCOL_ALL does not include TLS1.1 and higher! + WINHTTP_FLAG_SECURE_PROTOCOL_ALL = WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 + or WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 + or WINHTTP_FLAG_SECURE_PROTOCOL_TLS1; + + const WINHTTP_ERROR_BASE = 12000; ERROR_WINHTTP_OUT_OF_HANDLES = WINHTTP_ERROR_BASE + 1; @@ -254,6 +415,7 @@ const or WINHTTP_FLAG_ESCAPE_DISABLE; + type IWinHTTPRequest = interface ['{35C6D9D4-FDCE-42C6-B84C-9294E6FB904C}'] @@ -274,10 +436,11 @@ type end; IWinHTTPSession = interface - ['{B6F8BD98-0605-4A9E-B671-4CB191D74A5E}'] + ['{261ADCB7-5465-4407-8840-468C17F009F0}'] function Handle : HINTERNET; function Connect( const aHostName : UnicodeString; const aPort : INTERNET_PORT = INTERNET_DEFAULT_PORT) : IWinHTTPConnection; function SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean; + function EnableSecureProtocols( const aFlagSet : DWORD) : Boolean; end; IWinHTTPUrl = interface @@ -339,7 +502,7 @@ type // IWinHTTPSession function Connect( const aHostName : UnicodeString; const aPort : INTERNET_PORT = INTERNET_DEFAULT_PORT) : IWinHTTPConnection; function SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean; - + function EnableSecureProtocols( const aFlagSet : DWORD) : Boolean; public constructor Create( const aAgent : UnicodeString; const aAccessType : DWORD = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; @@ -444,6 +607,8 @@ function WinHttpConnect; stdcall; external WINHTTP_DLL; function WinHttpOpenRequest; stdcall; external WINHTTP_DLL; function WinHttpSendRequest; stdcall; external WINHTTP_DLL; function WinHttpSetTimeouts; stdcall; external WINHTTP_DLL; +function WinHttpQueryOption; stdcall; external WINHTTP_DLL; +function WinHttpSetOption; stdcall; external WINHTTP_DLL; function WinHttpAddRequestHeaders; stdcall; external WINHTTP_DLL; function WinHttpWriteData; stdcall; external WINHTTP_DLL; function WinHttpReceiveResponse; stdcall; external WINHTTP_DLL; @@ -521,6 +686,14 @@ begin end; +function TWinHTTPSessionImpl.EnableSecureProtocols( const aFlagSet : DWORD) : Boolean; +var dwSize : DWORD; +begin + dwSize := SizeOf(aFlagSet); + result := WinHttpSetOption( Handle, WINHTTP_OPTION_SECURE_PROTOCOLS, @aFlagset, dwSize); +end; + + { TWinHTTPConnectionImpl } constructor TWinHTTPConnectionImpl.Create( const aSession : IWinHTTPSession; const aHostName : UnicodeString; const aPort : INTERNET_PORT); diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas index 55bf92b..ebda7c6 100644 --- a/lib/delphi/test/TestClient.pas +++ b/lib/delphi/test/TestClient.pas @@ -29,6 +29,8 @@ unit TestClient; {$DEFINE SupportsAsync} {$ifend} +{$WARN SYMBOL_PLATFORM OFF} // Win32Check + interface uses @@ -1354,6 +1356,7 @@ end; procedure TClientThread.InitializeProtocolTransportStack; var streamtrans : IStreamTransport; + canSSL : Boolean; const DEBUG_TIMEOUT = 30 * 1000; RELEASE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT; @@ -1363,6 +1366,7 @@ begin // needed for HTTP clients as they utilize the MSXML COM components OleCheck( CoInitialize( nil)); + canSSL := FALSE; case FSetup.endpoint of trns_Sockets: begin Console.WriteLine('Using sockets ('+FSetup.host+' port '+IntToStr(FSetup.port)+')'); @@ -1374,6 +1378,7 @@ begin trns_WinHttp: begin Console.WriteLine('Using HTTPClient'); FTransport := InitializeHttpTransport( HTTP_TIMEOUTS); + canSSL := TRUE; end; trns_EvHttp: begin @@ -1403,7 +1408,7 @@ begin FTransport := TBufferedTransportImpl.Create( streamtrans, 32); // small buffer to test read() end; - if FSetup.useSSL then begin + if FSetup.useSSL and not canSSL then begin raise Exception.Create('SSL/TLS not implemented'); end;