1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Net . Security ;
4
5
using System . Runtime . CompilerServices ;
5
6
using System . Runtime . InteropServices ;
6
7
using System . Security . Cryptography ;
@@ -37,29 +38,6 @@ public static partial class Certificates
37
38
private static readonly X509BasicConstraintsExtension s_eeConstraints =
38
39
new X509BasicConstraintsExtension ( false , false , 0 , false ) ;
39
40
40
- private static X509Certificate2 s_dynamicServerCertificate ;
41
- private static X509Certificate2Collection s_dynamicCaCertificates ;
42
- private static object certLock = new object ( ) ;
43
-
44
-
45
- // These Get* methods make a copy of the certificates so that consumers own the lifetime of the
46
- // certificates handed back. Consumers are expected to dispose of their certs when done with them.
47
-
48
- public static X509Certificate2 GetDynamicServerCerttificate ( X509Certificate2Collection ? chainCertificates )
49
- {
50
- lock ( certLock )
51
- {
52
- if ( s_dynamicServerCertificate == null )
53
- {
54
- CleanupCertificates ( ) ;
55
- ( s_dynamicServerCertificate , s_dynamicCaCertificates ) = GenerateCertificates ( "localhost" , nameof ( Configuration ) + nameof ( Certificates ) ) ;
56
- }
57
-
58
- chainCertificates ? . AddRange ( s_dynamicCaCertificates ) ;
59
- return new X509Certificate2 ( s_dynamicServerCertificate ) ;
60
- }
61
- }
62
-
63
41
public static void CleanupCertificates ( [ CallerMemberName ] string ? testName = null , StoreName storeName = StoreName . CertificateAuthority )
64
42
{
65
43
string caName = $ "O={ testName } ";
@@ -78,7 +56,9 @@ public static void CleanupCertificates([CallerMemberName] string? testName = nul
78
56
}
79
57
}
80
58
}
81
- catch { } ;
59
+ catch
60
+ {
61
+ }
82
62
83
63
try
84
64
{
@@ -95,7 +75,9 @@ public static void CleanupCertificates([CallerMemberName] string? testName = nul
95
75
}
96
76
}
97
77
}
98
- catch { } ;
78
+ catch
79
+ {
80
+ }
99
81
}
100
82
101
83
internal static X509ExtensionCollection BuildTlsServerCertExtensions ( string serverName )
@@ -119,7 +101,68 @@ private static X509ExtensionCollection BuildTlsCertExtensions(string targetName,
119
101
return extensions ;
120
102
}
121
103
122
- public static ( X509Certificate2 certificate , X509Certificate2Collection ) GenerateCertificates ( string targetName , [ CallerMemberName ] string ? testName = null , bool longChain = false , bool serverCertificate = true , bool ephemeralKey = false )
104
+ internal class PkiHolder : IDisposable
105
+ {
106
+ internal CertificateAuthority Root { get ; }
107
+ internal CertificateAuthority [ ] Intermediates { get ; }
108
+ public X509Certificate2 EndEntity { get ; }
109
+ public X509Certificate2Collection IssuerChain { get ; }
110
+ internal RevocationResponder Responder { get ; }
111
+
112
+ private readonly string ? _testName ;
113
+
114
+ public PkiHolder ( string ? testName , CertificateAuthority root , CertificateAuthority [ ] intermediates , X509Certificate2 endEntity , RevocationResponder responder )
115
+ {
116
+ _testName = testName ;
117
+ Root = root ;
118
+ Intermediates = intermediates ;
119
+ EndEntity = endEntity ;
120
+ Responder = responder ;
121
+
122
+ // Walk the intermediates backwards so we build the chain collection as
123
+ // Issuer3
124
+ // Issuer2
125
+ // Issuer1
126
+ // Root
127
+ IssuerChain = new X509Certificate2Collection ( ) ;
128
+ for ( int i = intermediates . Length - 1 ; i >= 0 ; i -- )
129
+ {
130
+ CertificateAuthority authority = intermediates [ i ] ;
131
+
132
+ IssuerChain . Add ( authority . CloneIssuerCert ( ) ) ;
133
+ }
134
+
135
+ IssuerChain . Add ( root . CloneIssuerCert ( ) ) ;
136
+ }
137
+
138
+ public SslStreamCertificateContext CreateSslStreamCertificateContext ( )
139
+ {
140
+ return SslStreamCertificateContext . Create ( EndEntity , IssuerChain ) ;
141
+ }
142
+
143
+ public void Dispose ( )
144
+ {
145
+ foreach ( CertificateAuthority authority in Intermediates )
146
+ {
147
+ authority . Dispose ( ) ;
148
+ }
149
+ Root . Dispose ( ) ;
150
+ EndEntity . Dispose ( ) ;
151
+ Responder . Dispose ( ) ;
152
+
153
+ foreach ( X509Certificate2 authority in IssuerChain )
154
+ {
155
+ authority . Dispose ( ) ;
156
+ }
157
+
158
+ if ( PlatformDetection . IsWindows && _testName != null )
159
+ {
160
+ CleanupCertificates ( _testName ) ;
161
+ }
162
+ }
163
+ }
164
+
165
+ internal static PkiHolder GenerateCertificates ( string targetName , [ CallerMemberName ] string ? testName = null , bool longChain = false , bool serverCertificate = true , bool ephemeralKey = false )
123
166
{
124
167
const int keySize = 2048 ;
125
168
if ( PlatformDetection . IsWindows && testName != null )
@@ -131,7 +174,7 @@ public static (X509Certificate2 certificate, X509Certificate2Collection) Generat
131
174
X509ExtensionCollection extensions = BuildTlsCertExtensions ( targetName , serverCertificate ) ;
132
175
133
176
CertificateAuthority . BuildPrivatePki (
134
- PkiOptions . IssuerRevocationViaCrl ,
177
+ PkiOptions . AllRevocation ,
135
178
out RevocationResponder responder ,
136
179
out CertificateAuthority root ,
137
180
out CertificateAuthority [ ] intermediates ,
@@ -142,34 +185,15 @@ public static (X509Certificate2 certificate, X509Certificate2Collection) Generat
142
185
keyFactory : CertificateAuthority . KeyFactory . RSASize ( keySize ) ,
143
186
extensions : extensions ) ;
144
187
145
- // Walk the intermediates backwards so we build the chain collection as
146
- // Issuer3
147
- // Issuer2
148
- // Issuer1
149
- // Root
150
- for ( int i = intermediates . Length - 1 ; i >= 0 ; i -- )
151
- {
152
- CertificateAuthority authority = intermediates [ i ] ;
153
-
154
- chain . Add ( authority . CloneIssuerCert ( ) ) ;
155
- authority . Dispose ( ) ;
156
- }
157
-
158
- chain . Add ( root . CloneIssuerCert ( ) ) ;
159
-
160
- responder . Dispose ( ) ;
161
- root . Dispose ( ) ;
162
-
163
188
if ( ! ephemeralKey && PlatformDetection . IsWindows )
164
189
{
165
190
X509Certificate2 ephemeral = endEntity ;
166
191
endEntity = X509CertificateLoader . LoadPkcs12 ( endEntity . Export ( X509ContentType . Pfx ) , ( string ? ) null , X509KeyStorageFlags . Exportable ) ;
167
192
ephemeral . Dispose ( ) ;
168
193
}
169
194
170
- return ( endEntity , chain ) ;
195
+ return new PkiHolder ( testName , root , intermediates , endEntity , responder ) ;
171
196
}
172
-
173
197
}
174
198
}
175
199
}
0 commit comments