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+
4+ using System . Security . Cryptography ;
5+ using System . Security . Cryptography . X509Certificates ;
6+ using Microsoft . AspNetCore . Certificates . Generation ;
7+
8+ namespace Microsoft . AspNetCore . Internal . Tests ;
9+
10+ public class CertificateManagerTests
11+ {
12+ [ Fact ]
13+ public void CreateAspNetCoreHttpsDevelopmentCertificateIsValid ( )
14+ {
15+ var notBefore = DateTimeOffset . Now ;
16+ var notAfter = notBefore . AddMinutes ( 5 ) ;
17+ var certificate = CertificateManager . Instance . CreateAspNetCoreHttpsDevelopmentCertificate ( notBefore , notAfter ) ;
18+
19+ // Certificate should be valid for the expected time range
20+ Assert . Equal ( notBefore , certificate . NotBefore , TimeSpan . FromSeconds ( 1 ) ) ;
21+ Assert . Equal ( notAfter , certificate . NotAfter , TimeSpan . FromSeconds ( 1 ) ) ;
22+
23+ // Certificate should have a private key
24+ Assert . True ( certificate . HasPrivateKey ) ;
25+
26+ // Certificate should be recognized as an ASP.NET Core HTTPS development certificate
27+ Assert . True ( CertificateManager . IsHttpsDevelopmentCertificate ( certificate ) ) ;
28+
29+ // Certificate should include a Subject Key Identifier extension
30+ var subjectKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509SubjectKeyIdentifierExtension > ( ) ) ;
31+
32+ // Certificate should include an Authority Key Identifier extension
33+ var authorityKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509AuthorityKeyIdentifierExtension > ( ) ) ;
34+
35+ // The Authority Key Identifier should match the Subject Key Identifier
36+ Assert . True ( authorityKeyIdentifier . KeyIdentifier ? . Span . SequenceEqual ( subjectKeyIdentifier . SubjectKeyIdentifierBytes . Span ) ) ;
37+ }
38+
39+ [ Fact ]
40+ public void CreateSelfSignedCertificate_ExistingSubjectKeyIdentifierExtension ( )
41+ {
42+ var subject = new X500DistinguishedName ( "CN=TestCertificate" ) ;
43+ var notBefore = DateTimeOffset . Now ;
44+ var notAfter = notBefore . AddMinutes ( 5 ) ;
45+ var testSubjectKeyId = new byte [ ] { 1 , 2 , 3 , 4 , 5 } ;
46+ var extensions = new List < X509Extension >
47+ {
48+ new X509SubjectKeyIdentifierExtension ( testSubjectKeyId , critical : false ) ,
49+ } ;
50+
51+ var certificate = CertificateManager . CreateSelfSignedCertificate ( subject , extensions , notBefore , notAfter ) ;
52+
53+ Assert . Equal ( notBefore , certificate . NotBefore , TimeSpan . FromSeconds ( 1 ) ) ;
54+ Assert . Equal ( notAfter , certificate . NotAfter , TimeSpan . FromSeconds ( 1 ) ) ;
55+
56+ // Certificate had an existing Subject Key Identifier extension, so AKID should not be added
57+ Assert . Empty ( certificate . Extensions . OfType < X509AuthorityKeyIdentifierExtension > ( ) ) ;
58+
59+ var subjectKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509SubjectKeyIdentifierExtension > ( ) ) ;
60+ Assert . True ( subjectKeyIdentifier . SubjectKeyIdentifierBytes . Span . SequenceEqual ( testSubjectKeyId ) ) ;
61+ }
62+
63+ [ Fact ]
64+ public void CreateSelfSignedCertificate_ExistingRawSubjectKeyIdentifierExtension ( )
65+ {
66+ var subject = new X500DistinguishedName ( "CN=TestCertificate" ) ;
67+ var notBefore = DateTimeOffset . Now ;
68+ var notAfter = notBefore . AddMinutes ( 5 ) ;
69+ var testSubjectKeyId = new byte [ ] { 5 , 4 , 3 , 2 , 1 } ;
70+ // Pass the extension as a raw X509Extension to simulate pre-encoded data
71+ var extension = new X509SubjectKeyIdentifierExtension ( testSubjectKeyId , critical : false ) ;
72+ var extensions = new List < X509Extension >
73+ {
74+ new X509Extension ( extension . Oid , extension . RawData , extension . Critical ) ,
75+ } ;
76+
77+ var certificate = CertificateManager . CreateSelfSignedCertificate ( subject , extensions , notBefore , notAfter ) ;
78+
79+ Assert . Equal ( notBefore , certificate . NotBefore , TimeSpan . FromSeconds ( 1 ) ) ;
80+ Assert . Equal ( notAfter , certificate . NotAfter , TimeSpan . FromSeconds ( 1 ) ) ;
81+
82+ Assert . Empty ( certificate . Extensions . OfType < X509AuthorityKeyIdentifierExtension > ( ) ) ;
83+
84+ var subjectKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509SubjectKeyIdentifierExtension > ( ) ) ;
85+ Assert . True ( subjectKeyIdentifier . SubjectKeyIdentifierBytes . Span . SequenceEqual ( testSubjectKeyId ) ) ;
86+ }
87+
88+ [ Fact ]
89+ public void CreateSelfSignedCertificate_ExistingRawAuthorityKeyIdentifierExtension ( )
90+ {
91+ var subject = new X500DistinguishedName ( "CN=TestCertificate" ) ;
92+ var notBefore = DateTimeOffset . Now ;
93+ var notAfter = notBefore . AddMinutes ( 5 ) ;
94+ var testSubjectKeyId = new byte [ ] { 9 , 8 , 7 , 6 , 5 } ;
95+ // Pass the extension as a raw X509Extension to simulate pre-encoded data
96+ var subjectExtension = new X509SubjectKeyIdentifierExtension ( testSubjectKeyId , critical : false ) ;
97+ var authorityExtension = X509AuthorityKeyIdentifierExtension . CreateFromSubjectKeyIdentifier ( subjectExtension ) ;
98+ var extensions = new List < X509Extension >
99+ {
100+ new X509Extension ( authorityExtension . Oid , authorityExtension . RawData , authorityExtension . Critical ) ,
101+ } ;
102+
103+ var certificate = CertificateManager . CreateSelfSignedCertificate ( subject , extensions , notBefore , notAfter ) ;
104+
105+ Assert . Equal ( notBefore , certificate . NotBefore , TimeSpan . FromSeconds ( 1 ) ) ;
106+ Assert . Equal ( notAfter , certificate . NotAfter , TimeSpan . FromSeconds ( 1 ) ) ;
107+
108+ Assert . Empty ( certificate . Extensions . OfType < X509SubjectKeyIdentifierExtension > ( ) ) ;
109+
110+ var authorityKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509AuthorityKeyIdentifierExtension > ( ) ) ;
111+ Assert . True ( authorityKeyIdentifier . KeyIdentifier ? . Span . SequenceEqual ( testSubjectKeyId ) ) ;
112+ }
113+
114+ [ Fact ]
115+ public void CreateSelfSignedCertificate_NoSubjectKeyIdentifierExtension ( )
116+ {
117+ var subject = new X500DistinguishedName ( "CN=TestCertificate" ) ;
118+ var notBefore = DateTimeOffset . Now ;
119+ var notAfter = notBefore . AddMinutes ( 5 ) ;
120+ var extensions = new List < X509Extension > ( ) ;
121+
122+ var certificate = CertificateManager . CreateSelfSignedCertificate ( subject , extensions , notBefore , notAfter ) ;
123+
124+ Assert . Equal ( notBefore , certificate . NotBefore , TimeSpan . FromSeconds ( 1 ) ) ;
125+ Assert . Equal ( notAfter , certificate . NotAfter , TimeSpan . FromSeconds ( 1 ) ) ;
126+
127+ var subjectKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509SubjectKeyIdentifierExtension > ( ) ) ;
128+ var authorityKeyIdentifier = Assert . Single ( certificate . Extensions . OfType < X509AuthorityKeyIdentifierExtension > ( ) ) ;
129+
130+ // The Authority Key Identifier should match the Subject Key Identifier
131+ Assert . True ( authorityKeyIdentifier . KeyIdentifier ? . Span . SequenceEqual ( subjectKeyIdentifier . SubjectKeyIdentifierBytes . Span ) ) ;
132+ }
133+ }
0 commit comments