1 {==============================================================================|
2 | Project : Ararat Synapse | 001.001.001 |
3 |==============================================================================|
4 | Content: SSL/SSH support by Peter Gutmann's CryptLib |
5 |==============================================================================|
6 | Copyright (c)1999-2015, 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-2015. |
37 | All Rights Reserved. |
38 |==============================================================================|
39 | Contributor(s): |
40 |==============================================================================|
41 | History: see HISTORY.HTM from distribution package |
42 | (Found at URL: http://www.ararat.cz/synapse/) |
43 |==============================================================================}
44
45 {:@abstract(SSL/SSH plugin for CryptLib)
46
47 This plugin requires cl32.dll at least version 3.2.0! It can be used on Win32
48 and Linux. This library is staticly linked - when you compile your application
49 with this plugin, you MUST distribute it with Cryptib library, otherwise you
50 cannot run your application!
51
52 It can work with keys and certificates stored as PKCS#15 only! It must be stored
53 as disk file only, you cannot load them from memory! Each file can hold multiple
54 keys and certificates. You must identify it by 'label' stored in
55 @link(TSSLCryptLib.PrivateKeyLabel).
56
57 If you need to use secure connection and authorize self by certificate
58 (each SSL/TLS server or client with client authorization), then use
59 @link(TCustomSSL.PrivateKeyFile), @link(TSSLCryptLib.PrivateKeyLabel) and
60 @link(TCustomSSL.KeyPassword) properties.
61
62 If you need to use server what verifying client certificates, then use
63 @link(TCustomSSL.CertCAFile) as PKCS#15 file with public keyas of allowed clients. Clients
64 with non-matching certificates will be rejected by cryptLib.
65
66 This plugin is capable to create Ad-Hoc certificates. When you start SSL/TLS
67 server without explicitly assigned key and certificate, then this plugin create
68 Ad-Hoc key and certificate for each incomming connection by self. It slowdown
69 accepting of new connections!
70
71 You can use this plugin for SSHv2 connections too! You must explicitly set
72 @link(TCustomSSL.SSLType) to value LT_SSHv2 and set @link(TCustomSSL.username)
73 and @link(TCustomSSL.password). You can use special SSH channels too, see
74 @link(TCustomSSL).
75 }
76
77 {$IFDEF FPC}
78 {$MODE DELPHI}
79 {$ENDIF}
80 {$H+}
81
82 unit ssl_cryptlib;
83
84 interface
85
86 uses
87 Windows,
88 SysUtils,
89 blcksock, synsock, synautil, synacode,
90 cryptlib;
91
92 type
93 {:@abstract(class implementing CryptLib SSL/SSH plugin.)
94 Instance of this class will be created for each @link(TTCPBlockSocket).
95 You not need to create instance of this class, all is done by Synapse itself!}
96 TSSLCryptLib = class(TCustomSSL)
97 protected
98 FCryptSession: CRYPT_SESSION;
99 FPrivateKeyLabel: string;
100 FDelCert: Boolean;
101 FReadBuffer: string;
102 FTrustedCAs: array of integer;
SSLChecknull103 function SSLCheck(Value: integer): Boolean;
Initnull104 function Init(server:Boolean): Boolean;
DeInitnull105 function DeInit: Boolean;
Preparenull106 function Prepare(server:Boolean): Boolean;
GetStringnull107 function GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string;
CreateSelfSignedCertnull108 function CreateSelfSignedCert(Host: string): Boolean; override;
PopAllnull109 function PopAll: string;
110 public
111 {:See @inherited}
112 constructor Create(const Value: TTCPBlockSocket); override;
113 destructor Destroy; override;
114 {:Load trusted CA's in PEM format}
115 procedure SetCertCAFile(const Value: string); override;
116 {:See @inherited}
LibVersionnull117 function LibVersion: String; override;
118 {:See @inherited}
LibNamenull119 function LibName: String; override;
120 {:See @inherited}
121 procedure Assign(const Value: TCustomSSL); override;
122 {:See @inherited and @link(ssl_cryptlib) for more details.}
Connectnull123 function Connect: boolean; override;
124 {:See @inherited and @link(ssl_cryptlib) for more details.}
Acceptnull125 function Accept: boolean; override;
126 {:See @inherited}
Shutdownnull127 function Shutdown: boolean; override;
128 {:See @inherited}
BiShutdownnull129 function BiShutdown: boolean; override;
130 {:See @inherited}
SendBuffernull131 function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
132 {:See @inherited}
RecvBuffernull133 function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
134 {:See @inherited}
WaitingDatanull135 function WaitingData: Integer; override;
136 {:See @inherited}
GetSSLVersionnull137 function GetSSLVersion: string; override;
138 {:See @inherited}
GetPeerSubjectnull139 function GetPeerSubject: string; override;
140 {:See @inherited}
GetPeerIssuernull141 function GetPeerIssuer: string; override;
142 {:See @inherited}
GetPeerNamenull143 function GetPeerName: string; override;
144 {:See @inherited}
GetPeerFingerprintnull145 function GetPeerFingerprint: string; override;
146 {:See @inherited}
GetVerifyCertnull147 function GetVerifyCert: integer; override;
148 published
149 {:name of certificate/key within PKCS#15 file. It can hold more then one
150 certificate/key and each certificate/key must have unique label within one file.}
151 property PrivateKeyLabel: string read FPrivateKeyLabel Write FPrivateKeyLabel;
152 end;
153
154 implementation
155
156 {==============================================================================}
157
158 constructor TSSLCryptLib.Create(const Value: TTCPBlockSocket);
159 begin
160 inherited Create(Value);
161 FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
162 FPrivateKeyLabel := 'synapse';
163 FDelCert := false;
164 FTrustedCAs := nil;
165 end;
166
167 destructor TSSLCryptLib.Destroy;
168 begin
169 SetCertCAFile(''); // destroy certificates
170 DeInit;
171 inherited Destroy;
172 end;
173
174 procedure TSSLCryptLib.Assign(const Value: TCustomSSL);
175 begin
176 inherited Assign(Value);
177 if Value is TSSLCryptLib then
178 begin
179 FPrivateKeyLabel := TSSLCryptLib(Value).privatekeyLabel;
180 end;
181 end;
182
TSSLCryptLib.GetStringnull183 function TSSLCryptLib.GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string;
184 var
185 l: integer;
186 begin
187 l := 0;
188 cryptGetAttributeString(cryptHandle, attributeType, nil, l);
189 setlength(Result, l);
190 cryptGetAttributeString(cryptHandle, attributeType, pointer(Result), l);
191 setlength(Result, l);
192 end;
193
TSSLCryptLib.LibVersionnull194 function TSSLCryptLib.LibVersion: String;
195 var
196 x: integer;
197 begin
198 Result := GetString(CRYPT_UNUSED, CRYPT_OPTION_INFO_DESCRIPTION);
199 cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION, x);
200 Result := Result + ' v' + IntToStr(x);
201 cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION, x);
202 Result := Result + '.' + IntToStr(x);
203 cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_STEPPING, x);
204 Result := Result + '.' + IntToStr(x);
205 end;
206
LibNamenull207 function TSSLCryptLib.LibName: String;
208 begin
209 Result := 'ssl_cryptlib';
210 end;
211
SSLChecknull212 function TSSLCryptLib.SSLCheck(Value: integer): Boolean;
213 begin
214 Result := true;
215 FLastErrorDesc := '';
216 if Value = CRYPT_ERROR_COMPLETE then
217 Value := 0;
218 FLastError := Value;
219 if FLastError <> 0 then
220 begin
221 Result := False;
222 {$IF CRYPTLIB_VERSION >= 3400}
223 FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_ERRORMESSAGE);
224 {$ELSE}
225 FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_INT_ERRORMESSAGE);
226 {$IFEND}
227 end;
228 end;
229
CreateSelfSignedCertnull230 function TSSLCryptLib.CreateSelfSignedCert(Host: string): Boolean;
231 var
232 privateKey: CRYPT_CONTEXT;
233 keyset: CRYPT_KEYSET;
234 cert: CRYPT_CERTIFICATE;
235 publicKey: CRYPT_CONTEXT;
236 begin
237 if FPrivatekeyFile = '' then
238 FPrivatekeyFile := GetTempFile('', 'key');
239 cryptCreateContext(privateKey, CRYPT_UNUSED, CRYPT_ALGO_RSA);
240 cryptSetAttributeString(privateKey, CRYPT_CTXINFO_LABEL, Pointer(FPrivatekeyLabel),
241 Length(FPrivatekeyLabel));
242 cryptSetAttribute(privateKey, CRYPT_CTXINFO_KEYSIZE, 1024);
243 cryptGenerateKey(privateKey);
244 cryptKeysetOpen(keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, PChar(FPrivatekeyFile), CRYPT_KEYOPT_CREATE);
245 FDelCert := True;
246 cryptAddPrivateKey(keyset, privateKey, PChar(FKeyPassword));
247 cryptCreateCert(cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE);
248 cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1);
249 cryptGetPublicKey(keyset, publicKey, CRYPT_KEYID_NAME, PChar(FPrivatekeyLabel));
250 cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, publicKey);
251 cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, Pointer(host), Length(host));
252 cryptSignCert(cert, privateKey);
253 cryptAddPublicKey(keyset, cert);
254 cryptKeysetClose(keyset);
255 cryptDestroyCert(cert);
256 cryptDestroyContext(privateKey);
257 cryptDestroyContext(publicKey);
258 Result := True;
259 end;
260
PopAllnull261 function TSSLCryptLib.PopAll: string;
262 const
263 BufferMaxSize = 32768;
264 var
265 Outbuffer: string;
266 WriteLen: integer;
267 begin
268 Result := '';
269 repeat
270 setlength(outbuffer, BufferMaxSize);
271 Writelen := 0;
272 SSLCheck(CryptPopData(FCryptSession, @OutBuffer[1], BufferMaxSize, Writelen));
273 if FLastError <> 0 then
274 Break;
275 if WriteLen > 0 then
276 begin
277 setlength(outbuffer, WriteLen);
278 Result := Result + outbuffer;
279 end;
280 until WriteLen = 0;
281 end;
282
Initnull283 function TSSLCryptLib.Init(server:Boolean): Boolean;
284 var
285 st: CRYPT_SESSION_TYPE;
286 keysetobj: CRYPT_KEYSET;
287 cryptContext: CRYPT_CONTEXT;
288 x: integer;
289 aUserName : AnsiString;
290 aPassword: AnsiString;
291 begin
292 Result := False;
293 FLastErrorDesc := '';
294 FLastError := 0;
295 FDelCert := false;
296 FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
297 if server then
298 case FSSLType of
299 LT_all, LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2:
300 st := CRYPT_SESSION_SSL_SERVER;
301 LT_SSHv2:
302 st := CRYPT_SESSION_SSH_SERVER;
303 else
304 Exit;
305 end
306 else
307 case FSSLType of
308 LT_all, LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2:
309 st := CRYPT_SESSION_SSL;
310 LT_SSHv2:
311 st := CRYPT_SESSION_SSH;
312 else
313 Exit;
314 end;
315 if not SSLCheck(cryptCreateSession(FcryptSession, CRYPT_UNUSED, st)) then
316 Exit;
317 x := -1;
318 case FSSLType of
319 LT_TLSv1:
320 x := 0;
321 LT_TLSv1_1:
322 x := 1;
323 LT_TLSv1_2:
324 x := 2;
325 end;
326 if x >= 0 then
327 if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x)) then
328 Exit;
329
330 if (FCertComplianceLevel <> -1) then
331 if not SSLCheck(cryptSetAttribute (CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
332 FCertComplianceLevel)) then
333 Exit;
334
335 if FUsername <> '' then
336 begin
337 aUserName := fUserName;
338 aPassword := fPassword;
339 cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_USERNAME,
340 Pointer(FUsername), Length(FUsername));
341 cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_PASSWORD,
342 Pointer(FPassword), Length(FPassword));
343 end;
344 if FSSLType = LT_SSHv2 then
345 if FSSHChannelType <> '' then
346 begin
347 cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
348 cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
349 Pointer(FSSHChannelType), Length(FSSHChannelType));
350 if FSSHChannelArg1 <> '' then
351 cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
352 Pointer(FSSHChannelArg1), Length(FSSHChannelArg1));
353 if FSSHChannelArg2 <> '' then
354 cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG2,
355 Pointer(FSSHChannelArg2), Length(FSSHChannelArg2));
356 end;
357
358
359 if server and (FPrivatekeyFile = '') then
360 begin
361 if FPrivatekeyLabel = '' then
362 FPrivatekeyLabel := 'synapse';
363 if FkeyPassword = '' then
364 FkeyPassword := 'synapse';
365 CreateSelfSignedcert(FSocket.ResolveIPToName(FSocket.GetRemoteSinIP));
366 end;
367
368 if (FPrivatekeyLabel <> '') and (FPrivatekeyFile <> '') then
369 begin
370 if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
371 PChar(FPrivatekeyFile), CRYPT_KEYOPT_READONLY)) then
372 Exit;
373 try
374 if not SSLCheck(cryptGetPrivateKey(KeySetObj, cryptcontext, CRYPT_KEYID_NAME,
375 PChar(FPrivatekeyLabel), PChar(FKeyPassword))) then
376 Exit;
377 if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_PRIVATEKEY,
378 cryptcontext)) then
379 Exit;
380 finally
381 cryptKeysetClose(keySetObj);
382 cryptDestroyContext(cryptcontext);
383 end;
384 end;
385 if server and FVerifyCert then
386 begin
387 if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
388 PChar(FCertCAFile), CRYPT_KEYOPT_READONLY)) then
389 Exit;
390 try
391 if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_KEYSET,
392 keySetObj)) then
393 Exit;
394 finally
395 cryptKeysetClose(keySetObj);
396 end;
397 end;
398 Result := true;
399 end;
400
TSSLCryptLib.DeInitnull401 function TSSLCryptLib.DeInit: Boolean;
402 begin
403 Result := True;
404 if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then
405 CryptDestroySession(FcryptSession);
406 FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
407 FSSLEnabled := False;
408 if FDelCert then
409 SysUtils.DeleteFile(FPrivatekeyFile);
410 end;
411
Preparenull412 function TSSLCryptLib.Prepare(server:Boolean): Boolean;
413 begin
414 Result := false;
415 DeInit;
416 if Init(server) then
417 Result := true
418 else
419 DeInit;
420 end;
421
Connectnull422 function TSSLCryptLib.Connect: boolean;
423 begin
424 Result := False;
425 if FSocket.Socket = INVALID_SOCKET then
426 Exit;
427 if Prepare(false) then
428 begin
429 if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then
430 Exit;
431 if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then
432 Exit;
433 if FverifyCert then
434 if (GetVerifyCert <> 0) or (not DoVerifyCert) then
435 Exit;
436 FSSLEnabled := True;
437 Result := True;
438 FReadBuffer := '';
439 end;
440 end;
441
Acceptnull442 function TSSLCryptLib.Accept: boolean;
443 begin
444 Result := False;
445 if FSocket.Socket = INVALID_SOCKET then
446 Exit;
447 if Prepare(true) then
448 begin
449 if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then
450 Exit;
451 if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then
452 Exit;
453 FSSLEnabled := True;
454 Result := True;
455 FReadBuffer := '';
456 end;
457 end;
458
Shutdownnull459 function TSSLCryptLib.Shutdown: boolean;
460 begin
461 Result := BiShutdown;
462 end;
463
TSSLCryptLib.BiShutdownnull464 function TSSLCryptLib.BiShutdown: boolean;
465 begin
466 if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then
467 cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 0);
468 DeInit;
469 FReadBuffer := '';
470 Result := True;
471 end;
472
SendBuffernull473 function TSSLCryptLib.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
474 var
475 l: integer;
476 begin
477 FLastError := 0;
478 FLastErrorDesc := '';
479 SSLCheck(cryptPushData(FCryptSession, Buffer, Len, L));
480 cryptFlushData(FcryptSession);
481 Result := l;
482 end;
483
TSSLCryptLib.RecvBuffernull484 function TSSLCryptLib.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
485 begin
486 FLastError := 0;
487 FLastErrorDesc := '';
488 if Length(FReadBuffer) = 0 then
489 FReadBuffer := PopAll;
490 if Len > Length(FReadBuffer) then
491 Len := Length(FReadBuffer);
492 Move(Pointer(FReadBuffer)^, buffer^, Len);
493 Delete(FReadBuffer, 1, Len);
494 Result := Len;
495 end;
496
TSSLCryptLib.WaitingDatanull497 function TSSLCryptLib.WaitingData: Integer;
498 begin
499 Result := Length(FReadBuffer);
500 end;
501
TSSLCryptLib.GetSSLVersionnull502 function TSSLCryptLib.GetSSLVersion: string;
503 var
504 x: integer;
505 begin
506 Result := '';
507 if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
508 Exit;
509 cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x);
510 if FSSLType in [LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2, LT_all] then
511 case x of
512 0:
513 Result := 'TLSv1';
514 1:
515 Result := 'TLSv1.1';
516 2:
517 Result := 'TLSv1.2';
518 end;
519 if FSSLType in [LT_SSHv2] then
520 case x of
521 0:
522 Result := 'SSHv1';
523 1:
524 Result := 'SSHv2';
525 end;
526 end;
527
TSSLCryptLib.GetPeerSubjectnull528 function TSSLCryptLib.GetPeerSubject: string;
529 var
530 cert: CRYPT_CERTIFICATE;
531 begin
532 Result := '';
533 if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
534 Exit;
535 cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
536 cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME);
537 Result := GetString(cert, CRYPT_CERTINFO_DN);
538 cryptDestroyCert(cert);
539 end;
540
TSSLCryptLib.GetPeerNamenull541 function TSSLCryptLib.GetPeerName: string;
542 var
543 cert: CRYPT_CERTIFICATE;
544 begin
545 Result := '';
546 if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
547 Exit;
548 cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
549 cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME);
550 Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME);
551 cryptDestroyCert(cert);
552 end;
553
GetPeerIssuernull554 function TSSLCryptLib.GetPeerIssuer: string;
555 var
556 cert: CRYPT_CERTIFICATE;
557 begin
558 Result := '';
559 if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
560 Exit;
561 cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
562 cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_ISSUERNAME);
563 Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME);
564 cryptDestroyCert(cert);
565 end;
566
GetPeerFingerprintnull567 function TSSLCryptLib.GetPeerFingerprint: string;
568 var
569 cert: CRYPT_CERTIFICATE;
570 begin
571 Result := '';
572 if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
573 Exit;
574 cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
575 Result := GetString(cert, CRYPT_CERTINFO_FINGERPRINT);
576 cryptDestroyCert(cert);
577 end;
578
579
580 procedure TSSLCryptLib.SetCertCAFile(const Value: string);
581
582 var F:textfile;
583 bInCert:boolean;
584 s,sCert:string;
585 cert: CRYPT_CERTIFICATE;
586 idx:integer;
587
588 begin
589 if assigned(FTrustedCAs) then
590 begin
591 for idx := 0 to High(FTrustedCAs) do
592 cryptDestroyCert(FTrustedCAs[idx]);
593 FTrustedCAs:=nil;
594 end;
595 if Value<>'' then
596 begin
597 AssignFile(F,Value);
598 reset(F);
599 bInCert:=false;
600 idx:=0;
601 while not eof(F) do
602 begin
603 readln(F,s);
604 if pos('-----END CERTIFICATE-----',s)>0 then
605 begin
606 bInCert:=false;
607 cert:=0;
608 if (cryptImportCert(PAnsiChar(sCert),length(sCert)-2,CRYPT_UNUSED,cert)=CRYPT_OK) then
609 begin
610 cryptSetAttribute( cert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
611 SetLength(FTrustedCAs,idx+1);
612 FTrustedCAs[idx]:=cert;
613 idx:=idx+1;
614 end;
615 end;
616 if bInCert then
617 sCert:=sCert+s+#13#10;
618 if pos('-----BEGIN CERTIFICATE-----',s)>0 then
619 begin
620 bInCert:=true;
621 sCert:='';
622 end;
623 end;
624 CloseFile(F);
625 end;
626 end;
627
TSSLCryptLib.GetVerifyCertnull628 function TSSLCryptLib.GetVerifyCert: integer;
629 var
630 cert: CRYPT_CERTIFICATE;
631 itype,ilocus:integer;
632 begin
633 Result := -1;
634 if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
635 Exit;
636 cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
637 result:=cryptCheckCert(cert,CRYPT_UNUSED);
638 if result<>CRYPT_OK then
639 begin
640 //get extended error info if available
641 cryptGetAttribute(cert,CRYPT_ATTRIBUTE_ERRORtype,itype);
642 cryptGetAttribute(cert,CRYPT_ATTRIBUTE_ERRORLOCUS,ilocus);
643 cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME);
644 FLastError := Result;
645 FLastErrorDesc := format('SSL/TLS certificate verification failed for "%s"'#13#10'Status: %d. ERRORTYPE: %d. ERRORLOCUS: %d.',
646 [GetString(cert, CRYPT_CERTINFO_COMMONNAME),result,itype,ilocus]);
647 end;
648 cryptDestroyCert(cert);
649 end;
650
651 {==============================================================================}
652
653 var imajor,iminor,iver:integer;
654 // e: ESynapseError;
655
656 initialization
657 if cryptInit = CRYPT_OK then
658 SSLImplementation := TSSLCryptLib;
659 cryptAddRandom(nil, CRYPT_RANDOM_SLOWPOLL);
660 cryptGetAttribute (CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION,imajor);
661 cryptGetAttribute (CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION,iminor);
662 // according to the documentation CRYPTLIB version has 3 digits. recent versions use 4 digits
663 if CRYPTLIB_VERSION >1000 then
664 iver:=CRYPTLIB_VERSION div 100
665 else
666 iver:=CRYPTLIB_VERSION div 10;
667 if (iver <> imajor*10+iminor) then
668 begin
669 SSLImplementation :=TSSLNone;
670 // e := ESynapseError.Create(format('Error wrong cryptlib version (is %d.%d expected %d.%d). ',
671 // [imajor,iminor,iver div 10, iver mod 10]));
672 // e.ErrorCode := 0;
673 // e.ErrorMessage := format('Error wrong cryptlib version (%d.%d expected %d.%d)',
674 // [imajor,iminor,iver div 10, iver mod 10]);
675 // raise e;
676 end;
677 finalization
678 cryptEnd;
679 end.
680
681
682