[System] HttpListenerRequest: ignore bad cookies and keep request alive (#5657)
[mono.git] / mcs / class / System / Mono.AppleTls / ImportExport.cs
1 #if SECURITY_DEP && MONO_FEATURE_APPLETLS
2 // 
3 // ImportExport.cs
4 //
5 // Authors:
6 //      Sebastien Pouliot  <sebastien@xamarin.com>
7 //     
8 // Copyright 2011-2014 Xamarin Inc.
9 //
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:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
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.
28 //
29
30 using System;
31 using System.Runtime.InteropServices;
32 using System.Security.Cryptography;
33 using System.Security.Cryptography.X509Certificates;
34 using ObjCRuntimeInternal;
35 using Mono.Net;
36
37 #if MONO_FEATURE_BTLS
38 using Mono.Btls;
39 #else
40 using Mono.Security.Cryptography;
41 #endif
42
43 namespace Mono.AppleTls {
44
45         internal partial class SecImportExport {
46                 
47                 [DllImport (AppleTlsContext.SecurityLibrary)]
48                 extern static SecStatusCode SecPKCS12Import (IntPtr pkcs12_data, IntPtr options, out IntPtr items);
49                 
50                 static public SecStatusCode ImportPkcs12 (byte[] buffer, CFDictionary options, out CFDictionary[] array)
51                 {
52                         using (CFData data = CFData.FromData (buffer)) {
53                                 return ImportPkcs12 (data, options, out array);
54                         }
55                 }
56
57                 static public SecStatusCode ImportPkcs12 (CFData data, CFDictionary options, out CFDictionary [] array)
58                 {
59                         if (options == null)
60                                 throw new ArgumentNullException ("options");
61                         
62                         IntPtr handle;
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);
67                         return code;
68                 }
69
70 #if !MONOTOUCH
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);
81
82                 static public CFArray ItemImport (byte[] buffer, string password)
83                 {
84                         using (var data = CFData.FromData (buffer))
85                         using (var pwstring = CFString.Create (password)) {
86                                 SecItemImportExportKeyParameters keyParams = new SecItemImportExportKeyParameters ();
87                                 keyParams.passphrase = pwstring.Handle;
88
89                                 return ItemImport (data, SecExternalFormat.PKCS12, SecExternalItemType.Aggregate, SecItemImportExportFlags.None, keyParams);
90                         }
91                 }
92
93                 static CFArray ItemImport (CFData data, SecExternalFormat format, SecExternalItemType itemType,
94                                            SecItemImportExportFlags flags = SecItemImportExportFlags.None,
95                                            SecItemImportExportKeyParameters? keyParams = null)
96                 {
97                         return ItemImport (data, ref format, ref itemType, flags, keyParams);
98                 }
99
100                 static CFArray ItemImport (CFData data, ref SecExternalFormat format, ref SecExternalItemType itemType,
101                                            SecItemImportExportFlags flags = SecItemImportExportFlags.None,
102                                            SecItemImportExportKeyParameters? keyParams = null)
103                 {
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);
110                         }
111
112                         IntPtr result;
113                         var status = SecItemImport (data.Handle, IntPtr.Zero, ref format, ref itemType, flags, keyParamsPtr, IntPtr.Zero, out result);
114
115                         if (keyParamsPtr != IntPtr.Zero)
116                                 Marshal.FreeHGlobal (keyParamsPtr);
117
118                         if (status != SecStatusCode.Success)
119                                 throw new NotSupportedException (status.ToString ());
120
121                         return new CFArray (result, true);
122                 }
123
124                 [DllImport (AppleTlsContext.SecurityLibrary)]
125                 extern static /* SecIdentityRef */ IntPtr SecIdentityCreate (
126                         /* CFAllocatorRef */ IntPtr allocator,
127                         /* SecCertificateRef */ IntPtr certificate,
128                         /* SecKeyRef */ IntPtr privateKey);
129
130                 static public SecIdentity ItemImport (X509Certificate2 certificate)
131                 {
132                         if (!certificate.HasPrivateKey)
133                                 throw new NotSupportedException ();
134
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 ();
140
141                                 return new SecIdentity (identity, true);
142                         }
143                 }
144
145                 static byte[] ExportKey (RSA key)
146                 {
147 #if MONO_FEATURE_BTLS
148                         using (var btlsKey = MonoBtlsKey.CreateFromRSAPrivateKey (key))
149                                 return btlsKey.GetBytes (true);
150 #else
151                         return PKCS8.PrivateKeyInfo.Encode (key);
152 #endif
153                 }
154
155                 static SecKey ImportPrivateKey (X509Certificate2 certificate)
156                 {
157                         if (!certificate.HasPrivateKey)
158                                 throw new NotSupportedException ();
159
160                         CFArray items;
161                         using (var data = CFData.FromData (ExportKey ((RSA)certificate.PrivateKey)))
162                                 items = ItemImport (data, SecExternalFormat.OpenSSL, SecExternalItemType.PrivateKey);
163
164                         try {
165                                 if (items.Count != 1)
166                                         throw new InvalidOperationException ("Private key import failed.");
167
168                                 var imported = items[0];
169                                 if (CFType.GetTypeID (imported) != SecKey.GetTypeID ())
170                                         throw new InvalidOperationException ("Private key import doesn't return SecKey.");
171
172                                 return new SecKey (imported, items.Handle);
173                         } finally {
174                                 items.Dispose ();
175                         }
176                 }
177
178                 const int SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION = 0;
179
180                 // Native enum; don't change.
181                 enum SecExternalFormat : int {
182                         Unknown = 0,
183                         OpenSSL = 1,
184                         X509Cert = 9,
185                         PEMSequence = 10,
186                         PKCS7 = 11,
187                         PKCS12 = 12
188                 }
189
190                 // Native enum; don't change.
191                 enum SecExternalItemType : int {
192                         Unknown = 0,
193                         PrivateKey = 1,
194                         PublicKey = 2,
195                         SessionKey = 3,
196                         Certificate = 4,
197                         Aggregate = 5
198                 }
199
200                 // Native enum; don't change
201                 enum SecItemImportExportFlags : int {
202                         None,
203                         PemArmour = 0x00000001,   /* exported blob is PEM formatted */
204                 }
205
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. */
212
213                         IntPtr alertTitle;
214                         IntPtr alertPrompt;
215
216                         public IntPtr accessRef;       /* SecAccessRef */
217
218                         IntPtr keyUsage;
219                         IntPtr keyAttributes;
220                 }
221 #endif
222         }
223 }
224 #endif