{ 2020/05/11 5.01 Move tests from unit flcTests into seperate units. } {$INCLUDE flcTCPTest.inc} unit flcTCPTest_ClientServerTLS; interface { } { Test } { } {$IFDEF TCPCLIENTSERVER_TEST_TLS} procedure Test; {$ENDIF} implementation {$IFDEF TCPCLIENTSERVER_TEST_TLS} uses SysUtils, flcTLSTransportTypes, flcTLSTransportClient, flcSocketLib, flcTCPConnection, flcTCPClient, flcTCPServer, flcTCPTest_ClientServer; {$ENDIF} { } { Test } { } {$IFDEF TCPCLIENTSERVER_TEST_TLS} {$ASSERTIONS ON} procedure TestClientServerTLS_ReadWrite( const TestClientCount: Integer; const TestLargeBlock: Boolean; const TLSOptions: TTCPClientTLSOptions = DefaultTCPClientTLSOptions; const TLSClientOptions: TTCPClientTLSClientOptions = DefaultTLSClientOptions; const TLSVersionOptions: TTCPClientTLSVersionOptions = DefaultTLSClientVersionOptions; const TLSKeyExchangeOptions: TTCPClientTLSKeyExchangeOptions = DefaultTLSClientKeyExchangeOptions; const TLSCipherOptions: TTCPClientTLSCipherOptions = DefaultTLSClientCipherOptions; const TLSHashOptions: TTCPClientTLSHashOptions = DefaultTLSClientHashOptions ); procedure WaitClientConnected(const Client: TF5TCPClient); var I : Integer; begin // wait for client to connect and finish TLS I := 0; repeat Inc(I); Sleep(1); until (I >= 8000) or ( (Client.State in [csReady, csClosed]) and ( not Client.TLSEnabled or (Client.TLSClient.IsFinishedState or Client.TLSClient.IsReadyState) ) ); Assert(Client.State = csReady); Assert(Client.Connection.State = cnsConnected); Assert(not Client.TLSEnabled or Client.TLSClient.IsReadyState); end; var C : TF5TCPClientArray; S : TF5TCPServer; T : TTCPServerClientArray; TSC : TTCPServerClient; I, K : Integer; // CtL : TTLSCertificateList; DebugObj : TTCPClientServerTestObj; begin DebugObj := TTCPClientServerTestObj.Create; S := TF5TCPServer.Create(nil); SetLength(C, TestClientCount); SetLength(T, TestClientCount); for K := 0 to TestClientCount - 1 do begin C[K] := TF5TCPClient.Create(nil); // init client C[K].Tag := K + 1; C[K].OnLog := DebugObj.ClientLog; C[K].TLSOptions := TLSOptions; C[K].TLSClientOptions := TLSClientOptions; C[K].TLSVersionOptions := TLSVersionOptions; C[K].TLSKeyExchangeOptions := TLSKeyExchangeOptions; C[K].TLSCipherOptions := TLSCipherOptions; C[K].TLSHashOptions := TLSHashOptions; end; try // init server S.OnLog := DebugObj.ServerLog; S.AddressFamily := iaIP4; S.BindAddress := '127.0.0.1'; S.ServerPort := 12545; S.MaxClients := -1; S.TLSEnabled := True; (* S.TLSServer.PrivateKeyRSAPEM := // from stunnel pem file 'MIICXAIBAAKBgQCxUFMuqJJbI9KnB8VtwSbcvwNOltWBtWyaSmp7yEnqwWel5TFf' + 'cOObCuLZ69sFi1ELi5C91qRaDMow7k5Gj05DZtLDFfICD0W1S+n2Kql2o8f2RSvZ' + 'qD2W9l8i59XbCz1oS4l9S09L+3RTZV9oer/Unby/QmicFLNM0WgrVNiKywIDAQAB' + 'AoGAKX4KeRipZvpzCPMgmBZi6bUpKPLS849o4pIXaO/tnCm1/3QqoZLhMB7UBvrS' + 'PfHj/Tejn0jjHM9xYRHi71AJmAgzI+gcN1XQpHiW6kATNDz1r3yftpjwvLhuOcp9' + 'tAOblojtImV8KrAlVH/21rTYQI+Q0m9qnWKKCoUsX9Yu8UECQQDlbHL38rqBvIMk' + 'zK2wWJAbRvVf4Fs47qUSef9pOo+p7jrrtaTqd99irNbVRe8EWKbSnAod/B04d+cQ' + 'ci8W+nVtAkEAxdqPOnCISW4MeS+qHSVtaGv2kwvfxqfsQw+zkwwHYqa+ueg4wHtG' + '/9+UgxcXyCXrj0ciYCqURkYhQoPbWP82FwJAWWkjgTgqsYcLQRs3kaNiPg8wb7Yb' + 'NxviX0oGXTdCaAJ9GgGHjQ08lNMxQprnpLT8BtZjJv5rUOeBuKoXagggHQJAaUAF' + '91GLvnwzWHg5p32UgPsF1V14siX8MgR1Q6EfgKQxS5Y0Mnih4VXfnAi51vgNIk/2' + 'AnBEJkoCQW8BTYueCwJBALvz2JkaUfCJc18E7jCP7qLY4+6qqsq+wr0t18+ogOM9' + 'JIY9r6e1qwNxQ/j1Mud6gn6cRrObpRtEad5z2FtcnwY='; TLSCertificateListAppend(CtL, MIMEBase64Decode( // from stunnel pem file 'MIICDzCCAXigAwIBAgIBADANBgkqhkiG9w0BAQQFADBCMQswCQYDVQQGEwJQTDEf' + 'MB0GA1UEChMWU3R1bm5lbCBEZXZlbG9wZXJzIEx0ZDESMBAGA1UEAxMJbG9jYWxo' + 'b3N0MB4XDTk5MDQwODE1MDkwOFoXDTAwMDQwNzE1MDkwOFowQjELMAkGA1UEBhMC' + 'UEwxHzAdBgNVBAoTFlN0dW5uZWwgRGV2ZWxvcGVycyBMdGQxEjAQBgNVBAMTCWxv' + 'Y2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsVBTLqiSWyPSpwfF' + 'bcEm3L8DTpbVgbVsmkpqe8hJ6sFnpeUxX3Djmwri2evbBYtRC4uQvdakWgzKMO5O' + 'Ro9OQ2bSwxXyAg9FtUvp9iqpdqPH9kUr2ag9lvZfIufV2ws9aEuJfUtPS/t0U2Vf' + 'aHq/1J28v0JonBSzTNFoK1TYissCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZA' + 'MA0GCSqGSIb3DQEBBAUAA4GBAAhYFTngWc3tuMjVFhS4HbfFF/vlOgTu44/rv2F+' + 'ya1mEB93htfNxx3ofRxcjCdorqONZFwEba6xZ8/UujYfVmIGCBy4X8+aXd83TJ9A' + 'eSjTzV9UayOoGtmg8Dv2aj/5iabNeK1Qf35ouvlcTezVZt2ZeJRhqUHcGaE+apCN' + 'TC9Y')); S.TLSServer.CertificateList := CtL; *) S.TLSServer.PEMText := '-----BEGIN CERTIFICATE-----' + 'MIIDQjCCAiqgAwIBAgIJAKDslQh3d8kdMA0GCSqGSIb3DQEBBQUAMB8xHTAbBgNV' + 'BAMTFHd3dy5ldGVybmFsbGluZXMuY29tMB4XDTExMTAxODEwMzYwOVoXDTIxMTAx' + 'NTEwMzYwOVowHzEdMBsGA1UEAxMUd3d3LmV0ZXJuYWxsaW5lcy5jb20wggEiMA0G' + 'CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw/7d6zyehR69DaJCGbk3oMP7pSWya' + 'U1tDMG+CdqikLqHoo3SBshbvquOVFcy9yY8fECTbNXfOjhV0M6SJgGQ/SP/nfZgx' + 'MHAK9sWc5G6V5sqPqrTRgkv0Wu25mdO6FRh8DIxOMY0Ppqno5hHZ0emSj1amvtWX' + 'zBD6pXNGgrFln6HL2eyCwqlL0wTXWO/YrvblF/83Ln9i6luVQ9NtACQBiPcYqoNM' + '1OG142xYNpRNp7zrHkNCQeXVxmC6goCgj0BmcSqrUPayLdgkgv8hniUwLYQIt91r' + 'cxJwGNWxlbLgqQqTdhecKp01JVgO8jy3yFpMEoqCj9+BuuxVqDfvHK1tAgMBAAGj' + 'gYAwfjAdBgNVHQ4EFgQUbLgD+S3ZSNlU1nxTsjTmAQIfpCQwTwYDVR0jBEgwRoAU' + 'bLgD+S3ZSNlU1nxTsjTmAQIfpCShI6QhMB8xHTAbBgNVBAMTFHd3dy5ldGVybmFs' + 'bGluZXMuY29tggkAoOyVCHd3yR0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUF' + 'AAOCAQEACSQTcPC8ga5C/PysnoTNAk4OB+hdgMoS3Fv7ROUV9GqgYED6rJo0+CxD' + 'g19GLlKt/aBlglh4Ddc7X84dWtftS4JIjjVVkWevt8/sDoZ+ISd/tC9aDX3gOAlW' + 'RORhfp3Qtyy0AjZcIOAGNkzkotuMG/uOVifPFhTNXwa8hHOGN60riGXEj5sNFFop' + 'EaxplTfakVq8TxlQivnIETjrEbVX8XkOl4nlsHevC2suXE1ZkQIbQoaAy0WzGGUR' + '54GBIzXf32t80S71w5rs/mzVaGOeTZYcHtv5Epd9CNVrEle6w0NW9R7Ov4gXI9n8' + 'GV9jITGfsOdqu7j9Iaf7MVj+JRE7Dw==' + '-----END CERTIFICATE-----' + '-----BEGIN RSA PRIVATE KEY-----' + 'MIIEpQIBAAKCAQEAsP+3es8noUevQ2iQhm5N6DD+6UlsmlNbQzBvgnaopC6h6KN0' + 'gbIW76rjlRXMvcmPHxAk2zV3zo4VdDOkiYBkP0j/532YMTBwCvbFnORulebKj6q0' + '0YJL9FrtuZnTuhUYfAyMTjGND6ap6OYR2dHpko9Wpr7Vl8wQ+qVzRoKxZZ+hy9ns' + 'gsKpS9ME11jv2K725Rf/Ny5/YupblUPTbQAkAYj3GKqDTNThteNsWDaUTae86x5D' + 'QkHl1cZguoKAoI9AZnEqq1D2si3YJIL/IZ4lMC2ECLfda3MScBjVsZWy4KkKk3YX' + 'nCqdNSVYDvI8t8haTBKKgo/fgbrsVag37xytbQIDAQABAoIBAQCdnZnOCtrHjAZO' + 'iLbqfx9xPPBC3deQNdp3IpKqIvBaBAy6FZSSSfySwCKZiCgieXKxvraTXjGqBmyk' + 'ZbiHmYWrtV3szrLQWsnreYTQCbtQUYzgEquiRd1NZAt907XvZwm+rY3js8xhu5Bi' + 'jT4oMf1FPc9z/UxHOLmF+f+FMqy2SM2Fxh3jAsxJBaMVEJXpqdQDI86CATgYrqVY' + 'mlAWQcQ8pL0wwRctZ+XgjQH52V3sk4cIzqIBTO+MN6emmxDl9JdrGZKRei9YEIhG' + 'mFeXH7rsGg+TZtfvu1M9Kfy2fdgNwTUoTTn93v8gcrwCbyvl5JCzKy07Om/aOXFr' + 'I8bSWXIhAoGBANu07hegU99zIhvTWmh2Fuml0Lr+cHcZTObh+oeZg1xaDUrlnFOY' + '3fyA5x5Jxib3V7OOAeIz/AsmcYq/649nR8NfeiizY5or84Fy1mazRR8diGDV3nUG' + 'ZATv6yaOY/z31FOLaxT95tDvqWK+Qr5cykq4e6XDDp9P8odCIjJmUdt7AoGBAM48' + 'vCjtGQ99BVwkcFIj0IacRj3YKzsp06W6V2Z+czlKctJAMAQN8hu9IcXMEIUsi9GD' + 'MkyzzxjvGRdmIuS58IFqRbr/fIAQLVpY9SPAL771ZCFHmIrKrCYiLYAcg/BSoR29' + 'me6aFaEcLBFvzHPFNymdyMsaOHSRMZYUlq6VUbI3AoGBAINJeMURf00VRZqPD4VA' + 'm6x+813qUVY5/iQxgT2qVD7JaQwKbQHfZTdP58vHlesO/o9DGokLO1+GV27sBF0r' + 'AE0VLrBHkgs8nEQMVWYFVhaj1SzYYBhZ+0af/0qI5+LwTSanNxPSLS1JKVTiEIwk' + 'cpV37Bs/letJIMoGkNzBG8UlAoGBAKrSfZt8f3RnvmfKusoeZhsJF9kj0vMHOwob' + 'ZUc8152Nf7uMdPj2wCGfr3iRBOH5urnH7ILBsHjbmjHaZG6FYKMg7i7sbSf5vkcG' + 'Rc3d4u5NfSlfjwbuxlYzmvJxLAuDtXXX1MdgEyhGGG485uDBamZrDaTEzBwpIyRH' + 'W2OxxGBTAoGAZHJQKTajcqQQoRSgPPWWU3X8zdlu5hCgNU54bXaPAfJ6IBWvicMZ' + 'QLw+9mtshtz+Xy0aBbkxUeUlwwzexb9rg1KZppTq/yRqkOlEkI3ZdqiclTK13BCh' + '6r6dC2qqq+DVm9Nlm/S9Gab9YSIA0g5MFg5WLwu1KNwuOODE4Le/91c=' + '-----END RSA PRIVATE KEY-----'; Assert(S.State = ssInit); Assert(not S.Active); // start server S.Start; Assert(S.Active); I := 0; repeat Inc(I); Sleep(1); until (S.State <> ssStarting) or (I >= 5000); Sleep(100); Assert(S.State = ssReady); Assert(S.ClientCount = 0); for K := 0 to TestClientCount - 1 do begin // init client C[K].AddressFamily := cafIP4; C[K].Host := '127.0.0.1'; C[K].Port := '12545'; C[K].TLSEnabled := True; Assert(C[K].State = csInit); Assert(not C[K].Active); // start client C[K].WaitForStartup := True; C[K].Start; Assert(Assigned(C[K].Connection)); Assert(C[K].Active); end; for K := 0 to TestClientCount - 1 do // wait for client to connect WaitClientConnected(C[K]); // wait for server connections I := 0; repeat Inc(I); Sleep(1); until (S.ClientCount >= TestClientCount) or (I >= 5000); Assert(S.ClientCount = TestClientCount); // wait for server clients TSC := S.ClientIterateFirst; for K := 0 to TestClientCount - 1 do begin T[K] := TSC; Assert(Assigned(T[K])); Assert(T[K].State in [scsStarting, scsNegotiating, scsReady]); Assert(T[K].Connection.State in [cnsProxyNegotiation, cnsConnected]); I := 0; repeat Inc(I); Sleep(1); until (T[K].Connection.State = cnsConnected) or (I >= 5000); Assert(T[K].Connection.State = cnsConnected); Assert(not C[K].TLSEnabled or T[K].TLSClient.IsReadyState); TSC.ReleaseReference; TSC := S.ClientIterateNext(TSC); end; // test read/write TestClientServer_ReadWrite_Blocks( TestClientCount, TestLargeBlock, DebugObj, C, T); // release reference for K := 0 to TestClientCount - 1 do T[K].ReleaseReference; // stop clients for K := TestClientCount - 1 downto 0 do begin C[K].Stop; Assert(C[K].State = csStopped); end; I := 0; repeat Inc(I); Sleep(1); until (S.ClientCount = 0) or (I >= 5000); Assert(S.ClientCount = 0); // stop server S.Stop; Assert(not S.Active); finally for K := TestClientCount - 1 downto 0 do begin C[K].Finalise; FreeAndNil(C[K]); end; S.Finalise; FreeAndNil(S); DebugObj.Free; end; end; procedure Test_ClientServerTLS_ReadWrite; begin // TestClientServerTLS_ReadWrite(tmTLS, 1, True, [ctoDisableTLS10, ctoDisableTLS11, ctoDisableTLS12]); // SSL 3.0 TestClientServerTLS_ReadWrite(1, True, DefaultTCPClientTLSOptions, DefaultTLSClientOptions, [tlsvoTLS12]); // TLS 1.2 TestClientServerTLS_ReadWrite(1, True, DefaultTCPClientTLSOptions, DefaultTLSClientOptions, [tlsvoTLS11]); // TLS 1.1 TestClientServerTLS_ReadWrite(1, True, DefaultTCPClientTLSOptions, DefaultTLSClientOptions, [tlsvoTLS10]); // TLS 1.0 end; procedure Test; begin Test_ClientServerTLS_ReadWrite; end; {$ENDIF} end.