xtool/contrib/fundamentals/TLS/flcTLSTests.pas

414 lines
14 KiB
ObjectPascal

{******************************************************************************}
{ }
{ Library: Fundamentals TLS }
{ File name: flcTLSTests.pas }
{ File version: 5.05 }
{ Description: TLS tests }
{ }
{ Copyright: Copyright (c) 2008-2020, David J Butler }
{ All rights reserved. }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2008/01/18 0.01 Initial development. }
{ 2010/12/15 0.02 Client/Server test case. }
{ 2010/12/17 0.03 Client/Server test cases for TLS 1.0, 1.1 and 1.2. }
{ 2018/07/17 5.04 Revised for Fundamentals 5. }
{ 2020/05/11 5.05 Use client options. }
{ }
{ References: }
{ }
{ SSL 3 - www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt }
{ RFC 2246 - The TLS Protocol Version 1.0 }
{ RFC 4346 - The TLS Protocol Version 1.1 }
{ RFC 5246 - The TLS Protocol Version 1.2 }
{ RFC 4366 - Transport Layer Security (TLS) Extensions }
{ www.mozilla.org/projects/security/pki/nss/ssl/traces/trc-clnt-ex.html }
{ RFC 4492 - Elliptic Curve Cryptography (ECC) Cipher Suites }
{ }
{******************************************************************************}
// ----------------------------------------------------- -------------------------------------------
// CIPHER SUITE ClientServer Test
// ----------------------------------------------------- -------------------------------------------
// RSA_WITH_RC4_128_MD5 TESTED OK
// RSA_WITH_RC4_128_SHA TESTED OK
// RSA_WITH_DES_CBC_SHA TESTED OK
// RSA_WITH_AES_128_CBC_SHA TESTED OK
// RSA_WITH_AES_256_CBC_SHA TESTED OK
// RSA_WITH_AES_128_CBC_SHA256 TESTED OK TLS 1.2 only
// RSA_WITH_AES_256_CBC_SHA256 TESTED OK TLS 1.2 only
// NULL_WITH_NULL_NULL UNTESTED
// RSA_WITH_NULL_MD5 UNTESTED
// RSA_WITH_NULL_SHA UNTESTED
// RSA_WITH_IDEA_CBC_SHA UNTESTED
// RSA_WITH_3DES_EDE_CBC_SHA ERROR: SERVER DECRYPTION FAILED
// RSA_WITH_NULL_SHA256 ERROR
// DHE_RSA_WITH_AES_256_CBC_SHA TESTED OK TLS 1.2
// ----------------------------------------------------- -------------------------------------------
{$INCLUDE flcTLS.inc}
{$DEFINE TLS_TEST_LOG_TO_CONSOLE}
{$DEFINE Cipher_SupportEC}
unit flcTLSTests;
interface
{ }
{ Test }
{ }
{$IFDEF TLS_TEST}
procedure Test;
{$ENDIF}
implementation
uses
{ System }
SysUtils,
SyncObjs,
{ Utils }
flcStdTypes,
flcBase64,
flcStrings,
flcPEM,
flcASN1,
flcX509Certificate,
flcHugeInt,
{ Cipher }
flcCipherAES,
flcCipherRSA,
flcCipherDH,
{$IFDEF Cipher_SupportEC}
flcCipherEllipticCurve,
{$ENDIF}
{ TLS }
flcTLSConsts,
flcTLSProtocolVersion,
flcTLSRecord,
flcTLSAlert,
flcTLSAlgorithmTypes,
flcTLSRandom,
flcTLSCertificate,
flcTLSHandshake,
flcTLSCipher,
flcTLSPRF,
flcTLSKeys,
flcTLSTransportTypes,
flcTLSTransportConnection,
flcTLSTransportClient,
flcTLSTransportServer,
flcTLSTestCertificates;
{ }
{ Test }
{ }
{$IFDEF TLS_TEST}
type
TTLSClientServerTester = class
Lock : TCriticalSection;
Sr : TTLSServer;
Cl : TTLSClient;
SCl : TTLSServerClient;
constructor Create;
destructor Destroy; override;
procedure ServerTLSendProc(Server: TTLSServer; Client: TTLSServerClient; const Buffer; const Size: Integer);
procedure ClientTLSendProc(const Sender: TTLSConnection; const Buffer; const Size: Integer);
procedure Log(Msg: String);
procedure ClientLog(Sender: TTLSConnection; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
procedure ServerLog(Sender: TTLSServer; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
end;
constructor TTLSClientServerTester.Create;
begin
inherited Create;
Lock := TCriticalSection.Create;
Sr := TTLSServer.Create(ServerTLSendProc);
Sr.OnLog := ServerLog;
Cl := TTLSClient.Create(ClientTLSendProc);
Cl.OnLog := ClientLog;
end;
destructor TTLSClientServerTester.Destroy;
begin
FreeAndNil(Cl);
FreeAndNil(Sr);
FreeAndNil(Lock);
inherited Destroy;
end;
procedure TTLSClientServerTester.ServerTLSendProc(Server: TTLSServer; Client: TTLSServerClient; const Buffer; const Size: Integer);
begin
Assert(Assigned(Cl));
Cl.ProcessTransportLayerReceivedData(Buffer, Size);
end;
procedure TTLSClientServerTester.ClientTLSendProc(const Sender: TTLSConnection; const Buffer; const Size: Integer);
begin
Assert(Assigned(SCl));
SCl.ProcessTransportLayerReceivedData(Buffer, Size);
end;
{$IFDEF TLS_TEST_LOG_TO_CONSOLE}
procedure TTLSClientServerTester.Log(Msg: String);
var S : String;
begin
S := FormatDateTime('hh:nn:ss.zzz', Now) + ' ' + Msg;
Lock.Acquire;
try
Writeln(S);
finally
Lock.Release;
end;
end;
{$ELSE}
procedure TTLSClientServerTester.Log(Msg: String);
begin
end;
{$ENDIF}
procedure TTLSClientServerTester.ClientLog(Sender: TTLSConnection; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
begin
Log(IntToStr(LogLevel) + ' C:' + LogMsg);
end;
procedure TTLSClientServerTester.ServerLog(Sender: TTLSServer; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
begin
Log(IntToStr(LogLevel) + ' S:' + LogMsg);
end;
procedure TestClientServer(
const ClientOptions : TTLSClientOptions = [];
const VersionOptions : TTLSVersionOptions = DefaultTLSClientVersionOptions;
const KeyExchangeOptions : TTLSKeyExchangeOptions = DefaultTLSClientKeyExchangeOptions;
const CipherOptions : TTLSCipherOptions = DefaultTLSClientCipherOptions;
const HashOptions : TTLSHashOptions = DefaultTLSClientHashOptions
);
const
LargeBlockSize = TLS_PLAINTEXT_FRAGMENT_MAXSIZE * 8;
var CS : TTLSClientServerTester;
CtL : TTLSCertificateList;
S : RawByteString;
I, L : Integer;
begin
CS := TTLSClientServerTester.Create;
try
// initialise client
CS.Cl.ClientOptions := ClientOptions;
// initialise server
CS.Sr.PrivateKeyRSAPEM := RSA_STunnel_PrivateKeyRSAPEM;
TLSCertificateListAppend(CtL,
MIMEBase64Decode(RSA_STunnel_CertificatePEM));
CS.Sr.CertificateList := CtL;
CS.Sr.DHKeySize := 512;
// start server
CS.Sr.Start;
Assert(CS.Sr.State = tlssActive);
// start connection
CS.SCl := CS.Sr.AddClient(nil);
CS.SCl.Start;
CS.Cl.Start;
// negotiated
Assert(CS.Cl.IsReadyState);
Assert(CS.SCl.IsReadyState);
// application data (small block)
S := 'Fundamentals';
CS.Cl.Write(S[1], Length(S));
Assert(CS.SCl.AvailableToRead = 12);
S := '1234567890';
Assert(CS.SCl.Read(S[1], 3) = 3);
Assert(CS.SCl.AvailableToRead = 9);
Assert(S = 'Fun4567890');
Assert(CS.SCl.Read(S[1], 9) = 9);
Assert(CS.SCl.AvailableToRead = 0);
Assert(S = 'damentals0');
S := 'Fundamentals';
CS.SCl.Write(S[1], Length(S));
Assert(CS.Cl.AvailableToRead = 12);
S := '123456789012';
Assert(CS.Cl.Read(S[1], 12) = 12);
Assert(CS.Cl.AvailableToRead = 0);
Assert(S = 'Fundamentals');
// application data (large blocks)
for L := LargeBlockSize - 1 to LargeBlockSize + 1 do
begin
SetLength(S, L);
FillChar(S[1], L, #1);
CS.Cl.Write(S[1], L);
Assert(CS.SCl.AvailableToRead = L);
FillChar(S[1], L, #0);
CS.SCl.Read(S[1], L);
for I := 1 to L do
Assert(S[I] = #1);
Assert(CS.SCl.AvailableToRead = 0);
CS.SCl.Write(S[1], L);
Assert(CS.Cl.AvailableToRead = L);
FillChar(S[1], L, #0);
Assert(CS.Cl.Read(S[1], L) = L);
for I := 1 to L do
Assert(S[I] = #1);
Assert(CS.Cl.AvailableToRead = 0);
end;
// close
CS.Cl.Close;
Assert(CS.Cl.IsFinishedState);
Assert(CS.SCl.IsFinishedState);
// stop
CS.Sr.RemoveClient(CS.SCl);
CS.Sr.Stop;
finally
FreeAndNil(CS);
end;
end;
procedure Test_Units_Dependencies;
begin
flcPEM.Test;
flcASN1.Test;
flcX509Certificate.Test;
flcHugeInt.Test;
flcCipherAES.Test;
flcCipherRSA.Test;
flcCipherDH.Test;
{$IFDEF Cipher_SupportEC}
flcCipherEllipticCurve.Test;
{$ENDIF}
end;
procedure Test_Units_TLS;
begin
flcTLSAlert.Test;
flcTLSAlgorithmTypes.Test;
flcTLSRandom.Test;
flcTLSCipher.Test;
flcTLSHandshake.Test;
flcTLSKeys.Test;
flcTLSProtocolVersion.Test;
flcTLSPRF.Test;
flcTLSRecord.Test;
end;
procedure Test_ClientServer_TLSVersions;
begin
// TLS 1.2
TestClientServer([], [tlsvoTLS12]);
// TLS 1.1
TestClientServer([], [tlsvoTLS11]);
// TLS 1.0
TestClientServer([], [tlsvoTLS10]);
Sleep(100);
// SSL 3
// Fails with invalid parameter
//SelfTestClientServer([], [tlsvoSSL3]);
end;
procedure Test_ClientServer_KeyExchangeAlgos;
begin
// TLS 1.2 RSA
TestClientServer([], [tlsvoTLS12], [tlskeoRSA]);
// TLS 1.2 DHE_RSA
TestClientServer([], [tlsvoTLS12], [tlskeoDHE_RSA]);
// TLS 1.2 DH_anon
// Under development/testing
//SelfTestClientServer([], [tlsvoTLS12], [tlskeoDH_Anon]);
end;
procedure Test_ClientServer_CipherAlgos;
begin
// TLS 1.2 RC4
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
[tlscoRC4]);
// TLS 1.2 AES128
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
[tlscoAES128]);
// TLS 1.2 AES256
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
[tlscoAES256]);
// TLS 1.2 DES
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
[tlscoDES]);
// TLS 1.2 3DES
// No Cipher Suite
{SelfTestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
[tlsco3DES]);}
end;
procedure Test_ClientServer_HashAlgos;
begin
// TLS 1.2 SHA256
TestClientServer(
[], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions,
[tlshoSHA256]);
// TLS 1.2 SHA1
TestClientServer(
[], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions,
[tlshoSHA1]);
// TLS 1.2 MD5
TestClientServer(
[], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions,
[tlshoMD5]);
end;
procedure Test_ClientServer;
begin
Test_ClientServer_TLSVersions;
Test_ClientServer_KeyExchangeAlgos;
Test_ClientServer_CipherAlgos;
Test_ClientServer_HashAlgos;
end;
procedure Test;
begin
Test_Units_Dependencies;
Test_Units_TLS;
Test_ClientServer;
end;
{$ENDIF}
end.