1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 using System.IO;
7 using System.Runtime.InteropServices;
8 using System.Security.Authentication;
9 using System.Security.Cryptography.X509Certificates;
10 using System.Threading;
11 using Xunit;
12 
13 namespace System.Net.Test.Common
14 {
15     public static partial class Configuration
16     {
17         public static partial class Certificates
18         {
19             private const string CertificatePassword = "testcertificate";
20             private const string TestDataFolder = "TestData";
21 
22             private static Mutex m;
23             private const int MutexTimeout = 120 * 1000;
24 
Certificates()25             static Certificates()
26             {
27                 if (PlatformDetection.IsUap)
28                 {
29                     // UWP doesn't support Global mutexes.
30                     m = new Mutex(false, "Local\\CoreFXTest.Configuration.Certificates.LoadPfxCertificate");
31                 }
32                 else
33                 {
34                     m = new Mutex(false, "Global\\CoreFXTest.Configuration.Certificates.LoadPfxCertificate");
35                 }
36             }
37 
GetServerCertificate()38             public static X509Certificate2 GetServerCertificate() => GetCertWithPrivateKey(GetServerCertificateCollection());
39 
GetClientCertificate()40             public static X509Certificate2 GetClientCertificate() => GetCertWithPrivateKey(GetClientCertificateCollection());
41 
GetNoEKUCertificate()42             public static X509Certificate2 GetNoEKUCertificate() => GetCertWithPrivateKey(GetNoEKUCertificateCollection());
43 
GetSelfSignedServerCertificate()44             public static X509Certificate2 GetSelfSignedServerCertificate() => GetCertWithPrivateKey(GetSelfSignedServerCertificateCollection());
45 
GetSelfSignedClientCertificate()46             public static X509Certificate2 GetSelfSignedClientCertificate() => GetCertWithPrivateKey(GetSelfSignedClientCertificateCollection());
47 
GetServerCertificateCollection()48             public static X509Certificate2Collection GetServerCertificateCollection() => GetCertificateCollection("testservereku.contoso.com.pfx");
49 
GetClientCertificateCollection()50             public static X509Certificate2Collection GetClientCertificateCollection() => GetCertificateCollection("testclienteku.contoso.com.pfx");
51 
GetNoEKUCertificateCollection()52             public static X509Certificate2Collection GetNoEKUCertificateCollection() => GetCertificateCollection("testnoeku.contoso.com.pfx");
53 
GetSelfSignedServerCertificateCollection()54             public static X509Certificate2Collection GetSelfSignedServerCertificateCollection() => GetCertificateCollection("testselfsignedservereku.contoso.com.pfx");
55 
GetSelfSignedClientCertificateCollection()56             public static X509Certificate2Collection GetSelfSignedClientCertificateCollection() => GetCertificateCollection("testselfsignedclienteku.contoso.com.pfx");
57 
GetCertificateCollection(string certificateFileName)58             private static X509Certificate2Collection GetCertificateCollection(string certificateFileName)
59             {
60                 // On Windows, .Net Core applications should not import PFX files in parallel to avoid a known system-level race condition.
61                 // This bug results in corrupting the X509Certificate2 certificate state.
62                 try
63                 {
64                     Assert.True(m.WaitOne(MutexTimeout), "Cannot acquire the global certificate mutex.");
65 
66                     var certCollection = new X509Certificate2Collection();
67                     certCollection.Import(Path.Combine(TestDataFolder, certificateFileName), CertificatePassword, X509KeyStorageFlags.DefaultKeySet);
68 
69                     return certCollection;
70                 }
71                 catch (Exception ex)
72                 {
73                     Debug.Fail(nameof(Configuration.Certificates.GetCertificateCollection) + " threw " + ex.ToString());
74                     throw;
75                 }
76                 finally
77                 {
78                     m.ReleaseMutex();
79                 }
80             }
81 
GetCertWithPrivateKey(X509Certificate2Collection certCollection)82             private static X509Certificate2 GetCertWithPrivateKey(X509Certificate2Collection certCollection)
83             {
84                 X509Certificate2 certificate = null;
85 
86                 foreach (X509Certificate2 c in certCollection)
87                 {
88                     if (certificate == null && c.HasPrivateKey)
89                     {
90                         certificate = c;
91                     }
92                     else
93                     {
94                         c.Dispose();
95                     }
96                 }
97 
98                 Assert.NotNull(certificate);
99                 return certificate;
100             }
101         }
102     }
103 }
104