Moved chain building and validation from Mono.Security to System
authorGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Thu, 11 Mar 2010 06:02:08 +0000 (06:02 -0000)
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Thu, 11 Mar 2010 06:02:08 +0000 (06:02 -0000)
to better support the 2.0 validation callback.

svn path=/trunk/mcs/; revision=153443

15 files changed:
1  2 
mcs/class/Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/ChangeLog
mcs/class/Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerCertificate.cs
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ChangeLog
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslServerStream.cs
mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs
mcs/class/Mono.Security/Mono.Security.X509/ChangeLog
mcs/class/Mono.Security/Mono.Security.X509/OSX509Certificates.cs
mcs/class/Mono.Security/Mono.Security.dll.sources
mcs/class/System/System.Net/ChangeLog
mcs/class/System/System.Net/ServicePointManager.cs
mcs/class/System/System.Security.Cryptography.X509Certificates/ChangeLog
mcs/class/System/System.Security.Cryptography.X509Certificates/OSX509Certificates.cs
mcs/class/System/System.dll.sources
mcs/class/System/monotouch_System.dll.sources

index b3a60e26dcad9545ce2c19ef6f858332bb780ba7,b3a60e26dcad9545ce2c19ef6f858332bb780ba7..e1747f253bdcdbd07a1316e48322dfc93d694336
@@@ -1,3 -1,3 +1,8 @@@
++2010-03-11 Gonzalo Paniagua Javier <gonzalo@novell.com>
++
++      * TlsServerCertificate.cs: chain is built and validated in
++      System.dll now.
++
  2010-03-01 Gonzalo Paniagua Javier <gonzalo@novell.com>
  
        * TlsServerCertificate.cs:
index a747ba8aa95284d181f13fa7b1e2ad2504d596e9,a747ba8aa95284d181f13fa7b1e2ad2504d596e9..cf17da1223d8b27e205c239e92a1e70dbd8957fd
@@@ -195,9 -195,9 +195,26 @@@ namespace Mono.Security.Protocol.Tls.Ha
  
  #if NET_2_0
                        if (context.SslStream.HaveRemoteValidation2Callback) {
--                              if (context.SslStream.RaiseServerCertificateValidation2 (certificates))
++                              ValidationResult res = context.SslStream.RaiseServerCertificateValidation2 (certificates);
++                              if (res.Trusted)
                                        return;
--                              // Give a chance to the 1.x ICertificatePolicy callback
++
++                              long error = res.ErrorCode;
++                              switch (error) {
++                              case 0x800B0101:
++                                      description = AlertDescription.CertificateExpired;
++                                      break;
++                              case 0x800B010A:
++                                      description = AlertDescription.UnknownCA;
++                                      break;
++                              case 0x800B0109:
++                                      description = AlertDescription.UnknownCA;
++                                      break;
++                              default:
++                                      description = AlertDescription.CertificateUnknown;
++                                      break;
++                              }
++                              throw new TlsException (description, "Invalid certificate received from server.");
                        }
  #endif
                        // the leaf is the web server certificate
                                result = false;
                        }
  
--                      // Attempt to use OSX certificates
--                      //
--                      // Ideally we should return the SecTrustResult
--#if !MONOTOUCH
--                      if (System.IO.File.Exists (OSX509Certificates.SecurityLibrary)){
--#endif
--                              OSX509Certificates.SecTrustResult trustResult =  OSX509Certificates.TrustEvaluateSsl (certificates);
--
--                              // 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);
--#if !MONOTOUCH
--                      }
--#endif
--                      
                        if (!result) 
                        {
                                switch (verify.Status) 
index 9c2265cf2d7ccc4685250e81f7890d07e4cbcf67,9c2265cf2d7ccc4685250e81f7890d07e4cbcf67..7c677b39bbd3afa82ba9a4e70bc1eb2b48dcbe67
@@@ -1,3 -1,3 +1,9 @@@
++2010-03-11 Gonzalo Paniagua Javier <gonzalo@novell.com>
++
++      * SslStreamBase.cs:
++      * SslClientStream.cs:
++      * SslServerStream.cs: modify the 2.0 callback to return more info.
++
  2010-03-01 Gonzalo Paniagua Javier <gonzalo@novell.com>
  
        * HttpsClientStream.cs: use Address instead
index d157c7d72d63fe8cd269fc4e14be29ae676cb31e,d157c7d72d63fe8cd269fc4e14be29ae676cb31e..67add4f0e8aaaff67d1a61b6978b82b3a0cb2af4
@@@ -40,7 -40,7 +40,33 @@@ namespace Mono.Security.Protocol.Tl
        public delegate bool CertificateValidationCallback(
                X509Certificate certificate, 
                int[]                   certificateErrors);
--      public delegate bool CertificateValidationCallback2 (Mono.Security.X509.X509CertificateCollection collection);
++
++      public class ValidationResult {
++              bool trusted;
++              bool user_denied;
++              int error_code;
++
++              public ValidationResult (bool trusted, bool user_denied, int error_code)
++              {
++                      this.trusted = trusted;
++                      this.user_denied = user_denied;
++                      this.error_code = error_code;
++              }
++
++              public bool Trusted {
++                      get { return trusted; }
++              }
++
++              public bool UserDenied {
++                      get { return user_denied; }
++              }
++
++              public int ErrorCode {
++                      get { return error_code; }
++              }
++      }
++
++      public delegate ValidationResult CertificateValidationCallback2 (Mono.Security.X509.X509CertificateCollection collection);
  
        public delegate X509Certificate CertificateSelectionCallback(
                X509CertificateCollection       clientCertificates, 
                        get { return ServerCertValidation2 != null; }
                }
  
--              internal override bool OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
++              internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
                {
                        CertificateValidationCallback2 cb = ServerCertValidation2;
                        if (cb != null)
                                return cb (collection);
--                      return false;
++                      return null;
                }
  
                internal override bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors)
                        return base.RaiseRemoteCertificateValidation(certificate, certificateErrors);
                }
  
--              internal virtual bool RaiseServerCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
++              internal virtual ValidationResult RaiseServerCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
                {
                        return base.RaiseRemoteCertificateValidation2 (collection);
                }
index ee84396c5d1a74e0c81d745290cff1e97a8be7a9,ee84396c5d1a74e0c81d745290cff1e97a8be7a9..cc36ee83b74164a2e8235496372e4e8037777482
@@@ -309,12 -309,12 +309,12 @@@ namespace Mono.Security.Protocol.Tl
                        get { return ClientCertValidation2 != null; }
                }
  
--              internal override bool OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
++              internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
                {
                        CertificateValidationCallback2 cb = ClientCertValidation2;
                        if (cb != null)
                                return cb (collection);
--                      return false;
++                      return null;
                }
  
                internal bool RaiseClientCertificateValidation(
index 9006eb5c26ed41c6d7a3efecb6b414d032e73247,9006eb5c26ed41c6d7a3efecb6b414d032e73247..f347ccb2bdf72f6e32c170de56b59e468f05f6a5
@@@ -185,7 -185,7 +185,7 @@@ namespace Mono.Security.Protocol.Tl
                                                                                                                        X509CertificateCollection serverRequestedCertificates);
  
                internal abstract bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors);
--              internal abstract bool OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection);
++              internal abstract ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection);
                internal abstract bool HaveRemoteValidation2Callback { get; }
  
                internal abstract AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost);
                        return OnRemoteCertificateValidation(certificate, errors);
                }
  
--              internal bool RaiseRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
++              internal ValidationResult RaiseRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
                {
                        return OnRemoteCertificateValidation2 (collection);
                }
index b20c91c63e11270dbb1b786833d87ba358613c5b,b20c91c63e11270dbb1b786833d87ba358613c5b..4e2030119635246d38f5d5f22cbc99d383a5ec6d
@@@ -1,3 -1,3 +1,7 @@@
++2010-03-11 Gonzalo Paniagua Javier <gonzalo@novell.com>
++
++      * OSX509Certificates.cs: moved to System.dll.
++
  2010-02-27  Miguel de Icaza  <miguel@novell.com>
  
        * OSX509Certificates.cs: Add support to validate X509 certificate
diff --cc mcs/class/Mono.Security/Mono.Security.X509/OSX509Certificates.cs
index c032f9bb1e6d103ff2b42c5f6979c7466ae33b85,c032f9bb1e6d103ff2b42c5f6979c7466ae33b85..0000000000000000000000000000000000000000
deleted file mode 100644,100644
+++ /dev/null
@@@ -1,142 -1,142 +1,0 @@@
--// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
--//
--// Permission is hereby granted, free of charge, to any person obtaining
--// a copy of this software and associated documentation files (the
--// "Software"), to deal in the Software without restriction, including
--// without limitation the rights to use, copy, modify, merge, publish,
--// distribute, sublicense, and/or sell copies of the Software, and to
--// permit persons to whom the Software is furnished to do so, subject to
--// the following conditions:
--// 
--// The above copyright notice and this permission notice shall be
--// included in all copies or substantial portions of the Software.
--// 
--// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
--// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
--// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
--// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
--// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
--// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
--// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--//
--using System;
--using System.Runtime.InteropServices;
--using Mono.Security.X509;
--using Mono.Security.X509.Extensions;
--
--namespace Mono.Security.X509 {
--
--      internal class OSX509Certificates {
--              public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
--              public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
--      
--              [DllImport (SecurityLibrary)]
--              extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
--              
--              [DllImport (SecurityLibrary)]
--              extern static int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
--              
--              [DllImport (SecurityLibrary)]
--              extern static IntPtr SecPolicyCreateSSL (int server, IntPtr cfStringHostname);
--              
--              [DllImport (SecurityLibrary)]
--              extern static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
--
--              [DllImport (CoreFoundationLibrary)]
--              unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, IntPtr length);
--
--              [DllImport (CoreFoundationLibrary)]
--              unsafe extern static void CFRelease (IntPtr handle);
--
--              [DllImport (CoreFoundationLibrary)]
--              extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, IntPtr numValues, IntPtr callbacks);
--              
--              public enum SecTrustResult {
--                      Invalid,
--                      Proceed,
--                      Confirm,
--                      Deny,
--                      Unspecified,
--                      RecoverableTrustFailure,
--                      FatalTrustFailure,
--                      ResultOtherError,
--              }
--
--              static IntPtr sslsecpolicy = SecPolicyCreateSSL (0, IntPtr.Zero);
--
--              static IntPtr MakeCFData (byte [] data)
--              {
--                      unsafe {
--                              fixed (byte *ptr = &data [0])
--                                      return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
--                      }
--              }
--
--              static unsafe IntPtr FromIntPtrs (IntPtr [] values)
--              {
--                      fixed (IntPtr* pv = values) {
--                              return CFArrayCreate (
--                                      IntPtr.Zero, 
--                                      (IntPtr) pv,
--                                      (IntPtr) values.Length,
--                                      IntPtr.Zero);
--                      }
--              }
--              
--              public static SecTrustResult TrustEvaluateSsl (X509CertificateCollection certificates)
--              {
--                      try {
--                              return _TrustEvaluateSsl (certificates);
--                      } catch {
--                              return SecTrustResult.Deny;
--                      }
--              }
--              
--              static SecTrustResult _TrustEvaluateSsl (X509CertificateCollection certificates)
--              {
--                      if (certificates == null)
--                              throw new ArgumentNullException ("certificates");
--
--                      int certCount = certificates.Count;
--                      IntPtr [] cfDataPtrs = new IntPtr [certCount];
--                      IntPtr [] secCerts = new IntPtr [certCount];
--                      IntPtr certArray = IntPtr.Zero;
--                      
--                      try {
--                              for (int i = 0; i < certCount; i++)
--                                      cfDataPtrs [i] = MakeCFData (certificates [i].RawData);
--                              
--                              for (int i = 0; i < certCount; i++){
--                                      secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
--                                      if (secCerts [i] == IntPtr.Zero){
--                                              CFRelease (cfDataPtrs [i]);
--                                              return SecTrustResult.Deny;
--                                      }
--                              }
--                              certArray = FromIntPtrs (secCerts);
--                              IntPtr sectrust;
--                              int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
--                              if (code == 0){
--                                      SecTrustResult result;
--                                      code = SecTrustEvaluate (sectrust, out result);
--                                      if (code != 0)
--                                              return SecTrustResult.Deny;
--
--                                      CFRelease (sectrust);
--                                      CFRelease (sslsecpolicy);
--                                      
--                                      return result;
--                              }
--                              return SecTrustResult.Deny;
--                      } finally {
--                              for (int i = 0; i < certCount; i++)
--                                      if (secCerts [i] != IntPtr.Zero)
--                                              CFRelease (cfDataPtrs [i]);
--
--                              if (certArray != IntPtr.Zero)
--                                      CFRelease (certArray);
--                      }
--              }
--      }
--}
--              
index 44c2cc6de3861589b1c0a187876eee671f9187ec,44c2cc6de3861589b1c0a187876eee671f9187ec..f38e35e06aba5223770483a2a9ab2304b37a5a84
@@@ -36,7 -36,7 +36,6 @@@
  ./Mono.Security.Cryptography/SHA224.cs
  ./Mono.Security.Cryptography/SHA224Managed.cs
  ./Mono.Security.Cryptography/SymmetricTransform.cs
--./Mono.Security.X509/OSX509Certificates.cs
  ./Mono.Security.X509/PKCS12.cs
  ./Mono.Security.X509/X501Name.cs
  ./Mono.Security.X509/X509Builder.cs
index b19e3543251780fc443ebedae817260e11336ca5,eb928cb813548557afac803a64761be64aecee47..6c227732843b788a340f4c697639fa4a84a0452f
@@@ -1,47 -1,3 +1,50 @@@
++2010-03-11 Gonzalo Paniagua Javier <gonzalo@novell.com>
++
++      * ServicePointManager.cs: perform the entire chain validation here.
 +
 +2010-03-09 Gonzalo Paniagua Javier <gonzalo@novell.com>
 +
 +      * HttpConnection.cs: set the right position when a CR is found.
 +      Fixes bug #577891.
 +
 +2010-03-09 Gonzalo Paniagua Javier <gonzalo@novell.com>
 +
 +      * HttpListener.cs:
 +      * HttpListenerRequest.cs:
 +      * ListenerAsyncResult.cs:
 +      * HttpConnection.cs: make sure there is no pending input when reusing
 +      the connection.
 +
 +2010-03-08 Gonzalo Paniagua Javier <gonzalo@novell.com>
 +
 +      * HttpListenerContext.cs: split the auth header in 2 parts.
 +      * HttpListener.cs: backported SelectAuthenticationScheme and
 +      added new InternalEndGetContext used for connections that require
 +      authentication.
 +      * ListenerAsyncResult.cs: allow this object to be just a forwarder
 +      when nesting connections for authentication purposes.
 +      Fixes bug #585455.
 +
 +2010-03-06 Gonzalo Paniagua Javier <gonzalo@novell.com>
 +
 +      * WebClient.cs: fix for UploadStringAsync(). Closes bug #577818.
 +      Patch by Atsushi.
 +
 +2010-03-04  Atsushi Enomoto  <atsushi@ximian.com>
 +
 +      * HttpListenerContext.cs : WWW-Authenticate header should not be
 +        limited to Basic.
 +
 +2010-03-04  Atsushi Enomoto  <atsushi@ximian.com>
 +
 +      * HttpListenerContext.cs : The header line here is already trimmed
 +        "Authorization:" , so do not try to remove it.
 +
 +2010-03-04  Atsushi Enomoto  <atsushi@ximian.com>
 +
 +      * HttpListener.cs, ListenerAsyncResult.cs : fix authentication
 +        scheme selection mismatch.
 +
  2010-03-03  Atsushi Enomoto  <atsushi@ximian.com>
  
        * HttpListenerContext.cs, HttpListener.cs :
index dca551f4bbc0fb893d38e03aaa58fc126788602d,dca551f4bbc0fb893d38e03aaa58fc126788602d..a2692c615db9313fbf8c2048f861c44065243abf
@@@ -1,8 -1,8 +1,11 @@@
  //
  // System.Net.ServicePointManager
  //
--// Author:
++// Authors:
  //   Lawrence Pit (loz@cable.a2000.nl)
++//   Gonzalo Paniagua Javier (gonzalo@novell.com)
++//
++// Copyright (c) 2003-2010 Novell, Inc (http://www.novell.com)
  //
  
  //
@@@ -41,6 -41,6 +44,8 @@@ using System.Text.RegularExpressions
  using Mono.Security;
  using Mono.Security.Cryptography;
  using Mono.Security.X509.Extensions;
++using Mono.Security.Protocol.Tls;
++using MSX = Mono.Security.X509;
  #endif
  #endif
  
@@@ -160,8 -160,8 +165,7 @@@ namespace System.Ne
                // Properties
                
  #if NET_2_0
--              [Obsolete ("Use ServerCertificateValidationCallback instead",
--                         false)]
++              [Obsolete ("Use ServerCertificateValidationCallback instead", false)]
  #endif
                public static ICertificatePolicy CertificatePolicy {
                        get { return policy; }
  
                        // Used when the obsolete ICertificatePolicy is set to DefaultCertificatePolicy
                        // and the new ServerCertificateValidationCallback is not null
--                      internal bool ValidateChain (Mono.Security.X509.X509CertificateCollection certs)
++                      internal ValidationResult ValidateChain (Mono.Security.X509.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 false;
++                                      return null;
  
++                              ICertificatePolicy policy = ServicePointManager.CertificatePolicy;
                                RemoteCertificateValidationCallback cb = ServicePointManager.ServerCertificateValidationCallback;
--                              if (cb == null)
--                                      return false;
  
                                X509Chain chain = new X509Chain ();
                                chain.ChainPolicy = new X509ChainPolicy ();
                                }
  
                                X509Certificate2 leaf = new X509Certificate2 (certs [0].RawData);
++                              int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
                                SslPolicyErrors errors = 0;
                                if (!chain.Build (leaf))
                                        errors |= GetErrorsFromChain (chain);
--                              if (!CheckCertificateUsage (leaf)) // -2146762490: CERT_E_PURPOSE
++                              if (!CheckCertificateUsage (leaf)) {
                                        errors |= SslPolicyErrors.RemoteCertificateChainErrors;
--                              if (!CheckServerIdentity (leaf, Host))
++                                      status11 = -2146762490; //CERT_E_PURPOSE 0x800B0106
++                              }
++                              if (!CheckServerIdentity (leaf, Host)) {
                                        errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
--                              return cb (sender, leaf, chain, errors);
++                                      status11 = -2146762481; // CERT_E_CN_NO_MATCH 0x800B010F
++                              }
++
++                              bool result = false;
++                              // No certificate root found means no mozroots or monotouch
++                              if (Environment.OSVersion.Platform == PlatformID.MacOSX) {
++#if !MONOTOUCH
++                              if (System.IO.File.Exists (MSX.OSX509Certificates.SecurityLibrary)) {
++#endif
++                                      // Attempt to use OSX certificates
++                                      // Ideally we should return the SecTrustResult
++                                      MSX.OSX509Certificates.SecTrustResult trustResult;
++                                      try {
++                                              trustResult = MSX.OSX509Certificates.TrustEvaluateSsl (certs);
++                                              // 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;
++                                              errors = 0;
++                                      }
++#if !MONOTOUCH
++                              }
++#endif
++                              }
++
++                              if (policy != null && (!(policy is DefaultCertificatePolicy) || cb == null)) {
++                                      ServicePoint sp = null;
++                                      HttpWebRequest req = sender as HttpWebRequest;
++                                      if (req != null)
++                                              sp = req.ServicePoint;
++                                      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 (cb != null) {
++                                      result = cb (sender, leaf, chain, errors);
++                                      user_denied = !result;
++                              }
++                              return new ValidationResult (result, user_denied, status11);
++                      }
++
++                      static int GetStatusFromChain (X509Chain chain)
++                      {
++                              long result = 0;
++                              foreach (var status in chain.ChainStatus) {
++                                      X509ChainStatusFlags flags = status.Status;
++                                      if (flags == X509ChainStatusFlags.NoError)
++                                              continue;
++
++                                      // CERT_E_EXPIRED
++                                      if ((flags & X509ChainStatusFlags.NotTimeValid) != 0) result = 0x800B0101;
++                                      // CERT_E_VALIDITYPERIODNESTING
++                                      else if ((flags & X509ChainStatusFlags.NotTimeNested) != 0) result = 0x800B0102;
++                                      // CERT_E_REVOKED
++                                      else if ((flags & X509ChainStatusFlags.Revoked) != 0) result = 0x800B010C;
++                                      // TRUST_E_CERT_SIGNATURE
++                                      else if ((flags & X509ChainStatusFlags.NotSignatureValid) != 0) result = 0x80096004;
++                                      // CERT_E_WRONG_USAGE
++                                      else if ((flags & X509ChainStatusFlags.NotValidForUsage) != 0) result = 0x800B0110;
++                                      // CERT_E_UNTRUSTEDROOT
++                                      else if ((flags & X509ChainStatusFlags.UntrustedRoot) != 0) result = 0x800B0109;
++                                      // CRYPT_E_NO_REVOCATION_CHECK
++                                      else if ((flags & X509ChainStatusFlags.RevocationStatusUnknown) != 0) result = 0x80092012;
++                                      // CERT_E_CHAINING
++                                      else if ((flags & X509ChainStatusFlags.Cyclic) != 0) result = 0x800B010A;
++                                      // TRUST_E_FAIL - generic
++                                      else if ((flags & X509ChainStatusFlags.InvalidExtension) != 0) result = 0x800B010B;
++                                      // CERT_E_UNTRUSTEDROOT
++                                      else if ((flags & X509ChainStatusFlags.InvalidPolicyConstraints) != 0) result = 0x800B010D;
++                                      // TRUST_E_BASIC_CONSTRAINTS
++                                      else if ((flags & X509ChainStatusFlags.InvalidBasicConstraints) != 0) result = 0x80096019;
++                                      // CERT_E_INVALID_NAME
++                                      else if ((flags & X509ChainStatusFlags.InvalidNameConstraints) != 0) result = 0x800B0114;
++                                      // CERT_E_INVALID_NAME
++                                      else if ((flags & X509ChainStatusFlags.HasNotSupportedNameConstraint) != 0) result = 0x800B0114;
++                                      // CERT_E_INVALID_NAME
++                                      else if ((flags & X509ChainStatusFlags.HasNotDefinedNameConstraint) != 0) result = 0x800B0114;
++                                      // CERT_E_INVALID_NAME
++                                      else if ((flags & X509ChainStatusFlags.HasNotPermittedNameConstraint) != 0) result = 0x800B0114;
++                                      // CERT_E_INVALID_NAME
++                                      else if ((flags & X509ChainStatusFlags.HasExcludedNameConstraint) != 0) result = 0x800B0114;
++                                      // CERT_E_CHAINING
++                                      else if ((flags & X509ChainStatusFlags.PartialChain) != 0) result = 0x800B010A;
++                                      // CERT_E_EXPIRED
++                                      else if ((flags & X509ChainStatusFlags.CtlNotTimeValid) != 0) result = 0x800B0101;
++                                      // TRUST_E_CERT_SIGNATURE
++                                      else if ((flags & X509ChainStatusFlags.CtlNotSignatureValid) != 0) result = 0x80096004;
++                                      // CERT_E_WRONG_USAGE
++                                      else if ((flags & X509ChainStatusFlags.CtlNotValidForUsage) != 0) result = 0x800B0110;
++                                      // CRYPT_E_NO_REVOCATION_CHECK
++                                      else if ((flags & X509ChainStatusFlags.OfflineRevocation) != 0) result = 0x80092012;
++                                      // CERT_E_ISSUERCHAINING
++                                      else if ((flags & X509ChainStatusFlags.NoIssuanceChainPolicy) != 0) result = 0x800B0107;
++                                      else result = 0x800B010B; // TRUST_E_FAIL - generic
++
++                                      break; // Exit the loop on the first error
++                              }
++                              return (int) result;
                        }
  
                        static SslPolicyErrors GetErrorsFromChain (X509Chain chain)
        }
  }
  
++/*
++                      // Attempt to use OSX certificates
++                      //
++                      // Ideally we should return the SecTrustResult
++#if !MONOTOUCH
++                      if (System.IO.File.Exists (OSX509Certificates.SecurityLibrary)){
++#endif
++                              OSX509Certificates.SecTrustResult trustResult =  OSX509Certificates.TrustEvaluateSsl (certificates);
++
++                              // 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);
++#if !MONOTOUCH
++                      }
++#endif
++*/                    
index c2f5dd953fd7b72632731607ee8bccf119d3684d,c2f5dd953fd7b72632731607ee8bccf119d3684d..81ea79899f9e85099fd421162b34423c0a72ad4f
@@@ -1,3 -1,3 +1,7 @@@
++2010-03-11 Gonzalo Paniagua Javier <gonzalo@novell.com>
++
++      * OSX509Certificates.cs: moved here from Mono.Security.
++
  2009-07-10 Gonzalo Paniagua Javier <gonzalo@novell.com>
  
        * X509Chain.cs: revert my last change here since it caused 2 tests to
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d53eaca284bd8af2315889c50ab561d130008254
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,143 @@@
++// Copyright (C) 2010 Novell, Inc (http://www.novell.com)
++//
++// Permission is hereby granted, free of charge, to any person obtaining
++// a copy of this software and associated documentation files (the
++// "Software"), to deal in the Software without restriction, including
++// without limitation the rights to use, copy, modify, merge, publish,
++// distribute, sublicense, and/or sell copies of the Software, and to
++// permit persons to whom the Software is furnished to do so, subject to
++// the following conditions:
++// 
++// The above copyright notice and this permission notice shall be
++// included in all copies or substantial portions of the Software.
++// 
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
++// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
++// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++//
++#if SECURITY_DEP
++using System;
++using System.Runtime.InteropServices;
++using Mono.Security.X509;
++using Mono.Security.X509.Extensions;
++
++namespace Mono.Security.X509 {
++
++      internal class OSX509Certificates {
++              public const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
++              public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
++      
++              [DllImport (SecurityLibrary)]
++              extern static IntPtr SecCertificateCreateWithData (IntPtr allocator, IntPtr nsdataRef);
++              
++              [DllImport (SecurityLibrary)]
++              extern static int SecTrustCreateWithCertificates (IntPtr certOrCertArray, IntPtr policies, out IntPtr sectrustref);
++              
++              [DllImport (SecurityLibrary)]
++              extern static IntPtr SecPolicyCreateSSL (int server, IntPtr cfStringHostname);
++              
++              [DllImport (SecurityLibrary)]
++              extern static int SecTrustEvaluate (IntPtr secTrustRef, out SecTrustResult secTrustResultTime);
++
++              [DllImport (CoreFoundationLibrary)]
++              unsafe extern static IntPtr CFDataCreate (IntPtr allocator, byte *bytes, IntPtr length);
++
++              [DllImport (CoreFoundationLibrary)]
++              unsafe extern static void CFRelease (IntPtr handle);
++
++              [DllImport (CoreFoundationLibrary)]
++              extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, IntPtr numValues, IntPtr callbacks);
++              
++              public enum SecTrustResult {
++                      Invalid,
++                      Proceed,
++                      Confirm,
++                      Deny,
++                      Unspecified,
++                      RecoverableTrustFailure,
++                      FatalTrustFailure,
++                      ResultOtherError,
++              }
++
++              static IntPtr sslsecpolicy = SecPolicyCreateSSL (0, IntPtr.Zero);
++
++              static IntPtr MakeCFData (byte [] data)
++              {
++                      unsafe {
++                              fixed (byte *ptr = &data [0])
++                                      return CFDataCreate (IntPtr.Zero, ptr, (IntPtr) data.Length);
++                      }
++              }
++
++              static unsafe IntPtr FromIntPtrs (IntPtr [] values)
++              {
++                      fixed (IntPtr* pv = values) {
++                              return CFArrayCreate (
++                                      IntPtr.Zero, 
++                                      (IntPtr) pv,
++                                      (IntPtr) values.Length,
++                                      IntPtr.Zero);
++                      }
++              }
++              
++              public static SecTrustResult TrustEvaluateSsl (X509CertificateCollection certificates)
++              {
++                      try {
++                              return _TrustEvaluateSsl (certificates);
++                      } catch {
++                              return SecTrustResult.Deny;
++                      }
++              }
++              
++              static SecTrustResult _TrustEvaluateSsl (X509CertificateCollection certificates)
++              {
++                      if (certificates == null)
++                              throw new ArgumentNullException ("certificates");
++
++                      int certCount = certificates.Count;
++                      IntPtr [] cfDataPtrs = new IntPtr [certCount];
++                      IntPtr [] secCerts = new IntPtr [certCount];
++                      IntPtr certArray = IntPtr.Zero;
++                      
++                      try {
++                              for (int i = 0; i < certCount; i++)
++                                      cfDataPtrs [i] = MakeCFData (certificates [i].RawData);
++                              
++                              for (int i = 0; i < certCount; i++){
++                                      secCerts [i] = SecCertificateCreateWithData (IntPtr.Zero, cfDataPtrs [i]);
++                                      if (secCerts [i] == IntPtr.Zero){
++                                              CFRelease (cfDataPtrs [i]);
++                                              return SecTrustResult.Deny;
++                                      }
++                              }
++                              certArray = FromIntPtrs (secCerts);
++                              IntPtr sectrust;
++                              int code = SecTrustCreateWithCertificates (certArray, sslsecpolicy, out sectrust);
++                              if (code == 0){
++                                      SecTrustResult result;
++                                      code = SecTrustEvaluate (sectrust, out result);
++                                      if (code != 0)
++                                              return SecTrustResult.Deny;
++
++                                      CFRelease (sectrust);
++                                      CFRelease (sslsecpolicy);
++                                      
++                                      return result;
++                              }
++                              return SecTrustResult.Deny;
++                      } finally {
++                              for (int i = 0; i < certCount; i++)
++                                      if (secCerts [i] != IntPtr.Zero)
++                                              CFRelease (cfDataPtrs [i]);
++
++                              if (certArray != IntPtr.Zero)
++                                      CFRelease (certArray);
++                      }
++              }
++      }
++}
++#endif
index a354ce529a246411a5e99ed3568d8faf50470cdf,a354ce529a246411a5e99ed3568d8faf50470cdf..5427553b03cdb2024d2cabb6643e0261d1fff39d
@@@ -890,6 -890,6 +890,7 @@@ System.Security.Cryptography/OidCollect
  System.Security.Cryptography/Oid.cs
  System.Security.Cryptography/OidEnumerator.cs
  System.Security.Cryptography.X509Certificates/OpenFlags.cs
++System.Security.Cryptography.X509Certificates/OSX509Certificates.cs
  System.Security.Cryptography.X509Certificates/PublicKey.cs
  System.Security.Cryptography.X509Certificates/StoreLocation.cs
  System.Security.Cryptography.X509Certificates/StoreName.cs
index a24145200f090ebe68ef451dbcd922384847100a,a24145200f090ebe68ef451dbcd922384847100a..98d578110cce760a909b0beb64132b2c2e82d72b
@@@ -398,6 -398,6 +398,7 @@@ System.Security.Cryptography/Oid.c
  System.Security.Cryptography/OidEnumerator.cs
  
  System.Security.Cryptography.X509Certificates/OpenFlags.cs
++System.Security.Cryptography.X509Certificates/OSX509Certificates.cs
  System.Security.Cryptography.X509Certificates/PublicKey.cs
  System.Security.Cryptography.X509Certificates/StoreLocation.cs
  System.Security.Cryptography.X509Certificates/StoreName.cs