Beispiel #1
0
        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));
            }
        }
Beispiel #5
0
        /// <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));
            }
        }
Beispiel #6
0
        /// <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));
        }
Beispiel #8
0
 private PackageVerificationResult VerifyValidityAndTrust(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings)
 {
     throw new NotSupportedException();
 }
Beispiel #9
0
        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));
        }
Beispiel #10
0
        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));
        }
Beispiel #11
0
        public Task <PackageVerificationResult> GetTrustResultAsync(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            var result = VerifyValidityAndTrust(package, signature, settings);

            return(Task.FromResult(result));
        }
Beispiel #12
0
        /// <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));
        }
Beispiel #15
0
        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));
 }
Beispiel #20
0
 private Task <PackageVerificationResult> VerifyPackageIntegrityAsync(ISignedPackageReader package, Signature signature, SignedPackageVerifierSettings settings)
 {
     throw new NotSupportedException();
 }
Beispiel #21
0
        /// <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);
        }
Beispiel #22
0
        /// <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);
        }
Beispiel #23
0
        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)));
        }
Beispiel #24
0
 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));
        }
Beispiel #26
0
        /// <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));
        }
Beispiel #28
0
        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));
            }
        }