Merge pull request #472 from MelanieT/spmanager_fix
[mono.git] / mcs / class / System / System.Net / ServicePointManager.cs
index 23c56bd28e71cb96c1b108306a38205fa4ab0095..21de4e04e02fbe8f6e7bb1d3726c3c957e180929 100644 (file)
@@ -187,6 +187,8 @@ namespace System.Net
                                        throw new ArgumentOutOfRangeException ("value");
 
                                defaultConnectionLimit = value; 
+                if (manager != null)
+                                       manager.Add ("*", defaultConnectionLimit);
                        }
                }
 
@@ -303,6 +305,8 @@ namespace System.Net
                                throw new ArgumentNullException ("address");
 
                        RecycleServicePoints ();
+
+                       var origAddress = new Uri (address.Scheme + "://" + address.Authority);
                        
                        bool usesProxy = false;
                        bool useConnect = false;
@@ -321,7 +325,7 @@ namespace System.Net
                        
                        ServicePoint sp = null;
                        lock (servicePoints) {
-                               SPKey key = new SPKey (address, useConnect);
+                               SPKey key = new SPKey (origAddress, useConnect);
                                sp = servicePoints [key] as ServicePoint;
                                if (sp != null)
                                        return sp;
@@ -408,19 +412,8 @@ namespace System.Net
                        static bool is_macosx = System.IO.File.Exists (MSX.OSX509Certificates.SecurityLibrary);
                        static X509RevocationMode revocation_mode;
 
-#if MONODROID
-                       static readonly Converter<Mono.Security.X509.X509CertificateCollection, bool> monodroidCallback;
-#endif
-
                        static ChainValidationHelper ()
                        {
-#if MONODROID
-                               monodroidCallback = (Converter<Mono.Security.X509.X509CertificateCollection, bool>)
-                                       Delegate.CreateDelegate (typeof(Converter<Mono.Security.X509.X509CertificateCollection, bool>), 
-                                                       Type.GetType ("Android.Runtime.AndroidEnvironment, Mono.Android", true)
-                                                       .GetMethod ("TrustEvaluateSsl", 
-                                                               System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic));
-#endif
 #if !MONOTOUCH
                                revocation_mode = X509RevocationMode.NoCheck;
                                try {
@@ -464,7 +457,15 @@ namespace System.Net
                                int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
                                SslPolicyErrors errors = 0;
                                X509Chain chain = null;
-#if !MONOTOUCH
+                               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 (cb != null) {
+#endif
                                chain = new X509Chain ();
                                chain.ChainPolicy = new X509ChainPolicy ();
                                chain.ChainPolicy.RevocationMode = revocation_mode;
@@ -472,7 +473,9 @@ namespace System.Net
                                        X509Certificate2 c2 = new X509Certificate2 (certs [i].RawData);
                                        chain.ChainPolicy.ExtraStore.Add (c2);
                                }
-
+#if MONOTOUCH
+                               }
+#else
                                try {
                                        if (!chain.Build (leaf))
                                                errors |= GetErrorsFromChain (chain);
@@ -481,38 +484,36 @@ namespace System.Net
                                        Console.Error.WriteLine ("Please, report this problem to the Mono team");
                                        errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                                }
-#endif
-                               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
-                               }
+                               // 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
+                                       }
 
-                               bool result = false;
-                               // No certificate root found means no mozroots or monotouch
-#if !MONOTOUCH
-                               if (is_macosx) {
+                                       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
                                        MSX.OSX509Certificates.SecTrustResult trustResult = MSX.OSX509Certificates.SecTrustResult.Deny;
                                        try {
-                                               trustResult = MSX.OSX509Certificates.TrustEvaluateSsl (certs);
+                                               trustResult = MSX.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 == MSX.OSX509Certificates.SecTrustResult.Proceed ||
                                                                  trustResult == MSX.OSX509Certificates.SecTrustResult.Unspecified);
-
                                        } catch {
                                                // Ignore
                                        }
-                                       // Clear error status if the OS told us to trust the certificate
+                                       
                                        if (result) {
-                                               status11 = 0;
+                                               // 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
@@ -524,10 +525,13 @@ namespace System.Net
 #endif
 
 #if MONODROID
-                               result = monodroidCallback (certs);
+                               result = AndroidPlatform.TrustEvaluateSsl (certs, sender, leaf, chain, errors);
                                if (result) {
-                                       status11 = 0;
-                                       errors = 0;
+                                       // 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
 
@@ -609,7 +613,7 @@ namespace System.Net
                                }
                                return (int) result;
                        }
-
+#if !MONOTOUCH
                        static SslPolicyErrors GetErrorsFromChain (X509Chain chain)
                        {
                                SslPolicyErrors errors = SslPolicyErrors.None;
@@ -770,6 +774,7 @@ namespace System.Net
                                string start = pattern.Substring (0, index);
                                return (String.Compare (hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0);
                        }
+#endif
                }
 #endif
        }