Skip to content

Commit

Permalink
Add limited support for LocalCertificateSelectionCallback for QUIC (#…
Browse files Browse the repository at this point in the history
…70716)

* Inline state transition helpers

Fixes #55437

* Add high level comments for HandleEventReceive and ReadAsync

* [QUIC] Call `LocalCertificateSelectionCallback` to get client certificate

* Code review feedback
  • Loading branch information
rzikm authored Jun 16, 2022
1 parent 3874c65 commit 9a80f1d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,40 @@ public static SafeMsQuicConfigurationHandle Create(QuicClientConnectionOptions o

if (options.ClientAuthenticationOptions != null)
{
SslClientAuthenticationOptions clientAuthenticationOptions = options.ClientAuthenticationOptions;

#pragma warning disable SYSLIB0040 // NoEncryption and AllowNoEncryption are obsolete
if (options.ClientAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.NoEncryption)
if (clientAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.NoEncryption)
{
throw new PlatformNotSupportedException(SR.Format(SR.net_quic_ssl_option, nameof(options.ClientAuthenticationOptions.EncryptionPolicy)));
throw new PlatformNotSupportedException(SR.Format(SR.net_quic_ssl_option, nameof(clientAuthenticationOptions.EncryptionPolicy)));
}
#pragma warning restore SYSLIB0040

if (options.ClientAuthenticationOptions.ClientCertificates != null)
if (clientAuthenticationOptions.LocalCertificateSelectionCallback != null)
{
X509Certificate? cert = clientAuthenticationOptions.LocalCertificateSelectionCallback(
options,
clientAuthenticationOptions.TargetHost ?? string.Empty,
clientAuthenticationOptions.ClientCertificates ?? new X509CertificateCollection(),
null,
Array.Empty<string>());

if (cert is X509Certificate2 cert2 && cert2.Handle != IntPtr.Zero && cert2.HasPrivateKey)
{
certificate = cert;
}
}
else if (clientAuthenticationOptions.ClientCertificates != null)
{
foreach (var cert in options.ClientAuthenticationOptions.ClientCertificates)
foreach (X509Certificate cert in clientAuthenticationOptions.ClientCertificates)
{
try

if (cert is X509Certificate2 cert2 && cert2.Handle != IntPtr.Zero && cert2.HasPrivateKey)
{
if (((X509Certificate2)cert).HasPrivateKey)
{
// Pick first certificate with private key.
certificate = cert;
break;
}
// Pick first certificate with private key.
certificate = cert;
break;
}
catch { }
}
}
}
Expand Down
19 changes: 14 additions & 5 deletions src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public async Task CertificateCallbackThrowPropagates()
}

[Fact]
public async Task ConnectWithCertificateCallback()
public async Task ConnectWithServerCertificateCallback()
{
X509Certificate2 c1 = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
X509Certificate2 c2 = System.Net.Test.Common.Configuration.Certificates.GetClientCertificate(); // This 'wrong' certificate but should be sufficient
Expand Down Expand Up @@ -340,10 +340,12 @@ public async Task ConnectWithCertificateForLoopbackIP_IndicatesExpectedError(str
}

[ConditionalTheory]
[InlineData(true)]
[InlineData(false)]
[InlineData(true, true)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(false, false)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/64944", TestPlatforms.Windows)]
public async Task ConnectWithClientCertificate(bool sendCertificate)
public async Task ConnectWithClientCertificate(bool sendCertificate, bool useClientSelectionCallback)
{
if (PlatformDetection.IsWindows10Version20348OrLower)
{
Expand Down Expand Up @@ -371,7 +373,14 @@ public async Task ConnectWithClientCertificate(bool sendCertificate)

using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, listenerOptions);
QuicClientConnectionOptions clientOptions = CreateQuicClientOptions();
if (sendCertificate)
if (useClientSelectionCallback)
{
clientOptions.ClientAuthenticationOptions.LocalCertificateSelectionCallback = delegate
{
return sendCertificate ? ClientCertificate : null;
};
}
else if (sendCertificate)
{
clientOptions.ClientAuthenticationOptions.ClientCertificates = new X509CertificateCollection() { ClientCertificate };
}
Expand Down

0 comments on commit 9a80f1d

Please sign in to comment.