Recent

Author Topic: [Synapse] Issues with TTCPBlockSocket.DoSSLConnect and OpenSSL.  (Read 5250 times)

guest60499

  • Guest
[Synapse] Issues with TTCPBlockSocket.DoSSLConnect and OpenSSL.
« on: January 30, 2017, 09:21:12 pm »
Based on testing it appears Synapse doesn't complete the handshaking. The listener is started as follows:
Code: [Select]
socat openssl-listen:2000,reuseaddr,cert=../keys/id_rsa.pem,cafile=../keys/id_rsa.crt stdio
It's possible to use socat to connect back to myself. TTCPBlockSocket will connect and initiate a connection but will not proceed further than that. Attempting to connect to a website via HTTPS doesn't fail, it seems like the connection just stops before it is fully connected. Attempting to connect to a machine's SSH server will give you a version string. Sending anything will cause the server to fail with "unknown protocol."

It seems like Synapse doesn't provide a way to add a certificate file to the trust database, which is why I attempted to connect to a website. I can't find out what the error code means as LastErrorDesc is empty.

The code was implemented referring to the following: 1, 2, 3. I also searched the forums but didn't come up with much.

Code: [Select]
Unable to connect with SSL.
-2:
Code: Pascal  [Select][+][-]
  1. unit form;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  9.   ssl_openssl, blcksock;
  10.  
  11. type
  12.   TTCPClient = class(TThread)
  13.   private
  14.     FHost: String;
  15.     FPort: Integer;
  16.     Socket: TTCPBlockSocket;
  17.   protected
  18.     procedure Execute; override;
  19.     procedure SocketStatus(Sender: TObject;
  20.                            Reason: THookSocketReason;
  21.                            const Value: AnsiString);
  22.   public
  23.     constructor Create(CreateSuspended: Boolean;
  24.                        const StackSize: SizeUInt=DefaultStackSize);
  25.     property Host: String read FHost write FHost;
  26.     property Port: Integer read FPort write FPort;
  27.   end;
  28.  
  29.   { TMainForm }
  30.  
  31.   TMainForm = class(TForm)
  32.     procedure FormCreate(Sender: TObject);
  33.   private
  34.     TCPClient: TTCPClient;
  35.   public
  36.   end;
  37.  
  38. var
  39.   MainForm: TMainForm;
  40.  
  41. implementation
  42.  
  43. {$R *.lfm}
  44.  
  45. { TTCPClient }
  46.  
  47. procedure TTCPClient.Execute;
  48. label
  49.   ExitLoop;
  50. var
  51.   Line: String;
  52. begin
  53.   Socket.Connect(FHost, IntToStr(FPort));
  54.   Socket.SSLDoConnect;
  55.  
  56.   if Socket.LastError <> 0 then
  57.   begin
  58.      WriteLn('Unable to connect with SSL.');
  59.      WriteLn(Socket.LastError, ': ', Socket.LastErrorDesc);
  60.   end;
  61.  
  62.   repeat
  63.     while Socket.CanRead(1000) do
  64.     begin
  65.       Line := Socket.RecvString(1);
  66.       if Line = '' then
  67.          goto ExitLoop;
  68.       WriteLn(Line);
  69.     end;
  70.   until False;
  71.  
  72. ExitLoop:
  73.   WriteLn('Done.');
  74. end;
  75.  
  76. procedure TTCPClient.SocketStatus(Sender: TObject;
  77.                                   Reason: THookSocketReason;
  78.                                   const Value: AnsiString);
  79. var
  80.   Status: String;
  81. begin
  82.   case Reason of
  83.     HR_ResolvingBegin:
  84.       Status := 'ResolvingBegin';
  85.     HR_ResolvingEnd:
  86.       Status := 'ResolvingEnd';
  87.     HR_SocketCreate:
  88.       Status := 'SocketCreate';
  89.     HR_SocketClose:
  90.       Status := 'SocketClose';
  91.     HR_Connect:
  92.       Status := 'Connect';
  93.     HR_CanRead:
  94.       Status := 'CanRead';
  95.     HR_CanWrite:
  96.       Status := 'CanWrite';
  97.     HR_ReadCount:
  98.       Status := 'ReadCount';
  99.     HR_WriteCount:
  100.       Status := 'WriteCount';
  101.     HR_Wait:
  102.       Status := 'Wait';
  103.     HR_Error:
  104.       Status := 'Error';
  105.   end;
  106. end;
  107.  
  108. constructor TTCPClient.Create(CreateSuspended: Boolean;
  109.                               const StackSize: SizeUInt=DefaultStackSize);
  110. begin
  111.   inherited Create(CreateSuspended, StackSize);
  112.   Socket := TTCPBlockSocket.CreateWithSSL(TSSLOpenSSL);
  113.  
  114.   Socket.OnStatus := @SocketStatus;
  115.   Socket.ConvertLineEnd := True;
  116. end;
  117.  
  118. { TMainForm }
  119.  
  120. procedure TMainForm.FormCreate(Sender: TObject);
  121. begin
  122.   TCPClient := TTCPClient.Create(True);
  123.   TCPClient.Host := 'localhost';
  124.   TCPClient.Port := 2000;
  125.   TCPClient.Start;
  126. end;
  127.  
  128. end.
  129.  

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: [Synapse] Issues with TTCPBlockSocket.DoSSLConnect and OpenSSL.
« Reply #1 on: January 30, 2017, 11:35:50 pm »
Just to make sure everything is in the right place... does the following code work for you:

One button and memo on the form with openssl-libraries in place:
Code: Pascal  [Select][+][-]
  1. uses
  2.   ssl_openssl, blcksock;
  3.  
  4. procedure TForm1.Button1Click(Sender: TObject);
  5. var
  6.   Socket: TTCPBlockSocket;
  7.   HTTPHeader: String;
  8. begin
  9.   Socket := TTCPBlockSocket.Create;
  10.   try
  11.     Socket.Connect('www.microsoft.com', '443');
  12.     Socket.SSLDoConnect;
  13.     if Socket.LastError = 0 then
  14.     begin
  15.       HTTPHeader :=
  16.         'GET /nl-nl/ HTTP/1.0' + CRLF +
  17.         'Host: www.microsoft.com:443' + CRLF +
  18.         'Keep-Alive: 300' + CRLF +
  19.         'Connection: keep-alive' + CRLF + CRLF;
  20.       Socket.SendString(HTTPHeader);
  21.       Memo1.Lines.Add(Socket.RecvBufferStr(4096, 1000));
  22.       Memo1.Lines.Add('');
  23.       Memo1.Lines.Add('Library used: ' + Socket.SSL.LibName);
  24.       Memo1.Lines.Add('Version: ' + Socket.SSL.LibVersion);
  25.     end;
  26.   finally
  27.     Socket.Free;
  28.   end;
  29. end;

guest60499

  • Guest
Re: [Synapse] Issues with TTCPBlockSocket.DoSSLConnect and OpenSSL.
« Reply #2 on: January 31, 2017, 07:10:01 pm »
Unfortunately I receive no output. It just occurred to me to ensure the shared object file was in the project directory, as they might not be found in the LDPATH. One of the reasons is that Linux distributions tend to append numerical prefixes to allow installation of multiple system libraries.

Reading unit ssl_openssl pointed me towards unit ssl_openssl_lib, which specifies the names of the libraries:

Code: Pascal  [Select][+][-]
  1. var
  2.   {$IFNDEF MSWINDOWS}
  3.     {$IFDEF DARWIN}
  4.     DLLSSLName: string = 'libssl.dylib';
  5.     DLLUtilName: string = 'libcrypto.dylib';
  6.     {$ELSE}
  7.      {$IFDEF OS2}
  8.       {$IFDEF OS2GCC}
  9.     DLLSSLName: string = 'kssl.dll';
  10.     DLLUtilName: string = 'kcrypto.dll';
  11.       {$ELSE OS2GCC}
  12.     DLLSSLName: string = 'ssl.dll';
  13.     DLLUtilName: string = 'crypto.dll';
  14.       {$ENDIF OS2GCC}
  15.      {$ELSE OS2}
  16.     DLLSSLName: string = 'libssl.so';
  17.     DLLUtilName: string = 'libcrypto.so';
  18.      {$ENDIF OS2}
  19.     {$ENDIF}
  20.   {$ELSE}
  21.   DLLSSLName: string = 'ssleay32.dll';
  22.   DLLSSLName2: string = 'libssl32.dll';
  23.   DLLUtilName: string = 'libeay32.dll';
  24.   {$ENDIF}
  25. {$ENDIF}
  26.  

Having compiled the temporary project, the block with the names "libssl.so" and "libcrypto.so" is highlighted. I located the system libraries and copied them into the project folder and compiled and ran the project. As mentioned, nothing interesting happened.

rvk

  • Hero Member
  • *****
  • Posts: 6163
Re: [Synapse] Issues with TTCPBlockSocket.DoSSLConnect and OpenSSL.
« Reply #3 on: January 31, 2017, 07:35:03 pm »
Code: [Select]
DLLSSLName = 'libssl.so';
DLLUtilName = 'libcrypto.so';

Yeah, that's why I let you run that simple example. Those libraries need to be found. So you just have a openssl problem.

Did you copy the exact libssl.so or still libssl1.0.0.so or something?
libssl.so in your project directory doesn't work. See edit below.

Normally you create a symbolic link with the name libssl.so to the real libssl.so file.
Like:
Code: [Select]
# ls /usr/lib/i386-linux-gnu/libssl*.so
lrwxrwxrwx 1 root root 15 Jan 27 01:19 /usr/lib/i386-linux-gnu/libssl.so -> libssl.so.1.0.0

# cat /etc/ld.so.conf.d/i386-linux-gnu.conf
# Multiarch support
/lib/i386-linux-gnu
/usr/lib/i386-linux-gnu
/lib/i586-linux-gnu
/usr/lib/i586-linux-gnu
So my guess is you didn't install libsslx.y.z and libssl-dev correctly.
i.e. sudo apt-get install libssl1.0.0 libssl-dev

And where did you get the files? Are you sure you took the 32 bit ones if you compile your project in 32 bit (and 64 bit otherwise)?

What does the Socket.SSL.LibName and Socket.SSL.LibVersion give you? Is it blank (no openssl found) or does it show your libssl.so version?

Edit: O, and B.T.W. Linux doesn't check your project directory for the library.
See: http://wiki.freepascal.org/Lazarus/FPC_Libraries
Quote
Linux
A dynamic library filename always has the form 'lib'+packagename+'.so'+version. For example: libz.so.1 and libz.so.1.2.2.
Linux searches a library in this order:
  • first in the paths of the environment variable LD_LIBRARY_PATH
  • then in /lib
  • then /usr/lib
  • finally the paths of /etc/ld.so.conf
Using ldconfig after copying your library file into a lib directory may help with caching issues.
To share memory (GetMem/FreeMem, strings) with other libraries (not written in FPC) under Linux, you should use the unit cmem. This unit must be added as the very first unit in the uses section of the project main source file (typically .lpr), so that its initialization section is called before any other unit can allocate memory.

So you need to create a symbolic linked file libssl.so in one of these directories to you libsslx.y.z.so version libssl. And then run ldconfig. After that loading the library should work.
« Last Edit: January 31, 2017, 07:57:49 pm by rvk »

guest60499

  • Guest
Re: [Synapse] Issues with TTCPBlockSocket.DoSSLConnect and OpenSSL.
« Reply #4 on: January 31, 2017, 09:03:15 pm »
Thanks for the info rvk, it turns out I needed libssl-dev (under Debian). I'm glad to know that FreePascal does the sane thing when checking for libraries. Not that I assumed it didn't, necessarily, I was just very confused by the behavior...

Very grateful, thanks!

EDIT: As a note to anyone reading, setting CertCAFile to the path of the server's .crt will allow the verification of a self-signed certificate. For use with a socat server you will need to set verify=0 as I don't think Synapse supports offering a key as part of the client handshake.

 

TinyPortal © 2005-2018