New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add integration tests for CertificateValidationMessageHandler #341
Conversation
@@ -246,7 +246,7 @@ internal struct CERT_TRUST_STATUS | |||
[StructLayout(LayoutKind.Sequential)] | |||
internal unsafe struct CRL_ENTRY | |||
{ | |||
public CRYPTOAPI_BLOB SerializeNumber; | |||
public CRYPTOAPI_BLOB SerialNumber; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the proper name for the property (docs here).
@@ -107,6 +107,12 @@ private SignatureDecider MakeDeciderForRevokedCodeSigningCertificate(DateTime? r | |||
throw new InvalidOperationException($"Signature {signature.Key} has multiple trusted timestamps"); | |||
} | |||
|
|||
// Revoked certificates invalidate all dependent signatures at ingestion. | |||
if (signature.Status == PackageSignatureStatus.Unknown) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bug fix. We do not accept signatures with revoked certificates at ingestion, even if the revocation date is after the signing time.
@@ -52,7 +52,12 @@ public CertificateIntegrationTestFixture() | |||
|
|||
public Task<SigningTestServer> GetTestServerAsync() => _testServer.Value; | |||
public Task<Uri> GetTimestampServiceUrlAsync() => _timestampServiceUrl.Value; | |||
public Task<X509Certificate2> GetSigningCertificateAsync() => _signingCertificate.Value; | |||
|
|||
public async Task<X509Certificate2> GetSigningCertificateAsync() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before, this certificate was shared and would be disposed by the message handler - this caused weird issues in integration tests. A new X509Certificate2 is created now, so you can dispose it willy-nilly without affecting other tests.
@@ -230,7 +230,7 @@ public static IEnumerable<object[]> RevokedCodeSigningCertificateWithRevocationD | |||
{ | |||
yield return new object[] | |||
{ | |||
TimeSpan.FromDays(-1), SignatureDecision.Ignore, SignatureDecision.Ignore, SignatureDecision.Ignore | |||
TimeSpan.FromDays(-1), SignatureDecision.Reject, SignatureDecision.Ignore, SignatureDecision.Ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signatures should be rejected at ingestion time if their certificate is revoked, regardless of the revocation time.
var ca = await GetCertificateAuthority(); | ||
var ca2 = ca.CreateIntermediateCertificateAuthority(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some weird caching of certificates is happening. Windows is sometimes able to build a chain without the CA Issuer attribute if the intermediate certificate has been seen before.
With this change, a new intermediate CA with no CA responders is issued every time a new end certificate is requested. Since the intermediate CA's certificate has never seen before, caching certificates cannot help build the chain.
{ | ||
public static readonly DateTime RevocationTime = DateTime.UtcNow.AddDays(-4); | ||
public static readonly DateTime BeforeRevocationTime = RevocationTime.AddDays(-1); | ||
public static readonly DateTime AfterRevocationTime = RevocationTime.AddDays(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these be private
?
Also, I'm not sure what the default validity period is for your certificates, but I recommend minimizing the validity period of your test certificates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I'll lower the visibility.
We will need to update Test.Utility APIs to customize the "not after" date. I think I'll do this in a separate PR once a newer version has been released.
var certificateValidationService = new CertificateValidationService( | ||
_context.Object, | ||
_telemetryService.Object, | ||
new Mock<ILogger<CertificateValidationService>>().Object); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a shorthand for this:
Mock.Of<ILogger<CertificateValidationService>>()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion, I didn't know about that :)
|
||
var (publicCertificate, certificate) = IssueCertificate(ca, "Revoked Timestamping", CustomizeAsSigningCertificate); | ||
|
||
ca.Revoke(publicCertificate, reason: 0, revocationDate: revocationDate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revoke(...)
's second parameter is an int
, because BouncyCastle does not have an enum for revocation reasons. However, BouncyCastle does have a class (Org.BouncyCastle.Asn1.X509.CrlReason
) with some predefined revocation reasons. I could have created my own enum and map between the two, and maybe I should still do that. However, without that, I recommend passing CrlReason.Unspecified
(0) or some other field instead of passing a constant literal 0, which is frustratingly obtuse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go ahead and use a const for this. The Test.Utility package has an enum for the reason now - after the latest version is released, we will switch over to the enum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
var ca = await GetCertificateAuthority(); | ||
var ca2 = ca.CreateIntermediateCertificateAuthority(); | ||
|
||
responders.AddRange(testServer.RegisterResponders(ca2, addCa: false)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a suboptimal use of a IHttpResponder
's. SigningTestServer.RegisterResponder(...)
returns an IDisposable
, which deregisters an IHttpResponder
on disposal. Registered responders should be scoped as narrowly as possible. For the default, trusted chain (root, intermediate, end), it's reasonable to scope the responders for the lifetime of your test fixture. In all other cases, the registered responders should be deterministically disposed by each test, ideally with a using
statement. Here is an example of a responder that is scoped to a single test.
I think this should be scoped at the test level, since this method always creates a new, single-use ca2
and end certificate anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I went ahead and made a return type too as the tuple wasn't the prettiest.
|
||
ca.Revoke(publicCertificate, reason: 0, revocationDate: DateTimeOffset.UtcNow); | ||
ca2.Revoke(publicCertificate, reason: 0, revocationDate: DateTimeOffset.UtcNow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same feedback here for reason
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
public X509Certificate2 EndCertificate { get; } | ||
public X509Certificate2[] IntermediateCertificates { get; } | ||
|
||
public void Dispose() { /*=> _responders.Dispose()*/; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be commented out? Or removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch - this should not be commented out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
2ed6ed2
to
5f810f0
Compare
* Feed2Catalog: replace inner loops with one outer loop (#329) Resolve NuGet/Engineering#1526. * V3: rename asynchronous IStorage methods (#336) Progress on NuGet/NuGetGallery#6267. * Test: fix flaky basic search tests (#337) Progress on NuGet/NuGetGallery#6292. * Add signing to search service (#338) Progress on https://github.com/NuGet/Engineering/issues/1644 * Test: add registration tests (#341) Progress on NuGet/NuGetGallery#6317. * remove unused scripts (#340) * MonitoringProcessor: improve throughput (#342) Progress on NuGet/NuGetGallery#6327. * Catalog2Dnx: improve throughput (#335) Progress on NuGet/NuGetGallery#6267. * Functional tests should not be dependent on a specific hash and file size of the test package (#343) * Add MicroBuild dependency and signing of output DLLs (#345) Progress on https://github.com/NuGet/Engineering/issues/1644 * Rewrite SafeRoleEnvironment to not use Assembly.LoadWithPartialName (#339) * Test: improve and add registration tests (#346) More progress on NuGet/NuGetGallery#6317. * Use ServerCommon commit that is consistent with other repositories (#347) Progress on https://github.com/NuGet/Engineering/issues/1644 * [Monitoring] Ensure packages are signed (#348) This adds a validation to ensure indexed packages are signed by verifying that the package contains a [package signature file](https://github.com/NuGet/Home/wiki/Package-Signatures-Technical-Details#-the-package-signature-file). This validation is disabled for now. To enable this validation, the flag `-expectsSignature true` must be added to ng.exe's command line arguments. This validation will be enabled once all packages are repository signed. Part of NuGet/Engineering#1627 * V3: make stylistic consistency and cleanup changes (#349) Progress on NuGet/NuGetGallery#6411.
* Feed2Catalog: replace inner loops with one outer loop (#329) Resolve NuGet/Engineering#1526. * V3: rename asynchronous IStorage methods (#336) Progress on NuGet/NuGetGallery#6267. * Test: fix flaky basic search tests (#337) Progress on NuGet/NuGetGallery#6292. * Add signing to search service (#338) Progress on https://github.com/NuGet/Engineering/issues/1644 * Test: add registration tests (#341) Progress on NuGet/NuGetGallery#6317. * remove unused scripts (#340) * MonitoringProcessor: improve throughput (#342) Progress on NuGet/NuGetGallery#6327. * Catalog2Dnx: improve throughput (#335) Progress on NuGet/NuGetGallery#6267. * Functional tests should not be dependent on a specific hash and file size of the test package (#343) * Add MicroBuild dependency and signing of output DLLs (#345) Progress on https://github.com/NuGet/Engineering/issues/1644 * Rewrite SafeRoleEnvironment to not use Assembly.LoadWithPartialName (#339) * Test: improve and add registration tests (#346) More progress on NuGet/NuGetGallery#6317. * Use ServerCommon commit that is consistent with other repositories (#347) Progress on https://github.com/NuGet/Engineering/issues/1644 * [Monitoring] Ensure packages are signed (#348) This adds a validation to ensure indexed packages are signed by verifying that the package contains a [package signature file](https://github.com/NuGet/Home/wiki/Package-Signatures-Technical-Details#-the-package-signature-file). This validation is disabled for now. To enable this validation, the flag `-expectsSignature true` must be added to ng.exe's command line arguments. This validation will be enabled once all packages are repository signed. Part of NuGet/Engineering#1627 * V3: make stylistic consistency and cleanup changes (#349) Progress on NuGet/NuGetGallery#6411.
No description provided.