Esempio n. 1
0
        private static CmsSigner CreateCmsSigner(SignPackageRequest request)
        {
            // Subject Key Identifier (SKI) is smaller and less prone to accidental matching than issuer and serial
            // number.  However, to ensure cross-platform verification, SKI should only be used if the certificate
            // has the SKI extension attribute.
            CmsSigner signer;

            if (request.Certificate.Extensions[Oids.SubjectKeyIdentifier] == null)
            {
                signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, request.Certificate);
            }
            else
            {
                signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, request.Certificate);
            }

            request.BuildCertificateChainOnce();

            var chain = request.Chain;

            foreach (var certificate in chain)
            {
                signer.Certificates.Add(certificate);
            }

            var attributes = SigningUtility.GetSignedAttributes(request, chain);

            foreach (var attribute in attributes)
            {
                signer.SignedAttributes.Add(attribute);
            }

            // We built the chain ourselves and added certificates.
            // Passing any other value here would trigger another chain build
            // and possibly add duplicate certs to the collection.
            signer.IncludeOption   = X509IncludeOption.None;
            signer.DigestAlgorithm = request.SignatureHashAlgorithm.ConvertToOid();

            return(signer);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        /// <summary>
        /// Validates a SignedCms object containing a timestamp response.
        /// </summary>
        /// <param name="timestampCms">SignedCms response from the timestamp authority.</param>
        /// <param name="messageHash">Message hash that was signed and timestamped.</param>
        private bool IsTimestampValid(Timestamp timestamp, byte[] messageHash, bool failuresAreFatal, List <SignatureLog> issues)
        {
            var timestamperCertificate = timestamp.SignerInfo.Certificate;

            if (timestamperCertificate == null)
            {
                issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3020, Strings.TimestampNoCertificate));
                return(false);
            }

            if (SigningUtility.IsTimestampValid(timestamp, messageHash, failuresAreFatal, issues, _specification))
            {
                issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.TimestampValue, timestamp.GeneralizedTime.LocalDateTime.ToString()) + Environment.NewLine));

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

                //var signingCertificateAttribute = timestampSignerInfo.SignedAttributes.GetAttributeOrDefault(Oids.SigningCertificate);
                //if (signingCertificateAttribute == null)
                //{
                //    signingCertificateAttribute = timestampSignerInfo.SignedAttributes.GetAttributeOrDefault(Oids.SigningCertificateV2);
                //}
                // TODO: how are we going to use the signingCertificateAttribute?

                var certificateExtraStore = timestamp.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, DateTime.Now, NuGetVerificationCertificateType.Timestamp);

                    var chainBuildSucceed = SigningUtility.BuildCertificateChain(chain, timestamperCertificate, out var chainStatusList);

                    issues.Add(SignatureLog.DetailedLog(CertificateUtility.X509ChainToString(chain)));

                    if (chainBuildSucceed)
                    {
                        return(true);
                    }

                    var chainBuildingHasIssues = false;
                    IReadOnlyList <string> messages;

                    var timestampInvalidCertificateFlags = SigningUtility.NotIgnoredCertificateFlags |
                                                           (X509ChainStatusFlags.Revoked) |
                                                           (X509ChainStatusFlags.NotTimeValid) |
                                                           (X509ChainStatusFlags.CtlNotTimeValid);

                    if (SigningUtility.TryGetStatusMessage(chainStatusList, timestampInvalidCertificateFlags, out messages))
                    {
                        foreach (var message in messages)
                        {
                            issues.Add(SignatureLog.Issue(failuresAreFatal, 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 (SigningUtility.TryGetStatusMessage(chainStatusList, RevocationStatusFlags, out messages))
                    {
                        if (failuresAreFatal)
                        {
                            foreach (var message in messages)
                            {
                                issues.Add(SignatureLog.Issue(failuresAreFatal, NuGetLogCode.NU3028, message));
                            }
                        }
                        else if (!chainBuildingHasIssues)
                        {
                            return(true);
                        }
                        chainBuildingHasIssues = true;
                    }

                    // Debug log any errors
                    issues.Add(SignatureLog.DebugLog(string.Format(CultureInfo.CurrentCulture, Strings.ErrorInvalidCertificateChain, string.Join(", ", chainStatusList.Select(x => x.ToString())))));
                }
            }
            return(false);
        }