123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- unit opensslsockets;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, sockets, ssockets, sslsockets, sslbase, openssl, fpopenssl;
- Type
- { TOpenSSLSocketHandler }
- TOpenSSLSocketHandler = Class(TSSLSocketHandler)
- Private
- FSSL: TSSL;
- FCTX : TSSLContext;
- FSSLLastErrorString: string;
- FSSLLastError : Integer;
- Protected
- procedure SetSSLLastErrorString(AValue: string);
- Function FetchErrorInfo: Boolean;
- function CheckSSL(SSLResult: Integer): Boolean;
- function CheckSSL(SSLResult: Pointer): Boolean;
- function InitContext(NeedCertificate: Boolean): Boolean; virtual;
- function DoneContext: Boolean; virtual;
- function InitSslKeys: boolean;virtual;
- Function GetLastSSLErrorString : String; override;
- Function GetLastSSLErrorCode : Integer; override;
- Public
- Constructor create; override;
- destructor destroy; override;
- function CreateCertGenerator: TX509Certificate; override;
- function Connect : Boolean; override;
- function Close : Boolean; override;
- function Accept : Boolean; override;
- function Shutdown(BiDirectional : Boolean): boolean; override;
- function Send(Const Buffer; Count: Integer): Integer; override;
- function Recv(Const Buffer; Count: Integer): Integer; override;
- function BytesAvailable: Integer; override;
- // Result of last CheckSSL call.
- Function SSLLastError: integer;
- property SSLLastErrorString: string read FSSLLastErrorString write SetSSLLastErrorString;
- property SSL: TSSL read FSSL; // allow more lower level info and control
- end;
- implementation
- { TSocketHandler }
- Resourcestring
- SErrNoLibraryInit = 'Could not initialize OpenSSL library';
- Procedure MaybeInitSSLInterface;
- begin
- if not IsSSLloaded then
- if not InitSSLInterface then
- Raise EInOutError.Create(SErrNoLibraryInit);
- end;
- function TopenSSLSocketHandler.CreateCertGenerator: TX509Certificate;
- begin
- Result:=TOpenSSLX509Certificate.Create;
- end;
- procedure TOpenSSLSocketHandler.SetSSLLastErrorString(AValue: string);
- begin
- if FSSLLastErrorString=AValue then Exit;
- FSSLLastErrorString:=AValue;
- end;
- function TOpenSSLSocketHandler.Connect: Boolean;
- begin
- Result:=Inherited Connect;
- Result := Result and InitContext(False);
- if Result then
- begin
- Result:=CheckSSL(FSSL.SetFD(Socket.Handle));
- if Result then
- begin
- if SendHostAsSNI and (Socket is TInetSocket) then
- FSSL.Ctrl(SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,PAnsiChar(AnsiString((Socket as TInetSocket).Host)));
- Result:=CheckSSL(FSSL.Connect);
- //if Result and VerifyPeerCert then
- // Result:=(FSSL.VerifyResult<>0) or (not DoVerifyCert);
- if Result then
- Result:= DoVerifyCert;
- if Result then
- SetSSLActive(True);
- end;
- end;
- end;
- function TOpenSSLSocketHandler.Close: Boolean;
- begin
- Result:=Shutdown(False);
- end;
- Function TOpenSSLSocketHandler.FetchErrorInfo : Boolean;
- var
- S : AnsiString;
- begin
- FSSLLastErrorString:='';
- FSSLLastError:=ErrGetError;
- ErrClearError;
- Result:=(FSSLLastError<>0);
- if Result then
- begin
- S:=StringOfChar(#0,256);
- ErrErrorString(FSSLLastError,S,256);
- FSSLLastErrorString:=s;
- end;
- end;
- function TOpenSSLSocketHandler.CheckSSL(SSLResult : Integer) : Boolean;
- begin
- Result:=SSLResult>=1;
- if Not Result then
- begin
- FSSLLastError:=SSLResult;
- FetchErrorInfo;
- end;
- end;
- function TOpenSSLSocketHandler.CheckSSL(SSLResult: Pointer): Boolean;
- begin
- Result:=(SSLResult<>Nil);
- if not Result then
- Result:=FetchErrorInfo;
- end;
- function TOpenSSLSocketHandler.DoneContext: Boolean;
- begin
- FreeAndNil(FSSL);
- FreeAndNil(FCTX);
- ErrRemoveState(0);
- SetSSLActive(False);
- Result:=True;
- end;
- Function HandleSSLPwd(buf : PAnsiChar; len:Integer; flags:Integer; UD : Pointer):Integer; cdecl;
- var
- Pwd: AnsiString;
- H : TOpenSSLSocketHandler;
- begin
- if Not Assigned(UD) then
- PWD:=''
- else
- begin
- H:=TOpenSSLSocketHandler(UD);
- Pwd:=H.CertificateData.KeyPassword;
- end;
- if (len<Length(Pwd)+1) then
- SetLength(Pwd,len-1);
- pwd:=pwd+#0;
- Result:=Length(Pwd);
- Move(Pointer(Pwd)^,Buf^,Result);
- end;
- function TOpenSSLSocketHandler.InitSslKeys: boolean;
- begin
- Result:=(FCTX<>Nil);
- if not Result then
- Exit;
- if not CertificateData.Certificate.Empty then
- Result:=CheckSSL(FCTX.UseCertificate(CertificateData.Certificate));
- if Result and not CertificateData.PrivateKey.Empty then
- Result:=CheckSSL(FCTX.UsePrivateKey(CertificateData.PrivateKey));
- if Result and ((CertificateData.CertCA.FileName<>'') or (CertificateData.TrustedCertsDir<>'')) then
- Result:=CheckSSL(FCTX.LoadVerifyLocations(CertificateData.CertCA.FileName,CertificateData.TrustedCertsDir));
- if Result and not CertificateData.PFX.Empty then
- Result:=CheckSSL(FCTX.LoadPFX(CertificateData.PFX,CertificateData.KeyPassword));
- end;
- function TOpenSSLSocketHandler.GetLastSSLErrorString: String;
- begin
- Result:=FSSLLastErrorString;
- end;
- function TOpenSSLSocketHandler.GetLastSSLErrorCode: Integer;
- begin
- Result:=FSSLLastError;
- end;
- constructor TOpenSSLSocketHandler.create;
- begin
- inherited create;
- MaybeInitSSLInterface;
- end;
- destructor TOpenSSLSocketHandler.destroy;
- begin
- FreeAndNil(FCTX);
- FreeAndNil(FSSL);
- inherited destroy;
- end;
- function TOpenSSLSocketHandler.InitContext(NeedCertificate:Boolean): Boolean;
- Const
- VO : Array[Boolean] of Integer = (SSL_VERIFY_NONE,SSL_VERIFY_PEER);
- var
- s: AnsiString;
- begin
- Result:=DoneContext;
- if Not Result then
- Exit;
- try
- FCTX:=TSSLContext.Create(SSLType);
- Except
- CheckSSL(Nil);
- Result:=False;
- Exit;
- end;
- S:=CertificateData.CipherList;
- FCTX.SetCipherList(S);
- FCTX.SetVerify(VO[VerifypeerCert],Nil);
- FCTX.SetDefaultPasswdCb(@HandleSSLPwd);
- FCTX.SetDefaultPasswdCbUserdata(self);
- If NeedCertificate and CertificateData.NeedCertificateData then
- if Not CreateSelfSignedCertificate then
- begin
- DoneContext;
- Exit(False);
- end;
- if Not InitSSLKeys then
- begin
- DoneContext;
- Exit(False);
- end;
- try
- FSSL:=TSSL.Create(FCTX);
- Result:=True;
- Except
- CheckSSL(Nil);
- DoneContext;
- Result:=False;
- end;
- end;
- function TOpenSSLSocketHandler.Accept: Boolean;
- begin
- Result:=InitContext(True);
- if Result then
- begin
- Result:=CheckSSL(FSSL.setfd(Socket.Handle));
- if Result then
- Result:=CheckSSL(FSSL.Accept);
- end;
- SetSSLActive(Result);
- end;
- function TOpenSSLSocketHandler.Shutdown(BiDirectional : Boolean): boolean;
- var
- r : integer;
- begin
- Result:=assigned(FSsl);
- if Result then
- If Not BiDirectional then
- Result:=CheckSSL(FSSL.Shutdown)
- else
- begin
- r:=FSSL.Shutdown;
- if r<>0 then
- Result:=CheckSSL(r)
- else
- begin
- Result:=fpShutdown(Socket.Handle,1)=0;
- if Result then
- Result:=CheckSSL(FSsl.Shutdown);
- end
- end;
- If Result then
- Result:=DoneContext;
- end;
- function TOpenSSLSocketHandler.Send(Const Buffer; Count: Integer): Integer;
- var
- e: integer;
- begin
- FSSLLastError := 0;
- FSSLLastErrorString:='';
- repeat
- Result:=FSsl.Write(@Buffer,Count);
- e:=FSsl.GetError(Result);
- until Not (e in [SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE]);
- if (E=SSL_ERROR_ZERO_RETURN) then
- Result:=0
- else if (e<>0) then
- FSSLLastError:=e;
- end;
- function TOpenSSLSocketHandler.Recv(Const Buffer; Count: Integer): Integer;
- var
- e: integer;
- begin
- FSSLLastError:=0;
- FSSLLastErrorString:= '';
- repeat
- Result:=FSSL.Read(@Buffer ,Count);
- e:=FSSL.GetError(Result);
- if (e=SSL_ERROR_WANT_READ) and (Socket.IOTimeout>0) then
- e:=SSL_ERROR_ZERO_RETURN;
- until Not (e in [SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE]);
- if (E=SSL_ERROR_ZERO_RETURN) then
- Result:=0
- else if (e<>0) then
- FSSLLastError:=e;
- end;
- function TOpenSSLSocketHandler.BytesAvailable: Integer;
- begin
- Result:= FSSL.Pending;
- end;
- Function TOpenSSLSocketHandler.SSLLastError: integer;
- begin
- Result:=FSSLLastError;
- end;
- initialization
- TSSLSocketHandler.SetDefaultHandlerClass(TOpenSSLSocketHandler);
- end.
|