1
1
// Copyright (c) .NET Foundation. All rights reserved.
2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
+ using System ;
4
5
using System . IO ;
6
+ using System . Runtime . InteropServices ;
5
7
using System . Security . Cryptography . X509Certificates ;
8
+ using System . Threading ;
9
+ using Xunit ;
6
10
7
11
namespace Microsoft . AspNetCore . Testing
8
12
{
@@ -13,14 +17,28 @@ public static class TestResources
13
17
public static string TestCertificatePath { get ; } = Path . Combine ( _baseDir , "testCert.pfx" ) ;
14
18
public static string GetCertPath ( string name ) => Path . Combine ( _baseDir , name ) ;
15
19
16
- public static X509Certificate2 GetTestCertificate ( )
17
- {
18
- return new X509Certificate2 ( TestCertificatePath , "testPassword" ) ;
19
- }
20
+ private const int MutexTimeout = 120 * 1000 ;
21
+ private static readonly Mutex importPfxMutex = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ?
22
+ new Mutex ( initiallyOwned : false , "Global \\ KestrelTests.Certificates.LoadPfxCertificate" ) :
23
+ null ;
20
24
21
- public static X509Certificate2 GetTestCertificate ( string certName )
25
+ public static X509Certificate2 GetTestCertificate ( string certName = "testCert.pfx" )
22
26
{
23
- return new X509Certificate2 ( GetCertPath ( certName ) , "testPassword" ) ;
27
+ // On Windows, applications should not import PFX files in parallel to avoid a known system-level
28
+ // race condition bug in native code which can cause crashes/corruption of the certificate state.
29
+ if ( importPfxMutex != null )
30
+ {
31
+ Assert . True ( importPfxMutex . WaitOne ( MutexTimeout ) , "Cannot acquire the global certificate mutex." ) ;
32
+ }
33
+
34
+ try
35
+ {
36
+ return new X509Certificate2 ( GetCertPath ( certName ) , "testPassword" ) ;
37
+ }
38
+ finally
39
+ {
40
+ importPfxMutex ? . ReleaseMutex ( ) ;
41
+ }
24
42
}
25
43
}
26
44
}
0 commit comments