{******************************************************************************} { } { 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.