[utils] Fix inet_pton fallback.
[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                                 handle = IntPtr.Zero;
51                                 return true;
52                         }
53                 }
54
55                 [DllImport (BTLS_DYLIB)]
56                 extern static void mono_btls_ssl_destroy (IntPtr handle);
57
58                 [DllImport (BTLS_DYLIB)]
59                 extern static IntPtr mono_btls_ssl_new (IntPtr handle);
60
61                 [DllImport (BTLS_DYLIB)]
62                 extern static int mono_btls_ssl_use_certificate (IntPtr handle, IntPtr x509);
63
64                 [DllImport (BTLS_DYLIB)]
65                 extern static int mono_btls_ssl_use_private_key (IntPtr handle, IntPtr key);
66
67                 [DllImport (BTLS_DYLIB)]
68                 extern static int mono_btls_ssl_add_chain_certificate (IntPtr handle, IntPtr x509);
69
70                 [DllImport (BTLS_DYLIB)]
71                 extern static int mono_btls_ssl_accept (IntPtr handle);
72
73                 [DllImport (BTLS_DYLIB)]
74                 extern static int mono_btls_ssl_connect (IntPtr handle);
75
76                 [DllImport (BTLS_DYLIB)]
77                 extern static int mono_btls_ssl_handshake (IntPtr handle);
78
79                 [DllImport (BTLS_DYLIB)]
80                 extern static void mono_btls_ssl_close (IntPtr handle);
81
82                 [DllImport (BTLS_DYLIB)]
83                 extern static int mono_btls_ssl_shutdown (IntPtr handle);
84
85                 [DllImport (BTLS_DYLIB)]
86                 extern static void mono_btls_ssl_set_quiet_shutdown (IntPtr handle, int mode);
87
88                 [DllImport (BTLS_DYLIB)]
89                 extern static void mono_btls_ssl_set_bio (IntPtr handle, IntPtr bio);
90
91                 [DllImport (BTLS_DYLIB)]
92                 extern static int mono_btls_ssl_read (IntPtr handle, IntPtr data, int len);
93
94                 [DllImport (BTLS_DYLIB)]
95                 extern static int mono_btls_ssl_write (IntPtr handle, IntPtr data, int len);
96
97                 [DllImport (BTLS_DYLIB)]
98                 extern static int mono_btls_ssl_get_error (IntPtr handle, int ret_code);
99
100                 [DllImport (BTLS_DYLIB)]
101                 extern static int mono_btls_ssl_get_version (IntPtr handle);
102
103                 [DllImport (BTLS_DYLIB)]
104                 extern static void mono_btls_ssl_set_min_version (IntPtr handle, int version);
105
106                 [DllImport (BTLS_DYLIB)]
107                 extern static void mono_btls_ssl_set_max_version (IntPtr handle, int version);
108
109                 [DllImport (BTLS_DYLIB)]
110                 extern static int mono_btls_ssl_get_cipher (IntPtr handle);
111
112                 [DllImport (BTLS_DYLIB)]
113                 extern static int mono_btls_ssl_get_ciphers (IntPtr handle, out IntPtr data);
114
115                 [DllImport (BTLS_DYLIB)]
116                 extern static IntPtr mono_btls_ssl_get_peer_certificate (IntPtr handle);
117
118                 [DllImport (BTLS_DYLIB)]
119                 extern static int mono_btls_ssl_set_cipher_list (IntPtr handle, IntPtr str);
120
121                 [DllImport (BTLS_DYLIB)]
122                 extern static void mono_btls_ssl_print_errors_cb (IntPtr func, IntPtr ctx);
123
124                 [DllImport (BTLS_DYLIB)]
125                 extern static int mono_btls_ssl_set_verify_param (IntPtr handle, IntPtr param);
126
127                 [DllImport (BTLS_DYLIB)]
128                 extern static int mono_btls_ssl_set_server_name (IntPtr handle, IntPtr name);
129
130                 [DllImport (BTLS_DYLIB)]
131                 extern static IntPtr mono_btls_ssl_get_server_name (IntPtr handle);
132
133                 static BoringSslHandle Create_internal (MonoBtlsSslCtx ctx)
134                 {
135                         var handle = mono_btls_ssl_new (ctx.Handle.DangerousGetHandle ());
136                         if (handle == IntPtr.Zero)
137                                 throw new MonoBtlsException ();
138                         return new BoringSslHandle (handle);
139                 }
140
141                 MonoBtlsBio bio;
142                 PrintErrorsCallbackFunc printErrorsFunc;
143                 IntPtr printErrorsFuncPtr;
144
145                 public MonoBtlsSsl (MonoBtlsSslCtx ctx)
146                         : base (Create_internal (ctx))
147                 {
148                         printErrorsFunc = PrintErrorsCallback;
149                         printErrorsFuncPtr = Marshal.GetFunctionPointerForDelegate (printErrorsFunc);
150                 }
151
152                 new internal BoringSslHandle Handle {
153                         get { return (BoringSslHandle)base.Handle; }
154                 }
155
156                 public void SetBio (MonoBtlsBio bio)
157                 {
158                         CheckThrow ();
159                         this.bio = bio;
160                         mono_btls_ssl_set_bio (
161                                 Handle.DangerousGetHandle (),
162                                 bio.Handle.DangerousGetHandle ());
163                 }
164
165                 Exception ThrowError ([CallerMemberName] string callerName = null)
166                 {
167                         string errors;
168                         try {
169                                 if (callerName == null)
170                                         callerName = GetType ().Name;
171                                 errors = GetErrors ();
172                         } catch {
173                                 errors = null;
174                         }
175
176                         if (errors != null)
177                                 throw new MonoBtlsException ("{0} failed: {1}.", callerName, errors);
178                         else
179                                 throw new MonoBtlsException ("{0} failed.", callerName);
180                 }
181
182                 MonoBtlsSslError GetError (int ret_code)
183                 {
184                         CheckThrow ();
185                         bio.CheckLastError ();
186
187                         var error = mono_btls_ssl_get_error (
188                                 Handle.DangerousGetHandle (), ret_code);
189                         return (MonoBtlsSslError)error;
190                 }
191
192                 public void SetCertificate (MonoBtlsX509 x509)
193                 {
194                         CheckThrow ();
195
196                         var ret = mono_btls_ssl_use_certificate (
197                                 Handle.DangerousGetHandle (),
198                                 x509.Handle.DangerousGetHandle ());
199                         if (ret <= 0)
200                                 throw ThrowError ();
201                 }
202
203                 public void SetPrivateKey (MonoBtlsKey key)
204                 {
205                         CheckThrow ();
206
207                         var ret = mono_btls_ssl_use_private_key (
208                                 Handle.DangerousGetHandle (),
209                                 key.Handle.DangerousGetHandle ());
210                         if (ret <= 0)
211                                 throw ThrowError ();
212                 }
213
214                 public void AddIntermediateCertificate (MonoBtlsX509 x509)
215                 {
216                         CheckThrow ();
217
218                         var ret = mono_btls_ssl_add_chain_certificate (
219                                 Handle.DangerousGetHandle (),
220                                 x509.Handle.DangerousGetHandle ());
221                         if (ret <= 0)
222                                 throw ThrowError ();
223                 }
224
225                 public MonoBtlsSslError Accept ()
226                 {
227                         CheckThrow ();
228
229                         var ret = mono_btls_ssl_accept (Handle.DangerousGetHandle ());
230
231                         var error = GetError (ret);
232                         return error;
233                 }
234
235                 public MonoBtlsSslError Connect ()
236                 {
237                         CheckThrow ();
238
239                         var ret = mono_btls_ssl_connect (Handle.DangerousGetHandle ());
240
241                         var error = GetError (ret);
242                         return error;
243                 }
244
245                 public MonoBtlsSslError Handshake ()
246                 {
247                         CheckThrow ();
248
249                         var ret = mono_btls_ssl_handshake (Handle.DangerousGetHandle ());
250
251                         var error = GetError (ret);
252                         return error;
253                 }
254
255                 delegate int PrintErrorsCallbackFunc (IntPtr str, IntPtr len, IntPtr ctx);
256
257                 [Mono.Util.MonoPInvokeCallback (typeof (PrintErrorsCallbackFunc))]
258                 static int PrintErrorsCallback (IntPtr str, IntPtr len, IntPtr ctx)
259                 {
260                         var sb = (StringBuilder)GCHandle.FromIntPtr (ctx).Target;
261                         try {
262                                 var text = Marshal.PtrToStringAnsi (str, (int)len);
263                                 sb.Append (text);
264                                 return 1;
265                         } catch {
266                                 return 0;
267                         }
268                 }
269
270                 public string GetErrors ()
271                 {
272                         var text = new StringBuilder ();
273                         var handle = GCHandle.Alloc (text);
274
275                         try {
276                                 mono_btls_ssl_print_errors_cb (printErrorsFuncPtr, GCHandle.ToIntPtr (handle));
277                                 return text.ToString ();
278                         } finally {
279                                 if (handle.IsAllocated)
280                                         handle.Free ();
281                         }
282                 }
283
284                 public void PrintErrors ()
285                 {
286                         var errors = GetErrors ();
287                         if (string.IsNullOrEmpty (errors))
288                                 return;
289                         Console.Error.WriteLine (errors);
290                 }
291
292                 public MonoBtlsSslError Read (IntPtr data, ref int dataSize)
293                 {
294                         CheckThrow ();
295                         var ret = mono_btls_ssl_read (
296                                 Handle.DangerousGetHandle (), data, dataSize);
297
298                         if (ret > 0) {
299                                 dataSize = ret;
300                                 return MonoBtlsSslError.None;
301                         }
302
303                         var error = GetError (ret);
304                         if (ret == 0 && error == MonoBtlsSslError.Syscall) {
305                                 // End-of-stream
306                                 dataSize = 0;
307                                 return MonoBtlsSslError.None;
308                         }
309
310                         dataSize = 0;
311                         return error;
312                 }
313
314                 public MonoBtlsSslError Write (IntPtr data, ref int dataSize)
315                 {
316                         CheckThrow ();
317                         var ret = mono_btls_ssl_write (
318                                 Handle.DangerousGetHandle (), data, dataSize);
319
320                         if (ret >= 0) {
321                                 dataSize = ret;
322                                 return MonoBtlsSslError.None;
323                         }
324
325                         var error = mono_btls_ssl_get_error (
326                                 Handle.DangerousGetHandle (), ret);
327                         dataSize = 0;
328                         return (MonoBtlsSslError)error;
329                 }
330
331                 public int GetVersion ()
332                 {
333                         CheckThrow ();
334                         return mono_btls_ssl_get_version (Handle.DangerousGetHandle ());
335                 }
336
337                 public void SetMinVersion (int version)
338                 {
339                         CheckThrow ();
340                         mono_btls_ssl_set_min_version (Handle.DangerousGetHandle (), version);
341                 }
342
343                 public void SetMaxVersion (int version)
344                 {
345                         CheckThrow ();
346                         mono_btls_ssl_set_max_version (Handle.DangerousGetHandle (), version);
347                 }
348
349                 public int GetCipher ()
350                 {
351                         CheckThrow ();
352                         var cipher = mono_btls_ssl_get_cipher (Handle.DangerousGetHandle ());
353                         CheckError (cipher > 0);
354                         return cipher;
355                 }
356
357                 public short[] GetCiphers ()
358                 {
359                         CheckThrow ();
360                         IntPtr data;
361                         var count = mono_btls_ssl_get_ciphers (
362                                 Handle.DangerousGetHandle (), out data);
363                         CheckError (count > 0);
364                         try {
365                                 short[] ciphers = new short[count];
366                                 Marshal.Copy (data, ciphers, 0, count);
367                                 return ciphers;
368                         } finally {
369                                 FreeDataPtr (data);
370                         }
371                 }
372
373                 public void SetCipherList (string str)
374                 {
375                         CheckThrow ();
376                         IntPtr strPtr = IntPtr.Zero;
377                         try {
378                                 strPtr = Marshal.StringToHGlobalAnsi (str);
379                                 var ret = mono_btls_ssl_set_cipher_list (
380                                         Handle.DangerousGetHandle (), strPtr);
381                                 CheckError (ret);
382                         } finally {
383                                 if (strPtr != IntPtr.Zero)
384                                         Marshal.FreeHGlobal (strPtr);
385                         }
386                 }
387
388                 public MonoBtlsX509 GetPeerCertificate ()
389                 {
390                         CheckThrow ();
391                         var x509 = mono_btls_ssl_get_peer_certificate (
392                                 Handle.DangerousGetHandle ());
393                         if (x509 == IntPtr.Zero)
394                                 return null;
395                         return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (x509));
396                 }
397
398                 public void SetVerifyParam (MonoBtlsX509VerifyParam param)
399                 {
400                         CheckThrow ();
401                         var ret = mono_btls_ssl_set_verify_param (
402                                 Handle.DangerousGetHandle (),
403                                 param.Handle.DangerousGetHandle ());
404                         CheckError (ret);
405                 }
406
407                 public void SetServerName (string name)
408                 {
409                         CheckThrow ();
410                         IntPtr namePtr = IntPtr.Zero;
411                         try {
412                                 namePtr = Marshal.StringToHGlobalAnsi (name);
413                                 var ret = mono_btls_ssl_set_server_name (
414                                         Handle.DangerousGetHandle (), namePtr);
415                                 CheckError (ret);
416                         } finally {
417                                 if (namePtr != IntPtr.Zero)
418                                         Marshal.FreeHGlobal (namePtr);
419                         }
420                 }
421
422                 public string GetServerName ()
423                 {
424                         CheckThrow ();
425                         var namePtr = mono_btls_ssl_get_server_name (
426                                 Handle.DangerousGetHandle ());
427                         if (namePtr == IntPtr.Zero)
428                                 return null;
429                         return Marshal.PtrToStringAnsi (namePtr);
430                 }
431
432                 public void Shutdown ()
433                 {
434                         CheckThrow ();
435                         var ret = mono_btls_ssl_shutdown (Handle.DangerousGetHandle ());
436                         if (ret < 0)
437                                 throw ThrowError ();
438                 }
439
440                 public void SetQuietShutdown ()
441                 {
442                         CheckThrow ();
443                         mono_btls_ssl_set_quiet_shutdown (Handle.DangerousGetHandle (), 1);
444                 }
445
446                 protected override void Close ()
447                 {
448                         if (!Handle.IsInvalid)
449                                 mono_btls_ssl_close (Handle.DangerousGetHandle ());
450                 }
451         }
452 }
453 #endif