private SignatureVerificationStatus VerifySignature(Signature signature, Timestamp timestamp, bool failuresAreFatal, List <SignatureLog> issues) { var certificate = signature.SignerInfo.Certificate; if (certificate != null) { issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.VerificationAuthorCertDisplay, $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(certificate)}"))); try { signature.SignerInfo.CheckSignature(verifySignatureOnly: true); } catch (Exception e) { issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3012, Strings.ErrorSignatureVerificationFailed)); issues.Add(SignatureLog.DebugLog(e.ToString())); return(SignatureVerificationStatus.Invalid); } if (!SigningUtility.IsCertificateValidityPeriodInTheFuture(certificate)) { timestamp = timestamp ?? new Timestamp(); if (Rfc3161TimestampVerificationUtility.ValidateSignerCertificateAgainstTimestamp(certificate, timestamp)) { // Read signed attribute containing the original cert hashes // var signingCertificateAttribute = signature.SignerInfo.SignedAttributes.GetAttributeOrDefault(Oids.SigningCertificateV2); // TODO: how are we going to use the signingCertificateAttribute? var certificateExtraStore = signature.SignedCms.Certificates; using (var chain = new X509Chain()) { // This flags should only be set for verification scenarios, not signing chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.IgnoreCtlNotTimeValid; SigningUtility.SetCertBuildChainPolicy(chain.ChainPolicy, certificateExtraStore, timestamp.UpperLimit.LocalDateTime, NuGetVerificationCertificateType.Signature); var chainBuildingSucceed = SigningUtility.BuildCertificateChain(chain, certificate, out var chainStatusList); issues.Add(SignatureLog.DetailedLog(CertificateUtility.X509ChainToString(chain))); if (chainBuildingSucceed) { return(SignatureVerificationStatus.Trusted); } var chainBuildingHasIssues = false; IReadOnlyList <string> messages; if (SigningUtility.TryGetStatusMessage(chainStatusList, SigningUtility.NotIgnoredCertificateFlags, out messages)) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3018, 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. IReadOnlyList <X509ChainStatus> chainStatus = null; if (SigningUtility.ChainStatusListIncludesStatus(chainStatusList, X509ChainStatusFlags.Revoked, out chainStatus)) { var status = chainStatus.First(); issues.Add(SignatureLog.Issue(true, NuGetLogCode.NU3018, status.StatusInformation)); return(SignatureVerificationStatus.Invalid); } const X509ChainStatusFlags RevocationStatusFlags = X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation; if (SigningUtility.TryGetStatusMessage(chainStatusList, RevocationStatusFlags, out messages)) { if (failuresAreFatal) { foreach (var message in messages) { issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3018, message)); } } else if (!chainBuildingHasIssues) { return(SignatureVerificationStatus.Trusted); } chainBuildingHasIssues = true; } // Debug log any errors issues.Add(SignatureLog.DebugLog(string.Format(CultureInfo.CurrentCulture, Strings.ErrorInvalidCertificateChain, string.Join(", ", chainStatusList.Select(x => x.ToString()))))); } } else { issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3012, Strings.ErrorSignatureVerificationFailed)); } } else { issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3017, Strings.SignatureNotYetValid)); } } else { issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3010, Strings.ErrorNoCertificate)); } return(SignatureVerificationStatus.Untrusted); }