コード例 #1
0
            private static bool IsPolicyMatch(
                X509Certificate2[] certs,
                OidCollection?applicationPolicy,
                OidCollection?certificatePolicy)
            {
                bool hasApplicationPolicy = applicationPolicy != null && applicationPolicy.Count > 0;
                bool hasCertificatePolicy = certificatePolicy != null && certificatePolicy.Count > 0;

                if (!hasApplicationPolicy && !hasCertificatePolicy)
                {
                    return(true);
                }

                List <X509Certificate2> certsToRead = new List <X509Certificate2>(certs);
                CertificatePolicyChain  policyChain = new CertificatePolicyChain(certsToRead);

                if (hasCertificatePolicy && !policyChain.MatchesCertificatePolicies(certificatePolicy !))
                {
                    return(false);
                }

                if (hasApplicationPolicy && !policyChain.MatchesApplicationPolicies(applicationPolicy !))
                {
                    return(false);
                }

                return(true);
            }
コード例 #2
0
        internal void Execute(
            DateTime verificationTime,
            bool allowNetwork,
            OidCollection?applicationPolicy,
            OidCollection?certificatePolicy,
            X509RevocationFlag revocationFlag)
        {
            int osStatus;

            // Save the time code for determining which message to load for NotTimeValid.
            _verificationTime = verificationTime;
            int ret;

            using (SafeCFDateHandle cfEvaluationTime = Interop.CoreFoundation.CFDateCreate(verificationTime))
            {
                ret = Interop.AppleCrypto.AppleCryptoNative_X509ChainEvaluate(
                    _chainHandle !,
                    cfEvaluationTime,
                    allowNetwork,
                    out osStatus);
            }

            if (ret == 0)
            {
                throw Interop.AppleCrypto.CreateExceptionForOSStatus(osStatus);
            }

            if (ret != 1)
            {
                Debug.Fail($"AppleCryptoNative_X509ChainEvaluate returned unknown result {ret}");
                throw new CryptographicException();
            }

            (X509Certificate2, int)[] elements = ParseResults(_chainHandle !, _revocationMode);
コード例 #3
0
        internal static partial IChainPal?BuildChain(
            bool useMachineContext,
            ICertificatePal cert,
            X509Certificate2Collection?extraStore,
            OidCollection?applicationPolicy,
            OidCollection?certificatePolicy,
            X509RevocationMode revocationMode,
            X509RevocationFlag revocationFlag,
            X509Certificate2Collection?customTrustStore,
            X509ChainTrustMode trustMode,
            DateTime verificationTime,
            TimeSpan timeout,
            bool disableAia)
        {
            var chainPal = new AndroidCertPath();

            try
            {
                chainPal.Initialize(cert, extraStore, customTrustStore, trustMode);
                chainPal.Evaluate(verificationTime, applicationPolicy, certificatePolicy, revocationMode, revocationFlag);
            }
            catch
            {
                chainPal.Dispose();
                throw;
            }

            return(chainPal);
        }
コード例 #4
0
        /// <summary>
        /// Does not throw on error. Returns null ChainPal instead.
        /// </summary>
        public static ChainPal?BuildChain(
            bool useMachineContext,
            ICertificatePal cert,
            X509Certificate2Collection?extraStore,
            OidCollection?applicationPolicy,
            OidCollection?certificatePolicy,
            X509RevocationMode revocationMode,
            X509RevocationFlag revocationFlag,
            X509Certificate2Collection?customTrustStore,
            X509ChainTrustMode trustMode,
            DateTime verificationTime,
            TimeSpan timeout,
            bool disableAia)
        {
            CertificatePal certificatePal = (CertificatePal)cert;

            unsafe
            {
                using (SafeChainEngineHandle storeHandle = GetChainEngine(trustMode, customTrustStore, useMachineContext))
                    using (SafeCertStoreHandle extraStoreHandle = ConvertStoreToSafeHandle(extraStore))
                    {
                        CERT_CHAIN_PARA chainPara = default;
                        chainPara.cbSize = Marshal.SizeOf <CERT_CHAIN_PARA>();

                        int applicationPolicyCount;
                        using (SafeHandle applicationPolicyOids = applicationPolicy !.ToLpstrArray(out applicationPolicyCount))
                        {
                            if (!applicationPolicyOids.IsInvalid)
                            {
                                chainPara.RequestedUsage.dwType = CertUsageMatchType.USAGE_MATCH_TYPE_AND;
                                chainPara.RequestedUsage.Usage.cUsageIdentifier     = applicationPolicyCount;
                                chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = applicationPolicyOids.DangerousGetHandle();
                            }

                            int certificatePolicyCount;
                            using (SafeHandle certificatePolicyOids = certificatePolicy !.ToLpstrArray(out certificatePolicyCount))
                            {
                                if (!certificatePolicyOids.IsInvalid)
                                {
                                    chainPara.RequestedIssuancePolicy.dwType = CertUsageMatchType.USAGE_MATCH_TYPE_AND;
                                    chainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier     = certificatePolicyCount;
                                    chainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = certificatePolicyOids.DangerousGetHandle();
                                }

                                chainPara.dwUrlRetrievalTimeout = (int)Math.Floor(timeout.TotalMilliseconds);

                                FILETIME            ft    = FILETIME.FromDateTime(verificationTime);
                                CertChainFlags      flags = MapRevocationFlags(revocationMode, revocationFlag, disableAia);
                                SafeX509ChainHandle chain;
                                if (!Interop.crypt32.CertGetCertificateChain(storeHandle.DangerousGetHandle(), certificatePal.CertContext, &ft, extraStoreHandle, ref chainPara, flags, IntPtr.Zero, out chain))
                                {
                                    return(null);
                                }

                                return(new ChainPal(chain));
                            }
                        }
                    }
            }
        }
コード例 #5
0
ファイル: X509ChainPolicy.cs プロジェクト: lateralusX/runtime
 public void Reset()
 {
     _applicationPolicy  = null;
     _certificatePolicy  = null;
     _extraStore         = null;
     _customTrustStore   = null;
     _revocationMode     = X509RevocationMode.Online;
     _revocationFlag     = X509RevocationFlag.ExcludeRoot;
     _verificationFlags  = X509VerificationFlags.NoFlag;
     _trustMode          = X509ChainTrustMode.System;
     VerificationTime    = DateTime.Now;
     UrlRetrievalTimeout = TimeSpan.Zero; // default timeout
 }
コード例 #6
0
ファイル: ChainPal.cs プロジェクト: z77ma/runtime
 internal static partial IChainPal?BuildChain(
     bool useMachineContext,
     ICertificatePal cert,
     X509Certificate2Collection?extraStore,
     OidCollection?applicationPolicy,
     OidCollection?certificatePolicy,
     X509RevocationMode revocationMode,
     X509RevocationFlag revocationFlag,
     X509Certificate2Collection?customTrustStore,
     X509ChainTrustMode trustMode,
     DateTime verificationTime,
     TimeSpan timeout,
     bool disableAia);
コード例 #7
0
ファイル: Helpers.cs プロジェクト: jteer/runtime
        /// <summary>
        /// Convert each Oid's value to an ASCII string, then create an unmanaged array of "numOids" LPSTR pointers, one for each Oid.
        /// "numOids" is the number of LPSTR pointers. This is normally the same as oids.Count, except in the case where a malicious caller
        /// appends to the OidCollection while this method is in progress. In such a case, this method guarantees only that this won't create
        /// an unmanaged buffer overflow condition.
        /// </summary>
        public static SafeHandle ToLpstrArray(this OidCollection?oids, out int numOids)
        {
            if (oids == null || oids.Count == 0)
            {
                numOids = 0;
                return(SafeLocalAllocHandle.InvalidHandle);
            }

            // Copy the oid strings to a local array to prevent a security race condition where
            // the OidCollection or individual oids can be modified by another thread and
            // potentially cause a buffer overflow
            var oidStrings = new string[oids.Count];

            for (int i = 0; i < oidStrings.Length; i++)
            {
                oidStrings[i] = oids[i].Value !;
            }

            unsafe
            {
                int allocationSize = checked (oidStrings.Length * sizeof(void *));
                foreach (string oidString in oidStrings)
                {
                    checked
                    {
                        allocationSize += oidString.Length + 1; // Encoding.ASCII doesn't have a fallback, so it's fine to use String.Length
                    }
                }

                SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.Create(allocationSize);
                byte **pOidPointers = (byte **)(safeLocalAllocHandle.DangerousGetHandle());
                byte * pOidContents = (byte *)(pOidPointers + oidStrings.Length);

                for (int i = 0; i < oidStrings.Length; i++)
                {
                    string oidString = oidStrings[i];

                    pOidPointers[i] = pOidContents;

                    int bytesWritten = Encoding.ASCII.GetBytes(oidString, new Span <byte>(pOidContents, oidString.Length));
                    Debug.Assert(bytesWritten == oidString.Length);

                    pOidContents[oidString.Length] = 0;
                    pOidContents += oidString.Length + 1;
                }

                numOids = oidStrings.Length;
                return(safeLocalAllocHandle);
            }
        }
コード例 #8
0
 internal static partial IChainPal?BuildChain(
     bool useMachineContext,
     ICertificatePal cert,
     X509Certificate2Collection?extraStore,
     OidCollection?applicationPolicy,
     OidCollection?certificatePolicy,
     X509RevocationMode revocationMode,
     X509RevocationFlag revocationFlag,
     X509Certificate2Collection?customTrustStore,
     X509ChainTrustMode trustMode,
     DateTime verificationTime,
     TimeSpan timeout,
     bool disableAia)
 {
     throw new PlatformNotSupportedException(SR.SystemSecurityCryptographyX509Certificates_PlatformNotSupported);
 }
コード例 #9
0
        internal static partial IChainPal?BuildChain(
            bool useMachineContext,
            ICertificatePal cert,
            X509Certificate2Collection?extraStore,
            OidCollection?applicationPolicy,
            OidCollection?certificatePolicy,
            X509RevocationMode revocationMode,
            X509RevocationFlag revocationFlag,
            X509Certificate2Collection?customTrustStore,
            X509ChainTrustMode trustMode,
            DateTime verificationTime,
            TimeSpan timeout,
            bool disableAia)
        {
            if (OpenSslX509ChainEventSource.Log.IsEnabled())
            {
                OpenSslX509ChainEventSource.Log.ChainStart();
            }

            try
            {
                return(BuildChainCore(
                           useMachineContext,
                           cert,
                           extraStore,
                           applicationPolicy,
                           certificatePolicy,
                           revocationMode,
                           revocationFlag,
                           customTrustStore,
                           trustMode,
                           verificationTime,
                           timeout,
                           disableAia));
            }
            finally
            {
                if (OpenSslX509ChainEventSource.Log.IsEnabled())
                {
                    OpenSslX509ChainEventSource.Log.ChainStop();
                }
            }
        }
コード例 #10
0
            internal void Evaluate(
                DateTime verificationTime,
                OidCollection?applicationPolicy,
                OidCollection?certificatePolicy,
                X509RevocationMode revocationMode,
                X509RevocationFlag revocationFlag)
            {
                Debug.Assert(_chainContext != null);

                long timeInMsFromUnixEpoch = new DateTimeOffset(verificationTime).ToUnixTimeMilliseconds();

                _isValid = Interop.AndroidCrypto.X509ChainBuild(_chainContext, timeInMsFromUnixEpoch);
                if (!_isValid)
                {
                    // Android always validates name, time, signature, and trusted root.
                    // There is no way bypass that validation and build a path.
                    ChainElements = Array.Empty <X509ChainElement>();

                    Interop.AndroidCrypto.ValidationError[] errors = Interop.AndroidCrypto.X509ChainGetErrors(_chainContext);
                    var chainStatus = new X509ChainStatus[errors.Length];
                    for (int i = 0; i < errors.Length; i++)
                    {
                        Interop.AndroidCrypto.ValidationError error = errors[i];
                        chainStatus[i] = ValidationErrorToChainStatus(error);
                        Marshal.FreeHGlobal(error.Message);
                    }

                    ChainStatus = chainStatus;
                    return;
                }

                byte checkedRevocation;
                int  res = Interop.AndroidCrypto.X509ChainValidate(_chainContext, revocationMode, revocationFlag, out checkedRevocation);

                if (res != 1)
                {
                    throw new CryptographicException();
                }

                X509Certificate2[]     certs         = Interop.AndroidCrypto.X509ChainGetCertificates(_chainContext);
                List <X509ChainStatus> overallStatus = new List <X509ChainStatus>();

                List <X509ChainStatus>[] statuses = new List <X509ChainStatus> [certs.Length];

                // Android will stop checking after the first error it hits, so we track the first
                // instances of revocation and non-revocation errors to fix-up the status of elements
                // beyond the first error
                int firstNonRevocationErrorIndex = -1;
                int firstRevocationErrorIndex    = -1;
                Dictionary <int, List <X509ChainStatus> > errorsByIndex = GetStatusByIndex(_chainContext);

                foreach (int index in errorsByIndex.Keys)
                {
                    List <X509ChainStatus> errors = errorsByIndex[index];
                    for (int i = 0; i < errors.Count; i++)
                    {
                        X509ChainStatus status = errors[i];
                        AddUniqueStatus(overallStatus, ref status);
                    }

                    // -1 indicates that error is not tied to a specific index
                    if (index != -1)
                    {
                        statuses[index] = errorsByIndex[index];
                        if (errorsByIndex[index].Exists(s => s.Status == X509ChainStatusFlags.Revoked || s.Status == X509ChainStatusFlags.RevocationStatusUnknown))
                        {
                            firstRevocationErrorIndex = Math.Max(index, firstRevocationErrorIndex);
                        }
                        else
                        {
                            firstNonRevocationErrorIndex = Math.Max(index, firstNonRevocationErrorIndex);
                        }
                    }
                }

                if (firstNonRevocationErrorIndex > 0)
                {
                    // Assign PartialChain to everything from the first non-revocation error to the end certificate
                    X509ChainStatus partialChainStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.PartialChain,
                        StatusInformation = SR.Chain_PartialChain,
                    };
                    AddStatusFromIndexToEndCertificate(firstNonRevocationErrorIndex - 1, ref partialChainStatus, statuses, overallStatus);
                }

                if (firstRevocationErrorIndex > 0)
                {
                    // Assign RevocationStatusUnknown to everything from the first revocation error to the end certificate
                    X509ChainStatus revocationUnknownStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.RevocationStatusUnknown,
                        StatusInformation = SR.Chain_RevocationStatusUnknown,
                    };
                    AddStatusFromIndexToEndCertificate(firstRevocationErrorIndex - 1, ref revocationUnknownStatus, statuses, overallStatus);
                }

                if (revocationMode != X509RevocationMode.NoCheck && checkedRevocation == 0)
                {
                    // Revocation checking was requested, but not performed (due to basic validation failing)
                    // Assign RevocationStatusUnknown to everything
                    X509ChainStatus revocationUnknownStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.RevocationStatusUnknown,
                        StatusInformation = SR.Chain_RevocationStatusUnknown,
                    };
                    AddStatusFromIndexToEndCertificate(statuses.Length - 1, ref revocationUnknownStatus, statuses, overallStatus);
                }

                if (!IsPolicyMatch(certs, applicationPolicy, certificatePolicy))
                {
                    // Assign NotValidForUsage to everything
                    X509ChainStatus policyFailStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.NotValidForUsage,
                        StatusInformation = SR.Chain_NoPolicyMatch,
                    };
                    AddStatusFromIndexToEndCertificate(statuses.Length - 1, ref policyFailStatus, statuses, overallStatus);
                }

                X509ChainElement[] elements = new X509ChainElement[certs.Length];
                for (int i = 0; i < certs.Length; i++)
                {
                    X509ChainStatus[] elementStatus = statuses[i] == null?Array.Empty <X509ChainStatus>() : statuses[i].ToArray();

                    elements[i] = new X509ChainElement(certs[i], elementStatus, string.Empty);
                }

                ChainElements = elements;
                ChainStatus   = overallStatus.ToArray();
            }
コード例 #11
0
        private static IChainPal?BuildChainCore(
            bool useMachineContext,
            ICertificatePal cert,
            X509Certificate2Collection?extraStore,
            OidCollection?applicationPolicy,
            OidCollection?certificatePolicy,
            X509RevocationMode revocationMode,
            X509RevocationFlag revocationFlag,
            X509Certificate2Collection?customTrustStore,
            X509ChainTrustMode trustMode,
            DateTime verificationTime,
            TimeSpan timeout,
            bool disableAia)
        {
            if (timeout == TimeSpan.Zero)
            {
                // An input value of 0 on the timeout is treated as 15 seconds, to match Windows.
                timeout = TimeSpan.FromSeconds(15);
            }
            else if (timeout > s_maxUrlRetrievalTimeout || timeout < TimeSpan.Zero)
            {
                // Windows has a max timeout of 1 minute, so we'll match. Windows also treats
                // the timeout as unsigned, so a negative value gets treated as a large positive
                // value that is also clamped.
                timeout = s_maxUrlRetrievalTimeout;
            }

            // Let Unspecified mean Local, so only convert if the source was UTC.
            //
            // Converge on Local instead of UTC because OpenSSL is going to assume we gave it
            // local time.
            if (verificationTime.Kind == DateTimeKind.Utc)
            {
                verificationTime = verificationTime.ToLocalTime();
            }

            // Until we support the Disallowed store, ensure it's empty (which is done by the ctor)
            using (new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
            {
            }

            TimeSpan downloadTimeout = timeout;

            OpenSslX509ChainProcessor chainPal = OpenSslX509ChainProcessor.InitiateChain(
                ((OpenSslX509CertificateReader)cert).SafeHandle,
                customTrustStore,
                trustMode,
                verificationTime,
                downloadTimeout);

            Interop.Crypto.X509VerifyStatusCode status = chainPal.FindFirstChain(extraStore);

            if (OpenSslX509ChainEventSource.Log.IsEnabled())
            {
                OpenSslX509ChainEventSource.Log.FindFirstChainFinished(status);
            }

            if (!OpenSslX509ChainProcessor.IsCompleteChain(status))
            {
                if (disableAia)
                {
                    if (OpenSslX509ChainEventSource.Log.IsEnabled())
                    {
                        OpenSslX509ChainEventSource.Log.AiaDisabled();
                    }
                }
                else
                {
                    List <X509Certificate2>?tmp = null;
                    status = chainPal.FindChainViaAia(ref tmp);

                    if (OpenSslX509ChainEventSource.Log.IsEnabled())
                    {
                        OpenSslX509ChainEventSource.Log.FindChainViaAiaFinished(status, tmp?.Count ?? 0);
                    }

                    if (tmp != null)
                    {
                        if (status == Interop.Crypto.X509VerifyStatusCode.X509_V_OK)
                        {
                            SaveIntermediateCertificates(tmp);
                        }

                        foreach (X509Certificate2 downloaded in tmp)
                        {
                            downloaded.Dispose();
                        }
                    }
                }
            }

            if (revocationMode != X509RevocationMode.NoCheck)
            {
                if (OpenSslX509ChainProcessor.IsCompleteChain(status))
                {
                    // Checking the validity period for the certificates in the chain is done after the
                    // check for a trusted root, so accept expired (or not yet valid) as acceptable for
                    // processing revocation.
                    if (status != Interop.Crypto.X509VerifyStatusCode.X509_V_OK &&
                        status != Interop.Crypto.X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_NOT_YET_VALID &&
                        status != Interop.Crypto.X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_HAS_EXPIRED)
                    {
                        if (OpenSslX509ChainEventSource.Log.IsEnabled())
                        {
                            OpenSslX509ChainEventSource.Log.UntrustedChainWithRevocation();
                        }

                        revocationMode = X509RevocationMode.NoCheck;
                    }

                    chainPal.CommitToChain();
                    chainPal.ProcessRevocation(revocationMode, revocationFlag);
                }
            }

            chainPal.Finish(applicationPolicy, certificatePolicy);

#if DEBUG
            if (chainPal.ChainElements !.Length > 0)
            {
                X509Certificate2 reportedLeaf = chainPal.ChainElements[0].Certificate;
                Debug.Assert(reportedLeaf != null, "reportedLeaf != null");
                Debug.Assert(!ReferenceEquals(cert, reportedLeaf.Pal), "!ReferenceEquals(cert, reportedLeaf.Pal)");
            }
#endif
            return(chainPal);
        }
コード例 #12
0
ファイル: ChainPal.OpenSsl.cs プロジェクト: z77ma/runtime
        internal static partial IChainPal?BuildChain(
            bool useMachineContext,
            ICertificatePal cert,
            X509Certificate2Collection?extraStore,
            OidCollection?applicationPolicy,
            OidCollection?certificatePolicy,
            X509RevocationMode revocationMode,
            X509RevocationFlag revocationFlag,
            X509Certificate2Collection?customTrustStore,
            X509ChainTrustMode trustMode,
            DateTime verificationTime,
            TimeSpan timeout,
            bool disableAia)
        {
            if (timeout == TimeSpan.Zero)
            {
                // An input value of 0 on the timeout is treated as 15 seconds, to match Windows.
                timeout = TimeSpan.FromSeconds(15);
            }
            else if (timeout > s_maxUrlRetrievalTimeout || timeout < TimeSpan.Zero)
            {
                // Windows has a max timeout of 1 minute, so we'll match. Windows also treats
                // the timeout as unsigned, so a negative value gets treated as a large positive
                // value that is also clamped.
                timeout = s_maxUrlRetrievalTimeout;
            }

            // Let Unspecified mean Local, so only convert if the source was UTC.
            //
            // Converge on Local instead of UTC because OpenSSL is going to assume we gave it
            // local time.
            if (verificationTime.Kind == DateTimeKind.Utc)
            {
                verificationTime = verificationTime.ToLocalTime();
            }

            // Until we support the Disallowed store, ensure it's empty (which is done by the ctor)
            using (new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
            {
            }

            TimeSpan downloadTimeout = timeout;

            OpenSslX509ChainProcessor chainPal = OpenSslX509ChainProcessor.InitiateChain(
                ((OpenSslX509CertificateReader)cert).SafeHandle,
                customTrustStore,
                trustMode,
                verificationTime,
                downloadTimeout);

            Interop.Crypto.X509VerifyStatusCode status = chainPal.FindFirstChain(extraStore);

            if (!OpenSslX509ChainProcessor.IsCompleteChain(status) && !disableAia)
            {
                List <X509Certificate2>?tmp = null;
                status = chainPal.FindChainViaAia(ref tmp);

                if (tmp != null)
                {
                    if (status == Interop.Crypto.X509VerifyStatusCode.X509_V_OK)
                    {
                        SaveIntermediateCertificates(tmp);
                    }

                    foreach (X509Certificate2 downloaded in tmp)
                    {
                        downloaded.Dispose();
                    }
                }
            }

            // In NoCheck+OK then we don't need to build the chain any more, we already
            // know it's error-free.  So skip straight to finish.
            if (status != Interop.Crypto.X509VerifyStatusCode.X509_V_OK ||
                revocationMode != X509RevocationMode.NoCheck)
            {
                if (OpenSslX509ChainProcessor.IsCompleteChain(status))
                {
                    chainPal.CommitToChain();
                    chainPal.ProcessRevocation(revocationMode, revocationFlag);
                }
            }

            chainPal.Finish(applicationPolicy, certificatePolicy);

#if DEBUG
            if (chainPal.ChainElements !.Length > 0)
            {
                X509Certificate2 reportedLeaf = chainPal.ChainElements[0].Certificate;
                Debug.Assert(reportedLeaf != null, "reportedLeaf != null");
                Debug.Assert(!ReferenceEquals(cert, reportedLeaf.Pal), "!ReferenceEquals(cert, reportedLeaf.Pal)");
            }
#endif
            return(chainPal);
        }