-
Notifications
You must be signed in to change notification settings - Fork 692
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
Refactor signature object to add support for repository countersignatures #2006
Conversation
Had an offline discussion with @PatoBeltran. We should consider the following approach - Or if we want to keep the implementation simple then - |
@@ -364,6 +364,11 @@ public enum NuGetLogCode | |||
/// </summary> | |||
NU3029 = 3029, | |||
|
|||
/// <summary> | |||
/// The package signature cointains multiple repository countersignatures. |
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.
typo: contains
{ | ||
throw new NotSupportedException(); | ||
} | ||
|
||
private Task<Signature> TimestampSignature(SignPackageRequest request, ILogger logger, Signature signature, CancellationToken token) | ||
private Task<PrimarySignature> TimestampPrimarySignature(SignPackageRequest request, ILogger logger, PrimarySignature signature, CancellationToken token) |
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.
TimestampPrimarySignatureAsync
} | ||
|
||
private Task<Signature> TimestampSignature(SignPackageRequest request, ILogger logger, Signature signature, CancellationToken token) | ||
private Task<PrimarySignature> TimestampPrimarySignature(SignPackageRequest request, ILogger logger, PrimarySignature signature, CancellationToken token) |
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.
TimestampPrimarySignatureAsync
|
||
namespace NuGet.Packaging.Signing | ||
{ | ||
public class AuthorPrimarySignature : PrimarySignature |
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.
sealed
|
||
namespace NuGet.Packaging.Signing | ||
{ | ||
public class RepositoryPrimarySignature : PrimarySignature, IRepositorySignature |
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.
sealed
potentialNuGetV3ServiceIndexUrl = AttributeUtility.GetNuGetV3ServiceIndexUrl(counterSignature.SignedAttributes); | ||
} | ||
// This counter signature is not a valid repository countersignature | ||
catch (SignatureException) { } |
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.
After you determine it's a repository countersignature, do not catch this exception. Let the exception bubble up to indicate it's an invalid repository countersignature.
throw new SignatureException(NuGetLogCode.NU3030, Strings.Error_NotOneRepositoryCounterSignature); | ||
} | ||
|
||
var respoSignature = repositoryCounterSignatures.FirstOrDefault(); |
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.
typo: repoCountersignature
public static RepositoryCounterSignature GetRepositoryCounterSignature(PrimarySignature primarySignature) | ||
{ | ||
var counterSignatures = primarySignature.SignerInfo.CounterSignerInfos; | ||
var repositoryCounterSignatures = new List<SignerInfo>(); |
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.
You don't need a list.
Create a local:
RepositoryCounterSignature repositoryCountersignature = null;
When examining countersignatures, assign this local only if null; otherwise throw.
|
||
namespace NuGet.Packaging.Signing | ||
{ | ||
public class UnknownPrimarySignature : PrimarySignature |
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.
sealed
VerifySigningTimeAttribute(SignerInfo); | ||
} | ||
|
||
private static void VerifySigningTimeAttribute(SignerInfo signerInfo) |
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 verification applies to author signatures, repository signatures and repository countersignatures.
8334989
to
5b0840c
Compare
@@ -28,7 +28,7 @@ public static class CertificateUtility | |||
public static string X509Certificate2ToString(X509Certificate2 cert, HashAlgorithmName fingerprintAlgorithm) | |||
{ | |||
var certStringBuilder = new StringBuilder(); | |||
X509Certificate2ToString(cert, certStringBuilder, fingerprintAlgorithm, indentation: ""); | |||
X509Certificate2ToString(cert, certStringBuilder, fingerprintAlgorithm, indentation: " "); |
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 added indentation to all certs to match the output from signtool, see example in NuGet/Home#6005 (comment)
string.Join(", ", chainStatusList.Select(x => x.Status.ToString()))))); | ||
} | ||
} | ||
signatureIssues.AddRange(timestampIssues); |
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 to display first the details of the signature and afterwards for its timestamp (if present). This matches signtool and makes more sense to display first the signature. (example output of signtool NuGet/Home#6005 (comment))
NU3032 = 3032, | ||
|
||
/// <summary> | ||
/// A repository primary signature should not have a repository countersignatures. |
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.
A repository primary signature must not have a repository countersignature.
{ | ||
} | ||
|
||
internal override SignatureVerificationStatus Verify( |
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't we just pass a settings object instead of a bunch of flags? It's easier to maintain over time.
internal override SignatureVerificationStatus Verify( | ||
Timestamp timestamp, | ||
bool allowUntrusted, | ||
bool allowUntrustedSelfSignedCertificate, |
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.
#if IS_DESKTOP | ||
Uri NuGetV3ServiceIndexUrl { get; } | ||
|
||
IReadOnlyList<string> NuGetPackageOwners { get; } |
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.
PackageOwners
public interface IRepositorySignature | ||
{ | ||
#if IS_DESKTOP | ||
Uri NuGetV3ServiceIndexUrl { get; } |
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.
V3ServiceIndexUrl
ThrowForInvalidRepositoryCounterSignature(); | ||
} | ||
|
||
private static void ThrowForInvalidRepositoryCounterSignature() |
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.
You don't need this method. Just move the method body into ThrowForInvalidSignature()
.
X509Certificate2Collection certificateExtraStore, | ||
List<SignatureLog> issues) | ||
{ | ||
issues?.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.SignatureType, Type.ToString()))); |
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.
Why allow issues
to be null
here and in other files?
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 though it was a good idea to allow in the case you want to have the verification but don't care about logs, because even if there are no issues the same validation will be performed and you would get the same result. Do you think we should enforce the existence of issues?
@@ -29,7 +29,7 @@ public SignatureTests(CertificatesFixture fixture) | |||
public void Load_WhenDataNull_Throws() | |||
{ | |||
var exception = Assert.Throws<ArgumentNullException>( | |||
() => Signature.Load(data: null)); | |||
() => PrimarySignature.Load(data: null)); |
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.
Rename file to PrimarySignatureTests
.
@@ -80,25 +80,25 @@ public void GetPrimarySignatureCertificates_WithAuthorSignature_ReturnsCertifica | |||
public void GetPrimarySignatureTimestampSignatureCertificates_WhenSignatureNull_Throws() | |||
{ | |||
var exception = Assert.Throws<ArgumentNullException>( | |||
() => SignatureUtility.GetPrimarySignatureTimestampSignatureCertificates(signature: null)); | |||
() => SignatureUtility.GetPrimarySignatureTimestampCertificates(signature: null)); |
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 test (and others) were testing the method GetPrimarySignatureTimestampSignatureCertificates(...)
. The method name begins with the name of the member under test. Since you renamed the name of the member under test, update the test name too. This feedback applies globally.
<MemberName>_<TestCondition>_<ExpectedResult>
ThrowForInvalidPrimarySignature(); | ||
} | ||
|
||
protected static void ThrowForInvalidPrimarySignature() |
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.
Not sure this method is needed. Just move the body into ThrowForInvalidSignature()
.
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 decided to have this method not as part of ThrowForInvalidSignature()
because it is usefull as a static method in some of the static methods in this class, and because ThrowForInvalidSignature()
is an abstract method it cannot be static. Therefore I decided to have another method that is static with the desired implementation and just let ThrowForInvalidSignature()
call this method.
cb14d1f
to
8105baf
Compare
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.
Consider moving signed cms into signature.... otherwise looks good.
/// <summary> | ||
/// A SignedCms object holding the signature and SignerInfo. | ||
/// </summary> | ||
public SignedCms SignedCms { get; } |
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 can be moved into Signature
, since all signatures need to atleast be a SignedCms
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.
Countersignatures are represented as SignerInfo
, so they don't have their own SignedCms
only Primary signatures will have it, that's why I choose to leave it in this class. If we see the need for the primary signature's SignedCms in the countersignature we should consider moving it, but in the mean time I think it should stay here.
First part of NuGet/Home#6276
This work is being done in multiple PRs to avoid having one huge and difficult PR to review.
This PR refactors the current signature object to be able to have repository primary signatures, repository counter signatures in addition to the current author primary signatures.