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

Last change on this file was 60, checked in by chronos, 12 years ago
File size: 20.6 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
71
72const
73 DEFAULT_RECV_BUFFER=32768;
74
75type
76 {:@abstract(class implementing SecureBlackbox SSL plugin.)
77 Instance of this class will be created for each @link(TTCPBlockSocket).
78 You not need to create instance of this class, all is done by Synapse itself!}
79 TSSLSBB=class(TCustomSSL)
80 protected
81 FServer: Boolean;
82 FElSecureClient:TElSecureClient;
83 FElSecureServer:TElSecureServer;
84 FElCertStorage:TElMemoryCertStorage;
85 FElX509Certificate:TElX509Certificate;
86 FElX509CACertificate:TElX509Certificate;
87 FCipherSuites:TBits;
88 private
89 FRecvBuffer:String;
90 FRecvBuffers:String;
91 FRecvBuffersLock:TRTLCriticalSection;
92 FRecvDecodedBuffers:String;
93 function GetCipherSuite:Integer;
94 procedure Reset;
95 function Prepare(Server:Boolean):Boolean;
96 procedure OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean);
97 procedure OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt);
98 procedure OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt);
99 procedure OnData(Sender:TObject;Buffer:Pointer;Size:LongInt);
100 public
101 constructor Create(const Value: TTCPBlockSocket); override;
102 destructor Destroy; override;
103 {:See @inherited}
104 function LibVersion: String; override;
105 {:See @inherited}
106 function LibName: String; override;
107 {:See @inherited and @link(ssl_sbb) for more details.}
108 function Connect: boolean; override;
109 {:See @inherited and @link(ssl_sbb) for more details.}
110 function Accept: boolean; override;
111 {:See @inherited}
112 function Shutdown: boolean; override;
113 {:See @inherited}
114 function BiShutdown: boolean; override;
115 {:See @inherited}
116 function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
117 {:See @inherited}
118 function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
119 {:See @inherited}
120 function WaitingData: Integer; override;
121 {:See @inherited}
122 function GetSSLVersion: string; override;
123 {:See @inherited}
124 function GetPeerSubject: string; override;
125 {:See @inherited}
126 function GetPeerIssuer: string; override;
127 {:See @inherited}
128 function GetPeerName: string; override;
129 {:See @inherited}
130 function GetPeerFingerprint: string; override;
131 {:See @inherited}
132 function GetCertInfo: string; override;
133 published
134 property ElSecureClient:TElSecureClient read FElSecureClient write FElSecureClient;
135 property ElSecureServer:TElSecureServer read FElSecureServer write FElSecureServer;
136 property CipherSuites:TBits read FCipherSuites write FCipherSuites;
137 property CipherSuite:Integer read GetCipherSuite;
138 end;
139
140implementation
141
142var
143 FAcceptThread:THandle=0;
144
145// on error
146procedure TSSLSBB.OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean);
147
148begin
149 FLastErrorDesc:='';
150 FLastError:=ErrorCode;
151end;
152
153// on send
154procedure TSSLSBB.OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt);
155
156var
157 lResult:Integer;
158
159begin
160 if FSocket.Socket=INVALID_SOCKET then
161 Exit;
162 lResult:=Send(FSocket.Socket,Buffer,Size,0);
163 if lResult=SOCKET_ERROR then
164 begin
165 FLastErrorDesc:='';
166 FLastError:=WSAGetLastError;
167 end;
168end;
169
170// on receive
171procedure TSSLSBB.OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt);
172
173begin
174 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
175 try
176 if Length(FRecvBuffers)<=MaxSize then
177 begin
178 Written:=Length(FRecvBuffers);
179 Move(FRecvBuffers[1],Buffer^,Written);
180 FRecvBuffers:='';
181 end
182 else
183 begin
184 Written:=MaxSize;
185 Move(FRecvBuffers[1],Buffer^,Written);
186 Delete(FRecvBuffers,1,Written);
187 end;
188 finally
189 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
190 end;
191end;
192
193// on data
194procedure TSSLSBB.OnData(Sender:TObject;Buffer:Pointer;Size:LongInt);
195
196var
197 lString:String;
198
199begin
200 SetLength(lString,Size);
201 Move(Buffer^,lString[1],Size);
202 FRecvDecodedBuffers:=FRecvDecodedBuffers+lString;
203end;
204
205{ inherited }
206
207constructor TSSLSBB.Create(const Value: TTCPBlockSocket);
208
209var
210 loop1:Integer;
211
212begin
213 inherited Create(Value);
214 FServer:=FALSE;
215 FElSecureClient:=NIL;
216 FElSecureServer:=NIL;
217 FElCertStorage:=NIL;
218 FElX509Certificate:=NIL;
219 FElX509CACertificate:=NIL;
220 SetLength(FRecvBuffer,DEFAULT_RECV_BUFFER);
221 FRecvBuffers:='';
222 InitializeCriticalSection(FRecvBuffersLock);
223 FRecvDecodedBuffers:='';
224 FCipherSuites:=TBits.Create;
225 if FCipherSuites<>NIL then
226 begin
227 FCipherSuites.Size:=SB_SUITE_LAST+1;
228 for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
229 FCipherSuites[loop1]:=TRUE;
230 end;
231end;
232
233destructor TSSLSBB.Destroy;
234
235begin
236 Reset;
237 inherited Destroy;
238 if FCipherSuites<>NIL then
239 FreeAndNIL(FCipherSuites);
240 DeleteCriticalSection(FRecvBuffersLock);
241end;
242
243function TSSLSBB.LibVersion: String;
244
245begin
246 Result:='SecureBlackBox';
247end;
248
249function TSSLSBB.LibName: String;
250
251begin
252 Result:='ssl_sbb';
253end;
254
255function FileToString(lFile:String):String;
256
257var
258 lStream:TMemoryStream;
259
260begin
261 Result:='';
262 lStream:=TMemoryStream.Create;
263 if lStream<>NIL then
264 begin
265 lStream.LoadFromFile(lFile);
266 if lStream.Size>0 then
267 begin
268 lStream.Position:=0;
269 SetLength(Result,lStream.Size);
270 Move(lStream.Memory^,Result[1],lStream.Size);
271 end;
272 lStream.Free;
273 end;
274end;
275
276function TSSLSBB.GetCipherSuite:Integer;
277
278begin
279 if FServer then
280 Result:=FElSecureServer.CipherSuite
281 else
282 Result:=FElSecureClient.CipherSuite;
283end;
284
285procedure TSSLSBB.Reset;
286
287begin
288 if FElSecureServer<>NIL then
289 FreeAndNIL(FElSecureServer);
290 if FElSecureClient<>NIL then
291 FreeAndNIL(FElSecureClient);
292 if FElX509Certificate<>NIL then
293 FreeAndNIL(FElX509Certificate);
294 if FElX509CACertificate<>NIL then
295 FreeAndNIL(FElX509CACertificate);
296 if FElCertStorage<>NIL then
297 FreeAndNIL(FElCertStorage);
298 FSSLEnabled:=FALSE;
299end;
300
301function TSSLSBB.Prepare(Server:Boolean): Boolean;
302
303var
304 loop1:Integer;
305 lStream:TMemoryStream;
306 lCertificate,lPrivateKey,lCertCA:String;
307
308begin
309 Result:=FALSE;
310 FServer:=Server;
311
312 // reset, if necessary
313 Reset;
314
315 // init, certificate
316 if FCertificateFile<>'' then
317 lCertificate:=FileToString(FCertificateFile)
318 else
319 lCertificate:=FCertificate;
320 if FPrivateKeyFile<>'' then
321 lPrivateKey:=FileToString(FPrivateKeyFile)
322 else
323 lPrivateKey:=FPrivateKey;
324 if FCertCAFile<>'' then
325 lCertCA:=FileToString(FCertCAFile)
326 else
327 lCertCA:=FCertCA;
328 if (lCertificate<>'') and (lPrivateKey<>'') then
329 begin
330 FElCertStorage:=TElMemoryCertStorage.Create(NIL);
331 if FElCertStorage<>NIL then
332 FElCertStorage.Clear;
333
334 // apply ca certificate
335 if lCertCA<>'' then
336 begin
337 FElX509CACertificate:=TElX509Certificate.Create(NIL);
338 if FElX509CACertificate<>NIL then
339 begin
340 with FElX509CACertificate do
341 begin
342 lStream:=TMemoryStream.Create;
343 try
344 WriteStrToStream(lStream,lCertCA);
345 lStream.Seek(0,soFromBeginning);
346 LoadFromStream(lStream);
347 finally
348 lStream.Free;
349 end;
350 end;
351 if FElCertStorage<>NIL then
352 FElCertStorage.Add(FElX509CACertificate);
353 end;
354 end;
355
356 // apply certificate
357 FElX509Certificate:=TElX509Certificate.Create(NIL);
358 if FElX509Certificate<>NIL then
359 begin
360 with FElX509Certificate do
361 begin
362 lStream:=TMemoryStream.Create;
363 try
364 WriteStrToStream(lStream,lCertificate);
365 lStream.Seek(0,soFromBeginning);
366 LoadFromStream(lStream);
367 finally
368 lStream.Free;
369 end;
370 lStream:=TMemoryStream.Create;
371 try
372 WriteStrToStream(lStream,lPrivateKey);
373 lStream.Seek(0,soFromBeginning);
374 LoadKeyFromStream(lStream);
375 finally
376 lStream.Free;
377 end;
378 if FElCertStorage<>NIL then
379 FElCertStorage.Add(FElX509Certificate);
380 end;
381 end;
382 end;
383
384 // init, as server
385 if FServer then
386 begin
387 FElSecureServer:=TElSecureServer.Create(NIL);
388 if FElSecureServer<>NIL then
389 begin
390 // init, ciphers
391 for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
392 FElSecureServer.CipherSuites[loop1]:=FCipherSuites[loop1];
393 FElSecureServer.Versions:=[sbSSL2,sbSSL3,sbTLS1];
394 FElSecureServer.ClientAuthentication:=FALSE;
395 FElSecureServer.OnError:=OnError;
396 FElSecureServer.OnSend:=OnSend;
397 FElSecureServer.OnReceive:=OnReceive;
398 FElSecureServer.OnData:=OnData;
399 FElSecureServer.CertStorage:=FElCertStorage;
400 Result:=TRUE;
401 end;
402 end
403 else
404 // init, as client
405 begin
406 FElSecureClient:=TElSecureClient.Create(NIL);
407 if FElSecureClient<>NIL then
408 begin
409 // init, ciphers
410 for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do
411 FElSecureClient.CipherSuites[loop1]:=FCipherSuites[loop1];
412 FElSecureClient.Versions:=[sbSSL3,sbTLS1];
413 FElSecureClient.OnError:=OnError;
414 FElSecureClient.OnSend:=OnSend;
415 FElSecureClient.OnReceive:=OnReceive;
416 FElSecureClient.OnData:=OnData;
417 FElSecureClient.CertStorage:=FElCertStorage;
418 Result:=TRUE;
419 end;
420 end;
421end;
422
423function TSSLSBB.Connect:Boolean;
424
425var
426 lResult:Integer;
427
428begin
429 Result:=FALSE;
430 if FSocket.Socket=INVALID_SOCKET then
431 Exit;
432 if Prepare(FALSE) then
433 begin
434 FElSecureClient.Open;
435
436 // reset
437 FRecvBuffers:='';
438 FRecvDecodedBuffers:='';
439
440 // wait for open or error
441 while (not FElSecureClient.Active) and
442 (FLastError=0) do
443 begin
444 // data available?
445 if FRecvBuffers<>'' then
446 FElSecureClient.DataAvailable
447 else
448 begin
449 // socket recv
450 lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
451 if lResult=SOCKET_ERROR then
452 begin
453 FLastErrorDesc:='';
454 FLastError:=WSAGetLastError;
455 end
456 else
457 begin
458 if lResult>0 then
459 FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult)
460 else
461 Break;
462 end;
463 end;
464 end;
465 if FLastError<>0 then
466 Exit;
467 FSSLEnabled:=FElSecureClient.Active;
468 Result:=FSSLEnabled;
469 end;
470end;
471
472function TSSLSBB.Accept:Boolean;
473
474var
475 lResult:Integer;
476
477begin
478 Result:=FALSE;
479 if FSocket.Socket=INVALID_SOCKET then
480 Exit;
481 if Prepare(TRUE) then
482 begin
483 FAcceptThread:=GetCurrentThreadId;
484 FElSecureServer.Open;
485
486 // reset
487 FRecvBuffers:='';
488 FRecvDecodedBuffers:='';
489
490 // wait for open or error
491 while (not FElSecureServer.Active) and
492 (FLastError=0) do
493 begin
494 // data available?
495 if FRecvBuffers<>'' then
496 FElSecureServer.DataAvailable
497 else
498 begin
499 // socket recv
500 lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
501 if lResult=SOCKET_ERROR then
502 begin
503 FLastErrorDesc:='';
504 FLastError:=WSAGetLastError;
505 end
506 else
507 begin
508 if lResult>0 then
509 FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult)
510 else
511 Break;
512 end;
513 end;
514 end;
515 if FLastError<>0 then
516 Exit;
517 FSSLEnabled:=FElSecureServer.Active;
518 Result:=FSSLEnabled;
519 end;
520end;
521
522function TSSLSBB.Shutdown:Boolean;
523
524begin
525 Result:=BiShutdown;
526end;
527
528function TSSLSBB.BiShutdown: boolean;
529
530begin
531 Reset;
532 Result:=TRUE;
533end;
534
535function TSSLSBB.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
536
537begin
538 if FServer then
539 FElSecureServer.SendData(Buffer,Len)
540 else
541 FElSecureClient.SendData(Buffer,Len);
542 Result:=Len;
543end;
544
545function TSSLSBB.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
546
547begin
548 Result:=0;
549 try
550 // recv waiting, if necessary
551 if FRecvDecodedBuffers='' then
552 WaitingData;
553
554 // received
555 if Length(FRecvDecodedBuffers)<Len then
556 begin
557 Result:=Length(FRecvDecodedBuffers);
558 Move(FRecvDecodedBuffers[1],Buffer^,Result);
559 FRecvDecodedBuffers:='';
560 end
561 else
562 begin
563 Result:=Len;
564 Move(FRecvDecodedBuffers[1],Buffer^,Result);
565 Delete(FRecvDecodedBuffers,1,Result);
566 end;
567 except
568 // ignore
569 end;
570end;
571
572function TSSLSBB.WaitingData: Integer;
573
574var
575 lResult:Integer;
576 lRecvBuffers:Boolean;
577
578begin
579 Result:=0;
580 if FSocket.Socket=INVALID_SOCKET then
581 Exit;
582 // data available?
583 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
584 try
585 lRecvBuffers:=FRecvBuffers<>'';
586 finally
587 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
588 end;
589 if lRecvBuffers then
590 begin
591 if FServer then
592 FElSecureServer.DataAvailable
593 else
594 FElSecureClient.DataAvailable;
595 end
596 else
597 begin
598 // socket recv
599 lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0);
600 if lResult=SOCKET_ERROR then
601 begin
602 FLastErrorDesc:='';
603 FLastError:=WSAGetLastError;
604 end
605 else
606 begin
607 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
608 try
609 FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult);
610 finally
611 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
612 end;
613
614 // data available?
615 if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock);
616 try
617 lRecvBuffers:=FRecvBuffers<>'';
618 finally
619 if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock);
620 end;
621 if lRecvBuffers then
622 begin
623 if FServer then
624 FElSecureServer.DataAvailable
625 else
626 FElSecureClient.DataAvailable;
627 end;
628 end;
629 end;
630
631 // decoded buffers result
632 Result:=Length(FRecvDecodedBuffers);
633end;
634
635function TSSLSBB.GetSSLVersion: string;
636
637begin
638 Result:='SSLv3 or TLSv1';
639end;
640
641function TSSLSBB.GetPeerSubject: string;
642
643begin
644 Result := '';
645// if FServer then
646 // must return subject of the client certificate
647// else
648 // must return subject of the server certificate
649end;
650
651function TSSLSBB.GetPeerName: string;
652
653begin
654 Result := '';
655// if FServer then
656 // must return commonname of the client certificate
657// else
658 // must return commonname of the server certificate
659end;
660
661function TSSLSBB.GetPeerIssuer: string;
662
663begin
664 Result := '';
665// if FServer then
666 // must return issuer of the client certificate
667// else
668 // must return issuer of the server certificate
669end;
670
671function TSSLSBB.GetPeerFingerprint: string;
672
673begin
674 Result := '';
675// if FServer then
676 // must return a unique hash string of the client certificate
677// else
678 // must return a unique hash string of the server certificate
679end;
680
681function TSSLSBB.GetCertInfo: string;
682
683begin
684 Result := '';
685// if FServer then
686 // must return a text representation of the ASN of the client certificate
687// else
688 // must return a text representation of the ASN of the server certificate
689end;
690
691{==============================================================================}
692
693initialization
694 SSLImplementation := TSSLSBB;
695
696finalization
697
698end.
Note: See TracBrowser for help on using the repository browser.