static bool EvaluateSystem(XX509CertificateCollection certs, XX509CertificateCollection anchors, string host, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
        {
            var  leaf = certs [0];
            bool result;

#if MONODROID
            result = AndroidPlatform.TrustEvaluateSsl(certs);
            if (result)
            {
                // chain.Build() + GetErrorsFromChain() (above) will ALWAYS fail on
                // Android (there are no mozroots or preinstalled root certificates),
                // thus `errors` will ALWAYS have RemoteCertificateChainErrors.
                // Android just verified the chain; clear RemoteCertificateChainErrors.
                errors &= ~SslPolicyErrors.RemoteCertificateChainErrors;
            }
#else
            if (is_macosx)
            {
                // Attempt to use OSX certificates
                // Ideally we should return the SecTrustResult
                OSX509Certificates.SecTrustResult trustResult = OSX509Certificates.SecTrustResult.Deny;
                try {
                    trustResult = OSX509Certificates.TrustEvaluateSsl(certs, anchors, host);
                    // We could use the other values of trustResult to pass this extra information
                    // to the .NET 2 callback for values like SecTrustResult.Confirm
                    result = (trustResult == OSX509Certificates.SecTrustResult.Proceed ||
                              trustResult == OSX509Certificates.SecTrustResult.Unspecified);
                } catch {
                    result  = false;
                    errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                    // Ignore
                }

                if (result)
                {
                    // TrustEvaluateSsl was successful so there's no trust error
                    // IOW we discard our own chain (since we trust OSX one instead)
                    errors = 0;
                }
                else
                {
                    // callback and DefaultCertificatePolicy needs this since 'result' is not specified
                    status11 = (int)trustResult;
                    errors  |= SslPolicyErrors.RemoteCertificateChainErrors;
                }
            }
            else
            {
                result = BuildX509Chain(certs, chain, ref errors, ref status11);
            }
#endif

            return(result);
        }
Esempio n. 2
0
            // Used when the obsolete ICertificatePolicy is set to DefaultCertificatePolicy
            // and the new ServerCertificateValidationCallback is not null
            internal ValidationResult ValidateChain(MSX.X509CertificateCollection certs)
            {
                // user_denied is true if the user callback is called and returns false
                bool user_denied = false;

                if (certs == null || certs.Count == 0)
                {
                    return(null);
                }

                ICertificatePolicy policy = ServicePointManager.CertificatePolicy;

                X509Certificate2 leaf    = new X509Certificate2(certs [0].RawData);
                int             status11 = 0;     // Error code passed to the obsolete ICertificatePolicy callback
                SslPolicyErrors errors   = 0;
                X509Chain       chain    = null;
                bool            result   = false;

#if MONOTOUCH
                // The X509Chain is not really usable with MonoTouch (since the decision is not based on this data)
                // However if someone wants to override the results (good or bad) from iOS then they will want all
                // the certificates that the server provided (which generally does not include the root) so, only
                // if there's a user callback, we'll create the X509Chain but won't build it
                // ref: https://bugzilla.xamarin.com/show_bug.cgi?id=7245
                if (ServerCertificateValidationCallback != null)
                {
#endif
                chain             = new X509Chain();
                chain.ChainPolicy = new X509ChainPolicy();
#if !MONOTOUCH
                chain.ChainPolicy.RevocationMode = revocation_mode;
#endif
                for (int i = 1; i < certs.Count; i++)
                {
                    X509Certificate2 c2 = new X509Certificate2(certs [i].RawData);
                    chain.ChainPolicy.ExtraStore.Add(c2);
                }
#if MONOTOUCH
            }
#else
                try {
                    if (!chain.Build(leaf))
                    {
                        errors |= GetErrorsFromChain(chain);
                    }
                } catch (Exception e) {
                    Console.Error.WriteLine("ERROR building certificate chain: {0}", e);
                    Console.Error.WriteLine("Please, report this problem to the Mono team");
                    errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                }

                // for OSX and iOS we're using the native API to check for the SSL server policy and host names
                if (!is_macosx)
                {
                    if (!CheckCertificateUsage(leaf))
                    {
                        errors  |= SslPolicyErrors.RemoteCertificateChainErrors;
                        status11 = -2146762490;                         //CERT_E_PURPOSE 0x800B0106
                    }

                    if (!CheckServerIdentity(certs [0], host))
                    {
                        errors  |= SslPolicyErrors.RemoteCertificateNameMismatch;
                        status11 = -2146762481;                         // CERT_E_CN_NO_MATCH 0x800B010F
                    }
                }
                else
                {
#endif
            // Attempt to use OSX certificates
            // Ideally we should return the SecTrustResult
            OSX509Certificates.SecTrustResult trustResult = OSX509Certificates.SecTrustResult.Deny;
            try {
                trustResult = OSX509Certificates.TrustEvaluateSsl(certs, host);
                // We could use the other values of trustResult to pass this extra information
                // to the .NET 2 callback for values like SecTrustResult.Confirm
                result = (trustResult == OSX509Certificates.SecTrustResult.Proceed ||
                          trustResult == OSX509Certificates.SecTrustResult.Unspecified);
            } catch {
                // Ignore
            }

            if (result)
            {
                // TrustEvaluateSsl was successful so there's no trust error
                // IOW we discard our own chain (since we trust OSX one instead)
                errors = 0;
            }
            else
            {
                // callback and DefaultCertificatePolicy needs this since 'result' is not specified
                status11 = (int)trustResult;
                errors  |= SslPolicyErrors.RemoteCertificateChainErrors;
            }
#if !MONOTOUCH
        }
#endif

#if MONODROID && SECURITY_DEP
            result = AndroidPlatform.TrustEvaluateSsl(certs, sender, leaf, chain, errors);
            if (result)
            {
                // chain.Build() + GetErrorsFromChain() (above) will ALWAYS fail on
                // Android (there are no mozroots or preinstalled root certificates),
                // thus `errors` will ALWAYS have RemoteCertificateChainErrors.
                // Android just verified the chain; clear RemoteCertificateChainErrors.
                errors &= ~SslPolicyErrors.RemoteCertificateChainErrors;
            }
#endif

            if (policy != null && (!(policy is DefaultCertificatePolicy) || cb == null))
            {
                ServicePoint   sp  = null;
                HttpWebRequest req = sender as HttpWebRequest;
                if (req != null)
                {
                    sp = req.ServicePointNoLock;
                }
                if (status11 == 0 && errors != 0)
                {
                    status11 = GetStatusFromChain(chain);
                }

                // pre 2.0 callback
                result      = policy.CheckValidationResult(sp, leaf, req, status11);
                user_denied = !result && !(policy is DefaultCertificatePolicy);
            }
            // If there's a 2.0 callback, it takes precedence
            if (ServerCertificateValidationCallback != null)
            {
                result      = ServerCertificateValidationCallback(sender, leaf, chain, errors);
                user_denied = !result;
            }
            return(new ValidationResult(result, user_denied, status11));
        }
Esempio n. 3
0
        ValidationResult ValidateChain(string host, X509Certificate2Collection certs, SslPolicyErrors errors)
        {
            // user_denied is true if the user callback is called and returns false
            bool user_denied = false;
            bool result      = false;

            var hasCallback = certValidationCallback != null || callbackWrapper != null;

            X509Certificate2 leaf;

            if (certs == null || certs.Count == 0)
            {
                leaf = null;
            }
            else
            {
                leaf = certs [0];
            }

            if (tlsStream != null)
            {
                request.ServicePoint.SetServerCertificate(leaf);
            }

            if (leaf == null)
            {
                errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
                if (hasCallback)
                {
                    if (callbackWrapper != null)
                    {
                        result = callbackWrapper.Invoke(certValidationCallback, leaf, null, (MonoSslPolicyErrors)errors);
                    }
                    else
                    {
                        result = certValidationCallback.Invoke(sender, leaf, null, errors);
                    }
                    user_denied = !result;
                }
                return(new ValidationResult(result, user_denied, 0, (MonoSslPolicyErrors)errors));
            }

            bool needsChain;
            bool skipSystemValidators = false;

            if (!CertificateValidationHelper.SupportsX509Chain || is_mobile || is_macosx)
            {
                needsChain = false;
            }
            else if (settings != null)
            {
                skipSystemValidators = settings.SkipSystemValidators;
                needsChain           = !settings.SkipSystemValidators || settings.CallbackNeedsCertificateChain;
            }
            else
            {
                needsChain = true;
            }

            ICertificatePolicy policy = ServicePointManager.GetLegacyCertificatePolicy();

            int       status11 = 0;       // Error code passed to the obsolete ICertificatePolicy callback
            X509Chain chain    = null;

            if (needsChain)
            {
                chain             = new X509Chain();
                chain.ChainPolicy = new X509ChainPolicy();


#if !MONOTOUCH
                chain.ChainPolicy.RevocationMode = revocation_mode;
#endif
                for (int i = 1; i < certs.Count; i++)
                {
                    chain.ChainPolicy.ExtraStore.Add(certs [i]);
                }
            }

#if !MONOTOUCH
            if (needsChain)
            {
                try {
                    if (!chain.Build(leaf))
                    {
                        errors |= GetErrorsFromChain(chain);
                    }
                } catch (Exception e) {
                    Console.Error.WriteLine("ERROR building certificate chain: {0}", e);
                    Console.Error.WriteLine("Please, report this problem to the Mono team");
                    errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                }
            }

            // for OSX and iOS we're using the native API to check for the SSL server policy and host names
            if (!is_macosx)
            {
                if (!CheckCertificateUsage(leaf))
                {
                    errors  |= SslPolicyErrors.RemoteCertificateChainErrors;
                    status11 = -2146762490;                     //CERT_E_PURPOSE 0x800B0106
                }

                if (host != null && !CheckServerIdentity(leaf, host))
                {
                    errors  |= SslPolicyErrors.RemoteCertificateNameMismatch;
                    status11 = -2146762481;                     // CERT_E_CN_NO_MATCH 0x800B010F
                }
            }
#endif

            if (is_macosx && !skipSystemValidators)
            {
                // Attempt to use OSX certificates
                // Ideally we should return the SecTrustResult
                OSX509Certificates.SecTrustResult trustResult = OSX509Certificates.SecTrustResult.Deny;
                try {
                    trustResult = OSX509Certificates.TrustEvaluateSsl(certs, host);
                    // We could use the other values of trustResult to pass this extra information
                    // to the .NET 2 callback for values like SecTrustResult.Confirm
                    result = (trustResult == OSX509Certificates.SecTrustResult.Proceed ||
                              trustResult == OSX509Certificates.SecTrustResult.Unspecified);
                } catch {
                    // Ignore
                }

                if (result)
                {
                    // TrustEvaluateSsl was successful so there's no trust error
                    // IOW we discard our own chain (since we trust OSX one instead)
                    errors = 0;
                }
                else
                {
                    // callback and DefaultCertificatePolicy needs this since 'result' is not specified
                    status11 = (int)trustResult;
                    errors  |= SslPolicyErrors.RemoteCertificateChainErrors;
                }
            }


#if MONODROID && SECURITY_DEP
            if (!skipSystemValidators)
            {
                result = AndroidPlatform.TrustEvaluateSsl(certs, sender, leaf, chain, errors);
                if (result)
                {
                    // chain.Build() + GetErrorsFromChain() (above) will ALWAYS fail on
                    // Android (there are no mozroots or preinstalled root certificates),
                    // thus `errors` will ALWAYS have RemoteCertificateChainErrors.
                    // Android just verified the chain; clear RemoteCertificateChainErrors.
                    errors &= ~SslPolicyErrors.RemoteCertificateChainErrors;
                }
            }
#endif

            if (policy != null && (!(policy is DefaultCertificatePolicy) || certValidationCallback == null))
            {
                ServicePoint sp = null;
                if (request != null)
                {
                    sp = request.ServicePointNoLock;
                }
                if (status11 == 0 && errors != 0)
                {
                    status11 = GetStatusFromChain(chain);
                }

                // pre 2.0 callback
                result      = policy.CheckValidationResult(sp, leaf, request, status11);
                user_denied = !result && !(policy is DefaultCertificatePolicy);
            }
            // If there's a 2.0 callback, it takes precedence
            if (hasCallback)
            {
                if (callbackWrapper != null)
                {
                    result = callbackWrapper.Invoke(certValidationCallback, leaf, chain, (MonoSslPolicyErrors)errors);
                }
                else
                {
                    result = certValidationCallback.Invoke(sender, leaf, chain, errors);
                }
                user_denied = !result;
            }
            return(new ValidationResult(result, user_denied, status11, (MonoSslPolicyErrors)errors));
        }