internal SignatureVerificationStatusFlags Verify()

in src/NuGet.Core/NuGet.Packaging/Signing/Timestamp/Timestamp.cs [99:280]


        internal SignatureVerificationStatusFlags Verify(
            Signature signature,
            SignedPackageVerifierSettings settings,
            HashAlgorithmName fingerprintAlgorithm,
            List<SignatureLog> issues)
        {
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            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, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampNoCertificate, signature.FriendlyName)));
                return SignatureVerificationStatusFlags.NoCertificate;
            }

            var timestampFlags = VerificationUtility.ValidateTimestamp(this, signature, treatIssueAsError, issues, SigningSpecifications.V1);
            if (timestampFlags != SignatureVerificationStatusFlags.NoErrors)
            {
                return timestampFlags;
            }
            else
            {
                issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.TimestampValue, GeneralizedTime.LocalDateTime.ToString(CultureInfo.CurrentCulture)) + Environment.NewLine));

                issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture,
                    Strings.VerificationTimestamperCertDisplay,
                    signature.FriendlyName,
                    $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(timestamperCertificate, fingerprintAlgorithm)}")));

                SignatureVerificationStatusFlags flags = SignatureVerificationStatusFlags.NoErrors;
                var certificateExtraStore = SignedCms.Certificates;

                using (X509ChainHolder chainHolder = X509ChainHolder.CreateForTimestamping())
                {
                    IX509Chain chain = chainHolder.Chain2;

                    // 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);
                    string x509ChainString = CertificateUtility.X509ChainToString(chain.PrivateReference, fingerprintAlgorithm);

                    if (!string.IsNullOrWhiteSpace(x509ChainString))
                    {
                        issues.Add(SignatureLog.DetailedLog(x509ChainString));
                    }

                    if (chainBuildSucceed)
                    {
                        return SignatureVerificationStatusFlags.NoErrors;
                    }
                    else if (chainStatusList.Length == 0)
                    {
                        return SignatureVerificationStatusFlags.UnknownBuildStatus;
                    }
                    else
                    {
                        var chainBuildingHasIssues = false;
                        IEnumerable<string> messages;

                        var timestampInvalidCertificateFlags = CertificateChainUtility.DefaultObservedStatusFlags;

                        if (CertificateChainUtility.TryGetStatusAndMessage(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.TryGetStatusAndMessage(chainStatusList, X509ChainStatusFlags.UntrustedRoot, out messages))
                        {
                            SignatureUtility.LogAdditionalContext(chain, issues);

                            issues.Add(SignatureLog.Error(NuGetLogCode.NU3028, string.Format(CultureInfo.CurrentCulture, Strings.VerifyTimestampChainBuildingIssue_UntrustedRoot, signature.FriendlyName)));

                            flags |= SignatureVerificationStatusFlags.UntrustedRoot;
                            chainBuildingHasIssues = true;
                        }

                        if (CertificateChainUtility.TryGetStatusAndMessage(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.TryGetStatusAndMessage(chainStatusList, X509ChainStatusFlags.OfflineRevocation, out var _);
                        var unknownRevocationErrors = CertificateChainUtility.TryGetStatusAndMessage(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.NU3028, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampVerifyChainBuildingIssue, signature.FriendlyName, Strings.VerifyCertTrustOfflineWhileRevocationModeOnline)));
                                    }

                                    if (unknownRevocationMessage != null)
                                    {
                                        issues.Add(SignatureLog.Issue(!settings.AllowUnknownRevocation, NuGetLogCode.NU3028, unknownRevocationMessage));
                                    }

                                }
                            }

                            if (!chainBuildingHasIssues && (settings.AllowIgnoreTimestamp || settings.AllowUnknownRevocation))
                            {
                                return SignatureVerificationStatusFlags.NoErrors;
                            }

                            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;
            }
        }