context: /* wolfSSL.cs
   *
   * Copyright (C) 2006-2016 wolfSSL Inc.
   *
   * This file is part of wolfSSL.
   *
   * wolfSSL is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * wolfSSL is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
   */
  
  using System;
  using System.Runtime.InteropServices;
  using System.Text;
  using System.Threading;
  using System.IO;
  using System.Net;
  using System.Net.Sockets;
  
  namespace wolfSSL.CSharp {
      public class wolfssl
      {
          private const string wolfssl_dll = "wolfssl.dll";
  
          /********************************
           * Class for DTLS connections
           */
          /// <summary>
          /// Contains information regarding a DTLS conection having UdpClient udp and IPEndPoint ep.
          /// Used to keep memory alive.
          /// </summary>
          public class DTLS_con
          {
              public UdpClient udp;
              public IPEndPoint ep;
          }
  
  
          /********************************
           * Class for keeping ctx/ssl handles alive
           */
          [StructLayout(LayoutKind.Sequential)]
          private class ctx_handles
          {
              private GCHandle rec_cb;
              private GCHandle snd_cb;
              private GCHandle psk_cb;
              private GCHandle fd_pin;
              private IntPtr ctx;
  
              public void set_receive(GCHandle input)
              {
                  this.rec_cb = input;
              }
  
              public GCHandle get_receive()
              {
                  return this.rec_cb;
              }
  
              public void set_send(GCHandle input)
              {
                  this.snd_cb = input;
              }
  
              public GCHandle get_send()
              {
                  return this.snd_cb;
              }
  
              public void set_psk(GCHandle input)
              {
                  this.psk_cb = input;
              }
  
              public GCHandle get_psk()
              {
                  return this.psk_cb;
              }
  
              public void set_fd(GCHandle input)
              {
                  this.fd_pin = input;
              }
  
              public GCHandle get_fd()
              {
                  return this.fd_pin;
              }
  
              public void set_ctx(IntPtr input)
              {
                  this.ctx = input;
              }
  
              public IntPtr get_ctx()
              {
                  return this.ctx;
              }
  
              /// <summary>
              /// Called to free the pointers keeping handles alive
              /// </summary>
              public void free()
              {
                  log(INFO_LOG, "freeing handles");
                  if (!Object.Equals(this.rec_cb, default(GCHandle)))
                  {
                      this.rec_cb.Free();
                  }
                  if (!Object.Equals(this.snd_cb, default(GCHandle)))
                  {
                      this.snd_cb.Free();
                  }
                  if (!Object.Equals(this.psk_cb, default(GCHandle)))
                  {
                      this.psk_cb.Free();
                  }
                  if (!Object.Equals(this.fd_pin, default(GCHandle)))
                  {
                      this.fd_pin.Free();
                  }
              }
          }
  
  
          /********************************
           * Init wolfSSL library
           */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_Init();
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_Cleanup();
  
  
          /********************************
           * Methods of connection
           */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfTLSv1_2_server_method();
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSLv23_server_method();
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfTLSv1_2_client_method();
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSLv23_client_method();
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfDTLSv1_2_server_method();
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfDTLSv1_2_client_method();
  
  
          /********************************
           * Call backs
           */
          [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
          public delegate int CallbackIORecv_delegate(IntPtr ssl, IntPtr buf, int sz, IntPtr ctx);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_SetIORecv(IntPtr ctx, CallbackIORecv_delegate recv);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_SetIOReadCtx(IntPtr ssl, IntPtr rctx);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_GetIOReadCtx(IntPtr ssl);
  
          [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
          public delegate int CallbackIOSend_delegate(IntPtr ssl, IntPtr buf, int sz, IntPtr ctx);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_SetIOSend(IntPtr ctx, CallbackIOSend_delegate send);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_SetIOWriteCtx(IntPtr ssl, IntPtr wctx);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_GetIOWriteCtx(IntPtr ssl);
  
  
          /********************************
           * CTX structure
           */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_CTX_new(IntPtr method);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_CTX_use_certificate_file(IntPtr ctx, string file, int type);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_CTX_use_PrivateKey_file(IntPtr ctx, string file, int type);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static void wolfSSL_CTX_free(IntPtr ctx);
  
  
  
          /********************************
           * PSK
           */
          [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
          public delegate uint psk_delegate(IntPtr ssl, string identity, IntPtr key, uint max_sz);
          [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
          public delegate uint psk_client_delegate(IntPtr ssl, string hint, IntPtr identity, uint id_max_len, IntPtr key, uint max_sz);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static void wolfSSL_set_psk_server_callback(IntPtr ssl, psk_delegate psk_cb);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static void wolfSSL_CTX_set_psk_server_callback(IntPtr ctx, psk_delegate psk_cb);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static void wolfSSL_CTX_set_psk_client_callback(IntPtr ctx, psk_client_delegate psk_cb);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_CTX_use_psk_identity_hint(IntPtr ctx, StringBuilder identity);
  
  
          /********************************
           * SSL Structure
           */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_new(IntPtr ctx);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_accept(IntPtr ssl);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_connect(IntPtr ssl);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_read(IntPtr ssl, IntPtr buf, int sz);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_write(IntPtr ssl, IntPtr buf, int sz);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_shutdown(IntPtr ssl);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static void wolfSSL_free(IntPtr ssl);
  
  
          /********************************
           * Cipher lists
           */
          /* only supports full name from cipher_name[] delimited by : */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_CTX_set_cipher_list(IntPtr ctx, StringBuilder ciphers);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_set_cipher_list(IntPtr ssl, StringBuilder ciphers);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_get_ciphers(StringBuilder ciphers, int sz);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_get_cipher(IntPtr ssl);
          [DllImport(wolfssl_dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_CIPHER_get_name(IntPtr cipher);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_get_current_cipher(IntPtr ssl);
          [DllImport(wolfssl_dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_get_version(IntPtr ssl);
          [DllImport(wolfssl_dll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
          private extern static IntPtr wolfSSL_get_cipher_list(IntPtr ssl);
  
  
          /********************************
           * Error logging
           */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
          private extern static IntPtr wolfSSL_ERR_error_string(uint err, StringBuilder errOut);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_get_error(IntPtr ssl, int err);
          [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
          public delegate void loggingCb(int lvl, StringBuilder msg);
          private static loggingCb internal_log;
  
  
          /********************************
           * DH
           */
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_CTX_SetMinDhKey_Sz(IntPtr ctx, short size);
          [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)]
          private extern static int wolfSSL_SetTmpDH_file(IntPtr ssl, StringBuilder dhParam, int type);
  
  
          /********************************
           * Enum types from wolfSSL library
           */
          public static readonly int SSL_FILETYPE_PEM = 1;
          public static readonly int SSL_FILETYPE_ASN1= 2;
          public static readonly int SSL_FILETYPE_RAW = 3;
          public static readonly int CBIO_ERR_GENERAL    = -1;
          public static readonly int CBIO_ERR_WANT_READ  = -2;
          public static readonly int CBIO_ERR_WANT_WRITE = -2;
          public static readonly int CBIO_ERR_CONN_RST   = -3;
          public static readonly int CBIO_ERR_ISR        = -4;
          public static readonly int CBIO_ERR_CONN_CLOSE = -5;
          public static readonly int CBIO_ERR_TIMEOUT    = -6;
  
          public static readonly int ERROR_LOG = 0;
          public static readonly int INFO_LOG  = 1;
          public static readonly int ENTER_LOG = 2;
          public static readonly int LEAVE_LOG = 3;
          public static readonly int OTHER_LOG = 4;
  
          public static readonly int SUCCESS = 1;
          public static readonly int FAILURE = 0;
  
  
          private static IntPtr unwrap(IntPtr ctx)
          {
              try {
                  GCHandle gch = GCHandle.FromIntPtr(ctx);
                  ctx_handles handles = (ctx_handles)gch.Target;
                  return handles.get_ctx();
              } catch (Exception e)
              {
                  log(ERROR_LOG, "wolfssl pointer is incorrect " + e);
                  return IntPtr.Zero;
              }
          }
  
  
          /// <summary>
          /// Call back to allow recieving TLS information
          /// </summary>
          /// <param name="ssl">structure of ssl passed in</param>
          /// <param name="buf">buffer to contain recieved msg</param>
          /// <param name="sz">size of buffer</param>
          /// <param name="ctx">optional information passed in</param>
          /// <returns>size of message recieved</returns>
          private static int wolfSSLCbIORecv(IntPtr ssl, IntPtr buf, int sz, IntPtr ctx)
          {
              if (sz <= 0)
              {
  
gt:                 log(ERROR_LOG, "wolfssl recieve error, size less than 0");