#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 {
static readonly CFString ImportExportPassphase;
static readonly CFString ImportItemIdentity;
+ static readonly CFString ImportExportAccess;
+ static readonly CFString ImportExportKeychain;
static SecIdentity ()
{
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);
}
}
}
- 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 ());
}
}
- public static SecIdentity Import (X509Certificate2 certificate)
+ public static SecIdentity Import (X509Certificate2 certificate, ImportOptions options = null)
{
if (certificate == null)
throw new ArgumentNullException ("certificate");
*/
var password = Guid.NewGuid ().ToString ();
var pkcs12 = certificate.Export (X509ContentType.Pfx, password);
- return Import (pkcs12, password);
+ return Import (pkcs12, password, options);
}
~SecIdentity ()
partial class SecKey : INativeObject, IDisposable {
internal IntPtr handle;
+ internal IntPtr owner;
public SecKey (IntPtr handle, bool owns = false)
{
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 ();
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