@@ -729,6 +729,91 @@ public async Task ConnectWithClientCertificate(bool sendCertificate, ClientCertS
729
729
await serverConnection . DisposeAsync ( ) ;
730
730
}
731
731
732
+ [ Fact ]
733
+ [ PlatformSpecific ( TestPlatforms . Windows ) ]
734
+ public async Task Server_CertificateWithEphemeralKey_Throws ( )
735
+ {
736
+ ( X509Certificate2 serverCertificate , X509Certificate2Collection chain ) = Configuration . Certificates . GenerateCertificates ( nameof ( Server_CertificateWithEphemeralKey_Throws ) , ephemeralKey : true ) ;
737
+ Configuration . Certificates . CleanupCertificates ( nameof ( Server_CertificateWithEphemeralKey_Throws ) ) ;
738
+
739
+ try
740
+ {
741
+ QuicListenerOptions listenerOptions = new QuicListenerOptions ( )
742
+ {
743
+ ListenEndPoint = new IPEndPoint ( IPAddress . Loopback , 0 ) ,
744
+ ApplicationProtocols = new List < SslApplicationProtocol > ( ) { ApplicationProtocol } ,
745
+ ConnectionOptionsCallback = ( _ , _ , _ ) =>
746
+ {
747
+ var serverOptions = CreateQuicServerOptions ( ) ;
748
+ serverOptions . ServerAuthenticationOptions . ServerCertificate = null ;
749
+ serverOptions . ServerAuthenticationOptions . ServerCertificateContext = SslStreamCertificateContext . Create ( serverCertificate , chain ) ;
750
+ return ValueTask . FromResult ( serverOptions ) ;
751
+ }
752
+ } ;
753
+ await using QuicListener listener = await CreateQuicListener ( listenerOptions ) ;
754
+
755
+ QuicClientConnectionOptions clientOptions = CreateQuicClientOptions ( listener . LocalEndPoint ) ;
756
+ clientOptions . ClientAuthenticationOptions . RemoteCertificateValidationCallback = delegate { return true ; } ;
757
+
758
+ // client connection attempt will fail
759
+ await Assert . ThrowsAsync < AuthenticationException > ( async ( ) => await CreateQuicConnection ( clientOptions ) ) ;
760
+
761
+ // server-side failure will be reported from AcceptConnectionAsync
762
+ AuthenticationException e = await Assert . ThrowsAsync < AuthenticationException > ( async ( ) => await listener . AcceptConnectionAsync ( ) ) ;
763
+ Assert . Contains ( "ephemeral" , e . Message ) ;
764
+ }
765
+ finally
766
+ {
767
+ Configuration . Certificates . CleanupCertificates ( nameof ( Server_CertificateWithEphemeralKey_Throws ) ) ;
768
+ serverCertificate . Dispose ( ) ;
769
+ foreach ( X509Certificate c in chain )
770
+ {
771
+ c . Dispose ( ) ;
772
+ }
773
+ }
774
+ }
775
+
776
+ [ Fact ]
777
+ [ PlatformSpecific ( TestPlatforms . Windows ) ]
778
+ public async Task Client_CertificateWithEphemeralKey_Throws ( )
779
+ {
780
+ ( X509Certificate2 clientCertificate , X509Certificate2Collection chain ) = Configuration . Certificates . GenerateCertificates ( nameof ( Client_CertificateWithEphemeralKey_Throws ) , ephemeralKey : true ) ;
781
+ Configuration . Certificates . CleanupCertificates ( nameof ( Client_CertificateWithEphemeralKey_Throws ) ) ;
782
+
783
+ try
784
+ {
785
+ QuicListenerOptions listenerOptions = new QuicListenerOptions ( )
786
+ {
787
+ ListenEndPoint = new IPEndPoint ( IPAddress . Loopback , 0 ) ,
788
+ ApplicationProtocols = new List < SslApplicationProtocol > ( ) { ApplicationProtocol } ,
789
+ ConnectionOptionsCallback = ( _ , _ , _ ) =>
790
+ {
791
+ var serverOptions = CreateQuicServerOptions ( ) ;
792
+ serverOptions . ServerAuthenticationOptions . ClientCertificateRequired = true ;
793
+ serverOptions . ServerAuthenticationOptions . RemoteCertificateValidationCallback = delegate { return true ; } ;
794
+ return ValueTask . FromResult ( serverOptions ) ;
795
+ }
796
+ } ;
797
+ await using QuicListener listener = await CreateQuicListener ( listenerOptions ) ;
798
+
799
+ QuicClientConnectionOptions clientOptions = CreateQuicClientOptions ( listener . LocalEndPoint ) ;
800
+ clientOptions . ClientAuthenticationOptions . ClientCertificates = new X509CertificateCollection ( ) { clientCertificate } ;
801
+ clientOptions . ClientAuthenticationOptions . RemoteCertificateValidationCallback = delegate { return true ; } ;
802
+
803
+ AuthenticationException e = await Assert . ThrowsAsync < AuthenticationException > ( async ( ) => await CreateQuicConnection ( clientOptions ) ) ;
804
+ Assert . Contains ( "ephemeral" , e . Message ) ;
805
+ }
806
+ finally
807
+ {
808
+ Configuration . Certificates . CleanupCertificates ( nameof ( Client_CertificateWithEphemeralKey_Throws ) ) ;
809
+ clientCertificate . Dispose ( ) ;
810
+ foreach ( X509Certificate c in chain )
811
+ {
812
+ c . Dispose ( ) ;
813
+ }
814
+ }
815
+ }
816
+
732
817
[ Theory ]
733
818
[ InlineData ( false ) ]
734
819
[ InlineData ( true ) ]
0 commit comments