Use correct path separator for satellite assemblies in cross builds (#4976)
[mono.git] / mcs / class / System / Mono.Btls / MonoBtlsSsl.cs
1 //
2 // MonoBtlsSsl.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 #if SECURITY_DEP && MONO_FEATURE_BTLS
27 using System;
28 using System.IO;
29 using System.Text;
30 using System.Runtime.InteropServices;
31 using System.Runtime.CompilerServices;
32
33 namespace Mono.Btls
34 {
35         delegate int MonoBtlsVerifyCallback (MonoBtlsX509StoreCtx ctx);
36         delegate int MonoBtlsSelectCallback ();
37
38         class MonoBtlsSsl : MonoBtlsObject
39         {
40                 internal class BoringSslHandle : MonoBtlsHandle
41                 {
42                         public BoringSslHandle (IntPtr handle)
43                                 : base (handle, true)
44                         {
45                         }
46
47                         protected override bool ReleaseHandle ()
48                         {
49                                 mono_btls_ssl_destroy (handle);
50                                 return true;
51                         }
52                 }
53
54                 [DllImport (BTLS_DYLIB)]
55                 extern static void mono_btls_ssl_destroy (IntPtr handle);
56
57                 [DllImport (BTLS_DYLIB)]
58                 extern static IntPtr mono_btls_ssl_new (IntPtr handle);
59
60                 [DllImport (BTLS_DYLIB)]
61                 extern static int mono_btls_ssl_use_certificate (IntPtr handle, IntPtr x509);
62
63                 [DllImport (BTLS_DYLIB)]
64                 extern static int mono_btls_ssl_use_private_key (IntPtr handle, IntPtr key);
65
66                 [DllImport (BTLS_DYLIB)]
67                 extern static int mono_btls_ssl_add_chain_certificate (IntPtr handle, IntPtr x509);
68
69                 [DllImport (BTLS_DYLIB)]
70                 extern static int mono_btls_ssl_accept (IntPtr handle);
71
72                 [DllImport (BTLS_DYLIB)]
73                 extern static int mono_btls_ssl_connect (IntPtr handle);
74
75                 [DllImport (BTLS_DYLIB)]
76                 extern static int mono_btls_ssl_handshake (IntPtr handle);
77
78                 [DllImport (BTLS_DYLIB)]
79                 extern static void mono_btls_ssl_close (IntPtr handle);
80
81                 [DllImport (BTLS_DYLIB)]
82                 extern static void mono_btls_ssl_set_bio (IntPtr handle, IntPtr bio);
83
84                 [DllImport (BTLS_DYLIB)]
85                 extern static int mono_btls_ssl_read (IntPtr handle, IntPtr data, int len);
86
87                 [DllImport (BTLS_DYLIB)]
88                 extern static int mono_btls_ssl_write (IntPtr handle, IntPtr data, int len);
89
90                 [DllImport (BTLS_DYLIB)]
91                 extern static int mono_btls_ssl_get_error (IntPtr handle, int ret_code);
92
93                 [DllImport (BTLS_DYLIB)]
94                 extern static int mono_btls_ssl_get_version (IntPtr handle);
95
96                 [DllImport (BTLS_DYLIB)]
97                 extern static void mono_btls_ssl_set_min_version (IntPtr handle, int version);
98
99                 [DllImport (BTLS_DYLIB)]
100                 extern static void mono_btls_ssl_set_max_version (IntPtr handle, int version);
101
102                 [DllImport (BTLS_DYLIB)]
103                 extern static int mono_btls_ssl_get_cipher (IntPtr handle);
104
105                 [DllImport (BTLS_DYLIB)]
106                 extern static int mono_btls_ssl_get_ciphers (IntPtr handle, out IntPtr data);
107
108                 [DllImport (BTLS_DYLIB)]
109                 extern static IntPtr mono_btls_ssl_get_peer_certificate (IntPtr handle);
110
111                 [DllImport (BTLS_DYLIB)]
112                 extern static int mono_btls_ssl_set_cipher_list (IntPtr handle, IntPtr str);
113
114                 [DllImport (BTLS_DYLIB)]
115                 extern static void mono_btls_ssl_print_errors_cb (IntPtr func, IntPtr ctx);
116
117                 [DllImport (BTLS_DYLIB)]
118                 extern static int mono_btls_ssl_set_verify_param (IntPtr handle, IntPtr param);
119
120                 [DllImport (BTLS_DYLIB)]
121                 extern static int mono_btls_ssl_set_server_name (IntPtr handle, IntPtr name);
122
123                 [DllImport (BTLS_DYLIB)]
124                 extern static IntPtr mono_btls_ssl_get_server_name (IntPtr handle);
125
126                 static BoringSslHandle Create_internal (MonoBtlsSslCtx ctx)
127                 {
128                         var handle = mono_btls_ssl_new (ctx.Handle.DangerousGetHandle ());
129                         if (handle == IntPtr.Zero)
130                                 throw new MonoBtlsException ();
131                         return new BoringSslHandle (handle);
132                 }
133
134                 PrintErrorsCallbackFunc printErrorsFunc;
135                 IntPtr printErrorsFuncPtr;
136
137                 public MonoBtlsSsl (MonoBtlsSslCtx ctx)
138                         : base (Create_internal (ctx))
139                 {
140                         printErrorsFunc = PrintErrorsCallback;
141                         printErrorsFuncPtr = Marshal.GetFunctionPointerForDelegate (printErrorsFunc);
142                 }
143
144                 new internal BoringSslHandle Handle {
145                         get { return (BoringSslHandle)base.Handle; }
146                 }
147
148                 public void SetBio (MonoBtlsBio bio)
149                 {
150                         CheckThrow ();
151                         mono_btls_ssl_set_bio (
152                                 Handle.DangerousGetHandle (),
153                                 bio.Handle.DangerousGetHandle ());
154                 }
155
156                 Exception ThrowError ([CallerMemberName] string callerName = null)
157                 {
158                         string errors;
159                         try {
160                                 if (callerName == null)
161                                         callerName = GetType ().Name;
162                                 errors = GetErrors ();
163                         } catch {
164                                 errors = null;
165                         }
166
167                         if (errors != null) {
168                                 Console.Error.WriteLine ("ERROR: {0} failed: {1}", callerName, errors);
169                                 throw new MonoBtlsException ("{0} failed: {1}.", callerName, errors);
170                         } else {
171                                 Console.Error.WriteLine ("ERROR: {0} failed.", callerName);
172                                 throw new MonoBtlsException ("{0} failed.", callerName);
173                         }
174                 }
175
176                 MonoBtlsSslError GetError (int ret_code)
177                 {
178                         CheckThrow ();
179                         var error = mono_btls_ssl_get_error (
180                                 Handle.DangerousGetHandle (), ret_code);
181                         return (MonoBtlsSslError)error;
182                 }
183
184                 public void SetCertificate (MonoBtlsX509 x509)
185                 {
186                         CheckThrow ();
187
188                         var ret = mono_btls_ssl_use_certificate (
189                                 Handle.DangerousGetHandle (),
190                                 x509.Handle.DangerousGetHandle ());
191                         if (ret <= 0)
192                                 throw ThrowError ();
193                 }
194
195                 public void SetPrivateKey (MonoBtlsKey key)
196                 {
197                         CheckThrow ();
198
199                         var ret = mono_btls_ssl_use_private_key (
200                                 Handle.DangerousGetHandle (),
201                                 key.Handle.DangerousGetHandle ());
202                         if (ret <= 0)
203                                 throw ThrowError ();
204                 }
205
206                 public void AddIntermediateCertificate (MonoBtlsX509 x509)
207                 {
208                         CheckThrow ();
209
210                         var ret = mono_btls_ssl_add_chain_certificate (
211                                 Handle.DangerousGetHandle (),
212                                 x509.Handle.DangerousGetHandle ());
213                         if (ret <= 0)
214                                 throw ThrowError ();
215                 }
216
217                 public MonoBtlsSslError Accept ()
218                 {
219                         CheckThrow ();
220
221                         var ret = mono_btls_ssl_accept (Handle.DangerousGetHandle ());
222
223                         var error = GetError (ret);
224                         return error;
225                 }
226
227                 public MonoBtlsSslError Connect ()
228                 {
229                         CheckThrow ();
230
231                         var ret = mono_btls_ssl_connect (Handle.DangerousGetHandle ());
232
233                         var error = GetError (ret);
234                         return error;
235                 }
236
237                 public MonoBtlsSslError Handshake ()
238                 {
239                         CheckThrow ();
240
241                         var ret = mono_btls_ssl_handshake (Handle.DangerousGetHandle ());
242
243                         var error = GetError (ret);
244                         return error;
245                 }
246
247                 delegate int PrintErrorsCallbackFunc (IntPtr str, IntPtr len, IntPtr ctx);
248
249                 [Mono.Util.MonoPInvokeCallback (typeof (PrintErrorsCallbackFunc))]
250                 static int PrintErrorsCallback (IntPtr str, IntPtr len, IntPtr ctx)
251                 {
252                         var sb = (StringBuilder)GCHandle.FromIntPtr (ctx).Target;
253                         try {
254                                 var text = Marshal.PtrToStringAnsi (str, (int)len);
255                                 sb.Append (text);
256                                 return 1;
257                         } catch {
258                                 return 0;
259                         }
260                 }
261
262                 public string GetErrors ()
263                 {
264                         var text = new StringBuilder ();
265                         var handle = GCHandle.Alloc (text);
266
267                         try {
268                                 mono_btls_ssl_print_errors_cb (printErrorsFuncPtr, GCHandle.ToIntPtr (handle));
269                                 return text.ToString ();
270                         } finally {
271                                 if (handle.IsAllocated)
272                                         handle.Free ();
273                         }
274                 }
275
276                 public void PrintErrors ()
277                 {
278                         var errors = GetErrors ();
279                         if (string.IsNullOrEmpty (errors))
280                                 return;
281                         Console.Error.WriteLine (errors);
282                 }
283
284                 public MonoBtlsSslError Read (IntPtr data, ref int dataSize)
285                 {
286                         CheckThrow ();
287                         var ret = mono_btls_ssl_read (
288                                 Handle.DangerousGetHandle (), data, dataSize);
289
290                         if (ret >= 0) {
291                                 dataSize = ret;
292                                 return MonoBtlsSslError.None;
293                         }
294
295                         var error = mono_btls_ssl_get_error (
296                                 Handle.DangerousGetHandle (), ret);
297                         dataSize = 0;
298                         return (MonoBtlsSslError)error;
299                 }
300
301                 public MonoBtlsSslError Write (IntPtr data, ref int dataSize)
302                 {
303                         CheckThrow ();
304                         var ret = mono_btls_ssl_write (
305                                 Handle.DangerousGetHandle (), data, dataSize);
306
307                         if (ret >= 0) {
308                                 dataSize = ret;
309                                 return MonoBtlsSslError.None;
310                         }
311
312                         var error = mono_btls_ssl_get_error (
313                                 Handle.DangerousGetHandle (), ret);
314                         dataSize = 0;
315                         return (MonoBtlsSslError)error;
316                 }
317
318                 public int GetVersion ()
319                 {
320                         CheckThrow ();
321                         return mono_btls_ssl_get_version (Handle.DangerousGetHandle ());
322                 }
323
324                 public void SetMinVersion (int version)
325                 {
326                         CheckThrow ();
327                         mono_btls_ssl_set_min_version (Handle.DangerousGetHandle (), version);
328                 }
329
330                 public void SetMaxVersion (int version)
331                 {
332                         CheckThrow ();
333                         mono_btls_ssl_set_max_version (Handle.DangerousGetHandle (), version);
334                 }
335
336                 public int GetCipher ()
337                 {
338                         CheckThrow ();
339                         var cipher = mono_btls_ssl_get_cipher (Handle.DangerousGetHandle ());
340                         CheckError (cipher > 0);
341                         return cipher;
342                 }
343
344                 public short[] GetCiphers ()
345                 {
346                         CheckThrow ();
347                         IntPtr data;
348                         var count = mono_btls_ssl_get_ciphers (
349                                 Handle.DangerousGetHandle (), out data);
350                         CheckError (count > 0);
351                         try {
352                                 short[] ciphers = new short[count];
353                                 Marshal.Copy (data, ciphers, 0, count);
354                                 return ciphers;
355                         } finally {
356                                 FreeDataPtr (data);
357                         }
358                 }
359
360                 public void SetCipherList (string str)
361                 {
362                         CheckThrow ();
363                         IntPtr strPtr = IntPtr.Zero;
364                         try {
365                                 strPtr = Marshal.StringToHGlobalAnsi (str);
366                                 var ret = mono_btls_ssl_set_cipher_list (
367                                         Handle.DangerousGetHandle (), strPtr);
368                                 CheckError (ret);
369                         } finally {
370                                 if (strPtr != IntPtr.Zero)
371                                         Marshal.FreeHGlobal (strPtr);
372                         }
373                 }
374
375                 public MonoBtlsX509 GetPeerCertificate ()
376                 {
377                         CheckThrow ();
378                         var x509 = mono_btls_ssl_get_peer_certificate (
379                                 Handle.DangerousGetHandle ());
380                         if (x509 == IntPtr.Zero)
381                                 return null;
382                         return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (x509));
383                 }
384
385                 public void SetVerifyParam (MonoBtlsX509VerifyParam param)
386                 {
387                         CheckThrow ();
388                         var ret = mono_btls_ssl_set_verify_param (
389                                 Handle.DangerousGetHandle (),
390                                 param.Handle.DangerousGetHandle ());
391                         CheckError (ret);
392                 }
393
394                 public void SetServerName (string name)
395                 {
396                         CheckThrow ();
397                         IntPtr namePtr = IntPtr.Zero;
398                         try {
399                                 namePtr = Marshal.StringToHGlobalAnsi (name);
400                                 var ret = mono_btls_ssl_set_server_name (
401                                         Handle.DangerousGetHandle (), namePtr);
402                                 CheckError (ret);
403                         } finally {
404                                 if (namePtr != IntPtr.Zero)
405                                         Marshal.FreeHGlobal (namePtr);
406                         }
407                 }
408
409                 public string GetServerName ()
410                 {
411                         CheckThrow ();
412                         var namePtr = mono_btls_ssl_get_server_name (
413                                 Handle.DangerousGetHandle ());
414                         if (namePtr == IntPtr.Zero)
415                                 return null;
416                         return Marshal.PtrToStringAnsi (namePtr);
417                 }
418
419                 protected override void Close ()
420                 {
421                         mono_btls_ssl_close (Handle.DangerousGetHandle ());
422                 }
423         }
424 }
425 #endif