📄 idsslopenssl.pas
字号:
var
Password: String;
IdSSLContext: TIdSSLContext;
begin
LockPassCB.Enter;
try
Password := ''; {Do not Localize}
IdSSLContext := TIdSSLContext(userdata);
if (IdSSLContext.Parent is TIdSSLIOHandlerSocketOpenSSL) then begin
TIdSSLIOHandlerSocketOpenSSL(IdSSLContext.Parent).DoGetPassword(Password);
end;
if (IdSSLContext.Parent is TIdServerIOHandlerSSLOpenSSL) then begin
TIdServerIOHandlerSSLOpenSSL(IdSSLContext.Parent).DoGetPassword(Password);
end;
size := Length(Password);
StrLCopy(buf, PChar(Password + #0), size + 1);
Result := size;
finally
LockPassCB.Leave;
end;
end;
procedure InfoCallback(sslSocket: PSSL; where: Integer; ret: Integer); cdecl;
var
IdSSLSocket: TIdSSLSocket;
StatusStr : String;
begin
LockInfoCB.Enter;
try
IdSSLSocket := TIdSSLSocket(IdSslGetAppData(sslSocket));
StatusStr := Format(RSOSSLStatusString, [StrPas(IdSslStateStringLong(sslSocket))]);
if (IdSSLSocket.fParent is TIdSSLIOHandlerSocketOpenSSL) then begin
TIdSSLIOHandlerSocketOpenSSL(IdSSLSocket.fParent).DoStatusInfo(StatusStr);
end;
if (IdSSLSocket.fParent is TIdServerIOHandlerSSLOpenSSL) then begin
TIdServerIOHandlerSSLOpenSSL(IdSSLSocket.fParent).DoStatusInfo(StatusStr);
end;
finally
LockInfoCB.Leave;
end;
end;
{function RSACallback(sslSocket: PSSL; e: Integer; KeyLength: Integer):PRSA; cdecl;
const
RSA: PRSA = nil;
var
SSLSocket: TSSLWSocket;
IdSSLSocket: TIdSSLSocket;
begin
IdSSLSocket := TIdSSLSocket(IdSslGetAppData(sslSocket));
if Assigned(IdSSLSocket) then begin
IdSSLSocket.TriggerSSLRSACallback(KeyLength);
end;
if not Assigned(RSA) then begin
RSA := f_RSA_generate_key(KeyLength, RSA_F4, @RSAProgressCallback, ssl);
end;
Result := RSA;
end;}
function AddMins (const DT: TDateTime; const Mins: Extended): TDateTime;
begin
Result := DT + Mins / (60 * 24)
end;
function AddHrs (const DT: TDateTime; const Hrs: Extended): TDateTime;
begin
Result := DT + Hrs / 24.0
end;
{function GetLocalTZBias: LongInt;
var
TZ : TTimeZoneInformation;
begin
case GetTimeZoneInformation (TZ) of
TIME_ZONE_ID_STANDARD: Result := TZ.Bias + TZ.StandardBias;
TIME_ZONE_ID_DAYLIGHT: Result := TZ.Bias + TZ.DaylightBias;
else
Result := TZ.Bias;
end;
end;}
function GetLocalTime (const DT: TDateTime): TDateTime;
begin
Result := DT - TimeZoneBias{ / (24 * 60)};
end;
procedure SslLockingCallback(mode, n : integer; Afile : PChar; line : integer) cdecl;
var
Lock : TCriticalSection;
begin
with CallbackLockList.LockList do
try
Lock := TCriticalSection(Items[n]);
finally
CallbackLockList.UnlockList;
end;
if (mode and OPENSSL_CRYPTO_LOCK) > 0 then
Lock.Acquire
else
Lock.Release;
end;
procedure PrepareOpenSSLLocking;
var
i, cnt : integer;
begin
with CallbackLockList.LockList do
try
cnt := IdSslCryptoNumLocks;
for i := 0 to cnt-1 do
Add(TCriticalSection.Create);
finally
CallbackLockList.UnlockList;
end;
end;
function _GetThreadID : integer cdecl;
begin
// TODO: Verify how well this will work with fibers potentially running from
// thread to thread or many on the same thread.
Result := GetCurrentThreadHandle;
end;
function LoadOpenSLLibrary: Boolean;
begin
if not IdSSLOpenSSLHeaders.Load then begin
Result := False;
Exit;
end;
InitializeRandom;
// IdSslRandScreen;
IdSslLoadErrorStrings;
// Successful loading if true
result := IdSslAddSslAlgorithms > 0;
// Create locking structures, we need them for callback routines
// they are probably not thread safe
LockInfoCB := TCriticalSection.Create;
LockPassCB := TCriticalSection.Create;
LockVerifyCB := TCriticalSection.Create;
// Handle internal OpenSSL locking
CallbackLockList := TThreadList.Create;
IdSslSetLockingCallback(SslLockingCallback);
PrepareOpenSSLLocking;
IdSslSetIdCallback(_GetThreadID);
end;
procedure UnLoadOpenSLLibrary;
var
i : integer;
begin
FreeAndNil(LockInfoCB);
FreeAndNil(LockPassCB);
FreeAndNil(LockVerifyCB);
if Assigned(CallbackLockList) then
begin
with CallbackLockList.LockList do
try
for i := 0 to Count-1 do
TObject(Items[i]).Free;
Clear;
finally
CallbackLockList.UnlockList;
end;
FreeAndNil(CallbackLockList);
end;
IdSSLOpenSSLHeaders.Unload;
end;
function UTCTime2DateTime(UCTTime: PASN1_UTCTIME):TDateTime;
var
year : Word;
month : Word;
day : Word;
hour : Word;
min : Word;
sec : Word;
tz_h : Integer;
tz_m : Integer;
begin
Result := 0;
if IdSslUCTTimeDecode(UCTTime, year, month, day, hour, min, sec, tz_h, tz_m) > 0 Then Begin
Result := EncodeDate(year, month, day) + EncodeTime(hour, min, sec, 0);
AddMins(Result, tz_m);
AddHrs(Result, tz_h);
Result := GetLocalTime(Result);
end;
end;
function TranslateInternalVerifyToSLL(Mode: TIdSSLVerifyModeSet): Integer;
begin
Result := OPENSSL_SSL_VERIFY_NONE;
if sslvrfPeer in Mode then Result := Result or OPENSSL_SSL_VERIFY_PEER;
if sslvrfFailIfNoPeerCert in Mode then Result:= Result or OPENSSL_SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
if sslvrfClientOnce in Mode then Result:= Result or OPENSSL_SSL_VERIFY_CLIENT_ONCE;
end;
{function TranslateSLLVerifyToInternal(Mode: Integer): TIdSSLVerifyModeSet;
begin
Result := [];
if LogicalAnd(Mode, OPENSSL_SSL_VERIFY_PEER) then Result := Result + [sslvrfPeer];
if LogicalAnd(Mode, OPENSSL_SSL_VERIFY_FAIL_IF_NO_PEER_CERT) then Result := Result + [sslvrfFailIfNoPeerCert];
if LogicalAnd(Mode, OPENSSL_SSL_VERIFY_CLIENT_ONCE) then Result := Result + [sslvrfClientOnce];
end;}
function LogicalAnd(A, B: Integer): Boolean;
begin
Result := (A and B) = B;
end;
function VerifyCallback(Ok: Integer; ctx: PX509_STORE_CTX): Integer; cdecl;
var
hcert: PX509;
Certificate: TIdX509;
hSSL: PSSL;
IdSSLSocket: TIdSSLSocket;
// str: String;
VerifiedOK: Boolean;
Depth: Integer;
// Error: Integer;
begin
LockVerifyCB.Enter;
try
VerifiedOK := True;
try
hcert := IdSslX509StoreCtxGetCurrentCert(ctx);
hSSL := IdSslX509StoreCtxGetAppData(ctx);
Certificate := TIdX509.Create(hcert);
if hSSL <> nil then begin
IdSSLSocket := TIdSSLSocket(IdSslGetAppData(hSSL));
end
else begin
Result := Ok;
exit;
end;
//Error :=
IdSslX509StoreCtxGetError(ctx);
Depth := IdSslX509StoreCtxGetErrorDepth(ctx);
// str := Format('Certificate: %s', [Certificate.Subject.OneLine]); {Do not Localize}
// str := IdSSLSocket.GetSessionIDAsString;
// ShowMessage(str);
if (IdSSLSocket.fParent is TIdSSLIOHandlerSocketOpenSSL) then begin
VerifiedOK := TIdSSLIOHandlerSocketOpenSSL(IdSSLSocket.fParent).DoVerifyPeer(Certificate);
end;
if (IdSSLSocket.fParent is TIdServerIOHandlerSSLOpenSSL) then begin
VerifiedOK := TIdServerIOHandlerSSLOpenSSL(IdSSLSocket.fParent).DoVerifyPeer(Certificate);
end;
if not ((Ok>0) and (IdSSLSocket.fSSLContext.VerifyDepth>=Depth)) then begin
Ok := 0;
{if Error = OPENSSL_X509_V_OK then begin
Error := OPENSSL_X509_V_ERR_CERT_CHAIN_TOO_LONG;
end;}
end;
FreeAndNil(Certificate); // Used to be Certificate.Destroy - any reason for that?
except
end;
if VerifiedOK and (Ok > 0) then begin
Result := 1;
end
else begin
Result := 0;
end;
// Result := Ok; // testing
finally
LockVerifyCB.Leave;
end;
end;
//////////////////////////////////////////////////////
// TIdSSLOptions
///////////////////////////////////////////////////////
procedure TIdSSLOptions.AssignTo(ASource: TPersistent);
begin
if ASource is TIdSSLOptions then
with TIdSSLOptions(ASource) do begin
RootCertFile := Self.RootCertFile;
CertFile := Self.CertFile;
KeyFile := Self.KeyFile;
Method := Self.Method;
Mode := Self.Mode;
VerifyMode := Self.VerifyMode;
VerifyDepth := Self.VerifyDepth;
VerifyDirs := Self.VerifyDirs;
CipherList := Self.CipherList;
end
else
inherited AssignTo(ASource);
end;
///////////////////////////////////////////////////////
// TIdServerIOHandlerSSLOpenSSL
///////////////////////////////////////////////////////
{ TIdServerIOHandlerSSLOpenSSL }
procedure TIdServerIOHandlerSSLOpenSSL.InitComponent;
begin
inherited;
fIsInitialized := False;
fxSSLOptions := TIdSSLOptions.Create;
end;
destructor TIdServerIOHandlerSSLOpenSSL.Destroy;
begin
if fSSLContext <> nil then begin
FreeAndNil(fSSLContext);
end;
FreeAndNil(fxSSLOptions);
inherited Destroy;
end;
procedure TIdServerIOHandlerSSLOpenSSL.Init;
begin
// CreateSSLContext(SSLOptions.fMode);
// CreateSSLContext;
fSSLContext := TIdSSLContext.Create;
with fSSLContext do begin
Parent := self;
RootCertFile := SSLOptions.RootCertFile;
CertFile := SSLOptions.CertFile;
KeyFile := SSLOptions.KeyFile;
fVerifyDepth := SSLOptions.fVerifyDepth;
fVerifyMode := SSLOptions.fVerifyMode;
// fVerifyFile := SSLOptions.fVerifyFile;
fVerifyDirs := SSLOptions.fVerifyDirs;
fCipherList := SSLOptions.fCipherList;
if Assigned(fOnVerifyPeer) then begin
VerifyOn := True;
end
else begin
VerifyOn := False;
end;
if Assigned(fOnStatusInfo) then begin
StatusInfoOn := True;
end
else begin
StatusInfoOn := False;
end;
{ if Assigned(fOnGetPassword) then begin
PasswordRoutineOn := True;
end
else begin
PasswordRoutineOn := False;
end; }
fMethod := SSLOptions.Method;
fMode := SSLOptions.Mode;
fSSLContext.InitContext(sslCtxServer);
end;
fIsInitialized := True;
end;
{function TIdServerIOHandlerSSLOpenSSL.Accept(ASocket: TIdSocketHandle; AThread: TIdThread) : TIdIOHandler; }
function TIdServerIOHandlerSSLOpenSSL.Accept(
ASocket: TIdSocketHandle;
// This is a thread and not a yarn. Its the listener thread.
AListenerThread: TIdThread;
AYarn: TIdYarn
): TIdIOHandler;
var
tmpIdCIOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
if not fIsInitialized then begin
Init;
end;
tmpIdCIOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
tmpIdCIOpenSSL.PassThrough := true;
tmpIdCIOpenSSL.fIsPeer := True;
tmpIdCIOpenSSL.Open;
if tmpIdCIOpenSSL.Binding.Accept(ASocket.Handle) then begin
//we need to pass the SSLOptions for the saocket from the server
tmpIdCIOpenSSL.fxSSLOptions.Free;
tmpIdCIOpenSSL.fxSSLOptions := fxSSLOptions;
tmpIdCIOpenSSL.fSSLSocket := TIdSSLSocket.Create(self);
tmpIdCIOpenSSL.fSSLContext := fSSLContext;
result := tmpIdCIOpenSSL;
end else begin
result := nil;
FreeAndNil(tmpIdCIOpenSSL);
end;
end;
procedure TIdServerIOHandlerSSLOpenSSL.DoStatusInfo(Msg: String);
begin
if Assigned(fOnStatusInfo) then
fOnStatusInfo(Msg);
end;
procedure TIdServerIOHandlerSSLOpenSSL.DoGetPassword(var Password: String);
begin
if Assigned(fOnGetPassword) then
fOnGetPassword(Password);
end;
function TIdServerIOHandlerSSLOpenSSL.DoVerifyPeer(Certificate: TIdX509): Boolean;
begin
Result := True;
if Assigned(fOnVerifyPeer) then
Result := fOnVerifyPeer(Certificate);
end;
function TIdServerIOHandlerSSLOpenSSL.MakeFTPSvrPort : TIdSSLIOHandlerSocketBase;
var LIO : TIdSSLIOHandlerSocketOpenSSL;
begin
LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
LIO.PassThrough := true;
LIO.SSLOptions.Assign(SSLOptions);
LIO.OnGetPassword := OnGetPassword;
LIO.SSLOptions.Mode:= sslmBoth;{doesn't really matter}
LIO.IsPeer:=true;
LIO.SSLContext:= SSLContext;
Result := LIO;
end;
function TIdServerIOHandlerSSLOpenSSL.MakeFTPSvrPasv : TIdSSLIOHandlerSocketBase;
var LIO : TIdSSLIOHandlerSocketOpenSSL;
begin
LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
LIO.PassThrough := true;
LIO.SSLOptions.Assign(SSLOptions);
LIO.SSLContext := nil;
LIO.OnGetPassword := OnGetPassword;
LIO.SSLOptions.Mode:= sslmBoth;{or sslmServer}
LIO.IsPeer:=true;
Result := LIO;
end;
///////////////////////////////////////////////////////
// TIdSSLIOHandlerSocketOpenSSL
///////////////////////////////////////////////////////
function TIdServerIOHandlerSSLOpenSSL.MakeClientIOHandler: TIdSSLIOHandlerSocketBase;
var LIO : TIdSSLIOHandlerSocketOpenSSL;
begin
LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
LIO.PassThrough := true;
// LIO.SSLOptions.Free;
// LIO.SSLOptions := SSLOptions;
// LIO.SSLContext := SSLContext;
LIO.SSLOptions.Assign(SSLOptions);
// LIO.SSLContext := SSLContext;
LIO.SSLContext := nil;//SSLContext.Clone; // BGO: clone does not work, it must be either NIL, or SSLContext
LIO.OnGetPassword := OnGetPassword;
Result := LIO;
end;
{ TIdSSLIOHandlerSocketOpenSSL }
procedure TIdSSLIOHandlerSocketOpenSSL.InitComponent;
begin
inherited;
fIsPeer := False;
fxSSLOptions := TIdSSLOptions.Create;
fSSLLayerClosed := True;
fSSLContext := nil;
end;
destructor TIdSSLIOHandlerSocketOpenSSL.Destroy;
begin
FreeAndNil(fSSLSocket);
if not fIsPeer then begin
//we do not destroy these in IsPeer equals true
//because these do not belong to us when we are in a server.
FreeAndNil(fSSLContext);
FreeAndNil(fxSSLOptions);
end;
inherited Destroy;
end;
procedure TIdSSLIOHandlerSocketOpenSSL.ConnectClient;
begin
inherited ConnectClient;
DoBeforeConnect(self);
// CreateSSLContext(sslmClient);
// CreateSSLContext(SSLOptions.fMode);
StartSSL;
end;
procedure TIdSSLIOHandlerSocketOpenSSL.StartSSL;
begin
try
Init;
except
on EIdOSSLCouldNotLoadSSLLibrary do begin
if not PassThrough then raise;
end;
end;
if not PassThrough then begin
OpenEncodedConnection;
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -