未验证 提交 827474bb 编写于 作者: T Tomas Weinfurt 提交者: GitHub

fix quic cert validation with OpenSSL (#51015)

* fix quic cert validation with OpenSSL

* feedback from review

* update certificate conditions
上级 120f3746
......@@ -45,6 +45,7 @@
<ItemGroup>
<Reference Include="System.Collections" />
<Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Diagnostics.Tracing" />
<Reference Include="System.Memory" />
<Reference Include="System.Net.Primitives" />
......
......@@ -34,6 +34,7 @@ internal enum QUIC_CREDENTIAL_FLAGS : uint
DEFER_CERTIFICATE_VALIDATION = 0x00000020, // Schannel only currently.
REQUIRE_CLIENT_AUTHENTICATION = 0x00000040, // Schannel only currently.
USE_TLS_BUILTIN_CERTIFICATE_VALIDATION = 0x00000080,
USE_PORTABLE_CERTIFICATES = 0x00004000,
}
internal enum QUIC_CERTIFICATE_HASH_STORE_FLAGS
......
......@@ -426,6 +426,7 @@ internal struct ConnectionEventPeerCertificateReceived
internal IntPtr PlatformCertificateHandle;
internal uint DeferredErrorFlags;
internal uint DeferredStatus;
internal IntPtr PlatformCertificateChainHandle;
}
[StructLayout(LayoutKind.Explicit)]
......
......@@ -72,6 +72,12 @@ private static unsafe SafeMsQuicConfigurationHandle Create(QuicOptions options,
flags |= QUIC_CREDENTIAL_FLAGS.INDICATE_CERTIFICATE_RECEIVED | QUIC_CREDENTIAL_FLAGS.NO_CERTIFICATE_VALIDATION;
}
if (!OperatingSystem.IsWindows())
{
// Use certificate handles on Windows, fall-back to ASN1 otherwise.
flags |= QUIC_CREDENTIAL_FLAGS.USE_PORTABLE_CERTIFICATES;
}
Debug.Assert(!MsQuicApi.Api.Registration.IsInvalid);
var settings = new QuicSettings
......
......@@ -204,12 +204,7 @@ private static uint HandleEventPeerCertificateReceived(State state, ref Connecti
SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;
X509Chain? chain = null;
X509Certificate2? certificate = null;
if (!OperatingSystem.IsWindows())
{
// TODO fix validation with OpenSSL
return MsQuicStatusCodes.Success;
}
X509Certificate2Collection? additionalCertificates = null;
MsQuicConnection? connection = state.Connection;
if (connection == null)
......@@ -217,16 +212,46 @@ private static uint HandleEventPeerCertificateReceived(State state, ref Connecti
return MsQuicStatusCodes.InvalidState;
}
if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle != IntPtr.Zero)
{
certificate = new X509Certificate2(connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle);
}
try
{
if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle != IntPtr.Zero)
{
if (OperatingSystem.IsWindows())
{
certificate = new X509Certificate2(connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle);
}
else
{
unsafe
{
ReadOnlySpan<QuicBuffer> quicBuffer;
if (connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle != IntPtr.Zero)
{
quicBuffer = new ReadOnlySpan<QuicBuffer>((void*)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateChainHandle, sizeof(QuicBuffer));
if (quicBuffer[0].Length != 0 && quicBuffer[0].Buffer != null)
{
ReadOnlySpan<byte> asn1 = new ReadOnlySpan<byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length);
additionalCertificates = new X509Certificate2Collection();
additionalCertificates.Import(asn1);
if (additionalCertificates.Count > 0)
{
certificate = additionalCertificates[0];
}
}
}
else
{
quicBuffer = new ReadOnlySpan<QuicBuffer>((void*)connectionEvent.Data.PeerCertificateReceived.PlatformCertificateHandle, sizeof(QuicBuffer));
ReadOnlySpan<byte> asn1 = new ReadOnlySpan<byte>(quicBuffer[0].Buffer, (int)quicBuffer[0].Length);
certificate = new X509Certificate2(asn1);
}
}
}
}
if (certificate == null)
{
if (NetEventSource.Log.IsEnabled() && connection._remoteCertificateRequired) NetEventSource.Error(state.Connection, $"Remote certificate required, but no remote certificate received");
if (NetEventSource.Log.IsEnabled() && connection._remoteCertificateRequired) NetEventSource.Error(state.Connection, "Remote certificate required, but no remote certificate received");
sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable;
}
else
......@@ -236,6 +261,14 @@ private static uint HandleEventPeerCertificateReceived(State state, ref Connecti
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
chain.ChainPolicy.ApplicationPolicy.Add(connection._isServer ? s_clientAuthOid : s_serverAuthOid);
if (additionalCertificates != null && additionalCertificates.Count > 1)
{
for (int i = 1; i < additionalCertificates.Count; i++)
{
chain.ChainPolicy.ExtraStore.Add(additionalCertificates[i]);
}
}
if (!chain.Build(certificate))
{
sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
......
......@@ -3,21 +3,30 @@
using System.Collections.Generic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Net.Quic.Tests
{
// TODO: why do we have 2 base classes with some duplicated methods?
public class MsQuicTestBase
{
public X509Certificate2 ServerCertificate = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
public bool RemoteCertificateValidationCallback(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors)
{
Assert.Equal(ServerCertificate.GetCertHash(), certificate?.GetCertHash());
return true;
}
public SslServerAuthenticationOptions GetSslServerAuthenticationOptions()
{
return new SslServerAuthenticationOptions()
{
ApplicationProtocols = new List<SslApplicationProtocol>() { new SslApplicationProtocol("quictest") },
// TODO: use a cert. MsQuic currently only allows certs that are trusted.
ServerCertificate = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate()
ServerCertificate = ServerCertificate
};
}
......@@ -26,7 +35,7 @@ public SslClientAuthenticationOptions GetSslClientAuthenticationOptions()
return new SslClientAuthenticationOptions()
{
ApplicationProtocols = new List<SslApplicationProtocol>() { new SslApplicationProtocol("quictest") },
RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => { return true; }
RemoteCertificateValidationCallback = RemoteCertificateValidationCallback
};
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册