private static readonly bool s_traceEnabled =
Environment.GetEnvironmentVariable("TRACE_REVOCATION_RESPONSE") != null;
+ private static readonly byte[] s_invalidResponse =
+ "<html><marquee>The server is down for maintenence.</marquee></html>"u8.ToArray();
+
private readonly HttpListener _listener;
private readonly Dictionary<string, CertificateAuthority> _aiaPaths =
public string UriPrefix { get; }
- public bool RespondEmpty { get; set; }
+ public RespondKind RespondKind { get; set; }
public AiaResponseKind AiaResponseKind { get; set; }
public TimeSpan ResponseDelay { get; set; }
Thread.Sleep(ResponseDelay);
}
- byte[] certData = RespondEmpty ? Array.Empty<byte>() : GetCertDataForAiaResponseKind(AiaResponseKind, authority);
+ byte[] certData = RespondKind switch
+ {
+ RespondKind.Empty => Array.Empty<byte>(),
+ RespondKind.Invalid => s_invalidResponse,
+ _ => GetCertDataForAiaResponseKind(AiaResponseKind, authority),
+ };
responded = true;
context.Response.StatusCode = 200;
Thread.Sleep(ResponseDelay);
}
- byte[] crl = RespondEmpty ? Array.Empty<byte>() : authority.GetCrl();
+ byte[] crl = RespondKind switch
+ {
+ RespondKind.Empty => Array.Empty<byte>(),
+ RespondKind.Invalid => s_invalidResponse,
+ _ => authority.GetCrl(),
+ };
responded = true;
context.Response.StatusCode = 200;
return;
}
- byte[] ocspResponse = RespondEmpty ? Array.Empty<byte>() : authority.BuildOcspResponse(certId, nonce);
+ byte[] ocspResponse = RespondKind switch
+ {
+ RespondKind.Empty => Array.Empty<byte>(),
+ RespondKind.Invalid => s_invalidResponse,
+ _ => authority.BuildOcspResponse(certId, nonce),
+ };
if (DelayedActions.HasFlag(DelayedActionsFlag.Ocsp))
{
Cert = 0,
Pkcs12 = 1,
}
+
+ public enum RespondKind
+ {
+ Normal = 0,
+ Empty = 1,
+ Invalid = 2,
+ }
}
{
if (!Interop.Crypto.X509DecodeOcspToExpiration(ret, ocspRequest, subject, issuer, out DateTimeOffset expiration))
{
+ ret = null;
continue;
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates.Tests.Common;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Security.Tests
+{
+ public static class SslStreamCertificateContextTests
+ {
+ [Fact]
+ [OuterLoop("Subject to resource contention and load.")]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ public static async Task Create_OcspDoesNotReturnOrCacheInvalidStapleData()
+ {
+ string serverName = $"{nameof(Create_OcspDoesNotReturnOrCacheInvalidStapleData)}.example";
+
+ CertificateAuthority.BuildPrivatePki(
+ PkiOptions.EndEntityRevocationViaOcsp | PkiOptions.CrlEverywhere,
+ out RevocationResponder responder,
+ out CertificateAuthority rootAuthority,
+ out CertificateAuthority[] intermediateAuthorities,
+ out X509Certificate2 serverCert,
+ intermediateAuthorityCount: 1,
+ subjectName: serverName,
+ keySize: 2048,
+ extensions: TestHelper.BuildTlsServerCertExtensions(serverName));
+
+ using (responder)
+ using (rootAuthority)
+ using (CertificateAuthority intermediateAuthority = intermediateAuthorities[0])
+ using (serverCert)
+ using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert())
+ using (X509Certificate2 issuerCert = intermediateAuthority.CloneIssuerCert())
+ {
+ responder.RespondKind = RespondKind.Invalid;
+
+ SslStreamCertificateContext context = SslStreamCertificateContext.Create(
+ serverCert,
+ additionalCertificates: new X509Certificate2Collection { issuerCert },
+ offline: false);
+
+ MethodInfo fetchOcspAsyncMethod = typeof(SslStreamCertificateContext).GetMethod(
+ "DownloadOcspAsync",
+ BindingFlags.Instance | BindingFlags.NonPublic);
+ FieldInfo ocspResponseField = typeof(SslStreamCertificateContext).GetField(
+ "_ocspResponse",
+ BindingFlags.Instance | BindingFlags.NonPublic);
+
+ Assert.NotNull(fetchOcspAsyncMethod);
+ Assert.NotNull(ocspResponseField);
+
+ byte[] ocspFetch = await (ValueTask<byte[]>)fetchOcspAsyncMethod.Invoke(context, Array.Empty<object>());
+ Assert.Null(ocspFetch);
+
+ byte[] ocspResponseValue = (byte[])ocspResponseField.GetValue(context);
+ Assert.Null(ocspResponseValue);
+ }
+ }
+ }
+}
<Compile Include="ServerAsyncAuthenticateTest.cs" />
<Compile Include="ServerNoEncryptionTest.cs" />
<Compile Include="ServerRequireEncryptionTest.cs" />
+ <Compile Include="SslStreamCertificateContextTests.cs" />
<Compile Include="SslStreamConformanceTests.cs" />
<Compile Include="SslStreamStreamToStreamTest.cs" />
<Compile Include="SslStreamNetworkStreamTest.cs" />
using (endEntity)
using (X509Certificate2 intermediate2Cert = intermediate2.CloneIssuerCert())
{
- responder.RespondEmpty = true;
+ responder.RespondKind = RespondKind.Empty;
RetryHelper.Execute(() => {
using (ChainHolder holder = new ChainHolder())