1 #if SECURITY_DEP && MONO_FEATURE_APPLETLS
6 // Sebastien Pouliot <sebastien@xamarin.com>
8 // Copyright 2011-2014 Xamarin Inc.
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Runtime.InteropServices;
32 using System.Security.Cryptography;
33 using System.Security.Cryptography.X509Certificates;
34 using ObjCRuntimeInternal;
40 using Mono.Security.Cryptography;
43 namespace Mono.AppleTls {
45 internal partial class SecImportExport {
47 [DllImport (AppleTlsContext.SecurityLibrary)]
48 extern static SecStatusCode SecPKCS12Import (IntPtr pkcs12_data, IntPtr options, out IntPtr items);
50 static public SecStatusCode ImportPkcs12 (byte[] buffer, CFDictionary options, out CFDictionary[] array)
52 using (CFData data = CFData.FromData (buffer)) {
53 return ImportPkcs12 (data, options, out array);
57 static public SecStatusCode ImportPkcs12 (CFData data, CFDictionary options, out CFDictionary [] array)
60 throw new ArgumentNullException ("options");
63 SecStatusCode code = SecPKCS12Import (data.Handle, options.Handle, out handle);
64 array = CFArray.ArrayFromHandle <CFDictionary> (handle, h => new CFDictionary (h, false));
65 if (handle != IntPtr.Zero)
66 CFObject.CFRelease (handle);
71 [DllImport (AppleTlsContext.SecurityLibrary)]
72 extern static SecStatusCode SecItemImport (
73 /* CFDataRef */ IntPtr importedData,
74 /* CFStringRef */ IntPtr fileNameOrExtension, // optional
75 /* SecExternalFormat* */ ref SecExternalFormat inputFormat, // optional, IN/OUT
76 /* SecExternalItemType* */ ref SecExternalItemType itemType, // optional, IN/OUT
77 /* SecItemImportExportFlags */ SecItemImportExportFlags flags,
78 /* const SecItemImportExportKeyParameters* */ IntPtr keyParams, // optional
79 /* SecKeychainRef */ IntPtr importKeychain, // optional
80 /* CFArrayRef* */ out IntPtr outItems);
82 static public CFArray ItemImport (byte[] buffer, string password)
84 using (var data = CFData.FromData (buffer))
85 using (var pwstring = CFString.Create (password)) {
86 SecItemImportExportKeyParameters keyParams = new SecItemImportExportKeyParameters ();
87 keyParams.passphrase = pwstring.Handle;
89 return ItemImport (data, SecExternalFormat.PKCS12, SecExternalItemType.Aggregate, SecItemImportExportFlags.None, keyParams);
93 static CFArray ItemImport (CFData data, SecExternalFormat format, SecExternalItemType itemType,
94 SecItemImportExportFlags flags = SecItemImportExportFlags.None,
95 SecItemImportExportKeyParameters? keyParams = null)
97 return ItemImport (data, ref format, ref itemType, flags, keyParams);
100 static CFArray ItemImport (CFData data, ref SecExternalFormat format, ref SecExternalItemType itemType,
101 SecItemImportExportFlags flags = SecItemImportExportFlags.None,
102 SecItemImportExportKeyParameters? keyParams = null)
104 IntPtr keyParamsPtr = IntPtr.Zero;
105 if (keyParams != null) {
106 keyParamsPtr = Marshal.AllocHGlobal (Marshal.SizeOf (keyParams.Value));
107 if (keyParamsPtr == IntPtr.Zero)
108 throw new OutOfMemoryException ();
109 Marshal.StructureToPtr (keyParams.Value, keyParamsPtr, false);
113 var status = SecItemImport (data.Handle, IntPtr.Zero, ref format, ref itemType, flags, keyParamsPtr, IntPtr.Zero, out result);
115 if (keyParamsPtr != IntPtr.Zero)
116 Marshal.FreeHGlobal (keyParamsPtr);
118 if (status != SecStatusCode.Success)
119 throw new NotSupportedException (status.ToString ());
121 return new CFArray (result, true);
124 [DllImport (AppleTlsContext.SecurityLibrary)]
125 extern static /* SecIdentityRef */ IntPtr SecIdentityCreate (
126 /* CFAllocatorRef */ IntPtr allocator,
127 /* SecCertificateRef */ IntPtr certificate,
128 /* SecKeyRef */ IntPtr privateKey);
130 static public SecIdentity ItemImport (X509Certificate2 certificate)
132 if (!certificate.HasPrivateKey)
133 throw new NotSupportedException ();
135 using (var key = ImportPrivateKey (certificate))
136 using (var cert = new SecCertificate (certificate)) {
137 var identity = SecIdentityCreate (IntPtr.Zero, cert.Handle, key.Handle);
138 if (CFType.GetTypeID (identity) != SecIdentity.GetTypeID ())
139 throw new InvalidOperationException ();
141 return new SecIdentity (identity, true);
145 static byte[] ExportKey (RSA key)
147 #if MONO_FEATURE_BTLS
148 using (var btlsKey = MonoBtlsKey.CreateFromRSAPrivateKey (key))
149 return btlsKey.GetBytes (true);
151 return PKCS8.PrivateKeyInfo.Encode (key);
155 static SecKey ImportPrivateKey (X509Certificate2 certificate)
157 if (!certificate.HasPrivateKey)
158 throw new NotSupportedException ();
161 using (var data = CFData.FromData (ExportKey ((RSA)certificate.PrivateKey)))
162 items = ItemImport (data, SecExternalFormat.OpenSSL, SecExternalItemType.PrivateKey);
165 if (items.Count != 1)
166 throw new InvalidOperationException ("Private key import failed.");
168 var imported = items[0];
169 if (CFType.GetTypeID (imported) != SecKey.GetTypeID ())
170 throw new InvalidOperationException ("Private key import doesn't return SecKey.");
172 return new SecKey (imported, items.Handle);
178 const int SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION = 0;
180 // Native enum; don't change.
181 enum SecExternalFormat : int {
190 // Native enum; don't change.
191 enum SecExternalItemType : int {
200 // Native enum; don't change
201 enum SecItemImportExportFlags : int {
203 PemArmour = 0x00000001, /* exported blob is PEM formatted */
206 // Native struct; don't change
207 [StructLayout (LayoutKind.Sequential)]
208 struct SecItemImportExportKeyParameters {
209 public int version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */
210 public int flags; /* SecKeyImportExportFlags bits */
211 public IntPtr passphrase; /* SecExternalFormat.PKCS12 only. Legal types are CFStringRef and CFDataRef. */
216 public IntPtr accessRef; /* SecAccessRef */
219 IntPtr keyAttributes;