private async Task ConnectWithRevocation_WithCallback_Core( X509RevocationMode revocationMode, bool?offlineContext = false) { string offlinePart = offlineContext.HasValue ? offlineContext.GetValueOrDefault().ToString().ToLower() : "null"; string serverName = $"{revocationMode.ToString().ToLower()}.{offlinePart}.server.example"; (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); CertificateAuthority.BuildPrivatePki( PkiOptions.EndEntityRevocationViaOcsp | PkiOptions.CrlEverywhere, out RevocationResponder responder, out CertificateAuthority rootAuthority, out CertificateAuthority intermediateAuthority, out X509Certificate2 serverCert, subjectName: serverName, keySize: 2048, extensions: TestHelper.BuildTlsServerCertExtensions(serverName)); SslClientAuthenticationOptions clientOpts = new SslClientAuthenticationOptions { TargetHost = serverName, RemoteCertificateValidationCallback = CertificateValidationCallback, CertificateRevocationCheckMode = revocationMode, }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { X509Certificate2 temp = new X509Certificate2(serverCert.Export(X509ContentType.Pkcs12)); serverCert.Dispose(); serverCert = temp; } await using (clientStream) await using (serverStream) using (responder) using (rootAuthority) using (intermediateAuthority) using (serverCert) using (X509Certificate2 issuerCert = intermediateAuthority.CloneIssuerCert()) await using (SslStream tlsClient = new SslStream(clientStream)) await using (SslStream tlsServer = new SslStream(serverStream)) { intermediateAuthority.Revoke(serverCert, serverCert.NotBefore); SslServerAuthenticationOptions serverOpts = new SslServerAuthenticationOptions(); if (offlineContext.HasValue) { serverOpts.ServerCertificateContext = SslStreamCertificateContext.Create( serverCert, new X509Certificate2Collection(issuerCert), offlineContext.GetValueOrDefault()); if (revocationMode == X509RevocationMode.Offline) { if (offlineContext.GetValueOrDefault(false)) { // Add a delay just to show we're not winning because of race conditions. await Task.Delay(200); } else { if (!OperatingSystem.IsLinux()) { throw new InvalidOperationException( "This test configuration uses reflection and is only defined for Linux."); } FieldInfo pendingDownloadTaskField = typeof(SslStreamCertificateContext).GetField( "_pendingDownload", BindingFlags.Instance | BindingFlags.NonPublic); if (pendingDownloadTaskField is null) { throw new InvalidOperationException("Cannot find the pending download field."); } Task download = (Task)pendingDownloadTaskField.GetValue(serverOpts.ServerCertificateContext); // If it's null, it should mean it has already finished. If not, it might not have. if (download is not null) { await download; } } } } else { serverOpts.ServerCertificate = serverCert; } Task serverTask = tlsServer.AuthenticateAsServerAsync(serverOpts); Task clientTask = tlsClient.AuthenticateAsClientAsync(clientOpts); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(clientTask, serverTask); }
private async Task ConnectWithRevocation_WithCallback_Core( X509RevocationMode revocationMode, bool?offlineContext = false) { string offlinePart = offlineContext.HasValue ? offlineContext.GetValueOrDefault().ToString().ToLower() : "null"; string serverName = $"{revocationMode.ToString().ToLower()}.{offlinePart}.server.example"; (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); CertificateAuthority.BuildPrivatePki( PkiOptions.EndEntityRevocationViaOcsp | PkiOptions.CrlEverywhere, out RevocationResponder responder, out CertificateAuthority rootAuthority, out CertificateAuthority intermediateAuthority, out X509Certificate2 serverCert, subjectName: serverName, keySize: 2048, extensions: TestHelper.BuildTlsServerCertExtensions(serverName)); SslClientAuthenticationOptions clientOpts = new SslClientAuthenticationOptions { TargetHost = serverName, RemoteCertificateValidationCallback = CertificateValidationCallback, CertificateRevocationCheckMode = revocationMode, }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { X509Certificate2 temp = new X509Certificate2(serverCert.Export(X509ContentType.Pkcs12)); serverCert.Dispose(); serverCert = temp; } await using (clientStream) await using (serverStream) using (responder) using (rootAuthority) using (intermediateAuthority) using (serverCert) using (X509Certificate2 issuerCert = intermediateAuthority.CloneIssuerCert()) await using (SslStream tlsClient = new SslStream(clientStream)) await using (SslStream tlsServer = new SslStream(serverStream)) { intermediateAuthority.Revoke(serverCert, serverCert.NotBefore); SslServerAuthenticationOptions serverOpts = new SslServerAuthenticationOptions(); if (offlineContext.HasValue) { serverOpts.ServerCertificateContext = SslStreamCertificateContext.Create( serverCert, new X509Certificate2Collection(issuerCert), offlineContext.GetValueOrDefault()); if (revocationMode == X509RevocationMode.Offline) { // Give the OCSP response a better chance to finish. await Task.Delay(200); } } else { serverOpts.ServerCertificate = serverCert; } Task serverTask = tlsServer.AuthenticateAsServerAsync(serverOpts); Task clientTask = tlsClient.AuthenticateAsClientAsync(clientOpts); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(clientTask, serverTask); }