Skip to content

Commit

Permalink
flush CachedDirectoryStoreProvider on X509Store changes (#48149)
Browse files Browse the repository at this point in the history
* flush CachedDirectoryStoreProvider on X509Store changes

* reset _forceRefresh
  • Loading branch information
wfurt authored Feb 12, 2021
1 parent 10f20f8 commit 9db2d1d
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ public async Task SslStream_UntrustedCaWithCustomCallback_Throws(bool customCall
public async Task SslStream_ClientCertificate_SendsChain()
{
List<SslStream> streams = new List<SslStream>();
TestHelper.CleanupCertificates("SslStream_ClinetCertificate_SendsChain");
TestHelper.CleanupCertificates();
(X509Certificate2 clientCertificate, X509Certificate2Collection clientChain) = TestHelper.GenerateCertificates("SslStream_ClinetCertificate_SendsChain", serverCertificate: false);
using (X509Store store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser))
{
Expand All @@ -364,24 +364,14 @@ public async Task SslStream_ClientCertificate_SendsChain()
store.Close();
}

// There is race between adding certificate to the store and building chain
// Make sure we can build chain before proceeding to ssl handshale
using (var chain = new X509Chain())
{
int count = 25;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.DisableCertificateDownloads = false;
bool chainStatus = chain.Build(clientCertificate);
while (chain.ChainElements.Count != (clientChain.Count + 1) && count > 0)
{
Thread.Sleep(100);
count--;
chainStatus = chain.Build(clientCertificate);
}

// Verify we can construct full chain
Assert.True(chain.ChainElements.Count > clientChain.Count, "chain cannot be built");
Assert.True(chain.ChainElements.Count >= clientChain.Count, "chain cannot be built");
}

var clientOptions = new SslClientAuthenticationOptions() { TargetHost = "localhost", };
Expand Down Expand Up @@ -421,7 +411,7 @@ public async Task SslStream_ClientCertificate_SendsChain()
streams.Add(server);
}

TestHelper.CleanupCertificates("SslStream_ClinetCertificate_SendsChain");
TestHelper.CleanupCertificates();
clientCertificate.Dispose();
foreach (X509Certificate c in clientChain)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ internal static (NetworkStream ClientStream, NetworkStream ServerStream) GetConn

}

internal static void CleanupCertificates(string testName)
internal static void CleanupCertificates([CallerMemberName] string? testName = null)
{
string caName = $"O={testName}";
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,34 @@ internal sealed class CachedDirectoryStoreProvider

private SafeX509StackHandle? _nativeCollection;
private DateTime _loadLastWrite;
private bool _forceRefresh;

internal CachedDirectoryStoreProvider(string storeName)
{
string storePath = DirectoryBasedStoreProvider.GetStorePath(storeName);
_storeDirectoryInfo = new DirectoryInfo(storePath);
}

internal void DoRefresh()
{
_forceRefresh = true;
}

internal SafeX509StackHandle GetNativeCollection()
{
SafeX509StackHandle? ret = _nativeCollection;

TimeSpan elapsed = _recheckStopwatch.Elapsed;

if (ret == null || elapsed >= s_lastWriteRecheckInterval)
if (ret == null || elapsed >= s_lastWriteRecheckInterval || _forceRefresh)
{
lock (_recheckStopwatch)
{
_storeDirectoryInfo.Refresh();
DirectoryInfo info = _storeDirectoryInfo;

if (ret == null ||
_forceRefresh ||
elapsed >= s_assumeInvalidInterval ||
(info.Exists && info.LastWriteTimeUtc != _loadLastWrite))
{
Expand All @@ -65,6 +72,7 @@ internal SafeX509StackHandle GetNativeCollection()
ret = newColl;
_nativeCollection = newColl;
_recheckStopwatch.Restart();
_forceRefresh = false;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public static bool ReleaseSafeX509ChainHandle(IntPtr handle)
return true;
}

public static void FlushStores()
{
OpenSslX509ChainProcessor.FlushStores();
}

public static IChainPal BuildChain(
bool useMachineContext,
ICertificatePal cert,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public void Add(ICertificatePal certPal)
try
{
AddCertToStore(certPal);
ChainPal.FlushStores();
}
catch (CryptographicException)
{
Expand Down Expand Up @@ -223,6 +224,7 @@ public void Remove(ICertificatePal certPal)
}

File.Delete(currentFilename);
ChainPal.FlushStores();
}
} while (currentFilename != null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,13 @@ internal void CommitToChain()
Interop.Crypto.X509StoreCtxCommitToChain(_storeCtx);
}

internal static void FlushStores()
{
s_userRootStore.DoRefresh();
s_userPersonalStore.DoRefresh();
s_userIntermediateStore.DoRefresh();
}

internal void ProcessRevocation(
X509RevocationMode revocationMode,
X509RevocationFlag revocationFlag)
Expand Down

0 comments on commit 9db2d1d

Please sign in to comment.