Recent

Author Topic: sslsockets, TSSLSocketHandler, TInetSocket - example?  (Read 353 times)

prof7bit

  • Full Member
  • ***
  • Posts: 159
sslsockets, TSSLSocketHandler, TInetSocket - example?
« on: November 15, 2022, 04:23:07 pm »
There is a TInetSocket in ssockets (in fcl-net), It wraps a TCP socket into a TStream, I am using it to implement a TCP client like so:

Code: Pascal  [Select][+][-]
  1.     try
  2.       FSocket := TInetSocket.Create(Host, Port);
  3.       FSocket.WriteByte(42);
  4.       ...
  5.  

There is also a unit sslsockets that implements a TSSLSocketHandler that seems to be meant to be plugged into the TInetSocket constructor as the 3rd argument, probably to make it SSL capable.

But TSSLSocketHandler is not meant to be used directly because it has abstract methods. Is there any example of how this code is supposed to look like, how it is meant to be used? What do I need to implement to make the above connection with TInetSocket talk to an SSL server?

Warfley

  • Hero Member
  • *****
  • Posts: 996
Re: sslsockets, TSSLSocketHandler, TInetSocket - example?
« Reply #1 on: November 15, 2022, 05:20:14 pm »
Use "TSSLSocketHandler.GetDefaultHandler" to create an SSL handler with the default handler class. To register the default handler class to be OpenSSL simply import the "opensslsockets" unit in your uses clause and you should be fine
Code: Pascal  [Select][+][-]
  1. uses
  2.   ssockets, sslsockets, opensslsockets;
  3.  
  4. ...
  5. FSocket := TInetSocket.Create(Host, Port, TSSLSocketHandler.GetDefaultHandler);

prof7bit

  • Full Member
  • ***
  • Posts: 159
Re: sslsockets, TSSLSocketHandler, TInetSocket - example?
« Reply #2 on: November 16, 2022, 11:52:48 am »
Use "TSSLSocketHandler.GetDefaultHandler" to create an SSL handler with the default handler class. To register the default handler class to be OpenSSL simply import the "opensslsockets" unit in your uses clause and you should be fine
Code: Pascal  [Select][+][-]
  1. uses
  2.   ssockets, sslsockets, opensslsockets;
  3.  
  4. ...
  5. FSocket := TInetSocket.Create(Host, Port, TSSLSocketHandler.GetDefaultHandler);

Thank you.

Unfortunatley this does not seem to work. If I run that code (with FPC latest main) I get this exception:

Code: Text  [Select][+][-]
  1. An unhandled exception occurred at $00000000004AE9E1:
  2. EAccessViolation: Access violation
  3.   $00000000004AE9E1  Write,  line 624 of openssl/src/fpopenssl.pp
  4.   $0000000000460A18  WriteByte,  line 1221 of ../objpas/classes/streams.inc
  5.  

If I single step into it I notice that in

opensslsockets.pp, line 304,
in method TOpenSSLSocketHandler.Send
in that line:
Code: Pascal  [Select][+][-]
  1.     Result:=FSsl.Write(@Buffer,Count);
  2.  

FSsl is nil!

So there seems to be some initialization missing or broken.

I am using Ubuntu 22.04.1 LTS and I have libssl.so.3 (which is why I need FPC trunk)

Does the following minimal test program run on our system?
Code: Pascal  [Select][+][-]
  1. program test1;
  2.  
  3. uses
  4.   ssockets, sslsockets, opensslsockets;
  5.  
  6. var
  7.   FSocket: TInetSocket;
  8.  
  9. begin
  10.   FSocket := TInetSocket.Create('google.com', 443, TSSLSocketHandler.GetDefaultHandler);
  11.   FSocket.WriteByte(0);
  12.   FSocket.Free;
  13. end.
  14.  

prof7bit

  • Full Member
  • ***
  • Posts: 159
Re: sslsockets, TSSLSocketHandler, TInetSocket - example?
« Reply #3 on: November 16, 2022, 12:18:23 pm »
Found it.

I need to explicitly call Connect after Create. When a sockethandler is passed then the behavior of the constructor changes, without passing a handler the connect happens immediately.

prof7bit

  • Full Member
  • ***
  • Posts: 159
Re: sslsockets, TSSLSocketHandler, TInetSocket - example?
« Reply #4 on: November 16, 2022, 02:22:38 pm »
Ok, for the sake of completeness, I think I have figured out how to use this in a real world application, because there was another minor inconvenience when trying to shut down and close the socket while a thread is in a blocking read on that socket.

Also there is another minor inconvenience when using FPC stable or fixes release: the supported libssl versions are outdated (already fixed in main), it would not work on current Linux distributions anymore without patching the versions array.

This minimal demo example is what I came up with:
Code: Pascal  [Select][+][-]
  1. program test1;
  2.  
  3. uses
  4.   cthreads, Classes, sysutils, sockets, ssockets, sslsockets, opensslsockets, openssl;
  5.  
  6. type
  7.  
  8.   { TReadThread }
  9.  
  10.   TReadThread = class(TThread)
  11.     procedure Execute; override;
  12.   end;
  13.  
  14. const
  15.   SSL = True;
  16.  
  17. var
  18.   Thread: TReadThread;
  19.   Socket: TInetSocket;
  20.   SSLHandler: TOpenSSLSocketHandler;
  21.  
  22. { TReadThread }
  23.  
  24. procedure TReadThread.Execute;
  25. var
  26.   B: Byte;
  27. begin
  28.   writeln('thread: starting');
  29.   try
  30.     repeat
  31.       B := Socket.ReadByte;
  32.       writeln(B);
  33.     until Terminated;
  34.  
  35.   except
  36.     on E: EReadError do begin
  37.       WriteLn('thread: read error means socket was shut down');
  38.     end;
  39.     on E: Exception do begin
  40.       writeln('thread: some other exception');
  41.       Writeln(E.ClassName);
  42.     end;
  43.   end;
  44.   writeln('thread: ending');
  45. end;
  46.  
  47. begin
  48.  
  49.   // ############## connect
  50.  
  51.   if SSL then begin
  52.     if not InitSSLInterface then begin
  53.       writeln('did not find libssl version 1, trying version 3');
  54.       // this is already fixed in fpc trunk
  55.       openssl.DLLVersions[1] := '.3'; // patch the versions array
  56.     end;
  57.     if not InitSSLInterface then begin
  58.       writeln('coul not find any usable ssl support');
  59.       halt(1);
  60.     end;
  61.     SSLHandler := TOpenSSLSocketHandler.create;
  62.     Socket := TInetSocket.Create('google.com', 443, SSLHandler);
  63.     Socket.Connect;
  64.   end
  65.   else begin
  66.     Socket := TInetSocket.Create('google.com', 80);
  67.   end;
  68.   Thread := TReadThread.Create(False);
  69.  
  70.  
  71.   // wait some time while other thread is in blocking read
  72.   Sleep(1000);
  73.  
  74.  
  75.   // ############## close connection
  76.  
  77.   Thread.Terminate;
  78.  
  79.   writeln('force it to exit blocking read in a defined manner');
  80.   if SSL then begin
  81.     // we need to shutdown the ssl handler, not the socket,
  82.     // otherwise the entire program would crash
  83.     SSLHandler.Shutdown(True);
  84.   end
  85.   else begin
  86.     fpshutdown(Socket.Handle, SHUT_RDWR);
  87.   end;
  88.  
  89.   Socket.Free;
  90.   Sleep(1000);
  91.   writeln('done');
  92. end.
  93.  

This should output something like this:
Code: Text  [Select][+][-]
  1. did not find libssl version 1, trying version 3
  2. thread: starting
  3. force it to exit blocking read in a defined manner
  4. thread: read error means socket was shut down
  5. thread: ending
  6. done
  7.  
« Last Edit: November 16, 2022, 03:16:24 pm by prof7bit »

 

TinyPortal © 2005-2018