diff --git a/src/NLog.Web.AspNetCore/Enums/TlsHandshakeProperty.cs b/src/NLog.Web.AspNetCore/Enums/TlsHandshakeProperty.cs
new file mode 100644
index 00000000..7ed7a3b5
--- /dev/null
+++ b/src/NLog.Web.AspNetCore/Enums/TlsHandshakeProperty.cs
@@ -0,0 +1,37 @@
+namespace NLog.Web.Enums
+{
+ ///
+ /// Specifies which of the 7 properties of ITlsHandshakeFeature to emit
+ ///
+ public enum TlsHandshakeProperty
+ {
+ ///
+ /// Gets the CipherAlgorithmType.
+ ///
+ CipherAlgorithm,
+ ///
+ /// Gets the cipher strength
+ ///
+ CipherStrength,
+ ///
+ /// Gets the HashAlgorithmType.
+ ///
+ HashAlgorithm,
+ ///
+ /// Gets the hash strength.
+ ///
+ HashStrength,
+ ///
+ /// Gets the KeyExchangeAlgorithm.
+ ///
+ KeyExchangeAlgorithm,
+ ///
+ /// Gets the key exchange algorithm strength.
+ ///
+ KeyExchangeStrength,
+ ///
+ /// Gets the SslProtocols.
+ ///
+ Protocol
+ }
+}
diff --git a/src/NLog.Web.AspNetCore/LayoutRenderers/AspNetTlsHandshakeLayoutRenderer.cs b/src/NLog.Web.AspNetCore/LayoutRenderers/AspNetTlsHandshakeLayoutRenderer.cs
new file mode 100644
index 00000000..65b723d4
--- /dev/null
+++ b/src/NLog.Web.AspNetCore/LayoutRenderers/AspNetTlsHandshakeLayoutRenderer.cs
@@ -0,0 +1,79 @@
+#if ASP_NET_CORE3
+using Microsoft.AspNetCore.Connections.Features;
+using NLog.Config;
+using NLog.LayoutRenderers;
+using NLog.Web.Enums;
+using NLog.Web.Internal;
+using System.Text;
+
+namespace NLog.Web.LayoutRenderers
+{
+ ///
+ /// ASP.NET TLS Handshake
+ ///
+ ///
+ /// ${aspnet-tls-handshake:Property=CipherAlgorithm}
+ /// ${aspnet-tls-handshake:Property=CipherStrength}
+ /// ${aspnet-tls-handshake:Property=HashAlgorithm}
+ /// ${aspnet-tls-handshake:Property=HashStrength}
+ /// ${aspnet-tls-handshake:Property=KeyExchangeAlgorithm}
+ /// ${aspnet-tls-handshake:Property=KeyExchangeStrength}
+ /// ${aspnet-tls-handshake:Property=Protocol}
+ ///
+ [LayoutRenderer("aspnet-tls-handshake")]
+ public class AspNetTlsHandshakeLayoutRenderer : AspNetLayoutRendererBase
+ {
+ ///
+ /// Specifies which of the 7 properties of ITlsHandshakeFeature to emit
+ /// Defaults to the protocol
+ ///
+ [DefaultParameter]
+ public TlsHandshakeProperty Property { get; set; } = TlsHandshakeProperty.Protocol;
+
+ ///
+ /// Render TLS Handshake Information
+ ///
+ ///
+ ///
+ protected override void DoAppend(StringBuilder builder, LogEventInfo logEvent)
+ {
+ var features = HttpContextAccessor.HttpContext.TryGetFeatureCollection();
+ if(features == null)
+ {
+ return;
+ }
+ var tlsHandshake = features.Get();
+ if (tlsHandshake == null)
+ {
+ return;
+ }
+
+ switch (Property)
+ {
+ case TlsHandshakeProperty.CipherAlgorithm:
+ builder.Append(tlsHandshake.CipherAlgorithm);
+ break;
+ case TlsHandshakeProperty.CipherStrength:
+ builder.Append(tlsHandshake.CipherStrength);
+ break;
+ case TlsHandshakeProperty.HashAlgorithm:
+ builder.Append(tlsHandshake.HashAlgorithm);
+ break;
+ case TlsHandshakeProperty.HashStrength:
+ builder.Append(tlsHandshake.HashStrength);
+ break;
+ case TlsHandshakeProperty.KeyExchangeAlgorithm:
+ builder.Append(tlsHandshake.KeyExchangeAlgorithm);
+ break;
+ case TlsHandshakeProperty.KeyExchangeStrength:
+ builder.Append(tlsHandshake.KeyExchangeStrength);
+ break;
+ case TlsHandshakeProperty.Protocol:
+ builder.Append(tlsHandshake.Protocol);
+ break;
+ }
+
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Shared/Internal/HttpContextExtensions.cs b/src/Shared/Internal/HttpContextExtensions.cs
index 234999fc..9c0f35d6 100644
--- a/src/Shared/Internal/HttpContextExtensions.cs
+++ b/src/Shared/Internal/HttpContextExtensions.cs
@@ -4,6 +4,9 @@
using System.Web;
#else
using System.Text;
+#if ASP_NET_CORE3
+using Microsoft.AspNetCore.Connections.Features;
+#endif
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
#endif
@@ -61,6 +64,14 @@ internal static HttpResponse TryGetResponse(this HttpContext context)
InternalLogger.Debug("HttpContext Response Lookup returned null");
return response;
}
+
+ internal static IFeatureCollection TryGetFeatureCollection(this HttpContext context)
+ {
+ var features = context?.Features;
+ if (features == null)
+ InternalLogger.Debug("HttpContext Features Lookup returned null");
+ return features;
+ }
#endif
#if ASP_NET_CORE2
diff --git a/tests/NLog.Web.AspNetCore.Tests/LayoutRenderers/AspNetTlsHandshakeLayoutRendererTests.cs b/tests/NLog.Web.AspNetCore.Tests/LayoutRenderers/AspNetTlsHandshakeLayoutRendererTests.cs
new file mode 100644
index 00000000..437714c1
--- /dev/null
+++ b/tests/NLog.Web.AspNetCore.Tests/LayoutRenderers/AspNetTlsHandshakeLayoutRendererTests.cs
@@ -0,0 +1,143 @@
+#if ASP_NET_CORE3
+using Microsoft.AspNetCore.Connections.Features;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using NLog.Web.Enums;
+using NLog.Web.LayoutRenderers;
+using NSubstitute;
+using System.Security.Authentication;
+using Xunit;
+
+namespace NLog.Web.Tests.LayoutRenderers
+{
+ public class AspNetTlsHandshakeLayoutRendererTests : LayoutRenderersTestBase
+ {
+ private static void SetupFeature(HttpContext httpContext)
+ {
+ var tlsHandshakeFeature = Substitute.For();
+
+ tlsHandshakeFeature.CipherAlgorithm.Returns(CipherAlgorithmType.Aes256);
+ tlsHandshakeFeature.CipherStrength.Returns(256);
+
+ tlsHandshakeFeature.HashAlgorithm.Returns(HashAlgorithmType.Sha512);
+ tlsHandshakeFeature.HashStrength.Returns(512);
+
+ tlsHandshakeFeature.KeyExchangeAlgorithm.Returns(ExchangeAlgorithmType.RsaSign);
+ tlsHandshakeFeature.KeyExchangeStrength.Returns(1024);
+
+ tlsHandshakeFeature.Protocol.Returns(SslProtocols.Tls13);
+
+
+ var featureCollection = new FeatureCollection();
+ featureCollection.Set(tlsHandshakeFeature);
+
+ httpContext.Features.Returns(featureCollection);
+ }
+
+ [Fact]
+ public void CipherAlgorithmTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.CipherAlgorithm;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal(CipherAlgorithmType.Aes256.ToString(), result);
+ }
+
+
+ [Fact]
+ public void CipherStrengthTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.CipherStrength;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal("256", result);
+ }
+
+ [Fact]
+ public void HashAlgorithmTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.HashAlgorithm;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal(HashAlgorithmType.Sha512.ToString(), result);
+ }
+
+ [Fact]
+ public void HashStrengthTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.HashStrength;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal("512", result);
+ }
+
+ [Fact]
+ public void KeyExchangeAlgorithmTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.KeyExchangeAlgorithm;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal(ExchangeAlgorithmType.RsaSign.ToString(), result);
+ }
+
+ [Fact]
+ public void KeyExchangeStrengthTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.KeyExchangeStrength;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal("1024", result);
+ }
+
+ [Fact]
+ public void ProtocolTest()
+ {
+ // Arrange
+ var (renderer, httpContext) = CreateWithHttpContext();
+ renderer.Property = TlsHandshakeProperty.Protocol;
+ SetupFeature(httpContext);
+ // Act
+ var result = renderer.Render(new LogEventInfo());
+ // Assert
+ Assert.Equal(SslProtocols.Tls13.ToString(), result);
+ }
+
+
+ protected override void NullRendersEmptyString()
+ {
+ // Arrange
+ var (renderer, _) = CreateWithHttpContext();
+
+ // Act
+ string result = renderer.Render(LogEventInfo.CreateNullEvent());
+
+ // Assert
+ Assert.Equal("None", result);
+ }
+ }
+}
+#endif
\ No newline at end of file