public static void Verify(SignPackageRequest request, ILogger logger)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            if (!CertificateUtility.IsSignatureAlgorithmSupported(request.Certificate))
            {
                throw new SignatureException(NuGetLogCode.NU3013, Strings.SigningCertificateHasUnsupportedSignatureAlgorithm);
            }

            if (!CertificateUtility.IsCertificatePublicKeyValid(request.Certificate))
            {
                throw new SignatureException(NuGetLogCode.NU3014, Strings.SigningCertificateFailsPublicKeyLengthRequirement);
            }

            if (CertificateUtility.HasExtendedKeyUsage(request.Certificate, Oids.LifetimeSigningEku))
            {
                throw new SignatureException(NuGetLogCode.NU3015, Strings.ErrorCertificateHasLifetimeSigningEKU);
            }

            if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(request.Certificate))
            {
                throw new SignatureException(NuGetLogCode.NU3017, Strings.SignatureNotYetValid);
            }

            request.BuildSigningCertificateChainOnce(logger);
        }
Example #2
0
        internal static bool IsSigningCertificateValid(X509Certificate2 certificate, bool treatIssuesAsErrors, List <SignatureLog> issues)
        {
            var isValid = true;

            if (!CertificateUtility.IsSignatureAlgorithmSupported(certificate))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3013, Strings.SigningCertificateHasUnsupportedSignatureAlgorithm));
                isValid = false;
            }

            if (!CertificateUtility.IsCertificatePublicKeyValid(certificate))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3014, Strings.SigningCertificateFailsPublicKeyLengthRequirement));
                isValid = false;
            }

            if (CertificateUtility.HasExtendedKeyUsage(certificate, Oids.LifetimeSigningEku))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3015, Strings.ErrorCertificateHasLifetimeSigningEKU));
                isValid = false;
            }

            if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(certificate))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3017, Strings.SignatureNotYetValid));
                isValid = false;
            }

            return(isValid);
        }
        private static bool IsMatch(
            X509Certificate2 certificate,
            EssCertIdV2 essCertIdV2,
            Errors errors,
            bool isIssuerSerialRequired)
        {
            if (isIssuerSerialRequired)
            {
                if (essCertIdV2.IssuerSerial == null ||
                    essCertIdV2.IssuerSerial.GeneralNames.Count == 0)
                {
                    throw new SignatureException(errors.InvalidSignature, errors.InvalidSignatureString);
                }
            }

            if (essCertIdV2.IssuerSerial != null)
            {
                if (!AreSerialNumbersEqual(essCertIdV2.IssuerSerial, certificate))
                {
                    return(false);
                }

                if (!AreGeneralNamesEqual(essCertIdV2.IssuerSerial, certificate))
                {
                    return(false);
                }
            }

            var hashAlgorithmName = CryptoHashUtility.OidToHashAlgorithmName(essCertIdV2.HashAlgorithm.Algorithm.Value);
            var actualHash        = CertificateUtility.GetHash(certificate, hashAlgorithmName);

            return(essCertIdV2.CertificateHash.SequenceEqual(actualHash));
        }
Example #4
0
        private Signature CreateSignature(SignPackageRequest request, SignatureContent signatureContent)
        {
            var cmsSigner = CreateCmsSigner(request);

            if (request.PrivateKey != null)
            {
                return(CreateSignature(cmsSigner, signatureContent, request.PrivateKey));
            }

            var contentInfo = new ContentInfo(signatureContent.GetBytes());
            var cms         = new SignedCms(contentInfo);

            try
            {
                cms.ComputeSignature(cmsSigner);
            }
            catch (CryptographicException ex) when(ex.HResult == INVALID_PROVIDER_TYPE_HRESULT)
            {
                var exceptionBuilder = new StringBuilder();

                exceptionBuilder.AppendLine(Strings.SignFailureCertificateInvalidProviderType);
                exceptionBuilder.AppendLine(CertificateUtility.X509Certificate2ToString(request.Certificate));

                throw new SignatureException(NuGetLogCode.NU3016, exceptionBuilder.ToString());
            }

            return(Signature.Load(cms));
        }
        private static void ValidateTimestampCms(SigningSpecifications spec, SignedCms timestampCms)
        {
            var signerInfo = timestampCms.SignerInfos[0];

            try
            {
                signerInfo.CheckSignature(verifySignatureOnly: true);
            }
            catch (Exception e)
            {
                throw new TimestampException(NuGetLogCode.NU3021, Strings.TimestampSignatureValidationFailed, e);
            }

            if (!CertificateUtility.IsSignatureAlgorithmSupported(signerInfo.Certificate))
            {
                throw new TimestampException(NuGetLogCode.NU3022, Strings.TimestampUnsupportedSignatureAlgorithm);
            }

            if (!CertificateUtility.IsCertificatePublicKeyValid(signerInfo.Certificate))
            {
                throw new TimestampException(NuGetLogCode.NU3023, Strings.TimestampCertificateFailsPublicKeyLengthRequirement);
            }

            if (!spec.AllowedHashAlgorithmOids.Contains(signerInfo.DigestAlgorithm.Value))
            {
                throw new TimestampException(NuGetLogCode.NU3024, Strings.TimestampUnsupportedSignatureAlgorithm);
            }

            if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(signerInfo.Certificate))
            {
                throw new TimestampException(NuGetLogCode.NU3025, Strings.TimestampNotYetValid);
            }
        }
Example #6
0
        private static PrimarySignature CreatePrimarySignature(CmsSigner cmsSigner, SignPackageRequest request, byte[] signingData)
        {
            var contentInfo = new ContentInfo(signingData);
            var cms         = new SignedCms(contentInfo);

            try
            {
#if IS_DESKTOP
                cms.ComputeSignature(cmsSigner);
#else
                // In .NET Framework, this parameter is not used and a PIN prompt is always shown. In .NET Core, the silent flag needs to be set to false to show a PIN prompt.
                cms.ComputeSignature(cmsSigner, silent: false);
#endif
            }
            catch (CryptographicException ex) when(ex.HResult == INVALID_PROVIDER_TYPE_HRESULT)
            {
                var exceptionBuilder = new StringBuilder();

                exceptionBuilder.AppendLine(Strings.SignFailureCertificateInvalidProviderType);
                exceptionBuilder.AppendLine(CertificateUtility.X509Certificate2ToString(request.Certificate, Common.HashAlgorithmName.SHA256));

                throw new SignatureException(NuGetLogCode.NU3001, exceptionBuilder.ToString());
            }

            return(PrimarySignature.Load(cms));
        }
Example #7
0
        public string GetSigningCertificateFingerprint(HashAlgorithmName algorithm)
        {
            if (!Enum.IsDefined(typeof(HashAlgorithmName), algorithm))
            {
                throw new ArgumentException(
                          string.Format(
                              CultureInfo.CurrentCulture,
                              Strings.UnrecognizedEnumValue,
                              algorithm),
                          nameof(algorithm));
            }

            var certificate = SignerInfo.Certificate;

            if (certificate == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.Verify_ErrorNoCertificate, FriendlyName));
            }

            if (_signingCertificateFingerprintLookup == null)
            {
                _signingCertificateFingerprintLookup = new Dictionary <HashAlgorithmName, string>();
            }

            if (_signingCertificateFingerprintLookup.TryGetValue(algorithm, out var fingerprint))
            {
                return(fingerprint);
            }

            fingerprint = CertificateUtility.GetHashString(certificate, algorithm);

            _signingCertificateFingerprintLookup.Add(algorithm, fingerprint);

            return(fingerprint);
        }
Example #8
0
        internal static bool IsTimestampValid(Timestamp timestamp, byte[] data, bool treatIssuesAsErrors, List <SignatureLog> issues, SigningSpecifications spec)
        {
            var isValid    = true;
            var signerInfo = timestamp.SignerInfo;

            if (!timestamp.TstInfo.HasMessageHash(data))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3019, Strings.TimestampIntegrityCheckFailed));
                isValid = false;
            }

            if (timestamp.SignerInfo.Certificate != null)
            {
                try
                {
                    signerInfo.CheckSignature(verifySignatureOnly: true);
                }
                catch (Exception e)
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3021, Strings.TimestampSignatureValidationFailed));
                    issues.Add(SignatureLog.DebugLog(e.ToString()));
                    isValid = false;
                }

                if (!CertificateUtility.IsSignatureAlgorithmSupported(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3022, Strings.TimestampUnsupportedSignatureAlgorithm));
                    isValid = false;
                }

                if (!CertificateUtility.IsCertificatePublicKeyValid(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3023, Strings.TimestampCertificateFailsPublicKeyLengthRequirement));
                    isValid = false;
                }

                if (!spec.AllowedHashAlgorithmOids.Contains(signerInfo.DigestAlgorithm.Value))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3024, Strings.TimestampUnsupportedSignatureAlgorithm));
                    isValid = false;
                }

                if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3025, Strings.TimestampNotYetValid));
                    isValid = false;
                }
            }
            else
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3020, Strings.TimestampNoCertificate));
                isValid = false;
            }

            return(isValid);
        }
Example #9
0
        public static EssCertIdV2 Create(X509Certificate2 certificate, Common.HashAlgorithmName hashAlgorithmName)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }

            var algorithm    = new AlgorithmIdentifier(hashAlgorithmName.ConvertToOid());
            var hash         = CertificateUtility.GetHash(certificate, hashAlgorithmName);
            var issuerSerial = IssuerSerial.Create(certificate);

            return(new EssCertIdV2(algorithm, hash, issuerSerial));
        }
Example #10
0
        private static string GetCertificateFingerprint(
            Signature signature,
            HashAlgorithmName fingerprintAlgorithm,
            IDictionary <HashAlgorithmName, string> CertificateFingerprintLookUp)
        {
            if (!CertificateFingerprintLookUp.TryGetValue(fingerprintAlgorithm, out var fingerprintString))
            {
                fingerprintString = CertificateUtility.GetHashString(signature.SignerInfo.Certificate, fingerprintAlgorithm);
                CertificateFingerprintLookUp[fingerprintAlgorithm] = fingerprintString;
            }

            return(fingerprintString);
        }
        private static string GetCertificateFingerprint(
            Signature signature,
            HashAlgorithmName fingerprintAlgorithm,
            IDictionary <HashAlgorithmName, string> CertificateFingerprintLookUp)
        {
            if (!CertificateFingerprintLookUp.TryGetValue(fingerprintAlgorithm, out var fingerprintString))
            {
                var primarySignatureCertificateFingerprint = CertificateUtility.GetHash(signature.SignerInfo.Certificate, fingerprintAlgorithm);
                fingerprintString = BitConverter.ToString(primarySignatureCertificateFingerprint).Replace("-", "");
                CertificateFingerprintLookUp[fingerprintAlgorithm] = fingerprintString;
            }

            return(fingerprintString);
        }
Example #12
0
        internal unsafe void AddCountersignature(CmsSigner cmsSigner, CngKey privateKey)
        {
            using (var hb = new HeapBlockRetainer())
            {
                var signerInfo = NativeUtility.CreateSignerInfo(cmsSigner, privateKey, hb);

                NativeUtility.ThrowIfFailed(NativeMethods.CryptMsgCountersign(
                                                _handle,
                                                dwIndex: 0,
                                                cCountersigners: 1,
                                                rgCountersigners: signerInfo));

                AddCertificates(CertificateUtility.GetRawDataForCollection(cmsSigner.Certificates));
            }
        }
        internal static bool BuildCertificateChain(X509Chain chain, X509Certificate2 certificate, out X509ChainStatus[] status)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }

            var buildSuccess = chain.Build(certificate);

            status = new X509ChainStatus[chain.ChainStatus.Length];
            chain.ChainStatus.CopyTo(status, 0);

            // Check if time is not in the future
            return(buildSuccess && !CertificateUtility.IsCertificateValidityPeriodInTheFuture(certificate));
        }
        /// <summary>
        /// Get error/warning chain status flags for certificate chain validation during signing.
        /// </summary>
        /// <param name="certificate">The certificate to verify.</param>
        /// <param name="errorStatusFlags">Error chain status flags.</param>
        /// <param name="warningStatusFlags">Warning chain status flags.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="certificate" /> is <c>null</c>.</exception>
        public static void GetChainStatusFlagsForSigning(
            X509Certificate2 certificate,
            out X509ChainStatusFlags errorStatusFlags,
            out X509ChainStatusFlags warningStatusFlags)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }

            warningStatusFlags = X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;

            if (CertificateUtility.IsSelfIssued(certificate))
            {
                warningStatusFlags |= X509ChainStatusFlags.UntrustedRoot;
            }

            // Every status flag that isn't a warning is an error.
            errorStatusFlags = (~(X509ChainStatusFlags)0) & ~warningStatusFlags;
        }
Example #15
0
        private static PrimarySignature CreatePrimarySignature(CmsSigner cmsSigner, SignPackageRequest request, byte[] signingData)
        {
            var contentInfo = new ContentInfo(signingData);
            var cms         = new SignedCms(contentInfo);

            try
            {
                cms.ComputeSignature(cmsSigner);
            }
            catch (CryptographicException ex) when(ex.HResult == INVALID_PROVIDER_TYPE_HRESULT)
            {
                var exceptionBuilder = new StringBuilder();

                exceptionBuilder.AppendLine(Strings.SignFailureCertificateInvalidProviderType);
                exceptionBuilder.AppendLine(CertificateUtility.X509Certificate2ToString(request.Certificate, Common.HashAlgorithmName.SHA256));

                throw new SignatureException(NuGetLogCode.NU3001, exceptionBuilder.ToString());
            }

            return(PrimarySignature.Load(cms));
        }
Example #16
0
        internal static SignatureVerificationStatusFlags ValidateSigningCertificate(X509Certificate2 certificate, bool treatIssuesAsErrors, string signatureFriendlyName, List <SignatureLog> issues)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }

            if (issues == null)
            {
                throw new ArgumentNullException(nameof(issues));
            }

            var validationFlags = SignatureVerificationStatusFlags.NoErrors;

            if (!CertificateUtility.IsSignatureAlgorithmSupported(certificate))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3013, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_CertificateHasUnsupportedSignatureAlgorithm, signatureFriendlyName)));
                validationFlags |= SignatureVerificationStatusFlags.SignatureAlgorithmUnsupported;
            }

            if (!CertificateUtility.IsCertificatePublicKeyValid(certificate))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3014, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_CertificateFailsPublicKeyLengthRequirement, signatureFriendlyName)));
                validationFlags |= SignatureVerificationStatusFlags.CertificatePublicKeyInvalid;
            }

            if (CertificateUtility.HasExtendedKeyUsage(certificate, Oids.LifetimeSigningEku))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3015, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_CertificateHasLifetimeSigningEKU, signatureFriendlyName)));
                validationFlags |= SignatureVerificationStatusFlags.HasLifetimeSigningEku;
            }

            if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(certificate))
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3017, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_CertificateNotYetValid, signatureFriendlyName)));
                validationFlags |= SignatureVerificationStatusFlags.CertificateValidityInTheFuture;
            }

            return(validationFlags);
        }
        private bool IsSignatureAllowed(Signature signature)
        {
            // Get information needed for allow list verification
            var primarySignatureCertificateFingerprint       = CertificateUtility.GetHash(signature.SignerInfo.Certificate, _fingerprintAlgorithm);
            var primarySignatureCertificateFingerprintString = BitConverter.ToString(primarySignatureCertificateFingerprint).Replace("-", "");

            foreach (var allowedEntry in _allowList)
            {
                // Verify the certificate hash allow list objects
                var certificateHashEntry = allowedEntry as CertificateHashAllowListEntry;
                if (certificateHashEntry != null)
                {
                    if (certificateHashEntry.VerificationTarget.HasFlag(VerificationTarget.Primary) &&
                        StringComparer.OrdinalIgnoreCase.Equals(certificateHashEntry.CertificateFingerprint, primarySignatureCertificateFingerprintString))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Example #18
0
        private static PrimarySignature CreateRepositoryCountersignature(CmsSigner cmsSigner, SignPackageRequest request, PrimarySignature primarySignature)
        {
            var cms = new SignedCms();

            cms.Decode(primarySignature.GetBytes());

            try
            {
                cms.SignerInfos[0].ComputeCounterSignature(cmsSigner);
            }
            catch (CryptographicException ex) when(ex.HResult == INVALID_PROVIDER_TYPE_HRESULT)
            {
                var exceptionBuilder = new StringBuilder();

                exceptionBuilder.AppendLine(Strings.SignFailureCertificateInvalidProviderType);
                exceptionBuilder.AppendLine(CertificateUtility.X509Certificate2ToString(request.Certificate, Common.HashAlgorithmName.SHA256));

                throw new SignatureException(NuGetLogCode.NU3001, exceptionBuilder.ToString());
            }

            return(PrimarySignature.Load(cms));
        }
        /// <summary>
        /// Timestamps data present in the TimestampRequest.
        /// </summary>
        public byte[] TimestampData(TimestampRequest request, ILogger logger, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            // Get the signatureValue from the signerInfo object
            using (var signatureNativeCms = NativeCms.Decode(request.SignatureValue, detached: false))
            {
                var signatureValueHashByteArray = NativeCms.GetSignatureValueHash(
                    request.TimestampHashAlgorithm,
                    signatureNativeCms);

                // Allows us to track the request.
                var nonce = GenerateNonce();
                var rfc3161TimestampRequest = new Rfc3161TimestampRequest(
                    signatureValueHashByteArray,
                    request.TimestampHashAlgorithm.ConvertToSystemSecurityHashAlgorithmName(),
                    nonce: nonce,
                    requestSignerCertificates: true);

                // Request a timestamp
                // The response status need not be checked here as lower level api will throw if the response is invalid
                var timestampToken = rfc3161TimestampRequest.SubmitRequest(
                    _timestamperUrl,
                    TimeSpan.FromSeconds(_rfc3161RequestTimeoutSeconds));

                // ensure response is for this request
                ValidateTimestampResponseNonce(nonce, timestampToken);

                var timestampCms = timestampToken.AsSignedCms();

                byte[] timestampByteArray;

                using (var timestampNativeCms = NativeCms.Decode(timestampCms.Encode(), detached: false))
                    using (var timestampCertChain = new X509Chain())
                    {
                        var policy = timestampCertChain.ChainPolicy;

                        policy.ApplicationPolicy.Add(new Oid(Oids.TimeStampingEkuOid));
                        policy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid;

                        policy.ExtraStore.AddRange(timestampCms.Certificates);

                        policy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
                        policy.RevocationMode = X509RevocationMode.Online;

                        var timestampSignerCertificate = GetTimestampSignerCertificate(timestampCms);
                        if (DateTime.Now < timestampSignerCertificate.NotBefore)
                        {
                            throw new TimestampException(LogMessage.CreateError(
                                                             NuGetLogCode.NU3025,
                                                             string.Format(CultureInfo.CurrentCulture,
                                                                           Strings.TimestampCertificateInvalid,
                                                                           $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(timestampSignerCertificate)}")));
                        }

                        if (!timestampCertChain.Build(timestampSignerCertificate))
                        {
                            throw new TimestampException(LogMessage.CreateError(
                                                             NuGetLogCode.NU3028,
                                                             string.Format(CultureInfo.CurrentCulture,
                                                                           Strings.TimestampCertificateChainBuildFailure,
                                                                           $"{Environment.NewLine}{CertificateUtility.X509Certificate2ToString(timestampSignerCertificate)}")));
                        }

                        // Insert all the certificates into timestampCms
                        InsertTimestampCertChainIntoTimestampCms(timestampCms, timestampCertChain, timestampNativeCms);
                        timestampByteArray = timestampCms.Encode();
                    }

                signatureNativeCms.AddTimestamp(timestampByteArray);

                return(signatureNativeCms.Encode());
            }
        }
Example #20
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>
        /// <remarks>This is only public for ease of testing</remarks>
        /// <returns>Status of trust for signature.</returns>
        public virtual SignatureVerificationSummary Verify(
            Timestamp timestamp,
            SignatureVerifySettings settings,
            HashAlgorithmName fingerprintAlgorithm,
            X509Certificate2Collection certificateExtraStore)
        {
            settings = settings ?? SignatureVerifySettings.Default;
            var flags  = SignatureVerificationStatusFlags.NoErrors;
            var issues = new List <SignatureLog>();
            SignatureVerificationStatus status;

            var certificate = SignerInfo.Certificate;

            if (certificate == null)
            {
                issues.Add(SignatureLog.Issue(!settings.AllowIllegal, NuGetLogCode.NU3010, string.Format(CultureInfo.CurrentCulture, Strings.Verify_ErrorNoCertificate, FriendlyName)));

                flags |= SignatureVerificationStatusFlags.NoCertificate;
                status = settings.AllowIllegal? SignatureVerificationStatus.Valid: SignatureVerificationStatus.Disallowed;

                return(new SignatureVerificationSummary(Type, status, flags, issues));
            }

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

            try
            {
                SignerInfo.CheckSignature(verifySignatureOnly: true);
            }
            catch (Exception e)
            {
                issues.Add(SignatureLog.Issue(!settings.AllowIllegal, NuGetLogCode.NU3012, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_SignatureVerificationFailed, FriendlyName)));
                issues.Add(SignatureLog.DebugLog(e.ToString()));
                flags |= SignatureVerificationStatusFlags.SignatureCheckFailed;
                status = settings.AllowIllegal ? SignatureVerificationStatus.Valid : SignatureVerificationStatus.Disallowed;

                return(new SignatureVerificationSummary(Type, status, flags, issues));
            }

            DateTimeOffset?expirationTime   = null;
            var            certificateFlags = VerificationUtility.ValidateSigningCertificate(certificate, !settings.AllowIllegal, FriendlyName, issues);

            if (certificateFlags != SignatureVerificationStatusFlags.NoErrors)
            {
                flags |= certificateFlags;
            }
            else
            {
                timestamp = timestamp ?? new Timestamp();
                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, timestamp.UpperLimit.LocalDateTime, CertificateType.Signature);

                    if (settings.RevocationMode == RevocationMode.Offline)
                    {
                        chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
                    }
                    else
                    {
                        chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                    }

                    var chainBuildingSucceeded = CertificateChainUtility.BuildCertificateChain(chain, certificate, out var chainStatuses);
                    var x509ChainString        = CertificateUtility.X509ChainToString(chain, fingerprintAlgorithm);

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

                    var chainBuildingHasIssues = false;

                    if (!chainBuildingSucceeded)
                    {
                        var statusFlags = CertificateChainUtility.DefaultObservedStatusFlags;

                        IEnumerable <string> messages;
                        if (CertificateChainUtility.TryGetStatusMessage(chainStatuses, statusFlags, out messages))
                        {
                            foreach (var message in messages)
                            {
                                issues.Add(SignatureLog.Issue(!settings.AllowIllegal, NuGetLogCode.NU3012, string.Format(CultureInfo.CurrentCulture, Strings.VerifyChainBuildingIssue, FriendlyName, message)));
                            }

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

                        // 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(chainStatuses, X509ChainStatusFlags.Revoked, out messages))
                        {
                            issues.Add(SignatureLog.Error(NuGetLogCode.NU3012, string.Format(CultureInfo.CurrentCulture, Strings.VerifyChainBuildingIssue, FriendlyName, messages.First())));
                            flags |= SignatureVerificationStatusFlags.CertificateRevoked;

                            return(new SignatureVerificationSummary(Type, SignatureVerificationStatus.Suspect, flags, timestamp, issues));
                        }

                        if (CertificateChainUtility.TryGetStatusMessage(chainStatuses, X509ChainStatusFlags.UntrustedRoot, out messages))
                        {
                            if (settings.ReportUntrustedRoot)
                            {
                                issues.Add(SignatureLog.Issue(!settings.AllowUntrusted, NuGetLogCode.NU3018, string.Format(CultureInfo.CurrentCulture, Strings.VerifyChainBuildingIssue, FriendlyName, messages.First())));
                            }

                            if (!settings.AllowUntrusted)
                            {
                                chainBuildingHasIssues = true;
                                flags |= SignatureVerificationStatusFlags.UntrustedRoot;
                            }
                        }

                        var offlineRevocationErrors = CertificateChainUtility.TryGetStatusMessage(chainStatuses, X509ChainStatusFlags.OfflineRevocation, out var _);
                        var unknownRevocationErrors = CertificateChainUtility.TryGetStatusMessage(chainStatuses, X509ChainStatusFlags.RevocationStatusUnknown, out var unknownRevocationStatusMessages);
                        if (offlineRevocationErrors || unknownRevocationErrors)
                        {
                            if (settings.ReportUnknownRevocation)
                            {
                                string unknownRevocationMessage = null;

                                if (unknownRevocationErrors)
                                {
                                    unknownRevocationMessage = string.Format(CultureInfo.CurrentCulture, Strings.VerifyChainBuildingIssue, FriendlyName, unknownRevocationStatusMessages.First());
                                }

                                if (settings.RevocationMode == RevocationMode.Offline)
                                {
                                    if (offlineRevocationErrors)
                                    {
                                        issues.Add(SignatureLog.InformationLog(string.Format(CultureInfo.CurrentCulture, Strings.VerifyChainBuildingIssue, 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.VerifyChainBuildingIssue, FriendlyName, Strings.VerifyCertTrustOfflineWhileRevocationModeOnline)));
                                    }

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

                            if (!settings.AllowUnknownRevocation)
                            {
                                chainBuildingHasIssues = true;
                                flags |= SignatureVerificationStatusFlags.UnknownRevocation;
                            }
                        }

                        // Debug log any errors
                        issues.Add(SignatureLog.DebugLog(
                                       string.Format(
                                           CultureInfo.CurrentCulture,
                                           Strings.VerifyError_InvalidCertificateChain,
                                           FriendlyName,
                                           string.Join(", ", chainStatuses.Select(x => x.Status.ToString())))));
                    }

                    var isSignatureTimeValid = Rfc3161TimestampVerificationUtility.ValidateSignerCertificateAgainstTimestamp(certificate, timestamp);
                    if (isSignatureTimeValid && !chainBuildingHasIssues)
                    {
                        return(new SignatureVerificationSummary(Type, SignatureVerificationStatus.Valid, flags, timestamp, issues));
                    }
                    else if (!isSignatureTimeValid)
                    {
                        issues.Add(
                            SignatureLog.Issue(
                                !settings.AllowUntrusted,
                                NuGetLogCode.NU3037,
                                string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_SignatureNotTimeValid, FriendlyName)));

                        if (!settings.AllowUntrusted)
                        {
                            flags |= SignatureVerificationStatusFlags.CertificateExpired;
                        }

                        expirationTime = DateTime.SpecifyKind(certificate.NotAfter, DateTimeKind.Local);
                    }
                }
            }

            status = VerificationUtility.GetSignatureVerificationStatus(flags);

            return(new SignatureVerificationSummary(Type, status, flags, timestamp, expirationTime, issues));
        }
Example #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);
        }
Example #22
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);
        }
Example #23
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);
        }
Example #24
0
        internal static SignatureVerificationStatusFlags ValidateTimestamp(Timestamp timestamp, Signature signature, bool treatIssuesAsErrors, List <SignatureLog> issues, SigningSpecifications spec)
        {
            if (timestamp == null)
            {
                throw new ArgumentNullException(nameof(timestamp));
            }
            if (signature == null)
            {
                throw new ArgumentNullException(nameof(signature));
            }
            if (issues == null)
            {
                throw new ArgumentNullException(nameof(issues));
            }

            // Default to specification v1
            spec = spec ?? SigningSpecifications.V1;

            var validationFlags = SignatureVerificationStatusFlags.NoErrors;
            var signerInfo      = timestamp.SignerInfo;

            if (timestamp.SignerInfo.Certificate != null)
            {
                try
                {
                    signerInfo.CheckSignature(verifySignatureOnly: true);
                }
                catch (Exception e)
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3021, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampSignatureValidationFailed, signature.FriendlyName)));
                    issues.Add(SignatureLog.DebugLog(e.ToString()));
                    validationFlags |= SignatureVerificationStatusFlags.SignatureCheckFailed;
                }

                if (!CertificateUtility.IsSignatureAlgorithmSupported(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3022, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampUnsupportedSignatureAlgorithm, signature.FriendlyName)));
                    validationFlags |= SignatureVerificationStatusFlags.SignatureAlgorithmUnsupported;
                }

                if (!CertificateUtility.IsCertificatePublicKeyValid(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3023, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampCertificateFailsPublicKeyLengthRequirement, signature.FriendlyName)));
                    validationFlags |= SignatureVerificationStatusFlags.CertificatePublicKeyInvalid;
                }

                if (!spec.AllowedHashAlgorithmOids.Contains(signerInfo.DigestAlgorithm.Value))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3024, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampUnsupportedSignatureAlgorithm, signature.FriendlyName)));
                    validationFlags |= SignatureVerificationStatusFlags.HashAlgorithmUnsupported;
                }

                try
                {
                    var hashAlgorithm  = CryptoHashUtility.OidToHashAlgorithmName(timestamp.TstInfo.HashAlgorithmId.Value);
                    var signatureValue = signature.GetSignatureValue();
                    var messageHash    = hashAlgorithm.ComputeHash(signatureValue);

                    if (!timestamp.TstInfo.HasMessageHash(messageHash))
                    {
                        issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3019, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampIntegrityCheckFailed, signature.FriendlyName)));
                        validationFlags |= SignatureVerificationStatusFlags.IntegrityCheckFailed;
                    }
                }
                catch
                {
                    // If the hash algorithm is not supported OidToHashAlgorithmName will throw
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3030, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampMessageImprintUnsupportedHashAlgorithm, signature.FriendlyName)));
                    validationFlags |= SignatureVerificationStatusFlags.MessageImprintUnsupportedAlgorithm;
                }

                if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3025, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampNotYetValid, signature.FriendlyName)));
                    validationFlags |= SignatureVerificationStatusFlags.CertificateValidityInTheFuture;
                }

                if (!CertificateUtility.IsDateInsideValidityPeriod(signerInfo.Certificate, timestamp.GeneralizedTime))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3036, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampGeneralizedTimeInvalid, signature.FriendlyName)));
                    validationFlags |= SignatureVerificationStatusFlags.GeneralizedTimeOutsideValidity;
                }
            }
            else
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3020, string.Format(CultureInfo.CurrentCulture, Strings.VerifyError_TimestampNoCertificate, signature.FriendlyName)));
                validationFlags |= SignatureVerificationStatusFlags.NoCertificate;
            }

            return(validationFlags);
        }
        internal static bool IsTimestampValid(Timestamp timestamp, Signature signature, bool treatIssuesAsErrors, List <SignatureLog> issues, SigningSpecifications spec)
        {
            if (timestamp == null)
            {
                throw new ArgumentNullException(nameof(timestamp));
            }
            if (signature == null)
            {
                throw new ArgumentNullException(nameof(signature));
            }
            if (issues == null)
            {
                throw new ArgumentNullException(nameof(issues));
            }

            // Default to specification v1
            spec = spec ?? SigningSpecifications.V1;

            var isValid    = true;
            var signerInfo = timestamp.SignerInfo;

            if (timestamp.SignerInfo.Certificate != null)
            {
                try
                {
                    signerInfo.CheckSignature(verifySignatureOnly: true);
                }
                catch (Exception e)
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3021, Strings.TimestampSignatureValidationFailed));
                    issues.Add(SignatureLog.DebugLog(e.ToString()));
                    isValid = false;
                }

                if (!CertificateUtility.IsSignatureAlgorithmSupported(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3022, Strings.TimestampUnsupportedSignatureAlgorithm));
                    isValid = false;
                }

                if (!CertificateUtility.IsCertificatePublicKeyValid(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3023, Strings.TimestampCertificateFailsPublicKeyLengthRequirement));
                    isValid = false;
                }

                if (!spec.AllowedHashAlgorithmOids.Contains(signerInfo.DigestAlgorithm.Value))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3024, Strings.TimestampUnsupportedSignatureAlgorithm));
                    isValid = false;
                }

                try
                {
                    var hashAlgorithm  = CryptoHashUtility.OidToHashAlgorithmName(timestamp.TstInfo.HashAlgorithmId.Value);
                    var signatureValue = signature.GetSignatureValue();
                    var messageHash    = hashAlgorithm.ComputeHash(signatureValue);

                    if (!timestamp.TstInfo.HasMessageHash(messageHash))
                    {
                        issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3019, Strings.TimestampIntegrityCheckFailed));
                        isValid = false;
                    }
                }
                catch
                {
                    // If the hash algorithm is not supported OidToHashAlgorithmName will throw
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3030, Strings.TimestampMessageImprintUnsupportedHashAlgorithm));
                    isValid = false;
                }

                if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(signerInfo.Certificate))
                {
                    issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3025, Strings.TimestampNotYetValid));
                    isValid = false;
                }
            }
            else
            {
                issues.Add(SignatureLog.Issue(treatIssuesAsErrors, NuGetLogCode.NU3020, Strings.TimestampNoCertificate));
                isValid = false;
            }

            return(isValid);
        }
Example #26
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);
        }
        private static void ValidateTimestampCms(SigningSpecifications spec, SignedCms timestampCms, IRfc3161TimestampToken timestampToken)
        {
            var signerInfo = timestampCms.SignerInfos[0];

            try
            {
                signerInfo.CheckSignature(verifySignatureOnly: true);
            }
            catch (Exception e)
            {
                throw new TimestampException(NuGetLogCode.NU3021, Strings.SignError_TimestampSignatureValidationFailed, e);
            }

            if (signerInfo.Certificate == null)
            {
                throw new TimestampException(NuGetLogCode.NU3020, Strings.SignError_TimestampNoCertificate);
            }

            if (!CertificateUtility.IsSignatureAlgorithmSupported(signerInfo.Certificate))
            {
                var certificateSignatureAlgorithm = GetNameOrOidString(signerInfo.Certificate.SignatureAlgorithm);

                var supportedSignatureAlgorithms = string.Join(", ", spec.AllowedSignatureAlgorithms);

                var errorMessage = string.Format(CultureInfo.CurrentCulture,
                                                 Strings.TimestampCertificateUnsupportedSignatureAlgorithm,
                                                 certificateSignatureAlgorithm,
                                                 supportedSignatureAlgorithms);

                throw new TimestampException(NuGetLogCode.NU3022, errorMessage);
            }

            if (!CertificateUtility.IsCertificatePublicKeyValid(signerInfo.Certificate))
            {
                throw new TimestampException(NuGetLogCode.NU3023, Strings.SignError_TimestampCertificateFailsPublicKeyLengthRequirement);
            }

            if (!spec.AllowedHashAlgorithmOids.Contains(signerInfo.DigestAlgorithm.Value))
            {
                var digestAlgorithm = GetNameOrOidString(signerInfo.DigestAlgorithm);

                var supportedSignatureAlgorithms = string.Join(", ", spec.AllowedHashAlgorithms);

                var errorMessage = string.Format(CultureInfo.CurrentCulture,
                                                 Strings.TimestampSignatureUnsupportedDigestAlgorithm,
                                                 digestAlgorithm,
                                                 supportedSignatureAlgorithms);

                throw new TimestampException(NuGetLogCode.NU3024, errorMessage);
            }

            if (CertificateUtility.IsCertificateValidityPeriodInTheFuture(signerInfo.Certificate))
            {
                throw new TimestampException(NuGetLogCode.NU3025, Strings.SignError_TimestampNotYetValid);
            }

            if (!CertificateUtility.IsDateInsideValidityPeriod(signerInfo.Certificate, timestampToken.TokenInfo.Timestamp))
            {
                throw new TimestampException(NuGetLogCode.NU3036, Strings.SignError_TimestampGeneralizedTimeInvalid);
            }
        }
Example #28
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);
        }