Adding SSL encryption to TidTCPServer/TidTCPClient - delphi

I'm adding SSL encryption to an existing project in Delphi 7 using a TCP Server and Client with no certificates. I've attached the required SSL IOHandlers in each program, set the PassThrough to False in the OnConnected/Execute procedures, and the error I get during a connection attempt is:
Error connecting with SSL.
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure.
Using OpenSSL 1.0.2 DLL's, latest Indy10 from GitHub. I've used SSL with TIdHTTP with no issues.
I've been reading every search item on the subject but cannot find a solution.
Here is the TCPServer DFM.
object TCPServer: TIdTCPServer
Bindings = <>
DefaultPort = 2323
IOHandler = SSLHandler
OnConnect = TCPServerConnect
OnDisconnect = TCPServerDisconnect
OnException = TCPServerException
OnListenException = TCPServerListenException
OnExecute = TCPServerExecute
end
object SSLHandler: TIdServerIOHandlerSSLOpenSSL
SSLOptions.Method = sslvSSLv23
SSLOptions.Mode = sslmServer
SSLOptions.VerifyMode = []
SSLOptions.VerifyDepth = 0
SSLOptions.Versions = [sslvTLSv1_2]
end
procedure TVTServerForm.TCPServerConnect(AContext: TIdContext);
begin
TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).Passthrough := False;
end;
procedure TVTServerForm.TCPServerExecute(AContext: TIdContext);
begin
Cmd := Trim(AContext.Connection.IOHandler.ReadLn);
if Cmd = 'Login' then etc
TCPClient DFM...
object TCPClient: TIdTCPClient
IOHandler = SSLHandler
OnDisconnected = TCPClientDisconnected
OnWork = TCPClientWork
OnConnected = TCPClientConnected
ConnectTimeout = 10000
IPVersion = Id_IPv4
Port = 2323
ReadTimeout = 100000
Left = 728
Top = 468
end
object SSLHandler: TIdSSLIOHandlerSocketOpenSSL
Destination = ':2323'
MaxLineAction = maException
Port = 2323
DefaultPort = 0
ReadTimeout = 100000
SSLOptions.Method = sslvSSLv23
SSLOptions.Mode = sslmClient
SSLOptions.VerifyMode = []
SSLOptions.VerifyDepth = 0
SSLOptions.SSLVersions := [sslvTLSv1_2]
end
procedure TMainForm.TCPClientConnected(Sender: TObject);
var Ret: string;
begin
TIdSSLIOHandlerSocketBase(TCPClient.IOHandler).Passthrough := False;
TCPClient.IOHandler.Writeln('Login');
Ret := TCPClient.IOHandler.ReadLn;
etc

Related

DataSnap did not close SQL Server Connection's

I have DataSnap Server with connection to MS SQL Server database. I use Zeos Connection objects. Client is Android application. Both are made in Delphi XE10.2. When my android client lost connection to DataSnap Server connection to MS SQL Server remains still active and never close. If I gracefully closes Android client application it does not happen. After some disconnections I get message db error 10029 - Maximum number of DBPROCESSes already allocated and I must restart my DataSnap server. What should I do.
DataSnap server application looks like this.
ServerContainer Unit Form :
object ServerContainer1: TServerContainer1
OldCreateOrder = False
Height = 271
Width = 415
object DSServer1: TDSServer
Left = 96
Top = 11
end
object DSTCPServerTransport1: TDSTCPServerTransport
PoolSize = 100
Server = DSServer1
Filters = <>
Left = 96
Top = 73
end
object DSServerClass1: TDSServerClass
OnGetClass = DSServerClass1GetClass
Server = DSServer1
Left = 200
Top = 19
end
end
Code :
unit ServerContainerUnit1;
interface
uses System.SysUtils, System.Classes,
Datasnap.DSTCPServerTransport,
Datasnap.DSServer, Datasnap.DSCommonServer,
IPPeerServer, IPPeerAPI, Datasnap.DSAuth;
type
TServerContainer1 = class(TDataModule)
DSServer1: TDSServer;
DSTCPServerTransport1: TDSTCPServerTransport;
DSServerClass1: TDSServerClass;
procedure DSServerClass1GetClass(DSServerClass: TDSServerClass;
var PersistentClass: TPersistentClass);
private
{ Private declarations }
public
end;
var
ServerContainer1: TServerContainer1;
implementation
{$R *.dfm}
uses
ServerMethodsUnit1, main;
procedure TServerContainer1.DSServerClass1GetClass(
DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;
end.
Server Methods Unit looks like this :
Print screen of form
There is no code except EchoString and ReverseString function in this unit
On the client side I have DataModule with TSQLConnection, TDSProviderConnection and many TClientDataSets
One of procedure's in my client app looks like this :
procedure A();
begin
try
DM.PingCDS.Close;
DM.PingCDS.Open;
except
DM.Konekcija.Close;
DM.Konekcija.Open;
end;
DM.KorisnikCDS.Close;
DM.KorisnikCDS.Params.ParamByName('aplikacija').Value := 'S';
DM.KorisnikCDS.Open;
while not DM.KorisnikCDS.Eof do
begin
i := DM.KorisnikCDS.RecNo;
k := TKorisnik.Create;
k.user_name := DM.KorisnikCDSUSER_NAME.AsString;
k.pass := 'd' + inttostr(i);
k.IDKorisnik := DM.KorisnikCDSID_KORISNIK.AsInteger;
k.ImeIPrezime := DM.KorisnikCDSIME.AsString + ' ' + DM.KorisnikCDSPREZIME.AsString;
k.frame := TframeKorisnik.Create(hbKorisnici);
k.frame.Parent := hbKorisnici;
k.frame.Korisnik := k;
k.frame.Position.X := 10 + (i - 1) * k.frame.Width;
k.frame.Position.Y := 0;
k.frame.Name := 'frameKorisnik' + IntToStr(k.IDKorisnik);
k.frame.lblUserName.Text := k.user_name;
k.frame.Opacity := 0.7;
ms := TMemoryStream.Create;
(DM.KorisnikCDSSLIKA as TBlobField).SaveToStream(ms);
ms.Position := 0;
k.frame.imgKorisnik.Bitmap.LoadFromStream(ms);
ms.Free;
k.frame.OnTap := TapKorisnik;
//k.frame.OnMouseUp := KornisnikMouseUP;
ListaKorisnika.Add(k);
DM.KorisnikCDS.Next;
end;
DM.KorisnikCDS.Close;
end;
You can see that I created Ping query to determine is Connection to DataSnap Server still alive. If not I reconnect. I think that is the problem. If connection to DataSnap server broke, SQL connection still stay active and when I reconnect to DataSnap server I see new SQL Connection in Activity monitor. Old one never disconnect
This is print screen of Activity monitor with few connections that never ends.
Print screen of Activity monitor
I hope any one of you can help me

Delphi XE7 Indy Rest Api post with Ssl Connection Timeout 10060

I am trying post under the ssl address service and i got connection timeout 10060., My ssl library and Indy SSl configurations is true because i used same code on email sending with gmail and another services.
I posted with postman it works.
my code
const
Api = 'https://xxxx.xxxx.com/api/detection/Insert';
procedure TRestSender.SendThreats(CustomerId: Integer;
DetectionName, Filename: String);
var
PostData: TStringList;
res: string;
Https: TIdHttp;
IdSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
Https := Tidhttp.Create(nil);
PostData := TStringList.Create;
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
Https.ReadTimeout := 10000;
Https.ConnectTimeout:= 10000;
IdSSL.SSLOptions.Method := sslvTLSv1;
// IdSSL.OnStatusInfo:= ssl1StatusInfo;
IdSSL.SSLOptions.Mode := sslmClient;
Https.IOHandler := IdSSL;
try
PostData.Add('Content-Type:application/x-www-form-urlencoded');
PostData.Add('CustomerId=' + IntToStr(CustomerId));
PostData.Add('DetectionName=' + DetectionName);
PostData.Add('DeviceName=' + ComputerName());
PostData.Add('Filename=' + Filename);
PostData.Add('ApiUser=' + 'some-code');
PostData.Add('ApiPass=' + 'some-paswd');
res := Https.Post(Api, PostData);
finally
PostData.Free;
Https.Free;
IdSSL.Free;
end;
end;
I have two suggestions:
Wrong TLS version: More and more services disable TLS 1.0 and/or TLS1.1. The default version is TLS 1.0.
const
DEF_SSLVERSION = sslvTLSv1;
DEF_SSLVERSIONS = [sslvTLSv1];
So add the following line:
IdSSL.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1, sslvTLSv1];
Missing SNI support (an example for SNI).

IdHTTP + SOCKS + Socks5

I'm getting a general Indy error when using the IdHTTP client component in
conjunction with a SOCKS5 proxy server and using SSL.
If I use the IdHTTP component with my SOCKS5 proxy (and a non https URL),
everything works without problems.
If I use the IdHTTP component with an SSL URL (and no SOCKS5 proxy),
everything works without problems.
If I use the IdHTTP component with an SSL URL and a SOCKS5 proxy i get following error:
Line 405 of the error output
idSocks.pas (raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
Here is my code
var
HTTP : TIdHTTP;
Cookie : TIdCookieManager;
SSL : TIdSSLIOHandlerSocketOpenSSL;
Params : TStringList;
HTMLSource : String;
CurrentProxy : String;
ProxyPort : Integer;
ProxyHost : String;
ProxyUsername : String;
ProxyPW : String;
begin
Synchronize(AddItem);
HTTP := TIdHTTP.Create(NIL);
Cookie := TIdCookieManager.Create(HTTP);
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
HTTP.CookieManager := Cookie;
HTTP.IOHandler := SSL;
HTTP.HandleRedirects := True;
Params := TStringList.Create;
HTTP.Request.UserAgent := Task^.Useragent;
try
while True do begin
if terminated then Exit;
Params.Clear;
Cookie.CookieCollection.Clear;
if Task^.Proxytype >= 0 then begin // if proxy enabled
CurrentProxy := Task^.Form.GetProxyFromPool;
ProxyHost := ParsingW(':', CurrentProxy, 1);
ProxyPort := strtoint(ParsingW(':', CurrentProxy, 2));
HTTP.ConnectTimeout := (Task^.Proxytimeout * 1000);
if Task^.ProxyAuth then begin
ProxyUsername := ParsingW(':', CurrentProxy, 3);
ProxyPW := ParsingW(':', CurrentProxy, 4);
end;
end;
if Task^.Proxytype = 0 then begin //HTTP(s)
HTTP.ProxyParams.ProxyServer := ProxyHost;
HTTP.ProxyParams.ProxyPort := ProxyPort;
if Task^.ProxyAuth then begin
HTTP.ProxyParams.ProxyUsername := ProxyUsername;
HTTP.ProxyParams.ProxyPassword := ProxyPW;
end;
end;
if (Task^.Proxytype = 1) or (Task^.Proxytype = 2) then begin // Socks 4 or 5
SSL.TransparentProxy := TIdSocksInfo.Create(HTTP);
(SSL.TransparentProxy as TIdSocksInfo).Port := ProxyPort;
(SSL.TransparentProxy as TIdSocksInfo).Host := ProxyHost;
if Task^.ProxyAuth then begin
(SSL.TransparentProxy as TIdSocksInfo).Username := ProxyUsername;
(SSL.TransparentProxy as TIdSocksInfo).Password := ProxyPW;
(SSL.TransparentProxy as TIdSocksInfo).Authentication := saUsernamePassword;
end else begin
(SSL.TransparentProxy as TIdSocksInfo).Authentication := saNoAuthentication;
end;
if (Task^.Proxytype = 1) then (SSL.TransparentProxy as TIdSocksInfo).Version := svSocks4;
if (Task^.Proxytype = 2) then (SSL.TransparentProxy as TIdSocksInfo).Version := svSocks5;
end;
Did I miss something or is it not possible to connect to a a SSL site with a Socks5 Proxy?
The fact that you are getting an EIdSocksServerGeneralError raised means that TIdHTTP is successfully communicating with the SOCKS proxy and it is validating your request to access it with no authentication, but it is then failing to establish a connection with the target server that you specified in your HTTPS url. The proxy is replying with error code 1 (general failure). Make sure that the url is accurate. Either the proxy cannot resolve the hostname to an IP (try specifying an IP instead of a hostname in the url and see if it makes a difference), or the proxy does not have a valid route to reach that IP, or some other error is occurring on the proxy end. If you have access to the proxy, try looking at its logs to see what actually went wrong.

Sending message to gmail fails with "Start SSL negotiation command failed." error

Tips i followed is found here.
I do have libeay32.dll and ssleay32.dll in win32 folder.
dfm file:
object tidSMTP: TIdSMTP
IOHandler = tidSMTP_SSL
SASLMechanisms = <>
UseTLS = utUseExplicitTLS
end
object tidSMTP_SSL: TIdSSLIOHandlerSocketOpenSSL
Destination = 'smtp.gmail.com:587'
Host = 'smtp.gmail.com'
MaxLineAction = maException
Port = 587
DefaultPort = 0
SSLOptions.Mode = sslmUnassigned
SSLOptions.VerifyMode = []
SSLOptions.VerifyDepth = 0
end
and Send button click event:
procedure TForm1.btnSendClick(Sender: TObject);
var
mes:TIdMessage;
fromAddress:TIdEmailAddressItem;
toAddress:TIdEMailAddressItem;
begin
tidSMTP.Username := txtUsername.Text;
tidSMTP.Password := txtPassword.Text;
tidSMTP.Host := txtSMTPserver.Text; //smtp.gmail.com
tidSMTP.Port := StrToInt(txtSMTPport.Text); //587
fromAddress := TIdEMailAddressItem.Create;
fromAddress.Address := txtUsername.Text;
toAddress := TIdEMailAddressItem.Create;
toAddress.Address := txtTo.Text;
mes := TIdMessage.Create;
mes.ContentType := 'text/plain';
mes.From := fromAddress;
mes.ReceiptRecipient := toAddress;
mes.Subject := txtSubject.Text;
mes.Body := memoText.Lines;
tidSMTP.Connect;
tidSMTP.Send(mes);
tidSMTP.Disconnect;
end;
Any help would be appreciated!
Set you SSL Method to SSL version 3 (tidSMTP_SSL.SSLOptions.Method). I think it defaults to SSL version 2, but GMail does not support that.
SSLOptions.Method := sslvSSLv3;
Edit:
You can log the SSL Status info by assigning an eventhandler to the OnStatusInfo event of your IOHandler:
tidSMTP_SSL.OnStatusInfo := DoOnStatusInfo;
proceudre TForm1.DoOnStatusInfo(Msg: string);
begin
// when running from IDE, message will appear in
// EventLog (Ctrl+Alt+V), otherwise,
// use DebugViewer.exe
OutputDebugString(PChar(Msg));
end;
Maybe this will give you a clue about the failing negotation.
PS: I'm on Indy 9.0.0.18, so things may have changed for you.
Edit2:
If above does not help, please check if there is not a firewall / antivirus that is blocking smtp.gmail.com or port 587
I successfully make it worked like this:
procedure TForm1.btn2Click(Sender: TObject);
var
email : TIdMessage;
idSMTPGMail: TIdSMTP;
idSSLGMail : TIdSSLIOHandlerSocketOpenSSL;
begin
idSSLGMail := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
idSSLGMail.SSLOptions.Method := sslvTLSv1;
idSSLGMail.SSLOptions.Mode := sslmUnassigned;
idSMTPGMail := TIdSMTP.Create(nil);
idSMTPGMail.IOHandler := idSSLGMail;
idSMTPGMail.UseTLS := utUseExplicitTLS;
email := TIdMessage.Create(nil);
email.From.Address := txtUsername.Text;
email.Recipients.EMailAddresses := txtTo.Text;
email.Subject := txtSubject.Text;
email.Body.Text := memoText.Text;
idSMTPGMail.Host := 'smtp.gmail.com';
idSMTPGMail.Port := 587;
idSMTPGMail.UserName := txtUsername.Text;
idSMTPGMail.Password := txtPassword.Text;
idSMTPGMail.Connect;
idSMTPGMail.Send(email);
idSMTPGMail.Disconnect;
email.Free;
idSSLGMail.Free;
idSMTPGMail.Free;
Beep;
end;
I use the same TEdit, TMemo, but dynamically create the Indy components...

Setting Internet Proxy in IE on active dial up or vpn connection in delphi

I want to set proxy in action connection for IE with Delphi codes.
I test this code:
Procedure SetProxy(const Server: String);
var
Reg : TRegistry;
begin
Reg := TRegistry.Create;
Reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Internet Settings',False);
Reg.WriteString('ProxyServer',Server);
Reg.WriteBool('ProxyEnable',True);
Reg.CloseKey;
Reg.Free;
InternetSetOption(0, INTERNET_OPTION_SETTINGS_CHANGED, 0, 0);
end;
But it is change only LAN Setting in IE Internet Option.
Anyone have a solution for that?
Additional:
How can I retrieve Connection names list?
Amin, in your code you are setting the global proxy server. The setting for each connection is stored in this location HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections in a binary format which is not very well documented, so you must figure out the format and position to write the correct data.
Instead of the windows registry you can use the InternetSetOption function, check this sample application which update the proxy configuration for a particular connection.
program UpdateProxyApp;
{$APPTYPE CONSOLE}
uses
WinInet,
Windows,
SysUtils;
type
INTERNET_PER_CONN_OPTION = record
dwOption: DWORD;
Value: record
case Integer of
1: (dwValue: DWORD);
2: (pszValue: PAnsiChar);
3: (ftValue: TFileTime);
end;
end;
LPINTERNET_PER_CONN_OPTION = ^INTERNET_PER_CONN_OPTION;
INTERNET_PER_CONN_OPTION_LIST = record
dwSize: DWORD;
pszConnection: LPTSTR;
dwOptionCount: DWORD;
dwOptionError: DWORD;
pOptions: LPINTERNET_PER_CONN_OPTION;
end;
const
INTERNET_PER_CONN_FLAGS = 1;
INTERNET_PER_CONN_PROXY_SERVER = 2;
INTERNET_PER_CONN_PROXY_BYPASS = 3;
INTERNET_PER_CONN_AUTOCONFIG_URL = 4;
INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5;
PROXY_TYPE_DIRECT = $00000001;
PROXY_TYPE_PROXY = $00000002;
PROXY_TYPE_AUTO_PROXY_URL = $00000004;
PROXY_TYPE_AUTO_DETECT = $00000008;
INTERNET_OPTION_REFRESH = 37;
INTERNET_OPTION_PER_CONNECTION_OPTION = 75;
INTERNET_OPTION_SETTINGS_CHANGED = 39;
function SetConnectionProxy(const conn_name, proxy_addr : AnsiString) : Boolean;
var
list : INTERNET_PER_CONN_OPTION_LIST;
dwBufSize: DWORD;
Options : array[0..2] of INTERNET_PER_CONN_OPTION;
begin
dwBufSize := SizeOf(list);
list.dwSize := dwBufSize;
list.pszConnection := PAnsiChar(conn_name);
list.dwOptionCount := 3;
list.pOptions := #Options;
// Set the flags
Options[0].dwOption := INTERNET_PER_CONN_FLAGS;
Options[0].Value.dwValue := PROXY_TYPE_DIRECT OR PROXY_TYPE_PROXY;
// Set proxy name
Options[1].dwOption := INTERNET_PER_CONN_PROXY_SERVER;
Options[1].Value.pszValue:= PAnsiChar(proxy_addr);
// Set proxy override .
Options[2].dwOption := INTERNET_PER_CONN_PROXY_BYPASS;
Options[2].Value.pszValue:= PAnsiChar('local');
// Set the new settings
Result := InternetSetOption(nil, INTERNET_OPTION_PER_CONNECTION_OPTION, #list, dwBufSize);
InternetSetOption(nil, INTERNET_OPTION_SETTINGS_CHANGED, nil, 0);
InternetSetOption(nil, INTERNET_OPTION_REFRESH , nil, 0);
end;
begin
try
Writeln(Format('Settings updated %s',[BoolToStr(SetConnectionProxy('Your connection Name', '192.168.15.15:80'),True)]));
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.

Resources