Merge pull request #472 from MelanieT/spmanager_fix
[mono.git] / mcs / class / System / System.Net / ServicePointManager.cs
index 3e35e93a867020fca08fd47404f30aa09851b73d..21de4e04e02fbe8f6e7bb1d3726c3c957e180929 100644 (file)
@@ -114,14 +114,12 @@ namespace System.Net
                private static bool _checkCRL = false;
                private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
 
-#if NET_1_1
 #if TARGET_JVM
                static bool expectContinue = false;
 #else
                static bool expectContinue = true;
 #endif
                static bool useNagle;
-#endif
                static RemoteCertificateValidationCallback server_cert_cb;
                static bool tcp_keepalive;
                static int tcp_keepalive_time;
@@ -130,7 +128,11 @@ namespace System.Net
                // Fields
                
                public const int DefaultNonPersistentConnectionLimit = 4;
+#if MONOTOUCH
+               public const int DefaultPersistentConnectionLimit = 10;
+#else
                public const int DefaultPersistentConnectionLimit = 2;
+#endif
 
 #if !NET_2_1
                const string configKey = "system.net/connectionManagement";
@@ -140,7 +142,7 @@ namespace System.Net
                static ServicePointManager ()
                {
 #if !NET_2_1
-#if NET_2_0 && CONFIGURATION_DEP
+#if CONFIGURATION_DEP
                        object cfg = ConfigurationManager.GetSection (configKey);
                        ConnectionManagementSection s = cfg as ConnectionManagementSection;
                        if (s != null) {
@@ -166,22 +168,14 @@ namespace System.Net
                
                // Properties
                
-#if NET_2_0
                [Obsolete ("Use ServerCertificateValidationCallback instead", false)]
-#endif
                public static ICertificatePolicy CertificatePolicy {
                        get { return policy; }
                        set { policy = value; }
                }
 
-#if NET_1_0
-               // we need it for SslClientStream
-               internal
-#else
                [MonoTODO("CRL checks not implemented")]
-               public
-#endif
-               static bool CheckCertificateRevocationList {
+               public static bool CheckCertificateRevocationList {
                        get { return _checkCRL; }
                        set { _checkCRL = false; }      // TODO - don't yet accept true
                }
@@ -193,10 +187,11 @@ namespace System.Net
                                        throw new ArgumentOutOfRangeException ("value");
 
                                defaultConnectionLimit = value; 
+                if (manager != null)
+                                       manager.Add ("*", defaultConnectionLimit);
                        }
                }
 
-#if NET_2_0
                static Exception GetMustImplement ()
                {
                        return new NotImplementedException ();
@@ -223,7 +218,6 @@ namespace System.Net
                                throw GetMustImplement ();
                        }
                }
-#endif
                
                public static int MaxServicePointIdleTime {
                        get { 
@@ -270,7 +264,6 @@ namespace System.Net
                        }
                }
 
-#if NET_1_1
                public static bool Expect100Continue {
                        get { return expectContinue; }
                        set { expectContinue = value; }
@@ -280,7 +273,7 @@ namespace System.Net
                        get { return useNagle; }
                        set { useNagle = value; }
                }
-#endif
+
                // Methods
                public static void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval)
                {
@@ -312,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;
@@ -330,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;
@@ -410,26 +405,15 @@ namespace System.Net
                                return new ValidationResult (true, false, 0);
                        }
                }
-#elif NET_2_0 && SECURITY_DEP
+#elif SECURITY_DEP
                internal class ChainValidationHelper {
                        object sender;
                        string host;
                        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 {
@@ -473,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;
@@ -481,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);
@@ -490,49 +484,54 @@ 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 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
+                                               status11 = (int) trustResult;
+                                               errors |= SslPolicyErrors.RemoteCertificateChainErrors;
                                        }
 #if !MONOTOUCH
                                }
 #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
 
@@ -614,7 +613,7 @@ namespace System.Net
                                }
                                return (int) result;
                        }
-
+#if !MONOTOUCH
                        static SslPolicyErrors GetErrorsFromChain (X509Chain chain)
                        {
                                SslPolicyErrors errors = SslPolicyErrors.None;
@@ -775,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
        }