source: trunk/Packages/synapse/source/lib/ssl_sbb.pas

Last change on this file was 2, checked in by chronos, 12 years ago
  • Přidáno: Základní kostra projektu.
  • Přidáno: Knihovna synapse.
File size: 19.9 KB
Line 
1{==============================================================================|
2| Project : Ararat Synapse | 001.000.003 |
3|==============================================================================|
4| Content: SSL support for SecureBlackBox |
5|==============================================================================|
6| Copyright (c)1999-2005, Lukas Gebauer |
7| All rights reserved. |
8| |
9| Redistribution and use in source and binary forms, with or without |
10| modification, are permitted provided that the following conditions are met: |
11| |
12| Redistributions of source code must retain the above copyright notice, this |
13| list of conditions and the following disclaimer. |
14| |
15| Redistributions in binary form must reproduce the above copyright notice, |
16| this list of conditions and the following disclaimer in the documentation |
17| and/or other materials provided with the distribution. |
18| |
19| Neither the name of Lukas Gebauer nor the names of its contributors may |
20| be used to endorse or promote products derived from this software without |
21| specific prior written permission. |
22| |
23| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
27| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
29| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
30| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
33| DAMAGE. |
34|==============================================================================|
35| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
36| Portions created by Lukas Gebauer are Copyright (c)2005. |
37| All Rights Reserved. |
38|==============================================================================|
39| Contributor(s): |
40| Allen Drennan (adrennan@wiredred.com) |
41|==============================================================================|
42| History: see HISTORY.HTM from distribution package |
43| (Found at URL: http://www.ararat.cz/synapse/) |
44|==============================================================================}
45
46{:@abstract(SSL plugin for Eldos SecureBlackBox)
47
48For handling keys and certificates you can use this properties:
49@link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA),
50@link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate),
51@link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey),
52@link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate),
53@link(TCustomSSL.PFXFile). For usage of this properties and for possible formats
54of keys and certificates refer to SecureBlackBox documentation.
55}
56
57{$IFDEF FPC}
58 {$MODE DELPHI}
59{$ENDIF}
60{$H+}
61
62unit ssl_sbb;
63
64interface
65
66uses
67 SysUtils, Classes, Windows, blcksock, synsock, synautil, synacode,
68 SBClient, SBServer, SBX509, SBWinCertStorage, SBCustomCertStorage,
69 SBUtils, SBConstants, SBSessionPool;
70
71const
72 DEFAULT_RECV_BUFFER=32768;
73
74type
75 {:@abstract(class implementing SecureBlackbox SSL plugin.)
76 Instance of this class will be created for each @link(TTCPBlockSocket).
77 You not need to create instance of this class, all is done by Synapse itself!}
78 TSSLSBB=class(TCustomSSL)
79 protected
80 FServer: Boolean;
81 FElSecureClient:TElSecureClient;
82 FElSecureServer:TElSecureServer;
83 FElCertStorage:TElMemoryCertStorage;
84 FElX509Certificate:TElX509Certificate;
85 FElX509CACertificate:TElX509Certificate;
86 FCipherSuites:TBits;
87 private
88 FRecvBuffer:String;
89 FRecvBuffers:String;
90 FRecvBuffersLock:TRTLCriticalSection;
91 FRecvDecodedBuffers:String;
92 function GetCipherSuite:Integer;
93 procedure Reset;
94 function Prepare(Server:Boolean):Boolean;
95 procedure OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean);
96 procedure OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt);
97 procedure OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt);
98 procedure OnData(Sender:TObject;Buffer:Pointer;Size:LongInt);
99 public
100 constructor Create(const Value: TTCPBlockSocket); override;
101 destructor Destroy; override;
102 {:See @inherited}
103 function LibVersion: String; override;
104 {:See @inherited}
105 function LibName: String; override;
106 {:See @inherited and @link(ssl_sbb) for more details.}
107 function Connect: boolean; override;
108 {:See @inherited and @link(ssl_sbb) for more details.}
109 function Accept: boolean; override;
110 {:See @inherited}
111 function Shutdown: boolean; override;
112 {:See @inherited}
113 function BiShutdown: boolean; override;
114 {:See @inherited}
115 function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
116 {:See @inherited}
117 function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
118 {:See @inherited}
119 function WaitingData: Integer; override;
120 {:See @inherited}
121 function GetSSLVersion: string; override;
122 {:See @inherited}
123 function GetPeerSubject: string; override;
124 {:See @inherited}
125 function GetPeerIssuer: string; override;
126 {:See @inherited}
127 function GetPeerName: string; override;
128 {:See @inherited}
129 function GetPeerFingerprint: string; override;
130 {:See @inherited}
131 function GetCertInfo: string; override;
132 published
133 property ElSecureClient:TElSecureClient read FElSecureClient write FElSecureClient;
134 property ElSecureServer:TElSecureServer read FElSecureServer write FElSecureServer;
135 property CipherSuites:TBits read FCipherSuites write FCipherSuites;
136 property CipherSuite:Integer read GetCipherSuite;
137 end;
138
139implementation
140
141var
142 FAcceptThread:THandle=0;
143
144// on error
145procedure TSSLSBB.OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean);
146
147begin
148 FLastErrorDesc:='';
149 FLastError:=ErrorCode;
150end;
151
152// on send
153procedure TSSLSBB.OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt);
154
155var
156 lResult:Integer;
157
158begin
159 if FSocket.Socket=INVALID_SOCKET then
160 Exit;
161 lResult:=Send(FSocket.Socket,Buffer,Size,0);
162 if lResult=SOCKET_ERROR then
163 begin
164 FLastErrorDesc:='';
165 FLastError:=WSAGetLastError;
166 end;
167end;
168
169// on receive
170procedure TSSLSBB.OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt);
171
172begin
173 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
174 try
175 if Length(FRecvBuffers)<=MaxSize then
176 begin
177 Written:=Length(FRecvBuffers);
178 Move(FRecvBuffers[1],Buffer^,Written);
179 FRecvBuffers:='';
180 end
181 else
182 begin
183 Written:=MaxSize;
184 Move(FRecvBuffers[1],Buffer^,Written);
185 Delete(FRecvBuffers,1,Written);
186 end;
187 finally
188 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
189 end;
190end;
191
192// on data
193procedure TSSLSBB.OnData(Sender:TObject;Buffer:Pointer;Size:LongInt);
194
195var
196 lString:String;
197
198begin
199 SetLength(lString,Size);
200 Move(Buffer^,lString[1],Size);
201 FRecvDecodedBuffers:=FRecvDecodedBuffers+lString;
202end;
203
204{ inherited }
205
206constructor TSSLSBB.Create(const Value: TTCPBlockSocket);
207
208var
209 loop1:Integer;
210
211begin
212 inherited Create(Value);
213 FServer:=FALSE;
214 FElSecureClient:=NIL;
215 FElSecureServer:=NIL;
216 FElCertStorage:=NIL;
217 FElX509Certificate:=NIL;
218 FElX509CACertificate:=NIL;
219 SetLength(FRecvBuffer,DEFAULT_RECV_BUFFER);
220 FRecvBuffers:='';
221 InitializeCriticalSection(FRecvBuffersLock);
222 FRecvDecodedBuffers:='';
223 FCipherSuites:=TBits.Create;
224 if FCipherSuites<>NIL then
225 begin
226 FCipherSuites.Size:=SB_SUITE_LAST+1;
227 for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
228 FCipherSuites[loop1]:=TRUE;
229 end;
230end;
231
232destructor TSSLSBB.Destroy;
233
234begin
235 Reset;
236 inherited Destroy;
237 if FCipherSuites<>NIL then
238 FreeAndNIL(FCipherSuites);
239 DeleteCriticalSection(FRecvBuffersLock);
240end;
241
242function TSSLSBB.LibVersion: String;
243
244begin
245 Result:='SecureBlackBox';
246end;
247
248function TSSLSBB.LibName: String;
249
250begin
251 Result:='ssl_sbb';
252end;
253
254function FileToString(lFile:String):String;
255
256var
257 lStream:TMemoryStream;
258
259begin
260 Result:='';
261 lStream:=TMemoryStream.Create;
262 if lStream<>NIL then
263 begin
264 lStream.LoadFromFile(lFile);
265 if lStream.Size>0 then
266 begin
267 lStream.Position:=0;
268 SetLength(Result,lStream.Size);
269 Move(lStream.Memory^,Result[1],lStream.Size);
270 end;
271 lStream.Free;
272 end;
273end;
274
275function TSSLSBB.GetCipherSuite:Integer;
276
277begin
278 if FServer then
279 Result:=FElSecureServer.CipherSuite
280 else
281 Result:=FElSecureClient.CipherSuite;
282end;
283
284procedure TSSLSBB.Reset;
285
286begin
287 if FElSecureServer<>NIL then
288 FreeAndNIL(FElSecureServer);
289 if FElSecureClient<>NIL then
290 FreeAndNIL(FElSecureClient);
291 if FElX509Certificate<>NIL then
292 FreeAndNIL(FElX509Certificate);
293 if FElX509CACertificate<>NIL then
294 FreeAndNIL(FElX509CACertificate);
295 if FElCertStorage<>NIL then
296 FreeAndNIL(FElCertStorage);
297 FSSLEnabled:=FALSE;
298end;
299
300function TSSLSBB.Prepare(Server:Boolean): Boolean;
301
302var
303 loop1:Integer;
304 lStream:TMemoryStream;
305 lCertificate,lPrivateKey,lCertCA:String;
306
307begin
308 Result:=FALSE;
309 FServer:=Server;
310
311 // reset, if necessary
312 Reset;
313
314 // init, certificate
315 if FCertificateFile<>'' then
316 lCertificate:=FileToString(FCertificateFile)
317 else
318 lCertificate:=FCertificate;
319 if FPrivateKeyFile<>'' then
320 lPrivateKey:=FileToString(FPrivateKeyFile)
321 else
322 lPrivateKey:=FPrivateKey;
323 if FCertCAFile<>'' then
324 lCertCA:=FileToString(FCertCAFile)
325 else
326 lCertCA:=FCertCA;
327 if (lCertificate<>'') and (lPrivateKey<>'') then
328 begin
329 FElCertStorage:=TElMemoryCertStorage.Create(NIL);
330 if FElCertStorage<>NIL then
331 FElCertStorage.Clear;
332
333 // apply ca certificate
334 if lCertCA<>'' then
335 begin
336 FElX509CACertificate:=TElX509Certificate.Create(NIL);
337 if FElX509CACertificate<>NIL then
338 begin
339 with FElX509CACertificate do
340 begin
341 lStream:=TMemoryStream.Create;
342 try
343 WriteStrToStream(lStream,lCertCA);
344 lStream.Seek(0,soFromBeginning);
345 LoadFromStream(lStream);
346 finally
347 lStream.Free;
348 end;
349 end;
350 if FElCertStorage<>NIL then
351 FElCertStorage.Add(FElX509CACertificate);
352 end;
353 end;
354
355 // apply certificate
356 FElX509Certificate:=TElX509Certificate.Create(NIL);
357 if FElX509Certificate<>NIL then
358 begin
359 with FElX509Certificate do
360 begin
361 lStream:=TMemoryStream.Create;
362 try
363 WriteStrToStream(lStream,lCertificate);
364 lStream.Seek(0,soFromBeginning);
365 LoadFromStream(lStream);
366 finally
367 lStream.Free;
368 end;
369 lStream:=TMemoryStream.Create;
370 try
371 WriteStrToStream(lStream,lPrivateKey);
372 lStream.Seek(0,soFromBeginning);
373 LoadKeyFromStream(lStream);
374 finally
375 lStream.Free;
376 end;
377 if FElCertStorage<>NIL then
378 FElCertStorage.Add(FElX509Certificate);
379 end;
380 end;
381 end;
382
383 // init, as server
384 if FServer then
385 begin
386 FElSecureServer:=TElSecureServer.Create(NIL);
387 if FElSecureServer<>NIL then
388 begin
389 // init, ciphers
390 for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
391 FElSecureServer.CipherSuites[loop1]:=FCipherSuites[loop1];
392 FElSecureServer.Versions:=[sbSSL2,sbSSL3,sbTLS1];
393 FElSecureServer.ClientAuthentication:=FALSE;
394 FElSecureServer.OnError:=OnError;
395 FElSecureServer.OnSend:=OnSend;
396 FElSecureServer.OnReceive:=OnReceive;
397 FElSecureServer.OnData:=OnData;
398 FElSecureServer.CertStorage:=FElCertStorage;
399 Result:=TRUE;
400 end;
401 end
402 else
403 // init, as client
404 begin
405 FElSecureClient:=TElSecureClient.Create(NIL);
406 if FElSecureClient<>NIL then
407 begin
408 // init, ciphers
409 for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
410 FElSecureClient.CipherSuites[loop1]:=FCipherSuites[loop1];
411 FElSecureClient.Versions:=[sbSSL3,sbTLS1];
412 FElSecureClient.OnError:=OnError;
413 FElSecureClient.OnSend:=OnSend;
414 FElSecureClient.OnReceive:=OnReceive;
415 FElSecureClient.OnData:=OnData;
416 FElSecureClient.CertStorage:=FElCertStorage;
417 Result:=TRUE;
418 end;
419 end;
420end;
421
422function TSSLSBB.Connect:Boolean;
423
424var
425 lResult:Integer;
426
427begin
428 Result:=FALSE;
429 if FSocket.Socket=INVALID_SOCKET then
430 Exit;
431 if Prepare(FALSE) then
432 begin
433 FElSecureClient.Open;
434
435 // reset
436 FRecvBuffers:='';
437 FRecvDecodedBuffers:='';
438
439 // wait for open or error
440 while (not FElSecureClient.Active) and
441 (FLastError=0) do
442 begin
443 // data available?
444 if FRecvBuffers<>'' then
445 FElSecureClient.DataAvailable
446 else
447 begin
448 // socket recv
449 lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
450 if lResult=SOCKET_ERROR then
451 begin
452 FLastErrorDesc:='';
453 FLastError:=WSAGetLastError;
454 end
455 else
456 begin
457 if lResult>0 then
458 FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult)
459 else
460 Break;
461 end;
462 end;
463 end;
464 if FLastError<>0 then
465 Exit;
466 FSSLEnabled:=FElSecureClient.Active;
467 Result:=FSSLEnabled;
468 end;
469end;
470
471function TSSLSBB.Accept:Boolean;
472
473var
474 lResult:Integer;
475
476begin
477 Result:=FALSE;
478 if FSocket.Socket=INVALID_SOCKET then
479 Exit;
480 if Prepare(TRUE) then
481 begin
482 FAcceptThread:=GetCurrentThreadId;
483 FElSecureServer.Open;
484
485 // reset
486 FRecvBuffers:='';
487 FRecvDecodedBuffers:='';
488
489 // wait for open or error
490 while (not FElSecureServer.Active) and
491 (FLastError=0) do
492 begin
493 // data available?
494 if FRecvBuffers<>'' then
495 FElSecureServer.DataAvailable
496 else
497 begin
498 // socket recv
499 lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
500 if lResult=SOCKET_ERROR then
501 begin
502 FLastErrorDesc:='';
503 FLastError:=WSAGetLastError;
504 end
505 else
506 begin
507 if lResult>0 then
508 FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult)
509 else
510 Break;
511 end;
512 end;
513 end;
514 if FLastError<>0 then
515 Exit;
516 FSSLEnabled:=FElSecureServer.Active;
517 Result:=FSSLEnabled;
518 end;
519end;
520
521function TSSLSBB.Shutdown:Boolean;
522
523begin
524 Result:=BiShutdown;
525end;
526
527function TSSLSBB.BiShutdown: boolean;
528
529begin
530 Reset;
531 Result:=TRUE;
532end;
533
534function TSSLSBB.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
535
536begin
537 if FServer then
538 FElSecureServer.SendData(Buffer,Len)
539 else
540 FElSecureClient.SendData(Buffer,Len);
541 Result:=Len;
542end;
543
544function TSSLSBB.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
545
546begin
547 Result:=0;
548 try
549 // recv waiting, if necessary
550 if FRecvDecodedBuffers='' then
551 WaitingData;
552
553 // received
554 if Length(FRecvDecodedBuffers)<Len then
555 begin
556 Result:=Length(FRecvDecodedBuffers);
557 Move(FRecvDecodedBuffers[1],Buffer^,Result);
558 FRecvDecodedBuffers:='';
559 end
560 else
561 begin
562 Result:=Len;
563 Move(FRecvDecodedBuffers[1],Buffer^,Result);
564 Delete(FRecvDecodedBuffers,1,Result);
565 end;
566 except
567 // ignore
568 end;
569end;
570
571function TSSLSBB.WaitingData: Integer;
572
573var
574 lResult:Integer;
575 lRecvBuffers:Boolean;
576
577begin
578 Result:=0;
579 if FSocket.Socket=INVALID_SOCKET then
580 Exit;
581 // data available?
582 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
583 try
584 lRecvBuffers:=FRecvBuffers<>'';
585 finally
586 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
587 end;
588 if lRecvBuffers then
589 begin
590 if FServer then
591 FElSecureServer.DataAvailable
592 else
593 FElSecureClient.DataAvailable;
594 end
595 else
596 begin
597 // socket recv
598 lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
599 if lResult=SOCKET_ERROR then
600 begin
601 FLastErrorDesc:='';
602 FLastError:=WSAGetLastError;
603 end
604 else
605 begin
606 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
607 try
608 FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult);
609 finally
610 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
611 end;
612
613 // data available?
614 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
615 try
616 lRecvBuffers:=FRecvBuffers<>'';
617 finally
618 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
619 end;
620 if lRecvBuffers then
621 begin
622 if FServer then
623 FElSecureServer.DataAvailable
624 else
625 FElSecureClient.DataAvailable;
626 end;
627 end;
628 end;
629
630 // decoded buffers result
631 Result:=Length(FRecvDecodedBuffers);
632end;
633
634function TSSLSBB.GetSSLVersion: string;
635
636begin
637 Result:='SSLv3 or TLSv1';
638end;
639
640function TSSLSBB.GetPeerSubject: string;
641
642begin
643 Result := '';
644// if FServer then
645 // must return subject of the client certificate
646// else
647 // must return subject of the server certificate
648end;
649
650function TSSLSBB.GetPeerName: string;
651
652begin
653 Result := '';
654// if FServer then
655 // must return commonname of the client certificate
656// else
657 // must return commonname of the server certificate
658end;
659
660function TSSLSBB.GetPeerIssuer: string;
661
662begin
663 Result := '';
664// if FServer then
665 // must return issuer of the client certificate
666// else
667 // must return issuer of the server certificate
668end;
669
670function TSSLSBB.GetPeerFingerprint: string;
671
672begin
673 Result := '';
674// if FServer then
675 // must return a unique hash string of the client certificate
676// else
677 // must return a unique hash string of the server certificate
678end;
679
680function TSSLSBB.GetCertInfo: string;
681
682begin
683 Result := '';
684// if FServer then
685 // must return a text representation of the ASN of the client certificate
686// else
687 // must return a text representation of the ASN of the server certificate
688end;
689
690{==============================================================================}
691
692initialization
693 SSLImplementation := TSSLSBB;
694
695finalization
696
697end.
Note: See TracBrowser for help on using the repository browser.