fpopenssl.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. Small OOP wrapper around OpenSSL unit.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit fpopenssl;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, openssl, ctypes;
  16. Type
  17. TSSLType = (stAny,stSSLv2,stSSLv3,stTLSv1);
  18. // PASN1_INTEGER = SslPtr;
  19. { TSSLData }
  20. TSSLData = Class(TPersistent)
  21. private
  22. FFileName: String;
  23. FValue: String;
  24. Public
  25. Function Empty : Boolean;
  26. Procedure Assign(Source : TPersistent);override;
  27. Property FileName : String Read FFileName Write FFileName;
  28. Property Value: String Read FValue Write FValue;
  29. end;
  30. { TSocketHandler }
  31. { TSSLContext }
  32. TSSLContext = Class(TObject)
  33. private
  34. FCTX: PSSL_CTX;
  35. function UsePrivateKey(pkey: SslPtr): cInt;
  36. function UsePrivateKeyASN1(pk: cInt; d: String; len: cLong): cInt;
  37. function UsePrivateKeyFile(const Afile: String; Atype: cInt): cInt;
  38. Public
  39. Constructor Create(AContext : PSSL_CTX = Nil); overload;
  40. Constructor Create(AType : TSSLType); overload;
  41. Destructor Destroy; override;
  42. Function SetCipherList(Var ACipherList : String) : Integer;
  43. procedure SetVerify(mode: Integer; arg2: PFunction);
  44. procedure SetDefaultPasswdCb(cb: PPasswdCb);
  45. procedure SetDefaultPasswdCbUserdata(u: SslPtr);
  46. Function UsePrivateKey(Data : TSSLData) : cint;
  47. // Use certificate.
  48. Function UseCertificate(Data : TSSLData) : cint;
  49. function UseCertificateASN1(len: cLong; d: String):cInt;
  50. function UseCertificateFile(const Afile: String; Atype: cInt):cInt;
  51. function UseCertificateChainFile(const Afile: PChar):cInt;
  52. function UseCertificate(x: SslPtr):cInt;
  53. function LoadVerifyLocations(const CAfile: String; const CApath: String):cInt;
  54. function LoadPFX(Const S,APassword : AnsiString) : cint;
  55. function LoadPFX(Data : TSSLData; Const APAssword : Ansistring) : cint;
  56. Property CTX: PSSL_CTX Read FCTX;
  57. end;
  58. TSSL = Class(TObject)
  59. Public
  60. FSSL : PSSL;
  61. Public
  62. Constructor Create(ASSL : PSSL = Nil);
  63. Constructor Create(AContext : TSSLContext);
  64. destructor Destroy; override;
  65. function SetFd(fd: cInt):cInt;
  66. function Accept : cInt;
  67. function Connect : cInt;
  68. function Shutdown : cInt;
  69. function Read(buf: SslPtr; num: cInt):cInt;
  70. function Peek(buf: SslPtr; num: cInt):cInt;
  71. function Write(buf: SslPtr; num: cInt):cInt;
  72. Function PeerCertificate : PX509;
  73. function Ctrl(cmd: cInt; larg: clong; parg: Pointer): cInt;
  74. function Pending:cInt;
  75. Function GetError(AResult :cint) : cint;
  76. function GetCurrentCipher :SslPtr;
  77. function Version: String;
  78. function PeerName: string;
  79. function PeerNameHash: cardinal;
  80. function PeerSubject : String;
  81. Function PeerIssuer : String;
  82. Function PeerSerialNo : Integer;
  83. Function PeerFingerprint : String;
  84. Function CertInfo : String;
  85. function CipherName: string;
  86. function CipherBits: integer;
  87. function CipherAlgBits: integer;
  88. Function VerifyResult : Integer;
  89. Property SSL: PSSL Read FSSL;
  90. end;
  91. ESSL = Class(Exception);
  92. Function BioToString(B : PBIO) : AnsiString;
  93. implementation
  94. Resourcestring
  95. SErrCountNotGetContext = 'Failed to create SSL Context';
  96. SErrFailedToCreateSSL = 'Failed to create SSL';
  97. Function BioToString(B : PBIO) : AnsiString;
  98. Var
  99. L,RL : Integer;
  100. begin
  101. l:=bioctrlpending(B);
  102. Result:=StringOfChar(#0,l);
  103. RL:=BioRead(B,Result,L);
  104. if (RL>0) then
  105. SetLength(Result,RL)
  106. else
  107. SetLength(Result,0);
  108. end;
  109. { TSSLContext }
  110. Constructor TSSLContext.Create(AContext: PSSL_CTX);
  111. begin
  112. FCTX:=AContext
  113. end;
  114. Constructor TSSLContext.Create(AType: TSSLType);
  115. Var
  116. C : PSSL_CTX;
  117. begin
  118. Case AType of
  119. stAny: C := SslCtxNew(SslMethodV23);
  120. stSSLv2: C := SslCtxNew(SslMethodV2);
  121. stSSLv3: C := SslCtxNew(SslMethodV3);
  122. stTLSv1: C := SslCtxNew(SslMethodTLSV1);
  123. end;
  124. if (C=Nil) then
  125. Raise ESSL.Create(SErrCountNotGetContext);
  126. Create(C);
  127. end;
  128. Destructor TSSLContext.Destroy;
  129. begin
  130. SslCtxFree(FCTX);
  131. inherited Destroy;
  132. end;
  133. Function TSSLContext.SetCipherList(Var ACipherList: String): Integer;
  134. begin
  135. Result:=SSLCTxSetCipherList(FCTX,ACipherList);
  136. end;
  137. procedure TSSLContext.SetVerify(mode: Integer; arg2: PFunction);
  138. begin
  139. SslCtxSetVerify(FCtx,Mode,arg2);
  140. end;
  141. procedure TSSLContext.SetDefaultPasswdCb(cb: PPasswdCb);
  142. begin
  143. SslCtxSetDefaultPasswdCb(Fctx,cb)
  144. end;
  145. procedure TSSLContext.SetDefaultPasswdCbUserdata(u: SslPtr);
  146. begin
  147. SslCtxSetDefaultPasswdCbUserdata(FCTX,u);
  148. end;
  149. function TSSLContext.UsePrivateKey(pkey: SslPtr):cInt;
  150. begin
  151. Result:=SslCtxUsePrivateKey(FCTX,pkey);
  152. end;
  153. function TSSLContext.UsePrivateKeyASN1(pk: cInt; d: String; len: cLong):cInt;
  154. begin
  155. Result:=SslCtxUsePrivateKeyASN1(pk,FCtx,d,len);
  156. end;
  157. function TSSLContext.UsePrivateKeyFile(const Afile: String; Atype: cInt):cInt;
  158. begin
  159. Result:=SslCtxUsePrivateKeyFile(FCTX,AFile,AType);
  160. end;
  161. Function TSSLContext.UsePrivateKey(Data: TSSLData): cint;
  162. Var
  163. S : AnsiString;
  164. begin
  165. Result:=-1;
  166. If (Data.Value<>'') then
  167. begin
  168. S:=Data.Value;
  169. Result:=UsePrivateKeyASN1(EVP_PKEY_RSA,S,length(S));
  170. end
  171. else if (Data.FileName<>'') then
  172. begin
  173. S:=Data.FileName;
  174. Result:=UsePrivateKeyFile(S,SSL_FILETYPE_PEM);
  175. if (Result<>1) then
  176. Result:=UsePrivateKeyFile(S,SSL_FILETYPE_ASN1);
  177. end;
  178. end;
  179. Function TSSLContext.UseCertificate(Data: TSSLData): cint;
  180. Var
  181. S : AnsiString;
  182. begin
  183. Result:=-1;
  184. if (Data.Value<>'') then
  185. begin
  186. S:=Data.Value;
  187. Result:=UseCertificateASN1(length(S),S);
  188. end
  189. else if (Data.FileName<>'') then
  190. begin
  191. S:=Data.FileName;
  192. Result:=UseCertificateChainFile(PChar(S));
  193. if Result<>1 then
  194. begin
  195. Result:=UseCertificateFile(S,SSL_FILETYPE_PEM);
  196. if Result<>1 then
  197. Result:=UseCertificateFile(S,SSL_FILETYPE_ASN1);
  198. end;
  199. end
  200. end;
  201. function TSSLContext.UseCertificateASN1(len: cLong; d: String): cInt;
  202. begin
  203. Result:=sslctxUseCertificateASN1(FCTX,len,d);
  204. end;
  205. function TSSLContext.UseCertificateFile(const Afile: String; Atype: cInt): cInt;
  206. begin
  207. Result:=sslctxUseCertificateFile(FCTX,Afile,Atype);
  208. end;
  209. function TSSLContext.UseCertificateChainFile(const Afile: PChar): cInt;
  210. begin
  211. Result:=sslctxUseCertificateChainFile(FCTX,Afile);
  212. end;
  213. function TSSLContext.UseCertificate(x: SslPtr): cInt;
  214. begin
  215. Result:=SSLCTXusecertificate(FCTX,X);
  216. end;
  217. function TSSLContext.LoadVerifyLocations(const CAfile: String; const CApath: String): cInt;
  218. begin
  219. Result:=SslCtxLoadVerifyLocations(FCTX,CAfile,CApath);
  220. end;
  221. function TSSLContext.LoadPFX(Const S, APassword: AnsiString): cint;
  222. var
  223. b: PBIO;
  224. p12,c,pk,ca: SslPtr;
  225. begin
  226. Result:=-1;
  227. c:=nil;
  228. pk:=nil;
  229. ca:=nil;
  230. p12:=Nil;
  231. b:=BioNew(BioSMem);
  232. try
  233. BioWrite(b,S,Length(S));
  234. p12:=d2iPKCS12bio(b,nil);
  235. finally
  236. BioFreeAll(b);
  237. end;
  238. if Not Assigned(p12) then
  239. Exit;
  240. try
  241. try
  242. if PKCS12parse(p12,APassword,pk,c,ca)>0 then
  243. begin
  244. Result:=UseCertificate(c);
  245. if (Result>0) then
  246. Result:=UsePrivateKey(pk);
  247. end;
  248. finally
  249. EvpPkeyFree(pk);
  250. X509free(c);
  251. // SkX509PopFree(ca,_X509Free);
  252. end;
  253. finally
  254. PKCS12free(p12);
  255. end;
  256. end;
  257. function TSSLContext.LoadPFX(Data: TSSLData; Const APAssword : Ansistring): cint;
  258. Var
  259. S : String;
  260. begin
  261. Result:=-1;
  262. try
  263. if (Data.Value<>'') then
  264. S:=Data.Value
  265. else
  266. With TFileStream.Create(Data.FileName,fmOpenRead or fmShareDenyNone) do
  267. Try
  268. SetLength(S,Size);
  269. ReadBuffer(S[1],Size);
  270. finally
  271. Free;
  272. end;
  273. Result:=LoadPFX(s,APassword);
  274. except
  275. // Silently ignore
  276. Exit;
  277. end;
  278. end;
  279. { TSSLData }
  280. Function TSSLData.Empty: Boolean;
  281. begin
  282. Result:=(Value='') and (FileName='');
  283. end;
  284. Procedure TSSLData.Assign(Source: TPersistent);
  285. begin
  286. if Source is TSSLData then
  287. With TSSLData(Source) do
  288. begin
  289. Self.FValue:=FValue;
  290. Self.FFileName:=FFileName;
  291. end
  292. else
  293. inherited Assign(Source);
  294. end;
  295. { TSSL }
  296. Constructor TSSL.Create(ASSL: PSSL);
  297. begin
  298. FSSL:=ASSL;
  299. end;
  300. Constructor TSSL.Create(AContext: TSSLContext);
  301. begin
  302. FSSL:=Nil;
  303. if Assigned(AContext) and Assigned(AContext.CTX) then
  304. FSSL:=sslNew(AContext.CTX);
  305. If (FSSL=Nil) then
  306. Raise ESSL.Create(SErrFailedToCreateSSL)
  307. end;
  308. destructor TSSL.Destroy;
  309. begin
  310. sslfree(FSSL);
  311. inherited Destroy;
  312. end;
  313. function TSSL.Ctrl(cmd: cInt; larg: clong; parg: Pointer): cInt;
  314. begin
  315. Result:=sslCtrl(fSSL,cmd,larg,parg);
  316. end;
  317. function TSSL.SetFd(fd: cInt): cInt;
  318. begin
  319. Result:=sslSetFD(fSSL,fd);
  320. end;
  321. function TSSL.Accept: cInt;
  322. begin
  323. Result:=sslAccept(fSSL);
  324. end;
  325. function TSSL.Connect: cInt;
  326. begin
  327. Result:=sslConnect(fSSL);
  328. end;
  329. function TSSL.Shutdown: cInt;
  330. begin
  331. Result:=sslShutDown(fSSL);
  332. end;
  333. function TSSL.Read(buf: SslPtr; num: cInt): cInt;
  334. begin
  335. Result:=sslRead(FSSL,buf,num);
  336. end;
  337. function TSSL.Peek(buf: SslPtr; num: cInt): cInt;
  338. begin
  339. Result:=sslPeek(FSSL,buf,num);
  340. end;
  341. function TSSL.Write(buf: SslPtr; num: cInt): cInt;
  342. begin
  343. Result:=sslWrite(FSSL,buf,num);
  344. end;
  345. Function TSSL.PeerCertificate: PX509;
  346. begin
  347. Result:=sslGetPeercertificate(FSSL);
  348. end;
  349. function TSSL.Pending: cInt;
  350. begin
  351. Result:=sslPending(FSSL);
  352. end;
  353. Function TSSL.GetError(AResult: cint): cint;
  354. begin
  355. Result:=SslGetError(FSsl,AResult);
  356. end;
  357. function TSSL.GetCurrentCipher: SslPtr;
  358. begin
  359. Result:=SSLGetCurrentCipher(FSSL);
  360. end;
  361. function TSSL.Version: String;
  362. begin
  363. Result:=SSlGetVersion(FSsl);
  364. end;
  365. function TSSL.PeerName: string;
  366. var
  367. s : ansistring;
  368. p : Integer;
  369. begin
  370. Result:='';
  371. S:=PeerSubject;
  372. P:=Pos(S,'/CN=');
  373. if (P>0) then
  374. begin
  375. Delete(S,1,P+3);
  376. P:=Pos('/',S);
  377. if (P>0) then
  378. Result:=Copy(S,1,P-1);
  379. end;
  380. end;
  381. function TSSL.PeerNameHash: cardinal;
  382. var
  383. C : PX509;
  384. begin
  385. Result:=0;
  386. c:=PeerCertificate;
  387. if (C=Nil) then
  388. exit;
  389. try
  390. Result:=X509NameHash(X509GetSubjectName(C));
  391. finally
  392. X509Free(C);
  393. end;
  394. end;
  395. function TSSL.PeerSubject: String;
  396. var
  397. c : PX509;
  398. s : ansistring;
  399. begin
  400. Result:='';
  401. c:=PeerCertificate;
  402. if Assigned(c) then
  403. try
  404. setlength(s, 4096);
  405. Result:=X509NameOneline(X509GetSubjectName(c),s,Length(s));
  406. finally
  407. X509Free(c);
  408. end;
  409. end;
  410. Function TSSL.PeerIssuer: String;
  411. var
  412. C: PX509;
  413. S: ansistring;
  414. begin
  415. Result:='';
  416. C:=PeerCertificate;
  417. if (C=Nil) then
  418. Exit;
  419. try
  420. S:=StringOfChar(#0,4096);
  421. Result:=X509NameOneline(X509GetIssuerName(C),S,4096);
  422. finally
  423. X509Free(C);
  424. end;
  425. end;
  426. Function TSSL.PeerSerialNo: Integer;
  427. var
  428. C : PX509;
  429. SN : PASN1_INTEGER;
  430. begin
  431. Result:=-1;
  432. C:=PeerCertificate;
  433. if (C=Nil) then
  434. exit;
  435. try
  436. SN:=X509GetSerialNumber(C);
  437. Result:=Asn1IntegerGet(SN);
  438. finally
  439. X509Free(C);
  440. end;
  441. end;
  442. Function TSSL.PeerFingerprint: String;
  443. var
  444. C : PX509;
  445. L : integer;
  446. begin
  447. Result:='';
  448. C:=PeerCertificate;
  449. if (C=Nil) then
  450. Exit;
  451. try
  452. Result:=StringOfChar(#0,EVP_MAX_MD_SIZE);
  453. L:=0;
  454. X509Digest(C,EvpGetDigestByName('MD5'),Result,L);
  455. SetLength(Result,L);
  456. finally
  457. X509Free(C);
  458. end;
  459. end;
  460. Function TSSL.CertInfo: String;
  461. var
  462. C : PX509;
  463. B : PBIO;
  464. begin
  465. Result:='';
  466. C:=PeerCertificate;
  467. if (C=Nil) then
  468. Exit;
  469. try
  470. B:=BioNew(BioSMem);
  471. try
  472. X509Print(B,C);
  473. Result:=BioToString(B);
  474. finally
  475. BioFreeAll(B);
  476. end;
  477. finally
  478. X509Free(C);
  479. end;
  480. end;
  481. function TSSL.CipherName: string;
  482. begin
  483. Result:=SslCipherGetName(GetCurrentCipher);
  484. end;
  485. function TSSL.CipherBits: integer;
  486. var
  487. x: integer;
  488. begin
  489. x:=0;
  490. Result:=SSLCipherGetBits(GetCurrentCipher,x);
  491. end;
  492. function TSSL.CipherAlgBits: integer;
  493. begin
  494. Result:=0;
  495. SSLCipherGetBits(GetCurrentCipher,Result);
  496. end;
  497. Function TSSL.VerifyResult: Integer;
  498. begin
  499. Result:=SslGetVerifyResult(FSsl);
  500. end;
  501. end.