| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- {==============================================================================|
- | Project : Ararat Synapse | 001.000.003 |
- |==============================================================================|
- | Content: SSL support for SecureBlackBox |
- |==============================================================================|
- | Copyright (c)1999-2005, Lukas Gebauer |
- | All rights reserved. |
- | |
- | Redistribution and use in source and binary forms, with or without |
- | modification, are permitted provided that the following conditions are met: |
- | |
- | Redistributions of source code must retain the above copyright notice, this |
- | list of conditions and the following disclaimer. |
- | |
- | Redistributions in binary form must reproduce the above copyright notice, |
- | this list of conditions and the following disclaimer in the documentation |
- | and/or other materials provided with the distribution. |
- | |
- | Neither the name of Lukas Gebauer nor the names of its contributors may |
- | be used to endorse or promote products derived from this software without |
- | specific prior written permission. |
- | |
- | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
- | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
- | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
- | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
- | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
- | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
- | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
- | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
- | DAMAGE. |
- |==============================================================================|
- | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
- | Portions created by Lukas Gebauer are Copyright (c)2005. |
- | All Rights Reserved. |
- |==============================================================================|
- | Contributor(s): |
- | Allen Drennan (adrennan@wiredred.com) |
- |==============================================================================|
- | History: see HISTORY.HTM from distribution package |
- | (Found at URL: http://www.ararat.cz/synapse/) |
- |==============================================================================}
- {:@abstract(SSL plugin for Eldos SecureBlackBox)
- For handling keys and certificates you can use this properties:
- @link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA),
- @link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate),
- @link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey),
- @link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate),
- @link(TCustomSSL.PFXFile). For usage of this properties and for possible formats
- of keys and certificates refer to SecureBlackBox documentation.
- }
- {$IFDEF FPC}
- {$MODE DELPHI}
- {$ENDIF}
- {$H+}
- unit ssl_sbb;
- interface
- uses
- SysUtils, Classes, Windows, blcksock, synsock, synautil, synacode,
- SBClient, SBServer, SBX509, SBWinCertStorage, SBCustomCertStorage,
- SBUtils, SBConstants, SBSessionPool;
- const
- DEFAULT_RECV_BUFFER=32768;
- type
- {:@abstract(class implementing SecureBlackbox SSL plugin.)
- Instance of this class will be created for each @link(TTCPBlockSocket).
- You not need to create instance of this class, all is done by Synapse itself!}
- TSSLSBB=class(TCustomSSL)
- protected
- FServer: Boolean;
- FElSecureClient:TElSecureClient;
- FElSecureServer:TElSecureServer;
- FElCertStorage:TElMemoryCertStorage;
- FElX509Certificate:TElX509Certificate;
- FElX509CACertificate:TElX509Certificate;
- FCipherSuites:TBits;
- private
- FRecvBuffer:String;
- FRecvBuffers:String;
- FRecvBuffersLock:TRTLCriticalSection;
- FRecvDecodedBuffers:String;
- function GetCipherSuite:Integer;
- procedure Reset;
- function Prepare(Server:Boolean):Boolean;
- procedure OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean);
- procedure OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt);
- procedure OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt);
- procedure OnData(Sender:TObject;Buffer:Pointer;Size:LongInt);
- public
- constructor Create(const Value: TTCPBlockSocket); override;
- destructor Destroy; override;
- {:See @inherited}
- function LibVersion: String; override;
- {:See @inherited}
- function LibName: String; override;
- {:See @inherited and @link(ssl_sbb) for more details.}
- function Connect: boolean; override;
- {:See @inherited and @link(ssl_sbb) for more details.}
- function Accept: boolean; override;
- {:See @inherited}
- function Shutdown: boolean; override;
- {:See @inherited}
- function BiShutdown: boolean; override;
- {:See @inherited}
- function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
- {:See @inherited}
- function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
- {:See @inherited}
- function WaitingData: Integer; override;
- {:See @inherited}
- function GetSSLVersion: string; override;
- {:See @inherited}
- function GetPeerSubject: string; override;
- {:See @inherited}
- function GetPeerIssuer: string; override;
- {:See @inherited}
- function GetPeerName: string; override;
- {:See @inherited}
- function GetPeerFingerprint: string; override;
- {:See @inherited}
- function GetCertInfo: string; override;
- published
- property ElSecureClient:TElSecureClient read FElSecureClient write FElSecureClient;
- property ElSecureServer:TElSecureServer read FElSecureServer write FElSecureServer;
- property CipherSuites:TBits read FCipherSuites write FCipherSuites;
- property CipherSuite:Integer read GetCipherSuite;
- end;
- implementation
- var
- FAcceptThread:THandle=0;
- // on error
- procedure TSSLSBB.OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean);
- begin
- FLastErrorDesc:='';
- FLastError:=ErrorCode;
- end;
- // on send
- procedure TSSLSBB.OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt);
- var
- lResult:Integer;
- begin
- if FSocket.Socket=INVALID_SOCKET then
- Exit;
- lResult:=Send(FSocket.Socket,Buffer,Size,0);
- if lResult=SOCKET_ERROR then
- begin
- FLastErrorDesc:='';
- FLastError:=WSAGetLastError;
- end;
- end;
- // on receive
- procedure TSSLSBB.OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt);
- begin
- if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
- try
- if Length(FRecvBuffers)<=MaxSize then
- begin
- Written:=Length(FRecvBuffers);
- Move(FRecvBuffers[1],Buffer^,Written);
- FRecvBuffers:='';
- end
- else
- begin
- Written:=MaxSize;
- Move(FRecvBuffers[1],Buffer^,Written);
- Delete(FRecvBuffers,1,Written);
- end;
- finally
- if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
- end;
- end;
- // on data
- procedure TSSLSBB.OnData(Sender:TObject;Buffer:Pointer;Size:LongInt);
- var
- lString:String;
- begin
- SetLength(lString,Size);
- Move(Buffer^,lString[1],Size);
- FRecvDecodedBuffers:=FRecvDecodedBuffers+lString;
- end;
- { inherited }
- constructor TSSLSBB.Create(const Value: TTCPBlockSocket);
- var
- loop1:Integer;
- begin
- inherited Create(Value);
- FServer:=FALSE;
- FElSecureClient:=NIL;
- FElSecureServer:=NIL;
- FElCertStorage:=NIL;
- FElX509Certificate:=NIL;
- FElX509CACertificate:=NIL;
- SetLength(FRecvBuffer,DEFAULT_RECV_BUFFER);
- FRecvBuffers:='';
- InitializeCriticalSection(FRecvBuffersLock);
- FRecvDecodedBuffers:='';
- FCipherSuites:=TBits.Create;
- if FCipherSuites<>NIL then
- begin
- FCipherSuites.Size:=SB_SUITE_LAST+1;
- for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
- FCipherSuites[loop1]:=TRUE;
- end;
- end;
- destructor TSSLSBB.Destroy;
- begin
- Reset;
- inherited Destroy;
- if FCipherSuites<>NIL then
- FreeAndNIL(FCipherSuites);
- DeleteCriticalSection(FRecvBuffersLock);
- end;
- function TSSLSBB.LibVersion: String;
- begin
- Result:='SecureBlackBox';
- end;
- function TSSLSBB.LibName: String;
- begin
- Result:='ssl_sbb';
- end;
- function FileToString(lFile:String):String;
- var
- lStream:TMemoryStream;
- begin
- Result:='';
- lStream:=TMemoryStream.Create;
- if lStream<>NIL then
- begin
- lStream.LoadFromFile(lFile);
- if lStream.Size>0 then
- begin
- lStream.Position:=0;
- SetLength(Result,lStream.Size);
- Move(lStream.Memory^,Result[1],lStream.Size);
- end;
- lStream.Free;
- end;
- end;
- function TSSLSBB.GetCipherSuite:Integer;
- begin
- if FServer then
- Result:=FElSecureServer.CipherSuite
- else
- Result:=FElSecureClient.CipherSuite;
- end;
- procedure TSSLSBB.Reset;
- begin
- if FElSecureServer<>NIL then
- FreeAndNIL(FElSecureServer);
- if FElSecureClient<>NIL then
- FreeAndNIL(FElSecureClient);
- if FElX509Certificate<>NIL then
- FreeAndNIL(FElX509Certificate);
- if FElX509CACertificate<>NIL then
- FreeAndNIL(FElX509CACertificate);
- if FElCertStorage<>NIL then
- FreeAndNIL(FElCertStorage);
- FSSLEnabled:=FALSE;
- end;
- function TSSLSBB.Prepare(Server:Boolean): Boolean;
- var
- loop1:Integer;
- lStream:TMemoryStream;
- lCertificate,lPrivateKey,lCertCA:String;
- begin
- Result:=FALSE;
- FServer:=Server;
- // reset, if necessary
- Reset;
- // init, certificate
- if FCertificateFile<>'' then
- lCertificate:=FileToString(FCertificateFile)
- else
- lCertificate:=FCertificate;
- if FPrivateKeyFile<>'' then
- lPrivateKey:=FileToString(FPrivateKeyFile)
- else
- lPrivateKey:=FPrivateKey;
- if FCertCAFile<>'' then
- lCertCA:=FileToString(FCertCAFile)
- else
- lCertCA:=FCertCA;
- if (lCertificate<>'') and (lPrivateKey<>'') then
- begin
- FElCertStorage:=TElMemoryCertStorage.Create(NIL);
- if FElCertStorage<>NIL then
- FElCertStorage.Clear;
- // apply ca certificate
- if lCertCA<>'' then
- begin
- FElX509CACertificate:=TElX509Certificate.Create(NIL);
- if FElX509CACertificate<>NIL then
- begin
- with FElX509CACertificate do
- begin
- lStream:=TMemoryStream.Create;
- try
- WriteStrToStream(lStream,lCertCA);
- lStream.Seek(0,soFromBeginning);
- LoadFromStream(lStream);
- finally
- lStream.Free;
- end;
- end;
- if FElCertStorage<>NIL then
- FElCertStorage.Add(FElX509CACertificate);
- end;
- end;
- // apply certificate
- FElX509Certificate:=TElX509Certificate.Create(NIL);
- if FElX509Certificate<>NIL then
- begin
- with FElX509Certificate do
- begin
- lStream:=TMemoryStream.Create;
- try
- WriteStrToStream(lStream,lCertificate);
- lStream.Seek(0,soFromBeginning);
- LoadFromStream(lStream);
- finally
- lStream.Free;
- end;
- lStream:=TMemoryStream.Create;
- try
- WriteStrToStream(lStream,lPrivateKey);
- lStream.Seek(0,soFromBeginning);
- LoadKeyFromStream(lStream);
- finally
- lStream.Free;
- end;
- if FElCertStorage<>NIL then
- FElCertStorage.Add(FElX509Certificate);
- end;
- end;
- end;
- // init, as server
- if FServer then
- begin
- FElSecureServer:=TElSecureServer.Create(NIL);
- if FElSecureServer<>NIL then
- begin
- // init, ciphers
- for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
- FElSecureServer.CipherSuites[loop1]:=FCipherSuites[loop1];
- FElSecureServer.Versions:=[sbSSL2,sbSSL3,sbTLS1];
- FElSecureServer.ClientAuthentication:=FALSE;
- FElSecureServer.OnError:=OnError;
- FElSecureServer.OnSend:=OnSend;
- FElSecureServer.OnReceive:=OnReceive;
- FElSecureServer.OnData:=OnData;
- FElSecureServer.CertStorage:=FElCertStorage;
- Result:=TRUE;
- end;
- end
- else
- // init, as client
- begin
- FElSecureClient:=TElSecureClient.Create(NIL);
- if FElSecureClient<>NIL then
- begin
- // init, ciphers
- for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
- FElSecureClient.CipherSuites[loop1]:=FCipherSuites[loop1];
- FElSecureClient.Versions:=[sbSSL3,sbTLS1];
- FElSecureClient.OnError:=OnError;
- FElSecureClient.OnSend:=OnSend;
- FElSecureClient.OnReceive:=OnReceive;
- FElSecureClient.OnData:=OnData;
- FElSecureClient.CertStorage:=FElCertStorage;
- Result:=TRUE;
- end;
- end;
- end;
- function TSSLSBB.Connect:Boolean;
- var
- lResult:Integer;
- begin
- Result:=FALSE;
- if FSocket.Socket=INVALID_SOCKET then
- Exit;
- if Prepare(FALSE) then
- begin
- FElSecureClient.Open;
- // reset
- FRecvBuffers:='';
- FRecvDecodedBuffers:='';
- // wait for open or error
- while (not FElSecureClient.Active) and
- (FLastError=0) do
- begin
- // data available?
- if FRecvBuffers<>'' then
- FElSecureClient.DataAvailable
- else
- begin
- // socket recv
- lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
- if lResult=SOCKET_ERROR then
- begin
- FLastErrorDesc:='';
- FLastError:=WSAGetLastError;
- end
- else
- begin
- if lResult>0 then
- FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult)
- else
- Break;
- end;
- end;
- end;
- if FLastError<>0 then
- Exit;
- FSSLEnabled:=FElSecureClient.Active;
- Result:=FSSLEnabled;
- end;
- end;
- function TSSLSBB.Accept:Boolean;
- var
- lResult:Integer;
- begin
- Result:=FALSE;
- if FSocket.Socket=INVALID_SOCKET then
- Exit;
- if Prepare(TRUE) then
- begin
- FAcceptThread:=GetCurrentThreadId;
- FElSecureServer.Open;
- // reset
- FRecvBuffers:='';
- FRecvDecodedBuffers:='';
- // wait for open or error
- while (not FElSecureServer.Active) and
- (FLastError=0) do
- begin
- // data available?
- if FRecvBuffers<>'' then
- FElSecureServer.DataAvailable
- else
- begin
- // socket recv
- lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
- if lResult=SOCKET_ERROR then
- begin
- FLastErrorDesc:='';
- FLastError:=WSAGetLastError;
- end
- else
- begin
- if lResult>0 then
- FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult)
- else
- Break;
- end;
- end;
- end;
- if FLastError<>0 then
- Exit;
- FSSLEnabled:=FElSecureServer.Active;
- Result:=FSSLEnabled;
- end;
- end;
- function TSSLSBB.Shutdown:Boolean;
- begin
- Result:=BiShutdown;
- end;
- function TSSLSBB.BiShutdown: boolean;
- begin
- Reset;
- Result:=TRUE;
- end;
- function TSSLSBB.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
- begin
- if FServer then
- FElSecureServer.SendData(Buffer,Len)
- else
- FElSecureClient.SendData(Buffer,Len);
- Result:=Len;
- end;
- function TSSLSBB.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
- begin
- Result:=0;
- try
- // recv waiting, if necessary
- if FRecvDecodedBuffers='' then
- WaitingData;
- // received
- if Length(FRecvDecodedBuffers)<Len then
- begin
- Result:=Length(FRecvDecodedBuffers);
- Move(FRecvDecodedBuffers[1],Buffer^,Result);
- FRecvDecodedBuffers:='';
- end
- else
- begin
- Result:=Len;
- Move(FRecvDecodedBuffers[1],Buffer^,Result);
- Delete(FRecvDecodedBuffers,1,Result);
- end;
- except
- // ignore
- end;
- end;
- function TSSLSBB.WaitingData: Integer;
- var
- lResult:Integer;
- lRecvBuffers:Boolean;
- begin
- Result:=0;
- if FSocket.Socket=INVALID_SOCKET then
- Exit;
- // data available?
- if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
- try
- lRecvBuffers:=FRecvBuffers<>'';
- finally
- if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
- end;
- if lRecvBuffers then
- begin
- if FServer then
- FElSecureServer.DataAvailable
- else
- FElSecureClient.DataAvailable;
- end
- else
- begin
- // socket recv
- lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
- if lResult=SOCKET_ERROR then
- begin
- FLastErrorDesc:='';
- FLastError:=WSAGetLastError;
- end
- else
- begin
- if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
- try
- FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult);
- finally
- if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
- end;
- // data available?
- if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
- try
- lRecvBuffers:=FRecvBuffers<>'';
- finally
- if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
- end;
- if lRecvBuffers then
- begin
- if FServer then
- FElSecureServer.DataAvailable
- else
- FElSecureClient.DataAvailable;
- end;
- end;
- end;
- // decoded buffers result
- Result:=Length(FRecvDecodedBuffers);
- end;
- function TSSLSBB.GetSSLVersion: string;
- begin
- Result:='SSLv3 or TLSv1';
- end;
- function TSSLSBB.GetPeerSubject: string;
- begin
- Result := '';
- // if FServer then
- // must return subject of the client certificate
- // else
- // must return subject of the server certificate
- end;
- function TSSLSBB.GetPeerName: string;
- begin
- Result := '';
- // if FServer then
- // must return commonname of the client certificate
- // else
- // must return commonname of the server certificate
- end;
- function TSSLSBB.GetPeerIssuer: string;
- begin
- Result := '';
- // if FServer then
- // must return issuer of the client certificate
- // else
- // must return issuer of the server certificate
- end;
- function TSSLSBB.GetPeerFingerprint: string;
- begin
- Result := '';
- // if FServer then
- // must return a unique hash string of the client certificate
- // else
- // must return a unique hash string of the server certificate
- end;
- function TSSLSBB.GetCertInfo: string;
- begin
- Result := '';
- // if FServer then
- // must return a text representation of the ASN of the client certificate
- // else
- // must return a text representation of the ASN of the server certificate
- end;
- {==============================================================================}
- initialization
- SSLImplementation := TSSLSBB;
- finalization
- end.
|