@@ -44,13 +44,13 @@ internal class CertificateManager
44
44
45
45
// Setting to 0 means we don't append the version byte,
46
46
// which is what all machines currently have.
47
- public int AspNetHttpsCertificateVersion { get ; set ; } = 1 ;
47
+ public static int AspNetHttpsCertificateVersion { get ; set ; } = 1 ;
48
48
49
49
public static bool IsHttpsDevelopmentCertificate ( X509Certificate2 certificate ) =>
50
50
certificate . Extensions . OfType < X509Extension > ( )
51
51
. Any ( e => string . Equals ( AspNetHttpsOid , e . Oid . Value , StringComparison . Ordinal ) ) ;
52
52
53
- public IList < X509Certificate2 > ListCertificates (
53
+ public static IList < X509Certificate2 > ListCertificates (
54
54
CertificatePurpose purpose ,
55
55
StoreName storeName ,
56
56
StoreLocation location ,
@@ -232,6 +232,42 @@ public X509Certificate2 CreateAspNetCoreHttpsDevelopmentCertificate(DateTimeOffs
232
232
return certificate ;
233
233
}
234
234
235
+ internal static bool CheckDeveloperCertificateKey ( X509Certificate2 candidate )
236
+ {
237
+ // Tries to use the certificate key to validate it can't access it
238
+ try
239
+ {
240
+ // Search for the 'active' developer certificate, being very conservative about the possibility that there
241
+ // might be multiple repeated certificates and multiple HTTPS certificates that have been rolled over.
242
+ var devCert = ListCertificates ( CertificatePurpose . HTTPS , StoreName . My , StoreLocation . CurrentUser , isValid : false )
243
+ . OrderByDescending ( c => c . NotAfter )
244
+ . FirstOrDefault ( c => candidate . Thumbprint == c . Thumbprint && c . HasPrivateKey ) ;
245
+
246
+ if ( devCert == null )
247
+ {
248
+ return false ;
249
+ }
250
+
251
+ var rsa = devCert . GetRSAPrivateKey ( ) ;
252
+ if ( rsa == null )
253
+ {
254
+ return false ;
255
+ }
256
+
257
+ // Encrypting a random value is the ultimate test for a key validity.
258
+ // Windows and Mac OS both return HasPrivateKey = true if there is (or there has been) a private key associated
259
+ // with the certificate at some point.
260
+ var value = new byte [ 32 ] ;
261
+ RandomNumberGenerator . Fill ( value ) ;
262
+ rsa . Encrypt ( value , RSAEncryptionPadding . Pkcs1 ) ;
263
+ return true ;
264
+ }
265
+ catch ( Exception )
266
+ {
267
+ return false ;
268
+ }
269
+ }
270
+
235
271
public X509Certificate2 CreateSelfSignedCertificate (
236
272
X500DistinguishedName subject ,
237
273
IEnumerable < X509Extension > extensions ,
0 commit comments