| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- unit IdSSLDotNET;
- interface
- {$i IdCompilerDefines.inc}
- {*******************************************************}
- { }
- { Indy SSL Support for Microsoft.NET 2.0 }
- { }
- { Copyright (C) 2007 Indy Pit Crew }
- { Original author J. Peter Mugaas }
- { 2007-Aug-22 }
- { }
- {*******************************************************}
- uses
- Classes,
- IdException,
- IdGlobal,
- IdIOHandler,
- IdSocketHandle,
- IdSSL,
- IdThread,
- IdYarn,
- System.Collections,
- System.IO,
- System.Net.Sockets,
- System.Net.Security,
- System.Security.Authentication,
- System.Security.Cryptography.X509Certificates;
- const
- DEF_clientCertificateRequired = False;
- DEF_checkCertificateRevocation = True;
-
- type
- TOnValidatePeerCertificate = procedure (ASender : TObject;
- ACertificate : X509Certificate; AChain : X509Chain;
- AsslPolicyErrors : SslPolicyErrors; var VValid : Boolean) of object;
- TOnLocalCertificateSelectionCallback = procedure (ASender : TObject;
- AtargetHost : String;
- AlocalCertificates : X509CertificateCollection;
- AremoteCertificate : X509Certificate;
- AacceptableIssuers : array of String;
- VCert : X509Certificate) of object;
- TIdSSLIOHandlerSocketNET = class(TIdSSLIOHandlerSocketBase)
- protected
- FenabledSslProtocols: System.Security.Authentication.SslProtocols;
- FOnValidatePeerCertificate : TOnValidatePeerCertificate;
- FOnLocalCertificateSelection : TOnLocalCertificateSelectionCallback;
- FSSL : SslStream;
- FServerCertificate : X509Certificate;
- FClientCertificates : X509CertificateCollection;
- FOnSSLHandshakeDone : TNotifyEvent;
- FclientCertificateRequired : Boolean;
- FcheckCertificateRevocation : Boolean;
- procedure OpenEncodedConnection; virtual;
- //Ssl certificate validation callback
- function ValidatePeerCertificate(
- sender : System.&Object;
- certificate : X509Certificate;
- chain : X509Chain;
- sslPolicyErrors : SslPolicyErrors) : Boolean;
- function LocalCertificateSelectionCallback (
- sender : System.&Object;
- targetHost : String;
- localCertificates : X509CertificateCollection;
- remoteCertificate : X509Certificate;
- acceptableIssuers : array of String) : X509Certificate;
- function RecvEnc(var VBuffer: TIdBytes): Integer; override;
- function SendEnc(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer; override;
- procedure SetPassThrough(const Value: Boolean); override;
- procedure InitComponent; override;
- procedure ConnectClient; override;
- //
- function GetCipherAlgorithm: CipherAlgorithmType;
- function GetCipherStrength: Integer;
- function GetHashAlgorithm: HashAlgorithmType;
- function GetHashStrength: Integer;
- function GetIsEncrypted: Boolean;
- function GetIsSigned: Boolean;
- function GetKeyExchangeAlgorithm: ExchangeAlgorithmType;
- function GetKeyExchangeStrength: Integer;
- function GetRemoteCertificate: X509Certificate;
- function GetSslProtocol: SslProtocols;
- public
- procedure Close; override;
- procedure StartSSL; override;
- function Clone : TIdSSLIOHandlerSocketBase; override;
- property CipherAlgorithm : CipherAlgorithmType read GetCipherAlgorithm;
- property CipherStrength : Integer read GetCipherStrength;
- property HashAlgorithm : HashAlgorithmType read GetHashAlgorithm;
- property HashStrength : Integer read GetHashStrength;
- property IsEncrypted : Boolean read GetIsEncrypted;
- property IsSigned : Boolean read GetIsSigned;
- property KeyExchangeAlgorithm : ExchangeAlgorithmType read GetKeyExchangeAlgorithm;
- property KeyExchangeStrength : Integer read GetKeyExchangeStrength;
- property RemoteCertificate : X509Certificate read GetRemoteCertificate;
- property SslProtocol : SslProtocols read GetSslProtocol;
- published
- property enabledSslProtocols : System.Security.Authentication.SslProtocols read FenabledSslProtocols write FenabledSslProtocols;
- property ServerCertificate : X509Certificate read FServerCertificate write FServerCertificate;
- property ClientCertificates : X509CertificateCollection read FClientCertificates write FClientCertificates;
- property clientCertificateRequired : Boolean read FclientCertificateRequired write FclientCertificateRequired;
- property checkCertificateRevocation : Boolean read FcheckCertificateRevocation write FcheckCertificateRevocation;
- property OnSSLHandshakeDone : TNotifyEvent read FOnSSLHandshakeDone write FOnSSLHandshakeDone;
- property OnLocalCertificateSelection : TOnLocalCertificateSelectionCallback
- read FOnLocalCertificateSelection write FOnLocalCertificateSelection;
- property OnValidatePeerCertificate : TOnValidatePeerCertificate
- read FOnValidatePeerCertificate write FOnValidatePeerCertificate;
- end;
- TIdServerIOHandlerSSLNET = class(TIdServerIOHandlerSSLBase)
- protected
- FOnValidatePeerCertificate : TOnValidatePeerCertificate;
- FOnLocalCertificateSelection : TOnLocalCertificateSelectionCallback;
- FOnSSLHandshakeDone : TNotifyEvent;
- FenabledSslProtocols : System.Security.Authentication.SslProtocols;
- FServerCertificate : X509Certificate;
- FclientCertificateRequired : Boolean;
- FcheckCertificateRevocation : Boolean;
- procedure InitComponent; override;
- procedure SetIOHandlerValues(AIO : TIdSSLIOHandlerSocketNET);
- published
- public
- destructor Destroy; override;
- procedure Init; override;
- procedure Shutdown; override;
- function MakeClientIOHandler : TIdSSLIOHandlerSocketBase; override;
- //
- function MakeFTPSvrPort : TIdSSLIOHandlerSocketBase; override;
- function MakeFTPSvrPasv : TIdSSLIOHandlerSocketBase; override;
- function Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler; override;
- published
- property enabledSslProtocols : System.Security.Authentication.SslProtocols read FenabledSslProtocols write FenabledSslProtocols;
- property ServerCertificate : X509Certificate read FServerCertificate write FServerCertificate;
- property clientCertificateRequired : Boolean read FclientCertificateRequired write FclientCertificateRequired;
- property checkCertificateRevocation : Boolean read FcheckCertificateRevocation write FcheckCertificateRevocation;
- property OnSSLHandshakeDone : TNotifyEvent read FOnSSLHandshakeDone write FOnSSLHandshakeDone;
- property OnLocalCertificateSelection : TOnLocalCertificateSelectionCallback
- read FOnLocalCertificateSelection write FOnLocalCertificateSelection;
- property OnValidatePeerCertificate : TOnValidatePeerCertificate
- read FOnValidatePeerCertificate write FOnValidatePeerCertificate;
- end;
- EIdSSLNetException = class(EIdException);
- EIdSSLCertRequiredForSvr = class(EIdSSLNetException);
- EIdSSLNotAuthenticated = class(EIdSSLNetException);
- implementation
- uses
- IdResourceStringsSSLDotNet,
- IdStack,
- SysUtils;
- { TIdSSLIOHandlerSocketNET }
- function TIdSSLIOHandlerSocketNET.Clone: TIdSSLIOHandlerSocketBase;
- begin
- Result := TIdSSLIOHandlerSocketNET.Create(nil);
- TIdSSLIOHandlerSocketNET(Result).FenabledSslProtocols := FenabledSslProtocols;
- TIdSSLIOHandlerSocketNET(Result).FOnValidatePeerCertificate := FOnValidatePeerCertificate;
- TIdSSLIOHandlerSocketNET(Result).FOnLocalCertificateSelection := FOnLocalCertificateSelection;
- TIdSSLIOHandlerSocketNET(Result).FServerCertificate := FServerCertificate;
- TIdSSLIOHandlerSocketNET(Result).FClientCertificates := FClientCertificates;
- TIdSSLIOHandlerSocketNET(Result).FOnSSLHandshakeDone := FOnSSLHandshakeDone;
- end;
- procedure TIdSSLIOHandlerSocketNET.Close;
- begin
- if Assigned(FSSL) then
- begin
- FSSL.Close;
- FreeAndNil(FSSL);
- end;
- inherited;
- end;
- procedure TIdSSLIOHandlerSocketNET.ConnectClient;
- var
- LPassThrough: Boolean;
- begin
- // RLebeau 1/11/07: In case a proxy is being used, pass through
- // any data from the base class unencrypted when setting up that
- // connection. We should do this anyway since SSL hasn't been
- // initialized yet!
- LPassThrough := fPassThrough;
- fPassThrough := True;
- try
- inherited ConnectClient;
- finally
- fPassThrough := LPassThrough;
- end;
- StartSSL;
- end;
- function TIdSSLIOHandlerSocketNET.GetCipherAlgorithm: CipherAlgorithmType;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.CipherAlgorithm;
- end
- else
- begin
- Result := System.Security.Authentication.CipherAlgorithmType.None;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetCipherStrength: Integer;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.CipherStrength;
- end
- else
- begin
- Result := 0;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetHashAlgorithm: HashAlgorithmType;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.HashAlgorithm;
- end
- else
- begin
- Result := HashAlgorithmType.None;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetHashStrength: Integer;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.HashStrength;
- end
- else
- begin
- Result := 0;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetIsEncrypted: Boolean;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.IsEncrypted;
- end
- else
- begin
- Result := False;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetIsSigned: Boolean;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.IsSigned;
- end
- else
- begin
- Result := False;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetKeyExchangeAlgorithm: ExchangeAlgorithmType;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.KeyExchangeAlgorithm;
- end
- else
- begin
- Result := ExchangeAlgorithmType.None;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetKeyExchangeStrength: Integer;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.KeyExchangeStrength;
- end
- else
- begin
- Result := 0;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetRemoteCertificate: X509Certificate;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.RemoteCertificate;
- end
- else
- begin
- Result := nil;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.GetSslProtocol: SslProtocols;
- begin
- if Assigned(FSSL) then
- begin
- Result := FSSL.SslProtocol;
- end
- else
- begin
- Result := SslProtocols.None;
- end;
- end;
- procedure TIdSSLIOHandlerSocketNET.InitComponent;
- begin
- inherited;
- FenabledSslProtocols := System.Security.Authentication.SslProtocols.Default;
- FclientCertificateRequired := DEF_clientCertificateRequired;
- FcheckCertificateRevocation := DEF_checkCertificateRevocation;
- end;
- function TIdSSLIOHandlerSocketNET.LocalCertificateSelectionCallback(
- sender: TObject; targetHost: String;
- localCertificates: X509CertificateCollection;
- remoteCertificate: X509Certificate;
- acceptableIssuers: array of String): X509Certificate;
- var i : Integer;
- LIssuer : String;
- begin
- Result := nil;
- if Assigned(FOnLocalCertificateSelection) then
- begin
- FOnLocalCertificateSelection(Self,targetHost,localCertificates,remoteCertificate,Acceptableissuers,Result);
- end
- else
- begin
- if Assigned(acceptableIssuers) and
- (Length(acceptableIssuers)>0) and
- Assigned(localCertificates) and
- (localCertificates.Count > 0) then
- begin
- // Use the first certificate that is from an acceptable issuer.
- for I := 0 to LocalCertificates.Count -1 do
- begin
- LIssuer := LocalCertificates[i].Issuer;
- if (System.Array.IndexOf(acceptableIssuers, Lissuer)>-1) then
- begin
- Result := LocalCertificates[i];
- Exit;
- end;
- end;
- end;
- end;
- if (localCertificates <> nil) and
- (localCertificates.Count > 0) then
- begin
- Result := localCertificates[0];
- end;
- end;
- procedure TIdSSLIOHandlerSocketNET.OpenEncodedConnection;
- begin
- FSSL := System.Net.Security.SslStream.Create(
- System.Net.Sockets.NetworkStream.Create(FBinding.Handle,False),True,
- ValidatePeerCertificate,LocalCertificateSelectionCallback);
- if IsPeer then
- begin
- if Assigned(FServerCertificate) then
- begin
- FSSL.AuthenticateAsServer(FServerCertificate,FclientCertificateRequired,FenabledSslProtocols,FcheckCertificateRevocation);
- end
- else
- begin
- raise EIdSSLCertRequiredForSvr.Create(RSSSLNETCertificateRequired);
- end;
- end
- else
- begin
- if Assigned(FClientCertificates) then
- begin
- FSSL.AuthenticateAsClient(FHost,FClientCertificates,FenabledSslProtocols,True);
- if not FSSL.IsMutuallyAuthenticated then
- begin
- raise EIdSSLNotAuthenticated.Create(RSSSLNETNotAuthenticated);
- end;
- end
- else
- begin
- FSSL.AuthenticateAsClient(FHost,nil,FenabledSslProtocols,True);
- if not FSSL.IsAuthenticated then
- begin
- raise EIdSSLNotAuthenticated.Create(RSSSLNETNotAuthenticated);
- end;
- end;
- end;
- if Assigned(FOnSSLHandshakeDone) then
- begin
- FOnSSLHandshakeDone(Self);
- end;
- end;
- function TIdSSLIOHandlerSocketNET.RecvEnc(var VBuffer: TIdBytes): Integer;
- begin
- Result := FSSL.Read(VBuffer,0,Length(VBuffer));
- end;
- function TIdSSLIOHandlerSocketNET.SendEnc(const ABuffer: TIdBytes;
- const AOffset, ALength: Integer): Integer;
- begin
- FSSL.Write(ABuffer,AOffset,ALength);
- Result := ALength;
- end;
- procedure TIdSSLIOHandlerSocketNET.SetPassThrough(const Value: Boolean);
- begin
- if fPassThrough <> Value then begin
- if not Value then begin
- if BindingAllocated then begin
- OpenEncodedConnection;
- end;
- end
- else if FSSL <> nil then begin
- FSSL.Close;
- FreeAndNil(FSSL);
- end;
- fPassThrough := Value;
- end;
- end;
- procedure TIdSSLIOHandlerSocketNET.StartSSL;
- begin
- if not PassThrough then begin
- OpenEncodedConnection;
- end;
- end;
- function TIdSSLIOHandlerSocketNET.ValidatePeerCertificate(sender: TObject;
- certificate: X509Certificate; chain: X509Chain;
- sslPolicyErrors: SslPolicyErrors): Boolean;
- begin
- if Assigned(FOnValidatePeerCertificate) then
- begin
- FOnValidatePeerCertificate(sender,certificate,chain,sslPolicyErrors, Result);
- end
- else
- begin
- {
- This is a workaround for a quirk. If using this as a server, the validation routine
- may be called even though there may not be a client certificate and
- FclientCertificateRequired was set to false. It might be by design though.
- }
- case sslPolicyErrors of
- System.Net.Security.SslPolicyErrors.None : Result := True;
- System.Net.Security.SslPolicyErrors.RemoteCertificateNotAvailable :
- begin
- if IsPeer and (not FclientCertificateRequired) then
- begin
- Result := True;
- end
- else
- begin
- Result := False;
- end;
- end;
- else
- Result := False;
- end;
- end;
- end;
- { TIdServerIOHandlerSSLNET }
- function TIdServerIOHandlerSSLNET.Accept(ASocket: TIdSocketHandle;
- AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler;
- var
- LIO : TIdSSLIOHandlerSocketNET;
- begin
- LIO := TIdSSLIOHandlerSocketNET.Create(nil);
- LIO.PassThrough := True;
- LIO.IsPeer := True;
- LIO.Open;
- if LIO.Binding.Accept(ASocket.Handle) then begin
- SetIOHandlerValues(LIO);
- end else begin
- FreeAndNil(LIO);
- end;
- Result := LIO;
- end;
- destructor TIdServerIOHandlerSSLNET.Destroy;
- begin
- inherited;
- end;
- procedure TIdServerIOHandlerSSLNET.Init;
- begin
- inherited;
- end;
- procedure TIdServerIOHandlerSSLNET.InitComponent;
- begin
- inherited InitComponent;
- FenabledSslProtocols := System.Security.Authentication.SslProtocols.Default;
- FclientCertificateRequired := DEF_clientCertificateRequired;
- FcheckCertificateRevocation := DEF_checkCertificateRevocation;
- end;
- function TIdServerIOHandlerSSLNET.MakeClientIOHandler: TIdSSLIOHandlerSocketBase;
- var
- LIO : TIdSSLIOHandlerSocketNET;
- begin
- LIO := TIdSSLIOHandlerSocketNET.Create(nil);
- LIO.PassThrough := True;
- LIO.IsPeer := False;
- SetIOHandlerValues(LIO);
- Result := LIO;
- end;
- function TIdServerIOHandlerSSLNET.MakeFTPSvrPasv: TIdSSLIOHandlerSocketBase;
- var
- LIO : TIdSSLIOHandlerSocketNET;
- begin
- LIO := TIdSSLIOHandlerSocketNET.Create(nil);
- LIO.PassThrough := True;
- LIO.IsPeer := True;
- SetIOHandlerValues(LIO);
- Result := LIO;
- end;
- function TIdServerIOHandlerSSLNET.MakeFTPSvrPort: TIdSSLIOHandlerSocketBase;
- var
- LIO : TIdSSLIOHandlerSocketNET;
- begin
- LIO := TIdSSLIOHandlerSocketNET.Create(nil);
- LIO.PassThrough := True;
- LIO.IsPeer := True;
- SetIOHandlerValues(LIO);
- Result := LIO;
- end;
- procedure TIdServerIOHandlerSSLNET.SetIOHandlerValues(
- AIO: TIdSSLIOHandlerSocketNET);
- begin
- AIO.FServerCertificate := FServerCertificate;
- AIO.FclientCertificateRequired := FclientCertificateRequired;
- // AIO.FClientCertificates := FClientCertificates;
- AIO.FcheckCertificateRevocation := FcheckCertificateRevocation;
- AIO.FOnSSLHandshakeDone := FOnSSLHandshakeDone;
- AIO.FenabledSslProtocols := FenabledSslProtocols;
- AIO.FOnLocalCertificateSelection := FOnLocalCertificateSelection;
- AIO.FOnValidatePeerCertificate := FOnValidatePeerCertificate;
- end;
- procedure TIdServerIOHandlerSSLNET.Shutdown;
- begin
- inherited;
- end;
- initialization
- {$I IdSymbolDeprecatedOff.inc}
- RegisterSSL('Indy SSL Support for Microsoft.NET 2.0','Indy Pit Crew', {do not localize}
- 'Copyright © 1993 - 2023'#10#13 + {do not localize}
- 'Chad Z. Hower (Kudzu) and the Indy Pit Crew. All rights reserved.', {do not localize}
- 'Open SSL Support DLL Delphi and C++Builder interface', {do not localize}
- 'http://www.indyproject.org/'#10#13 + {do not localize}
- 'Original Author - J. Peter Mugaas', {do not localize}
- TIdSSLIOHandlerSocketNET,
- TIdServerIOHandlerSSLNET);
- {$I IdSymbolDeprecatedOn.inc}
- TIdSSLIOHandlerSocketNET.RegisterIOHandler;
- end.
|