opensslsockets.pp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. unit opensslsockets;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, sockets, ssockets, sslsockets, sslbase, openssl, fpopenssl;
  6. Type
  7. { TOpenSSLSocketHandler }
  8. TOpenSSLSocketHandler = Class(TSSLSocketHandler)
  9. Private
  10. FSSL: TSSL;
  11. FCTX : TSSLContext;
  12. FSSLLastErrorString: string;
  13. FSSLLastError : Integer;
  14. Protected
  15. procedure SetSSLLastErrorString(AValue: string);
  16. Function FetchErrorInfo: Boolean;
  17. function CheckSSL(SSLResult: Integer): Boolean;
  18. function CheckSSL(SSLResult: Pointer): Boolean;
  19. function InitContext(NeedCertificate: Boolean): Boolean; virtual;
  20. function DoneContext: Boolean; virtual;
  21. function InitSslKeys: boolean;virtual;
  22. Function GetLastSSLErrorString : String; override;
  23. Function GetLastSSLErrorCode : Integer; override;
  24. Public
  25. Constructor create; override;
  26. destructor destroy; override;
  27. function CreateCertGenerator: TX509Certificate; override;
  28. function Connect : Boolean; override;
  29. function Close : Boolean; override;
  30. function Accept : Boolean; override;
  31. function Shutdown(BiDirectional : Boolean): boolean; override;
  32. function Send(Const Buffer; Count: Integer): Integer; override;
  33. function Recv(Const Buffer; Count: Integer): Integer; override;
  34. function BytesAvailable: Integer; override;
  35. // Result of last CheckSSL call.
  36. Function SSLLastError: integer;
  37. property SSLLastErrorString: string read FSSLLastErrorString write SetSSLLastErrorString;
  38. property SSL: TSSL read FSSL; // allow more lower level info and control
  39. end;
  40. implementation
  41. { TSocketHandler }
  42. Resourcestring
  43. SErrNoLibraryInit = 'Could not initialize OpenSSL library';
  44. Procedure MaybeInitSSLInterface;
  45. begin
  46. if not IsSSLloaded then
  47. if not InitSSLInterface then
  48. Raise EInOutError.Create(SErrNoLibraryInit);
  49. end;
  50. function TopenSSLSocketHandler.CreateCertGenerator: TX509Certificate;
  51. begin
  52. Result:=TOpenSSLX509Certificate.Create;
  53. end;
  54. procedure TOpenSSLSocketHandler.SetSSLLastErrorString(AValue: string);
  55. begin
  56. if FSSLLastErrorString=AValue then Exit;
  57. FSSLLastErrorString:=AValue;
  58. end;
  59. function TOpenSSLSocketHandler.Connect: Boolean;
  60. begin
  61. Result:=Inherited Connect;
  62. Result := Result and InitContext(False);
  63. if Result then
  64. begin
  65. Result:=CheckSSL(FSSL.SetFD(Socket.Handle));
  66. if Result then
  67. begin
  68. if SendHostAsSNI and (Socket is TInetSocket) then
  69. FSSL.Ctrl(SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,PAnsiChar(AnsiString((Socket as TInetSocket).Host)));
  70. Result:=CheckSSL(FSSL.Connect);
  71. //if Result and VerifyPeerCert then
  72. // Result:=(FSSL.VerifyResult<>0) or (not DoVerifyCert);
  73. if Result then
  74. Result:= DoVerifyCert;
  75. if Result then
  76. SetSSLActive(True);
  77. end;
  78. end;
  79. end;
  80. function TOpenSSLSocketHandler.Close: Boolean;
  81. begin
  82. Result:=Shutdown(False);
  83. end;
  84. Function TOpenSSLSocketHandler.FetchErrorInfo : Boolean;
  85. var
  86. S : AnsiString;
  87. begin
  88. FSSLLastErrorString:='';
  89. FSSLLastError:=ErrGetError;
  90. ErrClearError;
  91. Result:=(FSSLLastError<>0);
  92. if Result then
  93. begin
  94. S:=StringOfChar(#0,256);
  95. ErrErrorString(FSSLLastError,S,256);
  96. FSSLLastErrorString:=s;
  97. end;
  98. end;
  99. function TOpenSSLSocketHandler.CheckSSL(SSLResult : Integer) : Boolean;
  100. begin
  101. Result:=SSLResult>=1;
  102. if Not Result then
  103. begin
  104. FSSLLastError:=SSLResult;
  105. FetchErrorInfo;
  106. end;
  107. end;
  108. function TOpenSSLSocketHandler.CheckSSL(SSLResult: Pointer): Boolean;
  109. begin
  110. Result:=(SSLResult<>Nil);
  111. if not Result then
  112. Result:=FetchErrorInfo;
  113. end;
  114. function TOpenSSLSocketHandler.DoneContext: Boolean;
  115. begin
  116. FreeAndNil(FSSL);
  117. FreeAndNil(FCTX);
  118. ErrRemoveState(0);
  119. SetSSLActive(False);
  120. Result:=True;
  121. end;
  122. Function HandleSSLPwd(buf : PAnsiChar; len:Integer; flags:Integer; UD : Pointer):Integer; cdecl;
  123. var
  124. Pwd: AnsiString;
  125. H : TOpenSSLSocketHandler;
  126. begin
  127. if Not Assigned(UD) then
  128. PWD:=''
  129. else
  130. begin
  131. H:=TOpenSSLSocketHandler(UD);
  132. Pwd:=H.CertificateData.KeyPassword;
  133. end;
  134. if (len<Length(Pwd)+1) then
  135. SetLength(Pwd,len-1);
  136. pwd:=pwd+#0;
  137. Result:=Length(Pwd);
  138. Move(Pointer(Pwd)^,Buf^,Result);
  139. end;
  140. function TOpenSSLSocketHandler.InitSslKeys: boolean;
  141. begin
  142. Result:=(FCTX<>Nil);
  143. if not Result then
  144. Exit;
  145. if not CertificateData.Certificate.Empty then
  146. Result:=CheckSSL(FCTX.UseCertificate(CertificateData.Certificate));
  147. if Result and not CertificateData.PrivateKey.Empty then
  148. Result:=CheckSSL(FCTX.UsePrivateKey(CertificateData.PrivateKey));
  149. if Result and ((CertificateData.CertCA.FileName<>'') or (CertificateData.TrustedCertsDir<>'')) then
  150. Result:=CheckSSL(FCTX.LoadVerifyLocations(CertificateData.CertCA.FileName,CertificateData.TrustedCertsDir));
  151. if Result and not CertificateData.PFX.Empty then
  152. Result:=CheckSSL(FCTX.LoadPFX(CertificateData.PFX,CertificateData.KeyPassword));
  153. end;
  154. function TOpenSSLSocketHandler.GetLastSSLErrorString: String;
  155. begin
  156. Result:=FSSLLastErrorString;
  157. end;
  158. function TOpenSSLSocketHandler.GetLastSSLErrorCode: Integer;
  159. begin
  160. Result:=FSSLLastError;
  161. end;
  162. constructor TOpenSSLSocketHandler.create;
  163. begin
  164. inherited create;
  165. MaybeInitSSLInterface;
  166. end;
  167. destructor TOpenSSLSocketHandler.destroy;
  168. begin
  169. FreeAndNil(FCTX);
  170. FreeAndNil(FSSL);
  171. inherited destroy;
  172. end;
  173. function TOpenSSLSocketHandler.InitContext(NeedCertificate:Boolean): Boolean;
  174. Const
  175. VO : Array[Boolean] of Integer = (SSL_VERIFY_NONE,SSL_VERIFY_PEER);
  176. var
  177. s: AnsiString;
  178. begin
  179. Result:=DoneContext;
  180. if Not Result then
  181. Exit;
  182. try
  183. FCTX:=TSSLContext.Create(SSLType);
  184. Except
  185. CheckSSL(Nil);
  186. Result:=False;
  187. Exit;
  188. end;
  189. S:=CertificateData.CipherList;
  190. FCTX.SetCipherList(S);
  191. FCTX.SetVerify(VO[VerifypeerCert],Nil);
  192. FCTX.SetDefaultPasswdCb(@HandleSSLPwd);
  193. FCTX.SetDefaultPasswdCbUserdata(self);
  194. If NeedCertificate and CertificateData.NeedCertificateData then
  195. if Not CreateSelfSignedCertificate then
  196. begin
  197. DoneContext;
  198. Exit(False);
  199. end;
  200. if Not InitSSLKeys then
  201. begin
  202. DoneContext;
  203. Exit(False);
  204. end;
  205. try
  206. FSSL:=TSSL.Create(FCTX);
  207. Result:=True;
  208. Except
  209. CheckSSL(Nil);
  210. DoneContext;
  211. Result:=False;
  212. end;
  213. end;
  214. function TOpenSSLSocketHandler.Accept: Boolean;
  215. begin
  216. Result:=InitContext(True);
  217. if Result then
  218. begin
  219. Result:=CheckSSL(FSSL.setfd(Socket.Handle));
  220. if Result then
  221. Result:=CheckSSL(FSSL.Accept);
  222. end;
  223. SetSSLActive(Result);
  224. end;
  225. function TOpenSSLSocketHandler.Shutdown(BiDirectional : Boolean): boolean;
  226. var
  227. r : integer;
  228. begin
  229. Result:=assigned(FSsl);
  230. if Result then
  231. If Not BiDirectional then
  232. Result:=CheckSSL(FSSL.Shutdown)
  233. else
  234. begin
  235. r:=FSSL.Shutdown;
  236. if r<>0 then
  237. Result:=CheckSSL(r)
  238. else
  239. begin
  240. Result:=fpShutdown(Socket.Handle,1)=0;
  241. if Result then
  242. Result:=CheckSSL(FSsl.Shutdown);
  243. end
  244. end;
  245. If Result then
  246. Result:=DoneContext;
  247. end;
  248. function TOpenSSLSocketHandler.Send(Const Buffer; Count: Integer): Integer;
  249. var
  250. e: integer;
  251. begin
  252. FSSLLastError := 0;
  253. FSSLLastErrorString:='';
  254. repeat
  255. Result:=FSsl.Write(@Buffer,Count);
  256. e:=FSsl.GetError(Result);
  257. until Not (e in [SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE]);
  258. if (E=SSL_ERROR_ZERO_RETURN) then
  259. Result:=0
  260. else if (e<>0) then
  261. FSSLLastError:=e;
  262. end;
  263. function TOpenSSLSocketHandler.Recv(Const Buffer; Count: Integer): Integer;
  264. var
  265. e: integer;
  266. begin
  267. FSSLLastError:=0;
  268. FSSLLastErrorString:= '';
  269. repeat
  270. Result:=FSSL.Read(@Buffer ,Count);
  271. e:=FSSL.GetError(Result);
  272. if (e=SSL_ERROR_WANT_READ) and (Socket.IOTimeout>0) then
  273. e:=SSL_ERROR_ZERO_RETURN;
  274. until Not (e in [SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE]);
  275. if (E=SSL_ERROR_ZERO_RETURN) then
  276. Result:=0
  277. else if (e<>0) then
  278. FSSLLastError:=e;
  279. end;
  280. function TOpenSSLSocketHandler.BytesAvailable: Integer;
  281. begin
  282. Result:= FSSL.Pending;
  283. end;
  284. Function TOpenSSLSocketHandler.SSLLastError: integer;
  285. begin
  286. Result:=FSSLLastError;
  287. end;
  288. initialization
  289. TSSLSocketHandler.SetDefaultHandlerClass(TOpenSSLSocketHandler);
  290. end.