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 ;
5
4
using System . Runtime . CompilerServices ;
6
5
using System . Runtime . InteropServices ;
7
6
using System . Security . Cryptography ;
@@ -38,6 +37,29 @@ public static partial class Certificates
38
37
private static readonly X509BasicConstraintsExtension s_eeConstraints =
39
38
new X509BasicConstraintsExtension ( false , false , 0 , false ) ;
40
39
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
+
41
63
public static void CleanupCertificates ( [ CallerMemberName ] string ? testName = null , StoreName storeName = StoreName . CertificateAuthority )
42
64
{
43
65
string caName = $ "O={ testName } ";
@@ -56,9 +78,7 @@ public static void CleanupCertificates([CallerMemberName] string? testName = nul
56
78
}
57
79
}
58
80
}
59
- catch
60
- {
61
- }
81
+ catch { } ;
62
82
63
83
try
64
84
{
@@ -75,9 +95,7 @@ public static void CleanupCertificates([CallerMemberName] string? testName = nul
75
95
}
76
96
}
77
97
}
78
- catch
79
- {
80
- }
98
+ catch { } ;
81
99
}
82
100
83
101
internal static X509ExtensionCollection BuildTlsServerCertExtensions ( string serverName )
@@ -101,68 +119,7 @@ private static X509ExtensionCollection BuildTlsCertExtensions(string targetName,
101
119
return extensions ;
102
120
}
103
121
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 )
122
+ public static ( X509Certificate2 certificate , X509Certificate2Collection ) GenerateCertificates ( string targetName , [ CallerMemberName ] string ? testName = null , bool longChain = false , bool serverCertificate = true , bool ephemeralKey = false )
166
123
{
167
124
const int keySize = 2048 ;
168
125
if ( PlatformDetection . IsWindows && testName != null )
@@ -174,7 +131,7 @@ internal static PkiHolder GenerateCertificates(string targetName, [CallerMemberN
174
131
X509ExtensionCollection extensions = BuildTlsCertExtensions ( targetName , serverCertificate ) ;
175
132
176
133
CertificateAuthority . BuildPrivatePki (
177
- PkiOptions . AllRevocation ,
134
+ PkiOptions . IssuerRevocationViaCrl ,
178
135
out RevocationResponder responder ,
179
136
out CertificateAuthority root ,
180
137
out CertificateAuthority [ ] intermediates ,
@@ -185,15 +142,34 @@ internal static PkiHolder GenerateCertificates(string targetName, [CallerMemberN
185
142
keyFactory : CertificateAuthority . KeyFactory . RSASize ( keySize ) ,
186
143
extensions : extensions ) ;
187
144
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
+
188
163
if ( ! ephemeralKey && PlatformDetection . IsWindows )
189
164
{
190
165
X509Certificate2 ephemeral = endEntity ;
191
166
endEntity = X509CertificateLoader . LoadPkcs12 ( endEntity . Export ( X509ContentType . Pfx ) , ( string ? ) null , X509KeyStorageFlags . Exportable ) ;
192
167
ephemeral . Dispose ( ) ;
193
168
}
194
169
195
- return new PkiHolder ( testName , root , intermediates , endEntity , responder ) ;
170
+ return ( endEntity , chain ) ;
196
171
}
172
+
197
173
}
198
174
}
199
175
}
0 commit comments