[System] HttpListenerRequest: ignore bad cookies and keep request alive (#5657)
[mono.git] / mcs / class / System / Mono.AppleTls / Certificate.cs
index e78a85f174e3e7e94f27443a37d802b7506f2389..7463ef1aa3afbb2119954b98b5716149945051a5 100644 (file)
 #if SECURITY_DEP && MONO_FEATURE_APPLETLS
 
 using System;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Security.Cryptography.X509Certificates;
 using Mono.Net;
 
-using ObjCRuntime;
+using ObjCRuntimeInternal;
 
 namespace Mono.AppleTls {
 
@@ -198,6 +199,8 @@ namespace Mono.AppleTls {
                 
                static readonly CFString ImportExportPassphase;
                static readonly CFString ImportItemIdentity;
+               static readonly CFString ImportExportAccess;
+               static readonly CFString ImportExportKeychain;
                
                static SecIdentity ()
                {
@@ -208,6 +211,8 @@ namespace Mono.AppleTls {
                        try {           
                                ImportExportPassphase = CFObject.GetStringConstant (handle, "kSecImportExportPassphrase");
                                ImportItemIdentity = CFObject.GetStringConstant (handle, "kSecImportItemIdentity");
+                               ImportExportAccess = CFObject.GetStringConstant (handle, "kSecImportExportAccess");
+                               ImportExportKeychain = CFObject.GetStringConstant (handle, "kSecImportExportKeychain");
                        } finally {
                                CFObject.dlclose (handle);
                        }
@@ -240,16 +245,46 @@ namespace Mono.AppleTls {
                        }
                }
 
-               public static SecIdentity Import (byte[] data, string password)
+               internal class ImportOptions
+               {
+#if !MONOTOUCH
+                       public SecAccess Access {
+                               get; set;
+                       }
+                       public SecKeyChain KeyChain {
+                               get; set;
+                       }
+#endif
+               }
+
+               static CFDictionary CreateImportOptions (CFString password, ImportOptions options = null)
+               {
+                       if (options == null)
+                               return CFDictionary.FromObjectAndKey (password.Handle, ImportExportPassphase.Handle);
+
+                       var items = new List<Tuple<IntPtr, IntPtr>> ();
+                       items.Add (new Tuple<IntPtr, IntPtr> (ImportExportPassphase.Handle, password.Handle));
+
+#if !MONOTOUCH
+                       if (options.KeyChain != null)
+                               items.Add (new Tuple<IntPtr, IntPtr> (ImportExportKeychain.Handle, options.KeyChain.Handle));
+                       if (options.Access != null)
+                               items.Add (new Tuple<IntPtr, IntPtr> (ImportExportAccess.Handle, options.Access.Handle));
+#endif
+
+                       return CFDictionary.FromKeysAndObjects (items);
+               }
+
+               public static SecIdentity Import (byte[] data, string password, ImportOptions options = null)
                {
                        if (data == null)
                                throw new ArgumentNullException ("data");
                        if (string.IsNullOrEmpty (password)) // SecPKCS12Import() doesn't allow empty passwords.
                                throw new ArgumentException ("password");
                        using (var pwstring = CFString.Create (password))
-                       using (var options = CFDictionary.FromObjectAndKey (pwstring.Handle, ImportExportPassphase.Handle)) {
+                       using (var optionDict = CreateImportOptions (pwstring, options)) {
                                CFDictionary [] array;
-                               SecStatusCode result = SecImportExport.ImportPkcs12 (data, options, out array);
+                               SecStatusCode result = SecImportExport.ImportPkcs12 (data, optionDict, out array);
                                if (result != SecStatusCode.Success)
                                        throw new InvalidOperationException (result.ToString ());
 
@@ -257,7 +292,7 @@ namespace Mono.AppleTls {
                        }
                }
 
-               public static SecIdentity Import (X509Certificate2 certificate)
+               public static SecIdentity Import (X509Certificate2 certificate, ImportOptions options = null)
                {
                        if (certificate == null)
                                throw new ArgumentNullException ("certificate");
@@ -270,7 +305,7 @@ namespace Mono.AppleTls {
                         */
                        var password = Guid.NewGuid ().ToString ();
                        var pkcs12 = certificate.Export (X509ContentType.Pfx, password);
-                       return Import (pkcs12, password);
+                       return Import (pkcs12, password, options);
                }
 
                ~SecIdentity ()
@@ -301,6 +336,7 @@ namespace Mono.AppleTls {
 
        partial class SecKey : INativeObject, IDisposable {
                internal IntPtr handle;
+               internal IntPtr owner;
                
                public SecKey (IntPtr handle, bool owns = false)
                {
@@ -309,6 +345,17 @@ namespace Mono.AppleTls {
                                CFObject.CFRetain (handle);
                }
 
+               /*
+                * SecItemImport() returns a SecArrayRef.  We need to free the array, not the items inside it.
+                * 
+                */
+               internal SecKey (IntPtr handle, IntPtr owner)
+               {
+                       this.handle = handle;
+                       this.owner = owner;
+                       CFObject.CFRetain (owner);
+               }
+
                [DllImport (AppleTlsContext.SecurityLibrary, EntryPoint="SecKeyGetTypeID")]
                public extern static IntPtr GetTypeID ();
                
@@ -331,11 +378,73 @@ namespace Mono.AppleTls {
 
                protected virtual void Dispose (bool disposing)
                {
-                       if (handle != IntPtr.Zero){
+                       if (owner != IntPtr.Zero) {
+                               CFObject.CFRelease (owner);
+                               owner = handle = IntPtr.Zero;
+                       } else if (handle != IntPtr.Zero) {
                                CFObject.CFRelease (handle);
                                handle = IntPtr.Zero;
                        }
                }
        }
+
+#if !MONOTOUCH
+       class SecAccess : INativeObject, IDisposable {
+               internal IntPtr handle;
+
+               public SecAccess (IntPtr handle, bool owns = false)
+               {
+                       this.handle = handle;
+                       if (!owns)
+                               CFObject.CFRetain (handle);
+               }
+
+               ~SecAccess ()
+               {
+                       Dispose (false);
+               }
+
+               public IntPtr Handle {
+                       get {
+                               return handle;
+                       }
+               }
+
+               [DllImport (AppleTlsContext.SecurityLibrary)]
+               extern static /* OSStatus */ SecStatusCode SecAccessCreate (/* CFStringRef */ IntPtr descriptor,  /* CFArrayRef */ IntPtr trustedList, /* SecAccessRef _Nullable * */ out IntPtr accessRef);
+
+               public static SecAccess Create (string descriptor)
+               {
+                       var descriptorHandle = CFString.Create (descriptor);
+                       if (descriptorHandle == null)
+                               throw new InvalidOperationException ();
+
+                       try {
+                               IntPtr accessRef;
+                               var result = SecAccessCreate (descriptorHandle.Handle, IntPtr.Zero, out accessRef);
+                               if (result != SecStatusCode.Success)
+                                       throw new InvalidOperationException (result.ToString ());
+
+                               return new SecAccess (accessRef, true);
+                       } finally {
+                               descriptorHandle.Dispose ();
+                       }
+               }
+
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+
+               protected virtual void Dispose (bool disposing)
+               {
+                       if (handle != IntPtr.Zero) {
+                               CFObject.CFRelease (handle);
+                               handle = IntPtr.Zero;
+                       }
+               }
+       }
+#endif
 }
 #endif