2222using NuGet . Services . Validation . Issues ;
2323using NuGetGallery ;
2424using Test . Utility . Signing ;
25+ using Validation . PackageSigning . ExtractAndValidateSignature . Tests . Support ;
2526using Xunit ;
2627using Xunit . Abstractions ;
2728using NuGetHashAlgorithmName = NuGet . Common . HashAlgorithmName ;
@@ -92,13 +93,13 @@ public SignatureValidatorIntegrationTests(CertificateIntegrationTestFixture fixt
9293
9394 public async Task < SignedPackageArchive > GetSignedPackage1Async ( )
9495 {
95- AllowCertificateThumbprint ( _fixture . LeafCertificate1Thumbprint ) ;
96+ AllowCertificateThumbprint ( await _fixture . GetSigningCertificateThumbprintAsync ( ) ) ;
9697 return await _fixture . GetSignedPackage1Async ( _output ) ;
9798 }
9899
99100 public async Task < MemoryStream > GetSignedPackageStream1Async ( )
100101 {
101- AllowCertificateThumbprint ( _fixture . LeafCertificate1Thumbprint ) ;
102+ AllowCertificateThumbprint ( await _fixture . GetSigningCertificateThumbprintAsync ( ) ) ;
102103 return await _fixture . GetSignedPackageStream1Async ( _output ) ;
103104 }
104105
@@ -136,31 +137,43 @@ public async Task RejectsUntrustedSigningCertificate()
136137
137138 // Assert
138139 VerifyPackageSigningStatus ( result , ValidationStatus . Failed , PackageSigningStatus . Invalid ) ;
139- Assert . NotEmpty ( result . Issues ) ;
140- var clientIssues = result
141- . Issues
142- . OfType < ClientSigningVerificationFailure > ( )
143- . Where ( x => x . ClientCode == "NU3021" )
144- . ToList ( ) ;
145- var untrustedIssue = Assert . Single ( clientIssues ) ;
140+ var issue = Assert . Single ( result . Issues ) ;
141+ var clientIssue = Assert . IsType < ClientSigningVerificationFailure > ( issue ) ;
142+ Assert . Equal ( "NU3021" , clientIssue . ClientCode ) ;
146143 Assert . Equal (
147144 "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider." ,
148- untrustedIssue . ClientMessage ) ;
145+ clientIssue . ClientMessage ) ;
149146 }
150147
151148 [ Fact ]
152- public async Task AcceptsTrustedCertificateWithUnavailableRevocation ( )
149+ public async Task RejectsUntrustedTimestampingCertificate ( )
153150 {
154151 // Arrange
155- using ( var trustedTestCert = new TrustedTestCert < X509Certificate2 > (
156- await TestResources . GetTestRootCertificateAsync ( ) ,
157- x => x ,
158- StoreName . Root ,
159- StoreLocation . LocalMachine ,
160- maximumValidityPeriod : TimeSpan . MaxValue ) )
152+ var testServer = await _fixture . GetTestServerAsync ( ) ;
153+ var untrustedRootCa = CertificateAuthority . Create ( testServer . Url ) ;
154+ var untrustedRootCertficate = new X509Certificate2 ( untrustedRootCa . Certificate . GetEncoded ( ) ) ;
155+ var timestampService = TimestampService . Create ( untrustedRootCa ) ;
156+ using ( testServer . RegisterDefaultResponders ( timestampService ) )
161157 {
162- _package = TestResources . SignedPackageLeaf1Reader ;
163- AllowCertificateThumbprint ( TestResources . Leaf1Thumbprint ) ;
158+ byte [ ] packageBytes ;
159+ using ( var temporaryTrust = new TrustedTestCert < X509Certificate2 > (
160+ untrustedRootCertficate ,
161+ x => x ,
162+ StoreName . Root ,
163+ StoreLocation . LocalMachine ) )
164+ {
165+ packageBytes = await _fixture . GenerateSignedPackageBytesAsync (
166+ TestResources . SignedPackageLeaf1 ,
167+ await _fixture . GetSigningCertificateAsync ( ) ,
168+ timestampService . Url ,
169+ _output ) ;
170+ }
171+
172+ AllowCertificateThumbprint ( await _fixture . GetSigningCertificateThumbprintAsync ( ) ) ;
173+
174+ _package = new SignedPackageArchive (
175+ new MemoryStream ( packageBytes ) ,
176+ new MemoryStream ( ) ) ;
164177
165178 // Act
166179 var result = await _target . ValidateAsync (
@@ -169,9 +182,124 @@ await TestResources.GetTestRootCertificateAsync(),
169182 _message ,
170183 _token ) ;
171184
185+ // Assert
186+ VerifyPackageSigningStatus ( result , ValidationStatus . Failed , PackageSigningStatus . Invalid ) ;
187+ var issue = Assert . Single ( result . Issues ) ;
188+ var clientIssue = Assert . IsType < ClientSigningVerificationFailure > ( issue ) ;
189+ Assert . Equal ( "NU3028" , clientIssue . ClientCode ) ;
190+ Assert . Equal (
191+ "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider." ,
192+ clientIssue . ClientMessage ) ;
193+ }
194+ }
195+
196+ [ Fact ]
197+ public async Task AcceptsTrustedTimestampingCertificateWithUnavailableRevocation ( )
198+ {
199+ // Arrange
200+ var testServer = await _fixture . GetTestServerAsync ( ) ;
201+ var trustedRootCa = CertificateAuthority . Create ( testServer . Url ) ;
202+ var trustedRootCertficate = new X509Certificate2 ( trustedRootCa . Certificate . GetEncoded ( ) ) ;
203+ var timestampService = TimestampService . Create ( trustedRootCa ) ;
204+ using ( var trust = new TrustedTestCert < X509Certificate2 > (
205+ trustedRootCertficate ,
206+ x => x ,
207+ StoreName . Root ,
208+ StoreLocation . LocalMachine ) )
209+ {
210+ byte [ ] packageBytes ;
211+ using ( testServer . RegisterDefaultResponders ( timestampService ) )
212+ {
213+ packageBytes = await _fixture . GenerateSignedPackageBytesAsync (
214+ TestResources . SignedPackageLeaf1 ,
215+ await _fixture . GetSigningCertificateAsync ( ) ,
216+ timestampService . Url ,
217+ _output ) ;
218+ }
219+
220+ // Wait one second for the OCSP response cached by the operating system during signing to get stale.
221+ // This can be mitigated by leaving the OCSP unavailable during signing once this work item is done:
222+ // https://github.com/NuGet/Home/issues/6508
223+ await Task . Delay ( TimeSpan . FromSeconds ( 1 ) ) ;
224+
225+ AllowCertificateThumbprint ( await _fixture . GetSigningCertificateThumbprintAsync ( ) ) ;
226+
227+ _package = new SignedPackageArchive (
228+ new MemoryStream ( packageBytes ) ,
229+ new MemoryStream ( ) ) ;
230+
231+ SignatureValidatorResult result ;
232+ using ( testServer . RegisterResponders ( timestampService , addOcsp : false ) )
233+ {
234+ // Act
235+ result = await _target . ValidateAsync (
236+ _packageKey ,
237+ _package ,
238+ _message ,
239+ _token ) ;
240+ }
241+
172242 // Assert
173243 VerifyPackageSigningStatus ( result , ValidationStatus . Succeeded , PackageSigningStatus . Valid ) ;
174244 Assert . Empty ( result . Issues ) ;
245+
246+ var allMessages = string . Join ( Environment . NewLine , _logger . Messages ) ;
247+ Assert . Contains ( "NU3028: The revocation function was unable to check revocation because the revocation server was offline." , allMessages ) ;
248+ Assert . Contains ( "NU3028: The revocation function was unable to check revocation for the certificate." , allMessages ) ;
249+ }
250+ }
251+
252+ [ Fact ]
253+ public async Task AcceptsTrustedSigningCertificateWithUnavailableRevocation ( )
254+ {
255+ // Arrange
256+ var testServer = await _fixture . GetTestServerAsync ( ) ;
257+ var rootCa = CertificateAuthority . Create ( testServer . Url ) ;
258+ var intermediateCa = rootCa . CreateIntermediateCertificateAuthority ( ) ;
259+ var rootCertificate = new X509Certificate2 ( rootCa . Certificate . GetEncoded ( ) ) ;
260+ var signingCertificate = _fixture . CreateSigningCertificate ( intermediateCa ) ;
261+ using ( var trust = new TrustedTestCert < X509Certificate2 > (
262+ rootCertificate ,
263+ x => x ,
264+ StoreName . Root ,
265+ StoreLocation . LocalMachine ) )
266+ {
267+ byte [ ] packageBytes ;
268+ using ( testServer . RegisterResponders ( intermediateCa ) )
269+ {
270+ packageBytes = await _fixture . GenerateSignedPackageBytesAsync (
271+ TestResources . SignedPackageLeaf1 ,
272+ signingCertificate ,
273+ await _fixture . GetTimestampServiceUrlAsync ( ) ,
274+ _output ) ;
275+ }
276+
277+ // Wait one second for the OCSP response cached by the operating system during signing to get stale.
278+ // This can be mitigated by leaving the OCSP unavailable during signing once this work item is done:
279+ // https://github.com/NuGet/Home/issues/6508
280+ await Task . Delay ( TimeSpan . FromSeconds ( 1 ) ) ;
281+
282+ AllowCertificateThumbprint ( signingCertificate . ComputeSHA256Thumbprint ( ) ) ;
283+
284+ _package = new SignedPackageArchive (
285+ new MemoryStream ( packageBytes ) ,
286+ new MemoryStream ( ) ) ;
287+
288+ SignatureValidatorResult result ;
289+ using ( testServer . RegisterResponders ( intermediateCa , addOcsp : false ) )
290+ {
291+ // Act
292+ result = await _target . ValidateAsync (
293+ _packageKey ,
294+ _package ,
295+ _message ,
296+ _token ) ;
297+ }
298+
299+ // Assert
300+ VerifyPackageSigningStatus ( result , ValidationStatus . Succeeded , PackageSigningStatus . Valid ) ;
301+ Assert . Empty ( result . Issues ) ;
302+
175303 var allMessages = string . Join ( Environment . NewLine , _logger . Messages ) ;
176304 Assert . Contains ( "NU3018: The revocation function was unable to check revocation because the revocation server was offline." , allMessages ) ;
177305 Assert . Contains ( "NU3018: The revocation function was unable to check revocation for the certificate." , allMessages ) ;
0 commit comments