Add axTLS sourcecode
[project/luci.git] / libs / nixio / axTLS / bindings / csharp / axTLS.cs
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 /** @} */