[btls]: Cleanup certificate store initialization (#4683)
authorMartin Baulig <mabaul@microsoft.com>
Thu, 13 Apr 2017 17:46:54 +0000 (13:46 -0400)
committerGitHub <noreply@github.com>
Thu, 13 Apr 2017 17:46:54 +0000 (13:46 -0400)
* [BTLS]: Cleanup certificate store initialization.

* Kill unused MonoBtlsX509Store.AddTrustedRoots().

* In server-mode, MonoBtlsProvider.SetupCertificateStore() now only adds
  certificates explicitly trused via MonoTlsSettings.TrustAnchors.

* MonoTlsProvider.ValidateCertificate() - which is called from
  X509Certificate2.Verify() via X509CertificateImplBtls.Verify() - now
  uses MonoTlsSettings.DefaultSettings and assumes client-mode.

* [appletls]: Actually use the new code that was added in PR #4671.

* [btls]: Add new MonoTlsSettings.CertificateValidationTime property.

This allows you to set a custom time for certificate expiration checks.

* [appletls]: Bind SecTrustSetVerifyDate() and check MonoTlsSettings.CertificateValidationTime.

mcs/class/Mono.Security/Mono.Security.Interface/MonoTlsSettings.cs
mcs/class/System/Mono.AppleTls/AppleCertificateHelper.cs
mcs/class/System/Mono.AppleTls/Trust.cs
mcs/class/System/Mono.Btls/MonoBtlsContext.cs
mcs/class/System/Mono.Btls/MonoBtlsProvider.cs
mcs/class/System/Mono.Btls/MonoBtlsX509Store.cs
mcs/class/System/System.Net/MacProxy.cs

index f8b9209620513990bfaddb6f4260cc1f2dcc6a4e..6a1bf86ed1fae893c05082843b554ae1db4fae7b 100644 (file)
@@ -1,4 +1,4 @@
-//
+//
 // MonoTlsSettings.cs
 //
 // Author:
@@ -64,6 +64,13 @@ namespace Mono.Security.Interface
                        set { callbackNeedsChain = value; }
                }
 
+               /*
+                * Use custom time for certificate expiration checks
+                */
+               public DateTime? CertificateValidationTime {
+                       get; set;
+               }
+
                /*
                 * This is only supported if CertificateValidationHelper.SupportsTrustAnchors is true.
                 */
@@ -165,6 +172,7 @@ namespace Mono.Security.Interface
                        UserSettings = other.UserSettings;
                        EnabledProtocols = other.EnabledProtocols;
                        EnabledCiphers = other.EnabledCiphers;
+                       CertificateValidationTime = other.CertificateValidationTime;
                        if (other.TrustAnchors != null)
                                TrustAnchors = new X509CertificateCollection (other.TrustAnchors);
                        if (other.CertificateSearchPaths != null) {
index 7f6e9bc9f63835a19e9a899ad87f03fe280198bf..3c8cb8372cda57b61f33069a5bb648ab17250b04 100644 (file)
@@ -139,6 +139,12 @@ namespace Mono.AppleTls
                                trust.SetAnchorCertificatesOnly (false);
                        }
 
+                       if (validator.Settings.CertificateValidationTime != null) {
+                               var status = trust.SetVerifyDate (validator.Settings.CertificateValidationTime.Value);
+                               if (status != SecStatusCode.Success)
+                                       throw new InvalidOperationException (status.ToString ());
+                       }
+
                        var result = trust.Evaluate ();
                        if (result == SecTrustResult.Unspecified)
                                return true;
index 99c2cd8906d8a544e5df06bc85fdee2afa928ffb..926a7315f07caeda1030b24598ded90efb9bca5a 100644 (file)
@@ -159,6 +159,15 @@ namespace Mono.AppleTls {
                        return SecTrustSetAnchorCertificatesOnly (handle, anchorCertificatesOnly);
                }
 
+               [DllImport (AppleTlsContext.SecurityLibrary)]
+               extern static SecStatusCode /* OSStatus */ SecTrustSetVerifyDate (IntPtr /* SecTrustRef */ trust, IntPtr /* CFDateRef */ date);
+
+               public SecStatusCode SetVerifyDate (DateTime date)
+               {
+                       using (var nativeDate = CFDate.Create (date))
+                               return SecTrustSetVerifyDate (handle, nativeDate.Handle);
+               }
+
                ~SecTrust ()
                {
                        Dispose (false);
index b0e1207a18fc749bfed9182a4d8327f49f9b5219..841daa270fa12ac1cd20b9f959a73c47c14f1dbb 100644 (file)
@@ -234,7 +234,7 @@ namespace Mono.Btls
                        if (!IsServer)
                                ctx.SetSelectCallback (SelectCallback);
 
-                       ctx.SetVerifyParam (MonoBtlsProvider.GetVerifyParam (ServerName, IsServer));
+                       ctx.SetVerifyParam (MonoBtlsProvider.GetVerifyParam (Settings, ServerName, IsServer));
 
                        TlsProtocolCode minProtocol, maxProtocol;
                        GetProtocolVersions (out minProtocol, out maxProtocol);
index b3ec0cc8bba8541e993c26de3c8c28bfbc7421f0..21aa003b4d8d7bea9aba8429bdb052f19bc7aca2 100644 (file)
@@ -111,7 +111,7 @@ namespace Mono.Btls
                        return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER, false);
                }
 
-               internal static MonoBtlsX509VerifyParam GetVerifyParam (string targetHost, bool serverMode)
+               internal static MonoBtlsX509VerifyParam GetVerifyParam (MonoTlsSettings settings, string targetHost, bool serverMode)
                {
                        MonoBtlsX509VerifyParam param;
                        if (serverMode)
@@ -119,12 +119,15 @@ namespace Mono.Btls
                        else
                                param = MonoBtlsX509VerifyParam.GetSslServer ();
 
-                       if (targetHost == null)
+                       if (targetHost == null && settings?.CertificateValidationTime == null)
                                return param;
 
                        try {
                                var copy = param.Copy ();
-                               copy.SetHost (targetHost);
+                               if (targetHost != null)
+                                       copy.SetHost (targetHost);
+                               if (settings?.CertificateValidationTime != null)
+                                       copy.SetTime (settings.CertificateValidationTime.Value);
                                return copy;
                        } finally {
                                param.Dispose ();
@@ -148,7 +151,7 @@ namespace Mono.Btls
 
                        using (var store = new MonoBtlsX509Store ())
                        using (var nativeChain = MonoBtlsProvider.GetNativeChain (certificates))
-                       using (var param = GetVerifyParam (targetHost, serverMode))
+                       using (var param = GetVerifyParam (validator.Settings, targetHost, serverMode))
                        using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
                                SetupCertificateStore (store, validator.Settings, serverMode);
 
@@ -176,7 +179,12 @@ namespace Mono.Btls
                {
                        using (var store = new MonoBtlsX509Store ())
                        using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
-                               SetupCertificateStore (store);
+                               /*
+                                * We're called from X509Certificate2.Verify() via X509CertificateImplBtls.Verify().
+                                *
+                                * Use the default settings and assume client-mode.
+                                */
+                               SetupCertificateStore (store, MonoTlsSettings.DefaultSettings, false);
 
                                storeCtx.Initialize (store, chain);
 
@@ -203,46 +211,62 @@ namespace Mono.Btls
 
                internal static void SetupCertificateStore (MonoBtlsX509Store store, MonoTlsSettings settings, bool server)
                {
-                       if (settings?.CertificateSearchPaths == null)
-                               AddTrustedRoots (store, settings, server);
+                       /*
+                        * In server-mode, we only add certificates which are explicitly trusted via
+                        * MonoTlsSettings.TrustAnchors.
+                        * 
+                        * MonoTlsSettings.CertificateSearchPaths is ignored on Android.
+                        * 
+                        */
 
 #if MONODROID
-                       SetupCertificateStore (store);
+                       AddTrustedRoots (store, settings, server);
+                       if (!server)
+                               SetupDefaultCertificateStore (store);
                        return;
 #else
-                       if (settings?.CertificateSearchPaths == null) {
-                               SetupCertificateStore (store);
+                       if (server || settings?.CertificateSearchPaths == null) {
+                               AddTrustedRoots (store, settings, server);
+                               if (!server)
+                                       SetupDefaultCertificateStore (store);
                                return;
                        }
 
                        foreach (var path in settings.CertificateSearchPaths) {
-                               if (string.Equals (path, "@default", StringComparison.Ordinal)) {
+                               switch (path) {
+                               case "@default":
                                        AddTrustedRoots (store, settings, server);
                                        AddUserStore (store);
                                        AddMachineStore (store);
-                               } else if (string.Equals (path, "@user", StringComparison.Ordinal))
+                                       break;
+                               case "@trusted":
+                                       AddTrustedRoots (store, settings, server);
+                                       break;
+                               case "@user":
                                        AddUserStore (store);
-                               else if (string.Equals (path, "@machine", StringComparison.Ordinal))
+                                       break;
+                               case "@machine":
                                        AddMachineStore (store);
-                               else if (string.Equals (path, "@trusted", StringComparison.Ordinal))
-                                       AddTrustedRoots (store, settings, server);
-                               else if (path.StartsWith ("@pem:", StringComparison.Ordinal)) {
-                                       var realPath = path.Substring (5);
-                                       if (Directory.Exists (realPath))
-                                               store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.PEM);
-                               } else if (path.StartsWith ("@der:", StringComparison.Ordinal)) {
-                                       var realPath = path.Substring (5);
-                                       if (Directory.Exists (realPath))
-                                               store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.ASN1);
-                               } else {
-                                       if (Directory.Exists (path))
-                                               store.AddDirectoryLookup (path, MonoBtlsX509FileType.PEM);
+                                       break;
+                               default:
+                                       if (path.StartsWith ("@pem:")) {
+                                               var realPath = path.Substring (5);
+                                               if (Directory.Exists (realPath))
+                                                       store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.PEM);
+                                               break;
+                                       } else if (path.StartsWith ("@der:")) {
+                                               var realPath = path.Substring (5);
+                                               if (Directory.Exists (realPath))
+                                                       store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.ASN1);
+                                               break;
+                                       }
+                                       throw new NotSupportedException (string.Format ("Invalid item `{0}' in MonoTlsSettings.CertificateSearchPaths.", path));
                                }
                        }
 #endif
                }
 
-               internal static void SetupCertificateStore (MonoBtlsX509Store store)
+               static void SetupDefaultCertificateStore (MonoBtlsX509Store store)
                {
 #if MONODROID
                        store.SetDefaultPaths ();
index 3aafbd4a7f585d24cee02456e29a97a8edd9569b..dae87724280245af3dfef80b462896ec53a04cc7 100644 (file)
@@ -24,6 +24,9 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 #if SECURITY_DEP && MONO_FEATURE_BTLS
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+#endif
 using System;
 using System.IO;
 using System.Collections.Generic;
@@ -31,6 +34,12 @@ using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
 using System.Security.Cryptography.X509Certificates;
 
+#if MONO_SECURITY_ALIAS
+using MonoSecurity::Mono.Security.Interface;
+#else
+using Mono.Security.Interface;
+#endif
+
 namespace Mono.Btls
 {
        class MonoBtlsX509Store : MonoBtlsObject
@@ -159,7 +168,7 @@ namespace Mono.Btls
 
                internal void AddTrustedRoots ()
                {
-                       MonoBtlsProvider.SetupCertificateStore (this);
+                       MonoBtlsProvider.SetupCertificateStore (this, MonoTlsSettings.DefaultSettings, false);
                }
 
                public MonoBtlsX509Lookup AddLookup (MonoBtlsX509LookupType type)
index 7dbb89571587bcbeff55aac49630cac7084296d4..4bbd4662512eb2cd729ea8ad0324daa6ade14666 100644 (file)
@@ -1341,4 +1341,54 @@ namespace Mono.Net
                }
        }
 
+       internal class CFDate : INativeObject, IDisposable {
+               IntPtr handle;
+
+               internal CFDate (IntPtr handle, bool owns)
+               {
+                       this.handle = handle;
+                       if (!owns)
+                               CFObject.CFRetain (handle);
+               }
+
+               ~CFDate ()
+               {
+                       Dispose (false);
+               }
+
+               [DllImport (CFObject.CoreFoundationLibrary)]
+               extern static IntPtr CFDateCreate (IntPtr allocator, /* CFAbsoluteTime */ double at);
+
+               public static CFDate Create (DateTime date)
+               {
+                       var referenceTime = new DateTime (2001, 1, 1);
+                       var difference = (date - referenceTime).TotalSeconds;
+                       var handle = CFDateCreate (IntPtr.Zero, difference);
+                       if (handle == IntPtr.Zero)
+                               throw new NotSupportedException ();
+                       return new CFDate (handle, true);
+               }
+
+               public IntPtr Handle {
+                       get {
+                               return handle;
+                       }
+               }
+
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+
+               protected virtual void Dispose (bool disposing)
+               {
+                       if (handle != IntPtr.Zero) {
+                               CFObject.CFRelease (handle);
+                               handle = IntPtr.Zero;
+                       }
+               }
+
+       }
+
 }