internal ClientPolicyContext(SignatureValidationMode policy, IReadOnlyCollection <TrustedSignerAllowListEntry> allowList) { Policy = policy; if (policy == SignatureValidationMode.Require) { VerifierSettings = SignedPackageVerifierSettings.GetRequireModeDefaultPolicy(); } else { VerifierSettings = SignedPackageVerifierSettings.GetAcceptModeDefaultPolicy(); } AllowList = allowList; }
internal override SignatureVerificationStatus Verify( Timestamp timestamp, SignedPackageVerifierSettings settings, HashAlgorithmName fingerprintAlgorithm, X509Certificate2Collection certificateExtraStore, List <SignatureLog> issues) { if (issues == null) { throw new ArgumentNullException(nameof(issues)); } settings = settings ?? SignedPackageVerifierSettings.GetDefault(); issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.SignatureType, Type.ToString()))); return(base.Verify(timestamp, settings, fingerprintAlgorithm, certificateExtraStore, issues)); }
public RepositorySignatureVerifier() { _fingerprintAlgorithm = HashAlgorithmName.SHA256; _settings = new SignedPackageVerifierSettings( allowUnsigned: false, allowIllegal: false, allowUntrusted: false, allowIgnoreTimestamp: false, allowMultipleTimestamps: false, allowNoTimestamp: false, allowUnknownRevocation: true, allowNoRepositoryCertificateList: true, allowNoClientCertificateList: true, alwaysVerifyCountersignature: false, repoAllowListEntries: null, clientAllowListEntries: null); }
/// <summary> /// Gets SignedPackageVerifierSettings from a given RepositorySignatureInfo. /// </summary> /// <param name="repoSignatureInfo">RepositorySignatureInfo to be used.</param> /// <param name="fallbackSettings">SignedPackageVerifierSettings to be used if RepositorySignatureInfo is unavailable.</param> /// <returns>SignedPackageVerifierSettings based on the RepositorySignatureInfo and SignedPackageVerifierSettings.</returns> public static SignedPackageVerifierSettings GetSignedPackageVerifierSettings( RepositorySignatureInfo repoSignatureInfo, SignedPackageVerifierSettings fallbackSettings) { if (fallbackSettings == null) { throw new ArgumentNullException(nameof(fallbackSettings)); } if (repoSignatureInfo == null) { return(fallbackSettings); } else { var repositoryAllowList = GetRepositoryAllowList(repoSignatureInfo.RepositoryCertificateInfos); // Allow unsigned only if the common settings allow it and repository does not have all packages signed var allowUnsigned = fallbackSettings.AllowUnsigned && !repoSignatureInfo.AllRepositorySigned; // Allow an empty repository certificate list only if the repository does not have all packages signed var allowNoRepositoryCertificateList = !repoSignatureInfo.AllRepositorySigned; // Allow untrusted only if the common settings allow it and repository does not have all packages signed var allowUntrusted = fallbackSettings.AllowUntrusted && !repoSignatureInfo.AllRepositorySigned; return(new SignedPackageVerifierSettings( allowUnsigned, fallbackSettings.AllowIllegal, allowUntrusted, fallbackSettings.AllowIgnoreTimestamp, fallbackSettings.AllowMultipleTimestamps, fallbackSettings.AllowNoTimestamp, fallbackSettings.AllowUnknownRevocation, fallbackSettings.ReportUnknownRevocation, allowNoRepositoryCertificateList, fallbackSettings.AllowNoClientCertificateList, fallbackSettings.VerificationTarget, fallbackSettings.SignaturePlacement, fallbackSettings.RepositoryCountersignatureVerificationBehavior, fallbackSettings.RevocationMode, repositoryAllowList?.AsReadOnly(), fallbackSettings.ClientCertificateList)); } }
/// <summary> /// Gets SignedPackageVerifierSettings from a given RepositorySignatureInfo. /// </summary> /// <param name="repoSignatureInfo">RepositorySignatureInfo to be used.</param> /// <param name="fallbackSettings">SignedPackageVerifierSettings to be used if RepositorySignatureInfo is unavailable.</param> /// <returns>SignedPackageVerifierSettings based on the RepositorySignatureInfo and SignedPackageVerifierSettings.</returns> public static SignedPackageVerifierSettings GetSignedPackageVerifierSettings( RepositorySignatureInfo repoSignatureInfo, SignedPackageVerifierSettings fallbackSettings) { if (fallbackSettings == null) { throw new ArgumentNullException(nameof(fallbackSettings)); } if (repoSignatureInfo == null) { return(fallbackSettings); } else { var repositoryAllowList = GetRepositoryAllowList(repoSignatureInfo.RepositoryCertificateInfos); // Allow unsigned only if the common settings allow it and repository does not have all packages signed var allowUnsigned = fallbackSettings.AllowUnsigned && !repoSignatureInfo.AllRepositorySigned; // Allow an empty repository certificate list only if the repository does not have all packages signed var allowNoRepositoryCertificateList = !repoSignatureInfo.AllRepositorySigned; return(new SignedPackageVerifierSettings( allowUnsigned: allowUnsigned, allowIllegal: fallbackSettings.AllowIllegal, allowUntrusted: fallbackSettings.AllowUntrusted, allowUntrustedSelfIssuedCertificate: fallbackSettings.AllowUntrustedSelfIssuedCertificate, allowIgnoreTimestamp: fallbackSettings.AllowIgnoreTimestamp, allowMultipleTimestamps: fallbackSettings.AllowMultipleTimestamps, allowNoTimestamp: fallbackSettings.AllowNoTimestamp, allowUnknownRevocation: fallbackSettings.AllowUnknownRevocation, allowNoRepositoryCertificateList: allowNoRepositoryCertificateList, allowNoClientCertificateList: fallbackSettings.AllowNoClientCertificateList, repoAllowListEntries: repositoryAllowList?.AsReadOnly(), clientAllowListEntries: fallbackSettings.ClientCertificateList)); } }
/// <summary> /// /// </summary> /// <param name="allowMultipleTimestamps"></param> /// <param name="allowIgnoreTimestamp"></param> /// <param name="allowNoTimestamp"></param> /// <param name="allowUnknownRevocation"></param> /// <param name="issues"></param> /// <returns></returns> internal Timestamp GetValidTimestamp( SignedPackageVerifierSettings settings, HashAlgorithmName fingerprintAlgorithm, List <SignatureLog> issues) { if (issues == null) { throw new ArgumentNullException(nameof(issues)); } var timestamps = Timestamps; settings = settings ?? SignedPackageVerifierSettings.Default; if (timestamps.Count == 0) { issues.Add(SignatureLog.Issue(!settings.AllowNoTimestamp, NuGetLogCode.NU3027, Strings.ErrorNoTimestamp)); if (!settings.AllowNoTimestamp) { throw new TimestampException(Strings.TimestampInvalid); } } if (timestamps.Count > 1 && !settings.AllowMultipleTimestamps) { issues.Add(SignatureLog.Issue(true, NuGetLogCode.NU3000, Strings.ErrorMultipleTimestamps)); throw new TimestampException(Strings.TimestampInvalid); } var timestamp = timestamps.FirstOrDefault(); if (timestamp != null && !timestamp.Verify(this, settings, fingerprintAlgorithm, issues) && !settings.AllowIgnoreTimestamp) { throw new TimestampException(Strings.TimestampInvalid); } return(timestamp); }
private SignatureVerificationSummary GetTimestamp( Signature signature, SignedPackageVerifierSettings verifierSettings, out Timestamp timestamp) { var issues = new List <SignatureLog>(); SignatureVerificationStatus status; SignatureVerificationStatusFlags statusFlags; var succeeded = signature.TryGetValidTimestamp(verifierSettings, _fingerprintAlgorithm, issues, out statusFlags, out timestamp); status = VerificationUtility.GetSignatureVerificationStatus(statusFlags); if (!succeeded) { if (statusFlags == SignatureVerificationStatusFlags.NoValidTimestamp || statusFlags == SignatureVerificationStatusFlags.MultipleTimestamps) { status = SignatureVerificationStatus.Disallowed; } } return(new SignatureVerificationSummary(signature.Type, status, statusFlags, issues)); }
private PackageVerificationResult VerifyValidityAndTrust(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings) { throw new NotSupportedException(); }
private PackageVerificationResult VerifyValidityAndTrust(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings) { var issues = new List <SignatureLog> { SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.SignatureType, signature.Type.ToString())) }; Timestamp validTimestamp; try { validTimestamp = GetValidTimestamp(signature, !settings.FailWithMultipleTimestamps, !settings.AllowIgnoreTimestamp, !settings.AllowNoTimestamp, issues); } catch (TimestampException) { return(new SignedPackageVerificationResult(SignatureVerificationStatus.Invalid, signature, issues)); } var status = VerifySignature(signature, validTimestamp, !settings.AllowUntrusted, issues); return(new SignedPackageVerificationResult(status, signature, issues)); }
private PackageVerificationResult VerifyValidityAndTrust(PrimarySignature signature, SignedPackageVerifierSettings settings) { var timestampIssues = new List <SignatureLog>(); Timestamp validTimestamp; try { validTimestamp = signature.GetValidTimestamp( settings, _fingerprintAlgorithm, timestampIssues); } catch (TimestampException) { return(new SignedPackageVerificationResult(SignatureVerificationStatus.Invalid, signature, timestampIssues)); } var certificateExtraStore = signature.SignedCms.Certificates; var signatureIssues = new List <SignatureLog>(); var status = signature.Verify( validTimestamp, settings, _fingerprintAlgorithm, certificateExtraStore, signatureIssues); signatureIssues.AddRange(timestampIssues); return(new SignedPackageVerificationResult(status, signature, signatureIssues)); }
public Task <PackageVerificationResult> GetTrustResultAsync(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings, CancellationToken token) { token.ThrowIfCancellationRequested(); var result = VerifyValidityAndTrust(package, signature, settings); return(Task.FromResult(result)); }
/// <summary> /// True if a provider trusts the package signature. /// </summary> private static bool IsValid(IEnumerable <PackageVerificationResult> verificationResults, SignedPackageVerifierSettings settings) { var hasItems = verificationResults.Any(); var valid = verificationResults.All(e => e.Trust == SignatureVerificationStatus.Valid || (settings.AllowIllegal && SignatureVerificationStatus.Illegal == e.Trust) || (settings.AllowUntrusted && SignatureVerificationStatus.Untrusted == e.Trust)); return(valid && hasItems); }
private PackageVerificationResult VerifyAllowList(ISignedPackageReader package, PrimarySignature signature, SignedPackageVerifierSettings settings) { throw new NotSupportedException(); }
private PackageVerificationResult VerifyAllowList(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings) { var status = SignatureVerificationStatus.Trusted; var issues = new List <SignatureLog>(); if (_allowList.Count() > 0 && !IsSignatureAllowed(signature)) { status = SignatureVerificationStatus.Invalid; issues.Add(SignatureLog.Issue(fatal: true, code: NuGetLogCode.NU3003, message: string.Format(CultureInfo.CurrentCulture, Strings.Error_NoMatchingCertificate, _fingerprintAlgorithm.ToString()))); } return(new SignedPackageVerificationResult(status, signature, issues)); }
private async Task <PackageVerificationResult> VerifyPackageIntegrityAsync(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings) { var status = SignatureVerificationStatus.Untrusted; var issues = new List <SignatureLog>(); var validHashOids = SigningSpecifications.V1.AllowedHashAlgorithmOids; var signatureHashOid = signature.SignatureContent.HashAlgorithm.ConvertToOidString(); if (validHashOids.Contains(signatureHashOid, StringComparer.InvariantCultureIgnoreCase)) { issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.SignatureHashAlgorithm, signature.SignatureContent.HashAlgorithm))); try { await package.ValidateIntegrityAsync(signature.SignatureContent, CancellationToken.None); status = SignatureVerificationStatus.Trusted; } catch (Exception e) { status = SignatureVerificationStatus.Invalid; issues.Add(SignatureLog.Issue(true, NuGetLogCode.NU3008, Strings.SignaturePackageIntegrityFailure)); issues.Add(SignatureLog.DebugLog(e.ToString())); } } else { issues.Add(SignatureLog.Issue(!settings.AllowUntrusted, NuGetLogCode.NU3016, Strings.SignatureFailureInvalidHashAlgorithmOid)); issues.Add(SignatureLog.DebugLog(string.Format(CultureInfo.CurrentCulture, Strings.SignatureDebug_HashOidFound, signatureHashOid))); } return(new SignedPackageVerificationResult(status, signature, issues)); }
private PackageVerificationResult Verify( PrimarySignature signature, SignedPackageVerifierSettings settings) { throw new NotSupportedException(); }
public Task <PackageVerificationResult> GetTrustResultAsync(ISignedPackageReader package, PrimarySignature signature, SignedPackageVerifierSettings settings, CancellationToken token) { return(Task.FromResult(VerifyAllowList(package, signature, settings))); }
/// <summary> /// True if a provider trusts the package signature. /// </summary> private static bool IsValid(IEnumerable <PackageVerificationResult> verificationResults, SignedPackageVerifierSettings settings) { return(verificationResults.Any() && verificationResults.All(e => e.Trust == SignatureVerificationStatus.Valid)); }
public PackageSignatureVerifier(IEnumerable <ISignatureVerificationProvider> verificationProviders, SignedPackageVerifierSettings settings) { _verificationProviders = verificationProviders?.ToList() ?? throw new ArgumentNullException(nameof(verificationProviders)); _settings = settings ?? throw new ArgumentNullException(nameof(settings)); }
private Task <PackageVerificationResult> VerifyPackageIntegrityAsync(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings) { throw new NotSupportedException(); }
/// <summary> /// Verify if the timestamp object meets the specification requirements. /// </summary> /// <param name="signature">Signature which this timestamp is for.</param> /// <param name="allowIgnoreTimestamp">Setting that tells if a timestamp can be ignored if it doesn't meet the requirements. Used to know if warnings or errors should be logged for an issue.</param> /// <param name="allowUnknownRevocation">Setting that tells if unkown revocation is valid when building the chain.</param> /// <param name="issues">List of log messages.</param> /// <returns>true if the timestamp meets the requierements, false otherwise.</returns> internal SignatureVerificationStatusFlags Verify( Signature signature, SignedPackageVerifierSettings settings, HashAlgorithmName fingerprintAlgorithm, List <SignatureLog> issues) { settings = settings ?? SignedPackageVerifierSettings.GetDefault(); var flags = SignatureVerificationStatusFlags.NoErrors; if (signature == null) { throw new ArgumentNullException(nameof(signature)); } if (issues == null) { throw new ArgumentNullException(nameof(issues)); } var treatIssueAsError = !settings.AllowIgnoreTimestamp; var timestamperCertificate = SignerInfo.Certificate; if (timestamperCertificate == null) { flags |= SignatureVerificationStatusFlags.NoCertificate; issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3020, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampNoCertificate, signature.FriendlyName))); return(flags); } flags |= VerificationUtility.ValidateTimestamp(this, signature, treatIssueAsError, issues, SigningSpecifications.V1); if (flags == SignatureVerificationStatusFlags.NoErrors) { issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.TimestampValue, GeneralizedTime.LocalDateTime.ToString()) + Environment.NewLine)); issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.VerificationTimestamperCertDisplay, signature.FriendlyName, $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(timestamperCertificate, fingerprintAlgorithm)}"))); var certificateExtraStore = SignedCms.Certificates; using (var chainHolder = new X509ChainHolder()) { var chain = chainHolder.Chain; // This flag should only be set for verification scenarios, not signing. chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid; CertificateChainUtility.SetCertBuildChainPolicy(chain.ChainPolicy, certificateExtraStore, DateTime.Now, CertificateType.Timestamp); if (settings.RevocationMode == RevocationMode.Offline) { chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; } else { chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; } var chainBuildSucceed = CertificateChainUtility.BuildCertificateChain(chain, timestamperCertificate, out var chainStatusList); var x509ChainString = CertificateUtility.X509ChainToString(chain, fingerprintAlgorithm); if (!string.IsNullOrWhiteSpace(x509ChainString)) { issues.Add(SignatureLog.DetailedLog(x509ChainString)); } if (chainBuildSucceed) { return(flags); } var chainBuildingHasIssues = false; IEnumerable <string> messages; var timestampInvalidCertificateFlags = CertificateChainUtility.DefaultObservedStatusFlags; if (CertificateChainUtility.TryGetStatusMessage(chainStatusList, timestampInvalidCertificateFlags, out messages)) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3028, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, message))); } flags |= SignatureVerificationStatusFlags.ChainBuildingFailure; chainBuildingHasIssues = true; } // For all the special cases, chain status list only has unique elements for each chain status flag present // therefore if we are checking for one specific chain status we can use the first of the returned list // if we are combining checks for more than one, then we have to use the whole list. if (CertificateChainUtility.TryGetStatusMessage(chainStatusList, X509ChainStatusFlags.UntrustedRoot, out messages)) { issues.Add(SignatureLog.Error(NuGetLogCode.NU3028, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, messages.First()))); flags |= SignatureVerificationStatusFlags.UntrustedRoot; chainBuildingHasIssues = true; } if (CertificateChainUtility.TryGetStatusMessage(chainStatusList, X509ChainStatusFlags.Revoked, out messages)) { issues.Add(SignatureLog.Error(NuGetLogCode.NU3028, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, messages.First()))); flags |= SignatureVerificationStatusFlags.CertificateRevoked; return(flags); } var offlineRevocationErrors = CertificateChainUtility.TryGetStatusMessage(chainStatusList, X509ChainStatusFlags.OfflineRevocation, out var _); var unknownRevocationErrors = CertificateChainUtility.TryGetStatusMessage(chainStatusList, X509ChainStatusFlags.RevocationStatusUnknown, out var unknownRevocationStatusMessages); if (offlineRevocationErrors || unknownRevocationErrors) { if (treatIssueAsError) { string unknownRevocationMessage = null; if (unknownRevocationErrors) { unknownRevocationMessage = string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, unknownRevocationStatusMessages.First()); } if (settings.RevocationMode == RevocationMode.Offline) { if (offlineRevocationErrors) { issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, Strings.VerifyCertTrustOfflineWhileRevocationModeOffline))); } if (unknownRevocationMessage != null) { issues.Add(SignatureLog.InformationLog(unknownRevocationMessage)); } } else { if (offlineRevocationErrors) { issues.Add(SignatureLog.Issue(!settings.AllowUnknownRevocation, NuGetLogCode.NU3018, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, Strings.VerifyCertTrustOfflineWhileRevocationModeOnline))); } if (unknownRevocationMessage != null) { issues.Add(SignatureLog.Issue(!settings.AllowUnknownRevocation, NuGetLogCode.NU3018, unknownRevocationMessage)); } } } if (!chainBuildingHasIssues && (settings.AllowIgnoreTimestamp || settings.AllowUnknownRevocation)) { return(flags); } flags |= SignatureVerificationStatusFlags.UnknownRevocation; chainBuildingHasIssues = true; } // Debug log any errors issues.Add( SignatureLog.DebugLog( string.Format( CultureInfo.CurrentCulture, $"{signature.FriendlyName}'s timestamp", Strings.VerifyError_InvalidCertificateChain, string.Join(", ", chainStatusList.Select(x => x.Status.ToString()))))); } } return(flags); }
/// <summary> /// Verify if the signature object meets the specification trust and validity requirements. /// </summary> /// <param name="timestamp">Timestamp for this signature, if signature is not timestamped it can be null.</param> /// <param name="allowUntrusted">Setting that tells if a signature that does not meet any soft failure requirements can still be allowed. Used to know if warnings or errors should be logged for an issue.</param> /// <param name="allowUnknownRevocation">Setting that tells if unkown revocation is valid when building the chain.</param> /// <param name="allowUntrustedSelfSignedCertificate">Setting that tells if an untrusted self-signed certificate should be allowed as the signing certificate.</param> /// <param name="fingerprintAlgorithm">Algorithm used to calculate and display the certificate's fingerprint.</param> /// <param name="certificateExtraStore">Collection of certificates to help the chain building engine as an extra store.</param> /// <param name="issues">List of log messages.</param> /// <returns>Status of trust for signature.</returns> internal virtual SignatureVerificationStatus Verify( Timestamp timestamp, SignedPackageVerifierSettings settings, HashAlgorithmName fingerprintAlgorithm, X509Certificate2Collection certificateExtraStore, List <SignatureLog> issues) { if (issues == null) { throw new ArgumentNullException(nameof(issues)); } settings = settings ?? SignedPackageVerifierSettings.Default; var treatIssueAsError = !settings.AllowUntrusted; var certificate = SignerInfo.Certificate; if (certificate == null) { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3010, Strings.ErrorNoCertificate)); return(SignatureVerificationStatus.Invalid); } issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.VerificationAuthorCertDisplay, $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(certificate, fingerprintAlgorithm)}"))); try { SignerInfo.CheckSignature(verifySignatureOnly: true); } catch (Exception e) { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3012, Strings.ErrorSignatureVerificationFailed)); issues.Add(SignatureLog.DebugLog(e.ToString())); return(SignatureVerificationStatus.Invalid); } if (VerificationUtility.IsSigningCertificateValid(certificate, treatIssueAsError, issues)) { timestamp = timestamp ?? new Timestamp(); if (Rfc3161TimestampVerificationUtility.ValidateSignerCertificateAgainstTimestamp(certificate, timestamp)) { using (var chainHolder = new X509ChainHolder()) { var chain = chainHolder.Chain; // These flags should only be set for verification scenarios not signing chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.IgnoreCtlNotTimeValid; CertificateChainUtility.SetCertBuildChainPolicy(chain.ChainPolicy, certificateExtraStore, timestamp.UpperLimit.LocalDateTime, CertificateType.Signature); var chainBuildingSucceed = CertificateChainUtility.BuildCertificateChain(chain, certificate, out var chainStatuses); issues.Add(SignatureLog.DetailedLog(CertificateUtility.X509ChainToString(chain, fingerprintAlgorithm))); if (chainBuildingSucceed) { return(SignatureVerificationStatus.Trusted); } var chainBuildingHasIssues = false; var statusFlags = CertificateChainUtility.DefaultObservedStatusFlags; var isSelfSignedCertificate = CertificateUtility.IsSelfIssued(certificate); if (isSelfSignedCertificate) { statusFlags &= ~X509ChainStatusFlags.UntrustedRoot; } IEnumerable <string> messages; if (CertificateChainUtility.TryGetStatusMessage(chainStatuses, statusFlags, out messages)) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3012, message)); } chainBuildingHasIssues = true; } // For all the special cases, chain status list only has unique elements for each chain status flag present // therefore if we are checking for one specific chain status we can use the first of the returned list // if we are combining checks for more than one, then we have to use the whole list. IEnumerable <X509ChainStatus> chainStatus = null; if (CertificateChainUtility.ChainStatusListIncludesStatus(chainStatuses, X509ChainStatusFlags.Revoked, out chainStatus)) { var status = chainStatus.First(); issues.Add(SignatureLog.Error(NuGetLogCode.NU3012, status.StatusInformation)); return(SignatureVerificationStatus.Invalid); } if (isSelfSignedCertificate && CertificateChainUtility.TryGetStatusMessage(chainStatuses, X509ChainStatusFlags.UntrustedRoot, out messages)) { issues.Add(SignatureLog.Issue(!settings.AllowUntrustedSelfIssuedCertificate, NuGetLogCode.NU3018, messages.First())); if (!chainBuildingHasIssues && settings.AllowUntrustedSelfIssuedCertificate) { return(SignatureVerificationStatus.Trusted); } } const X509ChainStatusFlags RevocationStatusFlags = X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation; if (CertificateChainUtility.TryGetStatusMessage(chainStatuses, RevocationStatusFlags, out messages)) { if (treatIssueAsError) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(!settings.AllowUnknownRevocation, NuGetLogCode.NU3018, message)); } } if (!chainBuildingHasIssues && settings.AllowUnknownRevocation) { return(SignatureVerificationStatus.Trusted); } chainBuildingHasIssues = true; } // Debug log any errors issues.Add(SignatureLog.DebugLog( string.Format( CultureInfo.CurrentCulture, Strings.ErrorInvalidCertificateChain, string.Join(", ", chainStatuses.Select(x => x.Status.ToString()))))); } } else { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3011, Strings.SignatureNotTimeValid)); } } return(SignatureVerificationStatus.Untrusted); }
private async Task <PackageVerificationResult> VerifyAllowListAsync(ISignedPackageReader package, PrimarySignature signature, SignedPackageVerifierSettings settings) { var treatIssuesAsErrors = !settings.AllowUntrusted; var certificateListVertificationRequests = new List <CertificateListVerificationRequest>() { new CertificateListVerificationRequest() { CertificateList = settings.ClientCertificateList, RequireCertificateList = !settings.AllowNoClientCertificateList, NoListErrorMessage = Strings.Error_NoClientAllowList, NoMatchErrorMessage = Strings.Error_NoMatchingClientCertificate, Signature = signature, TreatIssuesAsErros = treatIssuesAsErrors }, new CertificateListVerificationRequest() { CertificateList = settings.RepositoryCertificateList, RequireCertificateList = !settings.AllowNoRepositoryCertificateList, NoListErrorMessage = Strings.Error_NoRepoAllowList, NoMatchErrorMessage = Strings.Error_NoMatchingRepositoryCertificate, Signature = signature, TreatIssuesAsErros = treatIssuesAsErrors } }; var allowListResults = await Task.WhenAll(certificateListVertificationRequests.Select(r => VerifyAllowList(r))); return(new SignedPackageVerificationResult(GetValidity(allowListResults), signature, GetIssues(allowListResults))); }
public Task <PackageVerificationResult> GetTrustResultAsync(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings, CancellationToken token) { return(VerifyPackageIntegrityAsync(package, signature, settings)); }
private PackageVerificationResult Verify( PrimarySignature signature, SignedPackageVerifierSettings settings) { var certificateExtraStore = signature.SignedCms.Certificates; var repositoryCountersignatureExists = SignatureUtility.HasRepositoryCountersignature(signature); var isRepositoryCountersignatureVerificationRequested = settings.VerificationTarget.HasFlag(VerificationTarget.Repository) && settings.SignaturePlacement.HasFlag(SignaturePlacement.Countersignature); var allowDeferralToRepositoryCountersignature = isRepositoryCountersignatureVerificationRequested && repositoryCountersignatureExists; var status = SignatureVerificationStatus.Unknown; var issues = Enumerable.Empty <SignatureLog>(); var isUntrustedRootAllowed = IsUntrustedRootAllowed(signature); var verifySettings = new SignatureVerifySettings( allowIllegal: settings.AllowIllegal, allowUntrusted: settings.AllowUntrusted || isUntrustedRootAllowed, allowUnknownRevocation: settings.AllowUnknownRevocation, reportUnknownRevocation: settings.ReportUnknownRevocation, reportUntrustedRoot: !isUntrustedRootAllowed, revocationMode: settings.RevocationMode); SignatureVerificationSummary primarySummary = null; if (settings.SignaturePlacement.HasFlag(SignaturePlacement.PrimarySignature) && VerificationUtility.IsVerificationTarget(signature.Type, settings.VerificationTarget)) { primarySummary = VerifyValidityAndTrust(signature, settings, verifySettings, certificateExtraStore); issues = issues.Concat(primarySummary.Issues); status = primarySummary.Status; } Debug.Assert(isRepositoryCountersignatureVerificationRequested != (settings.RepositoryCountersignatureVerificationBehavior == SignatureVerificationBehavior.Never)); bool shouldVerifyRepositoryCountersignature; switch (settings.RepositoryCountersignatureVerificationBehavior) { case SignatureVerificationBehavior.IfExists: shouldVerifyRepositoryCountersignature = isRepositoryCountersignatureVerificationRequested && repositoryCountersignatureExists; break; case SignatureVerificationBehavior.IfExistsAndIsNecessary: // The repository countersignature should be evaluated if settings allow it, if a repository countersignature exists // and if either settings only allow a repository countersignature to be evaluated or the primary signature has some // validation/trust issues that may benefit from a repository countersignature fallback. shouldVerifyRepositoryCountersignature = isRepositoryCountersignatureVerificationRequested && repositoryCountersignatureExists && (primarySummary == null || (primarySummary != null && (HasUntrustedRoot(primarySummary) || IsSignatureExpired(primarySummary)))); break; case SignatureVerificationBehavior.Always: shouldVerifyRepositoryCountersignature = isRepositoryCountersignatureVerificationRequested; break; case SignatureVerificationBehavior.Never: shouldVerifyRepositoryCountersignature = false; break; default: throw new NotImplementedException(); } if (shouldVerifyRepositoryCountersignature) { var countersignature = RepositoryCountersignature.GetRepositoryCountersignature(signature); if (countersignature == null) { if (settings.RepositoryCountersignatureVerificationBehavior == SignatureVerificationBehavior.Always) { issues = issues.Concat(new[] { SignatureLog.Error(NuGetLogCode.NU3038, Strings.NoRepositoryCountersignature) }); status = SignatureVerificationStatus.Disallowed; } } else { isUntrustedRootAllowed = IsUntrustedRootAllowed(countersignature); verifySettings = new SignatureVerifySettings( allowIllegal: settings.AllowIllegal, allowUntrusted: settings.AllowUntrusted || isUntrustedRootAllowed, allowUnknownRevocation: settings.AllowUnknownRevocation, reportUnknownRevocation: settings.ReportUnknownRevocation, reportUntrustedRoot: !isUntrustedRootAllowed, revocationMode: settings.RevocationMode); var countersignatureSummary = VerifyValidityAndTrust(countersignature, settings, verifySettings, certificateExtraStore); if (primarySummary == null) { status = countersignatureSummary.Status; } else { if (countersignatureSummary.Status == SignatureVerificationStatus.Valid) { if (IsSignatureExpired(primarySummary) && HasUntrustedRoot(primarySummary)) { // Exclude the issue of the primary signature being untrusted since the repository countersignature fulfills the role of a trust anchor. issues = issues.Where(log => log.Code != NuGetLogCode.NU3018); if (countersignatureSummary.Timestamp != null && Rfc3161TimestampVerificationUtility.ValidateSignerCertificateAgainstTimestamp(signature.SignerInfo.Certificate, countersignatureSummary.Timestamp)) { // Exclude the issue of the primary signature being expired since the repository countersignature fulfills the role of a trusted timestamp. issues = issues.Where(log => log.Code != NuGetLogCode.NU3037); status = SignatureVerificationStatus.Valid; } } else if (IsSignatureExpired(primarySummary) && countersignatureSummary.Timestamp != null && Rfc3161TimestampVerificationUtility.ValidateSignerCertificateAgainstTimestamp(signature.SignerInfo.Certificate, countersignatureSummary.Timestamp)) { // Exclude the issue of the primary signature being expired since the repository countersignature fulfills the role of a trusted timestamp. issues = issues.Where(log => log.Code != NuGetLogCode.NU3037); status = SignatureVerificationStatus.Valid; } else if (HasUntrustedRoot(primarySummary)) { // Exclude the issue of the primary signature being untrusted since the repository countersignature fulfills the role of a trust anchor. issues = issues.Where(log => log.Code != NuGetLogCode.NU3018); status = SignatureVerificationStatus.Valid; } } // Both the primary signature and the repository countersignature were evaluated. // The overall status should be the more severe status of the two. status = (SignatureVerificationStatus)Math.Min((int)status, (int)countersignatureSummary.Status); } issues = issues.Concat(countersignatureSummary.Issues); } } return(new SignedPackageVerificationResult(status, signature, issues)); }
/// <summary> /// Verify if the timestamp object meets the specification requirements. /// </summary> /// <param name="signature">Signature which this timestamp is for.</param> /// <param name="allowIgnoreTimestamp">Setting that tells if a timestamp can be ignored if it doesn't meet the requirements. Used to know if warnings or errors should be logged for an issue.</param> /// <param name="allowUnknownRevocation">Setting that tells if unkown revocation is valid when building the chain.</param> /// <param name="issues">List of log messages.</param> /// <returns>true if the timestamp meets the requierements, false otherwise.</returns> internal bool Verify( Signature signature, SignedPackageVerifierSettings settings, HashAlgorithmName fingerprintAlgorithm, List <SignatureLog> issues) { settings = settings ?? SignedPackageVerifierSettings.GetDefault(); if (signature == null) { throw new ArgumentNullException(nameof(signature)); } if (issues == null) { throw new ArgumentNullException(nameof(issues)); } var treatIssueAsError = !settings.AllowIgnoreTimestamp; var timestamperCertificate = SignerInfo.Certificate; if (timestamperCertificate == null) { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3020, Strings.TimestampNoCertificate)); return(false); } if (VerificationUtility.IsTimestampValid(this, signature, treatIssueAsError, issues, SigningSpecifications.V1)) { issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.TimestampValue, GeneralizedTime.LocalDateTime.ToString()) + Environment.NewLine)); issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.VerificationTimestamperCertDisplay, $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(timestamperCertificate, fingerprintAlgorithm)}"))); var certificateExtraStore = SignedCms.Certificates; using (var chainHolder = new X509ChainHolder()) { var chain = chainHolder.Chain; // This flags should only be set for verification scenarios, not signing chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.IgnoreCtlNotTimeValid; CertificateChainUtility.SetCertBuildChainPolicy(chain.ChainPolicy, certificateExtraStore, DateTime.Now, CertificateType.Timestamp); var chainBuildSucceed = CertificateChainUtility.BuildCertificateChain(chain, timestamperCertificate, out var chainStatusList); issues.Add(SignatureLog.DetailedLog(CertificateUtility.X509ChainToString(chain, fingerprintAlgorithm))); if (chainBuildSucceed) { return(true); } var chainBuildingHasIssues = false; IEnumerable <string> messages; var timestampInvalidCertificateFlags = CertificateChainUtility.DefaultObservedStatusFlags | (X509ChainStatusFlags.Revoked) | (X509ChainStatusFlags.NotTimeValid) | (X509ChainStatusFlags.CtlNotTimeValid); if (CertificateChainUtility.TryGetStatusMessage(chainStatusList, timestampInvalidCertificateFlags, out messages)) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(treatIssueAsError, NuGetLogCode.NU3028, message)); } chainBuildingHasIssues = true; } // For all the special cases, chain status list only has unique elements for each chain status flag present // therefore if we are checking for one specific chain status we can use the first of the returned list // if we are combining checks for more than one, then we have to use the whole list. const X509ChainStatusFlags RevocationStatusFlags = X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation; if (CertificateChainUtility.TryGetStatusMessage(chainStatusList, RevocationStatusFlags, out messages)) { if (treatIssueAsError) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(!settings.AllowUnknownRevocation, NuGetLogCode.NU3028, message)); } } if (!chainBuildingHasIssues && (settings.AllowIgnoreTimestamp || settings.AllowUnknownRevocation)) { return(true); } chainBuildingHasIssues = true; } // Debug log any errors issues.Add( SignatureLog.DebugLog( string.Format( CultureInfo.CurrentCulture, Strings.ErrorInvalidCertificateChain, string.Join(", ", chainStatusList.Select(x => x.Status.ToString()))))); } } return(false); }
private PackageVerificationResult VerifyAllowList(ISignedPackageReader package, PrimarySignature signature, SignedPackageVerifierSettings settings) { var treatIssuesAsErrors = !settings.AllowUntrusted; var status = SignatureVerificationStatus.Valid; var issues = new List <SignatureLog>(); if (_allowList == null || _allowList.Count == 0) { if (_requireNonEmptyAllowList) { status = SignatureVerificationStatus.Disallowed; issues.Add(SignatureLog.Error(code: NuGetLogCode.NU3034, message: _emptyListErrorMessage)); } } else if (!IsSignatureAllowed(signature, _allowList)) { if (!settings.AllowUntrusted) { status = SignatureVerificationStatus.Disallowed; } issues.Add(SignatureLog.Issue(fatal: treatIssuesAsErrors, code: NuGetLogCode.NU3034, message: _noMatchErrorMessage)); } return(new SignedPackageVerificationResult(status, signature, issues)); }
public async Task <VerifySignaturesResult> VerifySignaturesAsync(ISignedPackageReader package, SignedPackageVerifierSettings settings, CancellationToken token, Guid parentId = default(Guid)) { if (package == null) { throw new ArgumentNullException(nameof(package)); } if (settings == null) { throw new ArgumentNullException(nameof(settings)); } var valid = false; var trustResults = new List <PackageVerificationResult>(); var packageSigningTelemetryEvent = new PackageSigningTelemetryEvent(); using (var telemetry = TelemetryActivity.Create(parentId, packageSigningTelemetryEvent)) { var isSigned = await package.IsSignedAsync(token); if (isSigned) { try { var signature = await package.GetPrimarySignatureAsync(token); if (signature != null) { // Verify that the signature is trusted var sigTrustResults = await Task.WhenAll(_verificationProviders.Select(e => e.GetTrustResultAsync(package, signature, settings, token))); valid = IsValid(sigTrustResults); trustResults.AddRange(sigTrustResults); } else { valid = false; } } catch (SignatureException e) { // SignatureException generated while parsing signatures var issues = new[] { SignatureLog.Issue(!settings.AllowIllegal, e.Code, e.Message), SignatureLog.DebugLog(e.ToString()) }; trustResults.Add(new InvalidSignaturePackageVerificationResult( settings.AllowIllegal ? SignatureVerificationStatus.Valid : SignatureVerificationStatus.Disallowed, issues)); valid = settings.AllowIllegal; } catch (CryptographicException e) { // CryptographicException generated while parsing the SignedCms object var issues = new[] { SignatureLog.Issue(!settings.AllowIllegal, NuGetLogCode.NU3003, Strings.ErrorPackageSignatureInvalid), SignatureLog.DebugLog(e.ToString()) }; trustResults.Add(new InvalidSignaturePackageVerificationResult( settings.AllowIllegal ? SignatureVerificationStatus.Valid : SignatureVerificationStatus.Disallowed, issues)); valid = settings.AllowIllegal; } } else if (settings.AllowUnsigned) { // An unsigned package is valid only if unsigned packages are allowed. valid = true; } else { var issues = new[] { SignatureLog.Issue(fatal: true, code: NuGetLogCode.NU3004, message: Strings.ErrorPackageNotSigned) }; trustResults.Add(new UnsignedPackageVerificationResult( settings.AllowIllegal ? SignatureVerificationStatus.Valid : SignatureVerificationStatus.Disallowed, issues)); valid = false; } var status = valid ? NuGetOperationStatus.Succeeded : NuGetOperationStatus.Failed; packageSigningTelemetryEvent.SetResult(isSigned ? PackageSignType.Signed : PackageSignType.Unsigned, status); return(new VerifySignaturesResult(valid, isSigned, trustResults)); } }