diff --git a/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj b/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj
index cbd3546a0..84fb9e318 100644
--- a/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj
+++ b/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj
@@ -39,7 +39,7 @@
-
+
diff --git a/source/Halibut.Tests/Halibut.Tests.csproj b/source/Halibut.Tests/Halibut.Tests.csproj
index a89c6a6e1..4862ad729 100644
--- a/source/Halibut.Tests/Halibut.Tests.csproj
+++ b/source/Halibut.Tests/Halibut.Tests.csproj
@@ -44,10 +44,11 @@
+
-
+
diff --git a/source/Halibut.Tests/Support/BackwardsCompatibility/LatestClientAndPreviousServiceVersionBuilder.cs b/source/Halibut.Tests/Support/BackwardsCompatibility/LatestClientAndPreviousServiceVersionBuilder.cs
index 4d0d041d2..e2a3c904b 100644
--- a/source/Halibut.Tests/Support/BackwardsCompatibility/LatestClientAndPreviousServiceVersionBuilder.cs
+++ b/source/Halibut.Tests/Support/BackwardsCompatibility/LatestClientAndPreviousServiceVersionBuilder.cs
@@ -1,12 +1,17 @@
using System;
+using System.Collections.Concurrent;
+using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using Halibut.Diagnostics;
using Halibut.Diagnostics.LogCreators;
using Halibut.Logging;
using Halibut.TestProxy;
using Halibut.Tests.Support.Logging;
using Halibut.Transport.Proxy;
using Octopus.TestPortForwarder;
+using Serilog;
+using ILog = Halibut.Diagnostics.ILog;
namespace Halibut.Tests.Support.BackwardsCompatibility
{
@@ -21,6 +26,7 @@ public class LatestClientAndPreviousServiceVersionBuilder : IClientAndServiceBui
ProxyFactory? proxyFactory;
Reference? proxyServiceReference;
LogLevel halibutLogLevel = LogLevel.Trace;
+ StringWriter? loggerStringWriter;
readonly OldServiceAvailableServices availableServices = new(false, false);
LatestClientAndPreviousServiceVersionBuilder(ServiceConnectionType serviceConnectionType, CertAndThumbprint serviceCertAndThumbprint)
@@ -59,6 +65,12 @@ public static LatestClientAndPreviousServiceVersionBuilder ForServiceConnectionT
}
}
+ public LatestClientAndPreviousServiceVersionBuilder RecordingLogs(out StringWriter stringWriter)
+ {
+ loggerStringWriter = stringWriter = new();
+ return this;
+ }
+
public LatestClientAndPreviousServiceVersionBuilder WithServiceVersion(Version? version)
{
this.version = version;
@@ -149,7 +161,11 @@ async Task IClientAndServiceBuilder.Build(CancellationToken c
public async Task Build(CancellationToken cancellationToken)
{
- var logger = new SerilogLoggerBuilder().Build().ForContext();
+ var logger = loggerStringWriter == null
+ ? new SerilogLoggerBuilder()
+ .Build().ForContext()
+ : new LoggerConfiguration().WriteTo.TextWriter(loggerStringWriter).CreateLogger();
+
CancellationTokenSource cancellationTokenSource = new();
if (version == null)
{
diff --git a/source/Halibut.Tests/TlsFixture.cs b/source/Halibut.Tests/TlsFixture.cs
new file mode 100644
index 000000000..f6d9f0577
--- /dev/null
+++ b/source/Halibut.Tests/TlsFixture.cs
@@ -0,0 +1,88 @@
+// Copyright 2012-2013 Octopus Deploy Pty. Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Authentication;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Halibut.Exceptions;
+using Halibut.Tests.Support;
+using Halibut.Tests.Support.BackwardsCompatibility;
+using Halibut.Tests.Support.TestAttributes;
+using Halibut.Tests.Support.TestCases;
+using Halibut.Tests.TestServices.Async;
+using Halibut.Tests.Util;
+using Halibut.TestUtils.Contracts;
+using NUnit.Framework;
+
+namespace Halibut.Tests
+{
+ public class TlsFixture : BaseTest
+ {
+ [Test]
+ [LatestClientAndLatestServiceTestCases(testNetworkConditions: false)]
+ public async Task LatestClientAndServiceUseBestAvailableSslProtocol(ClientAndServiceTestCase clientAndServiceTestCase)
+ {
+ await using (var clientAndService = await clientAndServiceTestCase.CreateTestCaseBuilder()
+ .WithStandardServices()
+ .AsLatestClientAndLatestServiceBuilder()
+ .RecordingClientLogs(out var clientLogs)
+ .RecordingServiceLogs(out var serviceLogs)
+ .Build(CancellationToken))
+ {
+ var echo = clientAndService.CreateAsyncClient();
+ await echo.SayHelloAsync("World");
+
+ var connectionInitiatorLogs = clientAndServiceTestCase.ServiceConnectionType == ServiceConnectionType.Listening
+ ? clientLogs
+ : serviceLogs;
+
+ // .NET does not support TLS 1.3 on Mac OS yet.
+ // https://github.com/dotnet/runtime/issues/1979
+ var expectedSslProtocol = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
+ ? SslProtocols.Tls12
+ : SslProtocols.Tls13;
+
+ connectionInitiatorLogs.Values
+ .SelectMany(log => log.GetLogs())
+ .Should().Contain(logEvent => logEvent.FormattedMessage.Contains($"using protocol {expectedSslProtocol}"));
+ }
+ }
+
+ [Test]
+ // [PreviousClientAndLatestServiceVersionsTestCases(testNetworkConditions: false)]
+ [LatestClientAndPreviousServiceVersionsTestCases(testNetworkConditions: false)]
+ public async Task PreviousClientXorServiceUsageMakeSslProtocolFallBackOnTls12(ClientAndServiceTestCase clientAndServiceTestCase)
+ {
+ await using (var clientAndService = await ((LatestClientAndPreviousServiceVersionBuilder)(clientAndServiceTestCase.CreateTestCaseBuilder()
+ .WithStandardServices()))
+ .RecordingLogs(out var stringWriter)
+ .Build(CancellationToken))
+ {
+ var echo = clientAndService.CreateAsyncClient();
+ await echo.SayHelloAsync("World");
+ const SslProtocols expectedProtocol = SslProtocols.Tls12;
+ var expectedLogFragment = clientAndServiceTestCase.ServiceConnectionType == ServiceConnectionType.Listening
+ ? $"client connected with {expectedProtocol}"
+ : $"using protocol {expectedProtocol}";
+ var logs = stringWriter.ToString();
+ logs.Should().Contain(expectedLogFragment);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/Halibut/Transport/DiscoveryClient.cs b/source/Halibut/Transport/DiscoveryClient.cs
index d95494d2a..79b343adb 100644
--- a/source/Halibut/Transport/DiscoveryClient.cs
+++ b/source/Halibut/Transport/DiscoveryClient.cs
@@ -42,7 +42,11 @@ public async Task DiscoverAsync(ServiceEndPoint serviceEndpoint
#if NETFRAMEWORK
// TODO: ASYNC ME UP!
// AuthenticateAsClientAsync in .NET 4.8 does not support cancellation tokens. So `cancellationToken` is not respected here.
- await ssl.AuthenticateAsClientAsync(serviceEndpoint.BaseUri.Host, new X509Certificate2Collection(), SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, false);
+ await ssl.AuthenticateAsClientAsync(
+ serviceEndpoint.BaseUri.Host,
+ new X509Certificate2Collection(),
+ SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13,
+ false);
#else
await ssl.AuthenticateAsClientEnforcingTimeout(serviceEndpoint, new X509Certificate2Collection(), cancellationToken);
#endif
diff --git a/source/Halibut/Transport/SecureListener.cs b/source/Halibut/Transport/SecureListener.cs
index 9ee69d548..2367c61d0 100644
--- a/source/Halibut/Transport/SecureListener.cs
+++ b/source/Halibut/Transport/SecureListener.cs
@@ -298,11 +298,17 @@ async Task ExecuteRequest(TcpClient client)
{
log.Write(EventType.SecurityNegotiation, "Performing TLS server handshake");
+ await ssl
+ .AuthenticateAsServerAsync(
+ serverCertificate,
+ true,
#pragma warning disable SYSLIB0039
- // See https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0039
- // TLS 1.0 and 1.1 are obsolete from .NET 7
- await ssl.AuthenticateAsServerAsync(serverCertificate, true, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, false).ConfigureAwait(false);
+ // See https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0039
+ // TLS 1.0 and 1.1 are obsolete from .NET 7
+ SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13,
#pragma warning restore SYSLIB0039
+ false)
+ .ConfigureAwait(false);
log.Write(EventType.SecurityNegotiation, "Secure connection established, client is not yet authenticated, client connected with {0}", ssl.SslProtocol.ToString());
diff --git a/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs b/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs
index 07dad0220..e63420b3e 100644
--- a/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs
+++ b/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs
@@ -26,7 +26,7 @@ internal static async Task AuthenticateAsClientEnforcingTimeout(
#pragma warning disable SYSLIB0039
// See https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0039
// TLS 1.0 and 1.1 are obsolete from .NET 7
- EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
+ EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13,
#pragma warning restore SYSLIB0039
CertificateRevocationCheckMode = X509RevocationMode.NoCheck
};
diff --git a/source/Halibut/Transport/TcpConnectionFactory.cs b/source/Halibut/Transport/TcpConnectionFactory.cs
index 41512bc64..3a13913a9 100644
--- a/source/Halibut/Transport/TcpConnectionFactory.cs
+++ b/source/Halibut/Transport/TcpConnectionFactory.cs
@@ -47,7 +47,11 @@ public async Task EstablishNewConnectionAsync(ExchangeProtocolBuild
#if NETFRAMEWORK
// TODO: ASYNC ME UP!
// AuthenticateAsClientAsync in .NET 4.8 does not support cancellation tokens. So `cancellationToken` is not respected here.
- await ssl.AuthenticateAsClientAsync(serviceEndpoint.BaseUri.Host, new X509Certificate2Collection(clientCertificate), SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, false);
+ await ssl.AuthenticateAsClientAsync(
+ serviceEndpoint.BaseUri.Host,
+ new X509Certificate2Collection(clientCertificate),
+ SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13,
+ false);
#else
await ssl.AuthenticateAsClientEnforcingTimeout(serviceEndpoint, new X509Certificate2Collection(clientCertificate), cancellationToken);
#endif
diff --git a/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj b/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj
index b9a5fa5f6..405b6263a 100644
--- a/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj
+++ b/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj
@@ -14,7 +14,7 @@
net8.0
-
+