2 * Copyright (c) 2007, Cameron Rich
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
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.
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.
32 * A wrapper around the unmanaged interface to give a semi-decent C# API
36 using System.Runtime.InteropServices;
37 using System.Net.Sockets;
40 * @defgroup csharp_api C# API.
42 * Ensure that the appropriate Dispose() methods are called when finished with
43 * various objects - otherwise memory leaks will result.
51 * @brief A representation of an SSL connection.
55 public IntPtr m_ssl; /**< A pointer to the real SSL type */
58 * @brief Store the reference to an SSL context.
59 * @param ip [in] A reference to an SSL object.
67 * @brief Free any used resources on this connection.
69 * A "Close Notify" message is sent on this connection (if possible).
70 * It is up to the application to close the socket.
74 axtls.ssl_free(m_ssl);
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.
82 public int HandshakeStatus()
84 return axtls.ssl_handshake_status(m_ssl);
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)
95 public byte GetCipherId()
97 return axtls.ssl_get_cipher_id(m_ssl);
101 * @brief Get the session id for a handshake.
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.
108 public byte[] GetSessionId()
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);
118 * @brief Retrieve an X.509 distinguished name component.
120 * When a handshake is complete and a certificate has been exchanged,
121 * then the details of the remote certificate can be retrieved.
123 * This will usually be used by a client to check that the server's
124 * common name matches the URL.
126 * A full handshake needs to occur for this call to work.
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)
137 public string GetCertificateDN(int component)
139 return axtls.ssl_get_cert_dn(m_ssl, component);
145 * @ingroup csharp_api
146 * @brief Some global helper functions.
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
159 public static int BuildMode()
161 return axtls.ssl_get_config(axtls.SSL_BUILD_MODE);
165 * @brief Return the number of chained certificates that the
166 * client/server supports.
167 * @return The number of supported server certificates.
169 public static int MaxCerts()
171 return axtls.ssl_get_config(axtls.SSL_MAX_CERT_CFG_OFFSET);
175 * @brief Return the number of CA certificates that the client/server
177 * @return The number of supported CA certificates.
179 public static int MaxCACerts()
181 return axtls.ssl_get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET);
185 * @brief Indicate if PEM is supported.
186 * @return true if PEM supported.
188 public static bool HasPEM()
190 return axtls.ssl_get_config(axtls.SSL_HAS_PEM) > 0 ? true : false;
194 * @brief Display the text string of the error.
195 * @param error_code [in] The integer error code.
197 public static void DisplayError(int error_code)
199 axtls.ssl_display_error(error_code);
203 * @brief Return the version of the axTLS project.
205 public static string Version()
207 return axtls.ssl_version();
213 * @ingroup csharp_api
214 * @brief A base object for SSLServer/SSLClient.
219 * @brief A reference to the real client/server context.
221 protected IntPtr m_ctx;
224 * @brief Establish a new client/server context.
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
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.
235 * @param options [in] Any particular options. At present the options
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
254 * @return A client/server context.
256 protected SSLCTX(uint options, int num_sessions)
258 m_ctx = axtls.ssl_ctx_new(options, num_sessions);
262 * @brief Remove a client/server context.
264 * Frees any used resources used by this context. Each connection will
265 * be sent a "Close Notify" alert (if possible).
267 public void Dispose()
269 axtls.ssl_ctx_free(m_ctx);
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
283 * @see ssl.h for the error code list.
284 * @note Use in_data before doing any successive ssl calls.
286 public int Read(SSL ssl, out byte[] in_data)
288 IntPtr ptr = IntPtr.Zero;
289 int ret = axtls.ssl_read(ssl.m_ssl, ref ptr);
291 if (ret > axtls.SSL_OK)
293 in_data = new byte[ret];
294 Marshal.Copy(ptr, in_data, 0, ret);
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.
311 public int Write(SSL ssl, byte[] out_data)
313 return axtls.ssl_write(ssl.m_ssl, out_data, out_data.Length);
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.
324 public int Write(SSL ssl, byte[] out_data, int out_len)
326 return axtls.ssl_write(ssl.m_ssl, out_data, out_len);
330 * @brief Find an ssl object based on a Socket reference.
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.
338 public SSL Find(Socket s)
340 int client_fd = s.Handle.ToInt32();
341 return new SSL(axtls. ssl_find(m_ctx, client_fd));
345 * @brief Authenticate a received certificate.
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.
352 public int VerifyCert(SSL ssl)
354 return axtls.ssl_verify_cert(ssl.m_ssl);
358 * @brief Force the client to perform its handshake again.
360 * For a client this involves sending another "client hello" message.
361 * For the server is means sending a "hello request" message.
363 * This is a blocking call on the client (until the handshake
365 * @param ssl [in] An SSL object reference.
366 * @return SSL_OK if renegotiation instantiation was ok
368 public int Renegotiate(SSL ssl)
370 return axtls.ssl_renegotiate(ssl.m_ssl);
374 * @brief Load a file into memory that is in binary DER or ASCII PEM
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)
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
391 public int ObjLoad(int obj_type, string filename, string password)
393 return axtls.ssl_obj_load(m_ctx, obj_type, filename, password);
397 * @brief Transfer binary data into the object loader.
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
407 public int ObjLoad(int obj_type, byte[] data, int len, string password)
409 return axtls.ssl_obj_memory_load(m_ctx, obj_type,
410 data, len, password);
416 * @ingroup csharp_api
417 * @brief The server context.
419 * All server connections are started within a server context.
421 public class SSLServer : SSLCTX
424 * @brief Start a new server context.
426 * @see SSLCTX for details.
428 public SSLServer(uint options, int num_sessions) :
429 base(options, num_sessions) {}
432 * @brief Establish a new SSL connection to an SSL client.
434 * It is up to the application to establish the initial socket
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.
441 public SSL Connect(Socket s)
443 int client_fd = s.Handle.ToInt32();
444 return new SSL(axtls.ssl_server_new(m_ctx, client_fd));
450 * @ingroup csharp_api
451 * @brief The client context.
453 * All client connections are started within a client context.
455 public class SSLClient : SSLCTX
458 * @brief Start a new client context.
460 * @see SSLCTX for details.
462 public SSLClient(uint options, int num_sessions) :
463 base(options, num_sessions) {}
466 * @brief Establish a new SSL connection to an SSL server.
468 * It is up to the application to establish the initial socket
471 * This is a blocking call - it will finish when the handshake is
472 * complete (or has failed).
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.
481 public SSL Connect(Socket s, byte[] session_id)
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,