Return to axTLS.cs CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / axTLS / bindings / csharp |
1.1 ! misho 1: /* ! 2: * Copyright (c) 2007, Cameron Rich ! 3: * ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms, with or without ! 7: * modification, are permitted provided that the following conditions are met: ! 8: * ! 9: * * Redistributions of source code must retain the above copyright notice, ! 10: * this list of conditions and the following disclaimer. ! 11: * * Redistributions in binary form must reproduce the above copyright notice, ! 12: * this list of conditions and the following disclaimer in the documentation ! 13: * and/or other materials provided with the distribution. ! 14: * * Neither the name of the axTLS project nor the names of its contributors ! 15: * may be used to endorse or promote products derived from this software ! 16: * without specific prior written permission. ! 17: * ! 18: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ! 19: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ! 20: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ! 21: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ! 22: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ! 23: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ! 24: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ! 25: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ! 26: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ! 27: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ! 28: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! 29: */ ! 30: ! 31: /** ! 32: * A wrapper around the unmanaged interface to give a semi-decent C# API ! 33: */ ! 34: ! 35: using System; ! 36: using System.Runtime.InteropServices; ! 37: using System.Net.Sockets; ! 38: ! 39: /** ! 40: * @defgroup csharp_api C# API. ! 41: * ! 42: * Ensure that the appropriate Dispose() methods are called when finished with ! 43: * various objects - otherwise memory leaks will result. ! 44: * @{ ! 45: */ ! 46: namespace axTLS ! 47: { ! 48: /** ! 49: * @class SSL ! 50: * @ingroup csharp_api ! 51: * @brief A representation of an SSL connection. ! 52: */ ! 53: public class SSL ! 54: { ! 55: public IntPtr m_ssl; /**< A pointer to the real SSL type */ ! 56: ! 57: /** ! 58: * @brief Store the reference to an SSL context. ! 59: * @param ip [in] A reference to an SSL object. ! 60: */ ! 61: public SSL(IntPtr ip) ! 62: { ! 63: m_ssl = ip; ! 64: } ! 65: ! 66: /** ! 67: * @brief Free any used resources on this connection. ! 68: * ! 69: * A "Close Notify" message is sent on this connection (if possible). ! 70: * It is up to the application to close the socket. ! 71: */ ! 72: public void Dispose() ! 73: { ! 74: axtls.ssl_free(m_ssl); ! 75: } ! 76: ! 77: /** ! 78: * @brief Return the result of a handshake. ! 79: * @return SSL_OK if the handshake is complete and ok. ! 80: * @see ssl.h for the error code list. ! 81: */ ! 82: public int HandshakeStatus() ! 83: { ! 84: return axtls.ssl_handshake_status(m_ssl); ! 85: } ! 86: ! 87: /** ! 88: * @brief Return the SSL cipher id. ! 89: * @return The cipher id which is one of: ! 90: * - SSL_AES128_SHA (0x2f) ! 91: * - SSL_AES256_SHA (0x35) ! 92: * - SSL_RC4_128_SHA (0x05) ! 93: * - SSL_RC4_128_MD5 (0x04) ! 94: */ ! 95: public byte GetCipherId() ! 96: { ! 97: return axtls.ssl_get_cipher_id(m_ssl); ! 98: } ! 99: ! 100: /** ! 101: * @brief Get the session id for a handshake. ! 102: * ! 103: * This will be a 32 byte sequence and is available after the first ! 104: * handshaking messages are sent. ! 105: * @return The session id as a 32 byte sequence. ! 106: * @note A SSLv23 handshake may have only 16 valid bytes. ! 107: */ ! 108: public byte[] GetSessionId() ! 109: { ! 110: IntPtr ptr = axtls.ssl_get_session_id(m_ssl); ! 111: byte sess_id_size = axtls.ssl_get_session_id_size(m_ssl); ! 112: byte[] result = new byte[sess_id_size]; ! 113: Marshal.Copy(ptr, result, 0, sess_id_size); ! 114: return result; ! 115: } ! 116: ! 117: /** ! 118: * @brief Retrieve an X.509 distinguished name component. ! 119: * ! 120: * When a handshake is complete and a certificate has been exchanged, ! 121: * then the details of the remote certificate can be retrieved. ! 122: * ! 123: * This will usually be used by a client to check that the server's ! 124: * common name matches the URL. ! 125: * ! 126: * A full handshake needs to occur for this call to work. ! 127: * ! 128: * @param component [in] one of: ! 129: * - SSL_X509_CERT_COMMON_NAME ! 130: * - SSL_X509_CERT_ORGANIZATION ! 131: * - SSL_X509_CERT_ORGANIZATIONAL_NAME ! 132: * - SSL_X509_CA_CERT_COMMON_NAME ! 133: * - SSL_X509_CA_CERT_ORGANIZATION ! 134: * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME ! 135: * @return The appropriate string (or null if not defined) ! 136: */ ! 137: public string GetCertificateDN(int component) ! 138: { ! 139: return axtls.ssl_get_cert_dn(m_ssl, component); ! 140: } ! 141: } ! 142: ! 143: /** ! 144: * @class SSLUtil ! 145: * @ingroup csharp_api ! 146: * @brief Some global helper functions. ! 147: */ ! 148: public class SSLUtil ! 149: { ! 150: ! 151: /** ! 152: * @brief Return the build mode of the axTLS project. ! 153: * @return The build mode is one of: ! 154: * - SSL_BUILD_SERVER_ONLY ! 155: * - SSL_BUILD_ENABLE_VERIFICATION ! 156: * - SSL_BUILD_ENABLE_CLIENT ! 157: * - SSL_BUILD_FULL_MODE ! 158: */ ! 159: public static int BuildMode() ! 160: { ! 161: return axtls.ssl_get_config(axtls.SSL_BUILD_MODE); ! 162: } ! 163: ! 164: /** ! 165: * @brief Return the number of chained certificates that the ! 166: * client/server supports. ! 167: * @return The number of supported server certificates. ! 168: */ ! 169: public static int MaxCerts() ! 170: { ! 171: return axtls.ssl_get_config(axtls.SSL_MAX_CERT_CFG_OFFSET); ! 172: } ! 173: ! 174: /** ! 175: * @brief Return the number of CA certificates that the client/server ! 176: * supports. ! 177: * @return The number of supported CA certificates. ! 178: */ ! 179: public static int MaxCACerts() ! 180: { ! 181: return axtls.ssl_get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET); ! 182: } ! 183: ! 184: /** ! 185: * @brief Indicate if PEM is supported. ! 186: * @return true if PEM supported. ! 187: */ ! 188: public static bool HasPEM() ! 189: { ! 190: return axtls.ssl_get_config(axtls.SSL_HAS_PEM) > 0 ? true : false; ! 191: } ! 192: ! 193: /** ! 194: * @brief Display the text string of the error. ! 195: * @param error_code [in] The integer error code. ! 196: */ ! 197: public static void DisplayError(int error_code) ! 198: { ! 199: axtls.ssl_display_error(error_code); ! 200: } ! 201: ! 202: /** ! 203: * @brief Return the version of the axTLS project. ! 204: */ ! 205: public static string Version() ! 206: { ! 207: return axtls.ssl_version(); ! 208: } ! 209: } ! 210: ! 211: /** ! 212: * @class SSLCTX ! 213: * @ingroup csharp_api ! 214: * @brief A base object for SSLServer/SSLClient. ! 215: */ ! 216: public class SSLCTX ! 217: { ! 218: /** ! 219: * @brief A reference to the real client/server context. ! 220: */ ! 221: protected IntPtr m_ctx; ! 222: ! 223: /** ! 224: * @brief Establish a new client/server context. ! 225: * ! 226: * This function is called before any client/server SSL connections are ! 227: * made. If multiple threads are used, then each thread will have its ! 228: * own SSLCTX context. Any number of connections may be made with a ! 229: * single context. ! 230: * ! 231: * Each new connection will use the this context's private key and ! 232: * certificate chain. If a different certificate chain is required, ! 233: * then a different context needs to be be used. ! 234: * ! 235: * @param options [in] Any particular options. At present the options ! 236: * supported are: ! 237: * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if ! 238: * the server authentication fails. The certificate can be ! 239: * authenticated later with a call to VerifyCert(). ! 240: * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client ! 241: * authentication i.e. each handshake will include a "certificate ! 242: * request" message from the server. ! 243: * - SSL_DISPLAY_BYTES (full mode build only): Display the byte ! 244: * sequences during the handshake. ! 245: * - SSL_DISPLAY_STATES (full mode build only): Display the state ! 246: * changes during the handshake. ! 247: * - SSL_DISPLAY_CERTS (full mode build only): Display the ! 248: * certificates that are passed during a handshake. ! 249: * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key ! 250: * details that are passed during a handshake. ! 251: * @param num_sessions [in] The number of sessions to be used for ! 252: * session caching. If this value is 0, then there is no session ! 253: * caching. ! 254: * @return A client/server context. ! 255: */ ! 256: protected SSLCTX(uint options, int num_sessions) ! 257: { ! 258: m_ctx = axtls.ssl_ctx_new(options, num_sessions); ! 259: } ! 260: ! 261: /** ! 262: * @brief Remove a client/server context. ! 263: * ! 264: * Frees any used resources used by this context. Each connection will ! 265: * be sent a "Close Notify" alert (if possible). ! 266: */ ! 267: public void Dispose() ! 268: { ! 269: axtls.ssl_ctx_free(m_ctx); ! 270: } ! 271: ! 272: /** ! 273: * @brief Read the SSL data stream. ! 274: * @param ssl [in] An SSL object reference. ! 275: * @param in_data [out] After a successful read, the decrypted data ! 276: * will be here. It will be null otherwise. ! 277: * @return The number of decrypted bytes: ! 278: * - if > 0, then the handshaking is complete and we are returning the ! 279: * number of decrypted bytes. ! 280: * - SSL_OK if the handshaking stage is successful (but not yet ! 281: * complete). ! 282: * - < 0 if an error. ! 283: * @see ssl.h for the error code list. ! 284: * @note Use in_data before doing any successive ssl calls. ! 285: */ ! 286: public int Read(SSL ssl, out byte[] in_data) ! 287: { ! 288: IntPtr ptr = IntPtr.Zero; ! 289: int ret = axtls.ssl_read(ssl.m_ssl, ref ptr); ! 290: ! 291: if (ret > axtls.SSL_OK) ! 292: { ! 293: in_data = new byte[ret]; ! 294: Marshal.Copy(ptr, in_data, 0, ret); ! 295: } ! 296: else ! 297: { ! 298: in_data = null; ! 299: } ! 300: ! 301: return ret; ! 302: } ! 303: ! 304: /** ! 305: * @brief Write to the SSL data stream. ! 306: * @param ssl [in] An SSL obect reference. ! 307: * @param out_data [in] The data to be written ! 308: * @return The number of bytes sent, or if < 0 if an error. ! 309: * @see ssl.h for the error code list. ! 310: */ ! 311: public int Write(SSL ssl, byte[] out_data) ! 312: { ! 313: return axtls.ssl_write(ssl.m_ssl, out_data, out_data.Length); ! 314: } ! 315: ! 316: /** ! 317: * @brief Write to the SSL data stream. ! 318: * @param ssl [in] An SSL obect reference. ! 319: * @param out_data [in] The data to be written ! 320: * @param out_len [in] The number of bytes to be written ! 321: * @return The number of bytes sent, or if < 0 if an error. ! 322: * @see ssl.h for the error code list. ! 323: */ ! 324: public int Write(SSL ssl, byte[] out_data, int out_len) ! 325: { ! 326: return axtls.ssl_write(ssl.m_ssl, out_data, out_len); ! 327: } ! 328: ! 329: /** ! 330: * @brief Find an ssl object based on a Socket reference. ! 331: * ! 332: * Goes through the list of SSL objects maintained in a client/server ! 333: * context to look for a socket match. ! 334: * @param s [in] A reference to a <A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnetsocketssocketclasstopic.asp">Socket</A> object. ! 335: * @return A reference to the SSL object. Returns null if the object ! 336: * could not be found. ! 337: */ ! 338: public SSL Find(Socket s) ! 339: { ! 340: int client_fd = s.Handle.ToInt32(); ! 341: return new SSL(axtls. ssl_find(m_ctx, client_fd)); ! 342: } ! 343: ! 344: /** ! 345: * @brief Authenticate a received certificate. ! 346: * ! 347: * This call is usually made by a client after a handshake is complete ! 348: * and the context is in SSL_SERVER_VERIFY_LATER mode. ! 349: * @param ssl [in] An SSL object reference. ! 350: * @return SSL_OK if the certificate is verified. ! 351: */ ! 352: public int VerifyCert(SSL ssl) ! 353: { ! 354: return axtls.ssl_verify_cert(ssl.m_ssl); ! 355: } ! 356: ! 357: /** ! 358: * @brief Force the client to perform its handshake again. ! 359: * ! 360: * For a client this involves sending another "client hello" message. ! 361: * For the server is means sending a "hello request" message. ! 362: * ! 363: * This is a blocking call on the client (until the handshake ! 364: * completes). ! 365: * @param ssl [in] An SSL object reference. ! 366: * @return SSL_OK if renegotiation instantiation was ok ! 367: */ ! 368: public int Renegotiate(SSL ssl) ! 369: { ! 370: return axtls.ssl_renegotiate(ssl.m_ssl); ! 371: } ! 372: ! 373: /** ! 374: * @brief Load a file into memory that is in binary DER or ASCII PEM ! 375: * format. ! 376: * ! 377: * These are temporary objects that are used to load private keys, ! 378: * certificates etc into memory. ! 379: * @param obj_type [in] The format of the file. Can be one of: ! 380: * - SSL_OBJ_X509_CERT (no password required) ! 381: * - SSL_OBJ_X509_CACERT (no password required) ! 382: * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) ! 383: * - SSL_OBJ_P8 (RC4-128 encrypted data supported) ! 384: * - SSL_OBJ_P12 (RC4-128 encrypted data supported) ! 385: * ! 386: * PEM files are automatically detected (if supported). ! 387: * @param filename [in] The location of a file in DER/PEM format. ! 388: * @param password [in] The password used. Can be null if not required. ! 389: * @return SSL_OK if all ok ! 390: */ ! 391: public int ObjLoad(int obj_type, string filename, string password) ! 392: { ! 393: return axtls.ssl_obj_load(m_ctx, obj_type, filename, password); ! 394: } ! 395: ! 396: /** ! 397: * @brief Transfer binary data into the object loader. ! 398: * ! 399: * These are temporary objects that are used to load private keys, ! 400: * certificates etc into memory. ! 401: * @param obj_type [in] The format of the memory data. ! 402: * @param data [in] The binary data to be loaded. ! 403: * @param len [in] The amount of data to be loaded. ! 404: * @param password [in] The password used. Can be null if not required. ! 405: * @return SSL_OK if all ok ! 406: */ ! 407: public int ObjLoad(int obj_type, byte[] data, int len, string password) ! 408: { ! 409: return axtls.ssl_obj_memory_load(m_ctx, obj_type, ! 410: data, len, password); ! 411: } ! 412: } ! 413: ! 414: /** ! 415: * @class SSLServer ! 416: * @ingroup csharp_api ! 417: * @brief The server context. ! 418: * ! 419: * All server connections are started within a server context. ! 420: */ ! 421: public class SSLServer : SSLCTX ! 422: { ! 423: /** ! 424: * @brief Start a new server context. ! 425: * ! 426: * @see SSLCTX for details. ! 427: */ ! 428: public SSLServer(uint options, int num_sessions) : ! 429: base(options, num_sessions) {} ! 430: ! 431: /** ! 432: * @brief Establish a new SSL connection to an SSL client. ! 433: * ! 434: * It is up to the application to establish the initial socket ! 435: * connection. ! 436: * ! 437: * Call Dispose() when the connection is to be removed. ! 438: * @param s [in] A reference to a <A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnetsocketssocketclasstopic.asp">Socket</A> object. ! 439: * @return An SSL object reference. ! 440: */ ! 441: public SSL Connect(Socket s) ! 442: { ! 443: int client_fd = s.Handle.ToInt32(); ! 444: return new SSL(axtls.ssl_server_new(m_ctx, client_fd)); ! 445: } ! 446: } ! 447: ! 448: /** ! 449: * @class SSLClient ! 450: * @ingroup csharp_api ! 451: * @brief The client context. ! 452: * ! 453: * All client connections are started within a client context. ! 454: */ ! 455: public class SSLClient : SSLCTX ! 456: { ! 457: /** ! 458: * @brief Start a new client context. ! 459: * ! 460: * @see SSLCTX for details. ! 461: */ ! 462: public SSLClient(uint options, int num_sessions) : ! 463: base(options, num_sessions) {} ! 464: ! 465: /** ! 466: * @brief Establish a new SSL connection to an SSL server. ! 467: * ! 468: * It is up to the application to establish the initial socket ! 469: * connection. ! 470: * ! 471: * This is a blocking call - it will finish when the handshake is ! 472: * complete (or has failed). ! 473: * ! 474: * Call Dispose() when the connection is to be removed. ! 475: * @param s [in] A reference to a <A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnetsocketssocketclasstopic.asp">Socket</A> object. ! 476: * @param session_id [in] A 32 byte session id for session resumption. ! 477: * This can be null if no session resumption is not required. ! 478: * @return An SSL object reference. Use SSL.handshakeStatus() to check ! 479: * if a handshake succeeded. ! 480: */ ! 481: public SSL Connect(Socket s, byte[] session_id) ! 482: { ! 483: int client_fd = s.Handle.ToInt32(); ! 484: byte sess_id_size = (byte)(session_id != null ? ! 485: session_id.Length : 0); ! 486: return new SSL(axtls.ssl_client_new(m_ctx, client_fd, session_id, ! 487: sess_id_size)); ! 488: } ! 489: } ! 490: } ! 491: /** @} */