mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-11 13:29:18 +02:00
* Small OO layer on top of SSL/SSLContext
git-svn-id: trunk@27524 -
This commit is contained in:
parent
ef399c78e5
commit
7e99d5ad08
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -5913,6 +5913,7 @@ packages/openssl/examples/genkeypair.lpi svneol=native#text/plain
|
||||
packages/openssl/examples/genkeypair.lpr svneol=native#text/plain
|
||||
packages/openssl/examples/test1.pas svneol=native#text/plain
|
||||
packages/openssl/fpmake.pp svneol=native#text/plain
|
||||
packages/openssl/src/fpopenssl.pp svneol=native#text/plain
|
||||
packages/openssl/src/openssl.pas svneol=native#text/plain
|
||||
packages/oracle/Makefile svneol=native#text/plain
|
||||
packages/oracle/Makefile.fpc svneol=native#text/plain
|
||||
|
@ -22,6 +22,7 @@ begin
|
||||
// P.Dependencies.Add('x11');
|
||||
|
||||
T:=P.Targets.AddUnit('openssl.pas');
|
||||
T:=P.Targets.AddUnit('fpopenssl.pp');
|
||||
|
||||
P.ExamplePath.Add('examples');
|
||||
P.Targets.AddExampleProgram('test1.pas');
|
||||
|
577
packages/openssl/src/fpopenssl.pp
Normal file
577
packages/openssl/src/fpopenssl.pp
Normal file
@ -0,0 +1,577 @@
|
||||
unit fpopenssl;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, openssl, ctypes;
|
||||
Type
|
||||
TSSLType = (stAny,stSSLv2,stSSLv3,stTLSv1);
|
||||
|
||||
// PASN1_INTEGER = SslPtr;
|
||||
|
||||
{ TSSLData }
|
||||
|
||||
TSSLData = Class(TPersistent)
|
||||
private
|
||||
FFileName: String;
|
||||
FValue: String;
|
||||
Public
|
||||
Function Empty : Boolean;
|
||||
Procedure Assign(Source : TPersistent);override;
|
||||
Property FileName : String Read FFileName Write FFileName;
|
||||
Property Value: String Read FValue Write FValue;
|
||||
end;
|
||||
|
||||
{ TSocketHandler }
|
||||
|
||||
{ TSSLContext }
|
||||
|
||||
TSSLContext = Class(TObject)
|
||||
private
|
||||
FCTX: PSSL_CTX;
|
||||
function UsePrivateKey(pkey: SslPtr): cInt;
|
||||
function UsePrivateKeyASN1(pk: cInt; d: String; len: cLong): cInt;
|
||||
function UsePrivateKeyFile(const Afile: String; Atype: cInt): cInt;
|
||||
Public
|
||||
Constructor Create(AContext : PSSL_CTX = Nil); overload;
|
||||
Constructor Create(AType : TSSLType); overload;
|
||||
Destructor Destroy; override;
|
||||
Function SetCipherList(Var ACipherList : String) : Integer;
|
||||
procedure SetVerify(mode: Integer; arg2: PFunction);
|
||||
procedure SetDefaultPasswdCb(cb: PPasswdCb);
|
||||
procedure SetDefaultPasswdCbUserdata(u: SslPtr);
|
||||
Function UsePrivateKey(Data : TSSLData) : cint;
|
||||
// Use certificate.
|
||||
Function UseCertificate(Data : TSSLData) : cint;
|
||||
function UseCertificateASN1(len: cLong; d: String):cInt;
|
||||
function UseCertificateFile(const Afile: String; Atype: cInt):cInt;
|
||||
function UseCertificateChainFile(const Afile: PChar):cInt;
|
||||
function UseCertificate(x: SslPtr):cInt;
|
||||
function LoadVerifyLocations(const CAfile: String; const CApath: String):cInt;
|
||||
function LoadPFX(Const S,APassword : AnsiString) : cint;
|
||||
function LoadPFX(Data : TSSLData; Const APAssword : Ansistring) : cint;
|
||||
Property CTX: PSSL_CTX Read FCTX;
|
||||
end;
|
||||
|
||||
TSSL = Class(TObject)
|
||||
Public
|
||||
FSSL : PSSL;
|
||||
Public
|
||||
Constructor Create(ASSL : PSSL = Nil);
|
||||
Constructor Create(AContext : TSSLContext);
|
||||
destructor Destroy; override;
|
||||
function SetFd(fd: cInt):cInt;
|
||||
function Accept : cInt;
|
||||
function Connect : cInt;
|
||||
function Shutdown : cInt;
|
||||
function Read(buf: SslPtr; num: cInt):cInt;
|
||||
function Peek(buf: SslPtr; num: cInt):cInt;
|
||||
function Write(buf: SslPtr; num: cInt):cInt;
|
||||
Function PeerCertificate : PX509;
|
||||
function Pending:cInt;
|
||||
Function GetError(AResult :cint) : cint;
|
||||
function GetCurrentCipher :SslPtr;
|
||||
function Version: String;
|
||||
function PeerName: string;
|
||||
function PeerNameHash: cardinal;
|
||||
function PeerSubject : String;
|
||||
Function PeerIssuer : String;
|
||||
Function PeerSerialNo : Integer;
|
||||
Function PeerFingerprint : String;
|
||||
Function CertInfo : String;
|
||||
function CipherName: string;
|
||||
function CipherBits: integer;
|
||||
function CipherAlgBits: integer;
|
||||
Function VerifyResult : Integer;
|
||||
Property SSL: PSSL Read FSSL;
|
||||
end;
|
||||
|
||||
ESSL = Class(Exception);
|
||||
|
||||
Function BioToString(B : PBIO) : AnsiString;
|
||||
|
||||
implementation
|
||||
|
||||
Resourcestring
|
||||
SErrCountNotGetContext = 'Failed to create SSL Context';
|
||||
SErrFailedToCreateSSL = 'Failed to create SSL';
|
||||
|
||||
Function BioToString(B : PBIO) : AnsiString;
|
||||
|
||||
Var
|
||||
L,RL : Integer;
|
||||
begin
|
||||
l:=bioctrlpending(B);
|
||||
Result:=StringOfChar(#0,l);
|
||||
RL:=BioRead(B,Result,L);
|
||||
if (RL>0) then
|
||||
SetLength(Result,RL)
|
||||
else
|
||||
SetLength(Result,0);
|
||||
end;
|
||||
|
||||
{ TSSLContext }
|
||||
|
||||
Constructor TSSLContext.Create(AContext: PSSL_CTX);
|
||||
begin
|
||||
FCTX:=AContext
|
||||
end;
|
||||
|
||||
Constructor TSSLContext.Create(AType: TSSLType);
|
||||
|
||||
Var
|
||||
C : PSSL_CTX;
|
||||
|
||||
begin
|
||||
Case AType of
|
||||
stAny: C := SslCtxNew(SslMethodV23);
|
||||
stSSLv2: C := SslCtxNew(SslMethodV2);
|
||||
stSSLv3: C := SslCtxNew(SslMethodV3);
|
||||
stTLSv1: C := SslCtxNew(SslMethodTLSV1);
|
||||
end;
|
||||
if (C=Nil) then
|
||||
Raise ESSL.Create(SErrCountNotGetContext);
|
||||
Create(C);
|
||||
end;
|
||||
|
||||
Destructor TSSLContext.Destroy;
|
||||
begin
|
||||
SslCtxFree(FCTX);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
Function TSSLContext.SetCipherList(Var ACipherList: String): Integer;
|
||||
begin
|
||||
Result:=SSLCTxSetCipherList(FCTX,ACipherList);
|
||||
end;
|
||||
|
||||
procedure TSSLContext.SetVerify(mode: Integer; arg2: PFunction);
|
||||
begin
|
||||
SslCtxSetVerify(FCtx,Mode,arg2);
|
||||
end;
|
||||
|
||||
procedure TSSLContext.SetDefaultPasswdCb(cb: PPasswdCb);
|
||||
begin
|
||||
SslCtxSetDefaultPasswdCb(Fctx,cb)
|
||||
end;
|
||||
|
||||
procedure TSSLContext.SetDefaultPasswdCbUserdata(u: SslPtr);
|
||||
begin
|
||||
SslCtxSetDefaultPasswdCbUserdata(FCTX,u);
|
||||
end;
|
||||
|
||||
function TSSLContext.UsePrivateKey(pkey: SslPtr):cInt;
|
||||
begin
|
||||
Result:=SslCtxUsePrivateKey(FCTX,pkey);
|
||||
end;
|
||||
|
||||
function TSSLContext.UsePrivateKeyASN1(pk: cInt; d: String; len: cLong):cInt;
|
||||
begin
|
||||
Result:=SslCtxUsePrivateKeyASN1(pk,FCtx,d,len);
|
||||
end;
|
||||
|
||||
function TSSLContext.UsePrivateKeyFile(const Afile: String; Atype: cInt):cInt;
|
||||
begin
|
||||
Result:=SslCtxUsePrivateKeyFile(FCTX,AFile,AType);
|
||||
end;
|
||||
|
||||
|
||||
Function TSSLContext.UsePrivateKey(Data: TSSLData): cint;
|
||||
|
||||
Var
|
||||
S : AnsiString;
|
||||
|
||||
begin
|
||||
Result:=-1;
|
||||
If (Data.Value<>'') then
|
||||
begin
|
||||
S:=Data.Value;
|
||||
Result:=UsePrivateKeyASN1(EVP_PKEY_RSA,S,length(S));
|
||||
end
|
||||
else if (Data.FileName<>'') then
|
||||
begin
|
||||
S:=Data.FileName;
|
||||
Result:=UsePrivateKeyFile(S,SSL_FILETYPE_PEM);
|
||||
if (Result<>1) then
|
||||
Result:=UsePrivateKeyFile(S,SSL_FILETYPE_ASN1);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TSSLContext.UseCertificate(Data: TSSLData): cint;
|
||||
|
||||
Var
|
||||
S : AnsiString;
|
||||
begin
|
||||
Result:=-1;
|
||||
if (Data.Value<>'') then
|
||||
begin
|
||||
S:=Data.Value;
|
||||
Result:=UseCertificateASN1(length(S),S);
|
||||
end
|
||||
else if (Data.FileName<>'') then
|
||||
begin
|
||||
S:=Data.FileName;
|
||||
Result:=UseCertificateChainFile(PChar(S));
|
||||
if Result<>1 then
|
||||
begin
|
||||
Result:=UseCertificateFile(S,SSL_FILETYPE_PEM);
|
||||
if Result<>1 then
|
||||
Result:=UseCertificateFile(S,SSL_FILETYPE_ASN1);
|
||||
end;
|
||||
end
|
||||
end;
|
||||
|
||||
function TSSLContext.UseCertificateASN1(len: cLong; d: String): cInt;
|
||||
begin
|
||||
Result:=sslctxUseCertificateASN1(FCTX,len,d);
|
||||
end;
|
||||
|
||||
function TSSLContext.UseCertificateFile(const Afile: String; Atype: cInt): cInt;
|
||||
begin
|
||||
Result:=sslctxUseCertificateFile(FCTX,Afile,Atype);
|
||||
end;
|
||||
|
||||
function TSSLContext.UseCertificateChainFile(const Afile: PChar): cInt;
|
||||
begin
|
||||
Result:=sslctxUseCertificateChainFile(FCTX,Afile);
|
||||
end;
|
||||
|
||||
function TSSLContext.UseCertificate(x: SslPtr): cInt;
|
||||
begin
|
||||
Result:=SSLCTXusecertificate(FCTX,X);
|
||||
end;
|
||||
|
||||
function TSSLContext.LoadVerifyLocations(const CAfile: String; const CApath: String): cInt;
|
||||
begin
|
||||
Result:=SslCtxLoadVerifyLocations(FCTX,CAfile,CApath);
|
||||
end;
|
||||
|
||||
function TSSLContext.LoadPFX(Const S, APassword: AnsiString): cint;
|
||||
|
||||
var
|
||||
b: PBIO;
|
||||
p12,c,pk,ca: SslPtr;
|
||||
|
||||
begin
|
||||
Result:=-1;
|
||||
c:=nil;
|
||||
pk:=nil;
|
||||
ca:=nil;
|
||||
p12:=Nil;
|
||||
b:=BioNew(BioSMem);
|
||||
try
|
||||
BioWrite(b,S,Length(S));
|
||||
p12:=d2iPKCS12bio(b,nil);
|
||||
finally
|
||||
BioFreeAll(b);
|
||||
end;
|
||||
if Not Assigned(p12) then
|
||||
Exit;
|
||||
try
|
||||
try
|
||||
if PKCS12parse(p12,APassword,pk,c,ca)>0 then
|
||||
begin
|
||||
Result:=UseCertificate(c);
|
||||
if (Result>0) then
|
||||
Result:=UsePrivateKey(pk);
|
||||
end;
|
||||
finally
|
||||
EvpPkeyFree(pk);
|
||||
X509free(c);
|
||||
// SkX509PopFree(ca,_X509Free);
|
||||
end;
|
||||
finally
|
||||
PKCS12free(p12);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSSLContext.LoadPFX(Data: TSSLData; Const APAssword : Ansistring): cint;
|
||||
|
||||
Var
|
||||
S : String;
|
||||
|
||||
begin
|
||||
Result:=-1;
|
||||
try
|
||||
if (Data.Value<>'') then
|
||||
S:=Data.Value
|
||||
else
|
||||
With TFileStream.Create(Data.FileName,fmOpenRead or fmShareDenyNone) do
|
||||
Try
|
||||
SetLength(S,Size);
|
||||
ReadBuffer(S[1],Size);
|
||||
finally
|
||||
Free;
|
||||
end;
|
||||
Result:=LoadPFX(s,APassword);
|
||||
except
|
||||
// Silently ignore
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TSSLData }
|
||||
|
||||
Function TSSLData.Empty: Boolean;
|
||||
begin
|
||||
Result:=(Value='') and (FileName='');
|
||||
end;
|
||||
|
||||
Procedure TSSLData.Assign(Source: TPersistent);
|
||||
|
||||
|
||||
begin
|
||||
if Source is TSSLData then
|
||||
With TSSLData(Source) do
|
||||
begin
|
||||
Self.FValue:=FValue;
|
||||
Self.FFileName:=FFileName;
|
||||
end
|
||||
else
|
||||
inherited Assign(Source);
|
||||
end;
|
||||
|
||||
{ TSSL }
|
||||
|
||||
Constructor TSSL.Create(ASSL: PSSL);
|
||||
begin
|
||||
FSSL:=ASSL;
|
||||
end;
|
||||
|
||||
Constructor TSSL.Create(AContext: TSSLContext);
|
||||
begin
|
||||
FSSL:=Nil;
|
||||
if Assigned(AContext) and Assigned(AContext.CTX) then
|
||||
FSSL:=sslNew(AContext.CTX);
|
||||
If (FSSL=Nil) then
|
||||
Raise ESSL.Create(SErrFailedToCreateSSL)
|
||||
end;
|
||||
|
||||
destructor TSSL.Destroy;
|
||||
begin
|
||||
sslfree(FSSL);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TSSL.SetFd(fd: cInt): cInt;
|
||||
begin
|
||||
Result:=sslSetFD(fSSL,fd);
|
||||
end;
|
||||
|
||||
function TSSL.Accept: cInt;
|
||||
begin
|
||||
Result:=sslAccept(fSSL);
|
||||
end;
|
||||
|
||||
function TSSL.Connect: cInt;
|
||||
begin
|
||||
Result:=sslConnect(fSSL);
|
||||
end;
|
||||
|
||||
function TSSL.Shutdown: cInt;
|
||||
begin
|
||||
Result:=sslShutDown(fSSL);
|
||||
end;
|
||||
|
||||
function TSSL.Read(buf: SslPtr; num: cInt): cInt;
|
||||
begin
|
||||
Result:=sslRead(FSSL,buf,num);
|
||||
end;
|
||||
|
||||
function TSSL.Peek(buf: SslPtr; num: cInt): cInt;
|
||||
begin
|
||||
Result:=sslPeek(FSSL,buf,num);
|
||||
end;
|
||||
|
||||
function TSSL.Write(buf: SslPtr; num: cInt): cInt;
|
||||
begin
|
||||
Result:=sslWrite(FSSL,buf,num);
|
||||
end;
|
||||
|
||||
Function TSSL.PeerCertificate: PX509;
|
||||
begin
|
||||
Result:=sslGetPeercertificate(FSSL);
|
||||
end;
|
||||
|
||||
function TSSL.Pending: cInt;
|
||||
begin
|
||||
Result:=sslPending(FSSL);
|
||||
end;
|
||||
|
||||
Function TSSL.GetError(AResult: cint): cint;
|
||||
begin
|
||||
Result:=SslGetError(FSsl,AResult);
|
||||
end;
|
||||
|
||||
function TSSL.GetCurrentCipher: SslPtr;
|
||||
begin
|
||||
Result:=SSLGetCurrentCipher(FSSL);
|
||||
end;
|
||||
|
||||
function TSSL.Version: String;
|
||||
begin
|
||||
Result:=SSlGetVersion(FSsl);
|
||||
end;
|
||||
|
||||
function TSSL.PeerName: string;
|
||||
var
|
||||
s : ansistring;
|
||||
p : Integer;
|
||||
begin
|
||||
Result:='';
|
||||
S:=PeerSubject;
|
||||
P:=Pos(S,'/CN=');
|
||||
if (P>0) then
|
||||
begin
|
||||
Delete(S,1,P+3);
|
||||
P:=Pos('/',S);
|
||||
if (P>0) then
|
||||
Result:=Copy(S,1,P-1);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSSL.PeerNameHash: cardinal;
|
||||
var
|
||||
C : PX509;
|
||||
begin
|
||||
Result:=0;
|
||||
c:=PeerCertificate;
|
||||
if (C=Nil) then
|
||||
exit;
|
||||
try
|
||||
Result:=X509NameHash(X509GetSubjectName(C));
|
||||
finally
|
||||
X509Free(C);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSSL.PeerSubject: String;
|
||||
var
|
||||
c : PX509;
|
||||
s : ansistring;
|
||||
|
||||
begin
|
||||
Result:='';
|
||||
c:=PeerCertificate;
|
||||
if Assigned(c) then
|
||||
try
|
||||
setlength(s, 4096);
|
||||
Result:=X509NameOneline(X509GetSubjectName(c),s,Length(s));
|
||||
finally
|
||||
X509Free(c);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TSSL.PeerIssuer: String;
|
||||
|
||||
var
|
||||
C: PX509;
|
||||
S: ansistring;
|
||||
|
||||
begin
|
||||
Result:='';
|
||||
C:=PeerCertificate;
|
||||
if (C=Nil) then
|
||||
Exit;
|
||||
try
|
||||
S:=StringOfChar(#0,4096);
|
||||
Result:=X509NameOneline(X509GetIssuerName(C),S,4096);
|
||||
finally
|
||||
X509Free(C);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TSSL.PeerSerialNo: Integer;
|
||||
var
|
||||
C : PX509;
|
||||
SN : PASN1_INTEGER;
|
||||
|
||||
begin
|
||||
Result:=-1;
|
||||
C:=PeerCertificate;
|
||||
if (C=Nil) then
|
||||
exit;
|
||||
try
|
||||
SN:=X509GetSerialNumber(C);
|
||||
Result:=Asn1IntegerGet(SN);
|
||||
finally
|
||||
X509Free(C);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TSSL.PeerFingerprint: String;
|
||||
var
|
||||
C : PX509;
|
||||
L : integer;
|
||||
|
||||
begin
|
||||
Result:='';
|
||||
C:=PeerCertificate;
|
||||
if (C=Nil) then
|
||||
Exit;
|
||||
try
|
||||
Result:=StringOfChar(#0,EVP_MAX_MD_SIZE);
|
||||
L:=0;
|
||||
X509Digest(C,EvpGetDigestByName('MD5'),Result,L);
|
||||
SetLength(Result,L);
|
||||
finally
|
||||
X509Free(C);
|
||||
end;
|
||||
end;
|
||||
|
||||
Function TSSL.CertInfo: String;
|
||||
var
|
||||
C : PX509;
|
||||
B : PBIO;
|
||||
|
||||
begin
|
||||
Result:='';
|
||||
C:=PeerCertificate;
|
||||
if (C=Nil) then
|
||||
Exit;
|
||||
try
|
||||
B:=BioNew(BioSMem);
|
||||
try
|
||||
X509Print(B,C);
|
||||
Result:=BioToString(B);
|
||||
finally
|
||||
BioFreeAll(B);
|
||||
end;
|
||||
finally
|
||||
X509Free(C);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSSL.CipherName: string;
|
||||
begin
|
||||
Result:=SslCipherGetName(GetCurrentCipher);
|
||||
end;
|
||||
|
||||
function TSSL.CipherBits: integer;
|
||||
|
||||
var
|
||||
x: integer;
|
||||
|
||||
begin
|
||||
x:=0;
|
||||
Result:=SSLCipherGetBits(GetCurrentCipher,x);
|
||||
end;
|
||||
|
||||
function TSSL.CipherAlgBits: integer;
|
||||
|
||||
begin
|
||||
Result:=0;
|
||||
SSLCipherGetBits(GetCurrentCipher,Result);
|
||||
end;
|
||||
|
||||
Function TSSL.VerifyResult: Integer;
|
||||
|
||||
begin
|
||||
Result:=SslGetVerifyResult(FSsl);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user