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: /** @} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>