Browse Source

* Small OO layer on top of SSL/SSLContext

git-svn-id: trunk@27524 -
michael 11 years ago
parent
commit
7e99d5ad08
3 changed files with 579 additions and 0 deletions
  1. 1 0
      .gitattributes
  2. 1 0
      packages/openssl/fpmake.pp
  3. 577 0
      packages/openssl/src/fpopenssl.pp

+ 1 - 0
.gitattributes

@@ -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

+ 1 - 0
packages/openssl/fpmake.pp

@@ -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 - 0
packages/openssl/src/fpopenssl.pp

@@ -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.
+