Annotation of embedaddon/axTLS/samples/csharp/axssl.cs, revision 1.1.1.1
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: * Demonstrate the use of the axTLS library in C# with a set of
33: * command-line parameters similar to openssl. In fact, openssl clients
34: * should be able to communicate with axTLS servers and visa-versa.
35: *
36: * This code has various bits enabled depending on the configuration. To enable
37: * the most interesting version, compile with the 'full mode' enabled.
38: *
39: * To see what options you have, run the following:
40: * > axssl.csharp.exe s_server -?
41: * > axssl.csharp.exe s_client -?
42: *
43: * The axtls shared library must be in the same directory or be found
44: * by the OS.
45: */
46:
47: using System;
48: using System.Net;
49: using System.Net.Sockets;
50: using axTLS;
51:
52: public class axssl
53: {
54: /*
55: * Main()
56: */
57: public static void Main(string[] args)
58: {
59: if (args.Length == 1 && args[0] == "version")
60: {
61: Console.WriteLine("axssl.csharp " + SSLUtil.Version());
62: Environment.Exit(0);
63: }
64:
65: axssl runner = new axssl();
66:
67: if (args.Length < 1 || (args[0] != "s_server" && args[0] != "s_client"))
68: runner.print_options(args.Length > 0 ? args[0] : "");
69:
70: int build_mode = SSLUtil.BuildMode();
71:
72: if (args[0] == "s_server")
73: runner.do_server(build_mode, args);
74: else
75: runner.do_client(build_mode, args);
76: }
77:
78: /*
79: * do_server()
80: */
81: private void do_server(int build_mode, string[] args)
82: {
83: int i = 1;
84: int port = 4433;
85: uint options = axtls.SSL_DISPLAY_CERTS;
86: bool quiet = false;
87: string password = null;
88: string private_key_file = null;
89:
90: /* organise the cert/ca_cert lists */
91: int cert_size = SSLUtil.MaxCerts();
92: int ca_cert_size = SSLUtil.MaxCACerts();
93: string[] cert = new string[cert_size];
94: string[] ca_cert = new string[ca_cert_size];
95: int cert_index = 0;
96: int ca_cert_index = 0;
97:
98: while (i < args.Length)
99: {
100: if (args[i] == "-accept")
101: {
102: if (i >= args.Length-1)
103: {
104: print_server_options(build_mode, args[i]);
105: }
106:
107: port = Int32.Parse(args[++i]);
108: }
109: else if (args[i] == "-quiet")
110: {
111: quiet = true;
112: options &= ~(uint)axtls.SSL_DISPLAY_CERTS;
113: }
114: else if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY)
115: {
116: if (args[i] == "-cert")
117: {
118: if (i >= args.Length-1 || cert_index >= cert_size)
119: {
120: print_server_options(build_mode, args[i]);
121: }
122:
123: cert[cert_index++] = args[++i];
124: }
125: else if (args[i] == "-key")
126: {
127: if (i >= args.Length-1)
128: {
129: print_server_options(build_mode, args[i]);
130: }
131:
132: private_key_file = args[++i];
133: options |= axtls.SSL_NO_DEFAULT_KEY;
134: }
135: else if (args[i] == "-pass")
136: {
137: if (i >= args.Length-1)
138: {
139: print_server_options(build_mode, args[i]);
140: }
141:
142: password = args[++i];
143: }
144: else if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION)
145: {
146: if (args[i] == "-verify")
147: {
148: options |= axtls.SSL_CLIENT_AUTHENTICATION;
149: }
150: else if (args[i] == "-CAfile")
151: {
152: if (i >= args.Length-1 || ca_cert_index >= ca_cert_size)
153: {
154: print_server_options(build_mode, args[i]);
155: }
156:
157: ca_cert[ca_cert_index++] = args[++i];
158: }
159: else if (build_mode == axtls.SSL_BUILD_FULL_MODE)
160: {
161: if (args[i] == "-debug")
162: {
163: options |= axtls.SSL_DISPLAY_BYTES;
164: }
165: else if (args[i] == "-state")
166: {
167: options |= axtls.SSL_DISPLAY_STATES;
168: }
169: else if (args[i] == "-show-rsa")
170: {
171: options |= axtls.SSL_DISPLAY_RSA;
172: }
173: else
174: print_server_options(build_mode, args[i]);
175: }
176: else
177: print_server_options(build_mode, args[i]);
178: }
179: else
180: print_server_options(build_mode, args[i]);
181: }
182: else
183: print_server_options(build_mode, args[i]);
184:
185: i++;
186: }
187:
188: /* Create socket for incoming connections */
189: IPEndPoint ep = new IPEndPoint(IPAddress.Any, port);
190: TcpListener server_sock = new TcpListener(ep);
191: server_sock.Start();
192:
193: /**********************************************************************
194: * This is where the interesting stuff happens. Up until now we've
195: * just been setting up sockets etc. Now we do the SSL handshake.
196: **********************************************************************/
197: SSLServer ssl_ctx = new SSLServer(
198: options, axtls.SSL_DEFAULT_SVR_SESS);
199:
200: if (ssl_ctx == null)
201: {
202: Console.Error.WriteLine("Error: Server context is invalid");
203: Environment.Exit(1);
204: }
205:
206: if (private_key_file != null)
207: {
208: int obj_type = axtls.SSL_OBJ_RSA_KEY;
209:
210: if (private_key_file.EndsWith(".p8"))
211: obj_type = axtls.SSL_OBJ_PKCS8;
212: else if (private_key_file.EndsWith(".p12"))
213: obj_type = axtls.SSL_OBJ_PKCS12;
214:
215: if (ssl_ctx.ObjLoad(obj_type,
216: private_key_file, password) != axtls.SSL_OK)
217: {
218: Console.Error.WriteLine("Private key '" + private_key_file +
219: "' is undefined.");
220: Environment.Exit(1);
221: }
222: }
223:
224: for (i = 0; i < cert_index; i++)
225: {
226: if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT,
227: cert[i], null) != axtls.SSL_OK)
228: {
229: Console.WriteLine("Certificate '" + cert[i] +
230: "' is undefined.");
231: Environment.Exit(1);
232: }
233: }
234:
235: for (i = 0; i < ca_cert_index; i++)
236: {
237: if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT,
238: ca_cert[i], null) != axtls.SSL_OK)
239: {
240: Console.WriteLine("Certificate '" + cert[i] +
241: "' is undefined.");
242: Environment.Exit(1);
243: }
244: }
245:
246: byte[] buf = null;
247: int res;
248:
249: for (;;)
250: {
251: if (!quiet)
252: {
253: Console.WriteLine("ACCEPT");
254: }
255:
256: Socket client_sock = server_sock.AcceptSocket();
257:
258: SSL ssl = ssl_ctx.Connect(client_sock);
259:
260: /* do the actual SSL handshake */
261: while ((res = ssl_ctx.Read(ssl, out buf)) == axtls.SSL_OK)
262: {
263: /* check when the connection has been established */
264: if (ssl.HandshakeStatus() == axtls.SSL_OK)
265: break;
266:
267: /* could do something else here */
268: }
269:
270: if (res == axtls.SSL_OK) /* connection established and ok */
271: {
272: if (!quiet)
273: {
274: display_session_id(ssl);
275: display_cipher(ssl);
276: }
277:
278: /* now read (and display) whatever the client sends us */
279: for (;;)
280: {
281: /* keep reading until we get something interesting */
282: while ((res = ssl_ctx.Read(ssl, out buf)) == axtls.SSL_OK)
283: {
284: /* could do something else here */
285: }
286:
287: if (res < axtls.SSL_OK)
288: {
289: if (!quiet)
290: {
291: Console.WriteLine("CONNECTION CLOSED");
292: }
293:
294: break;
295: }
296:
297: /* convert to string */
298: char[] str = new char[res];
299: for (i = 0; i < res; i++)
300: {
301: str[i] = (char)buf[i];
302: }
303:
304: Console.Write(str);
305: }
306: }
307: else if (!quiet)
308: {
309: SSLUtil.DisplayError(res);
310: }
311:
312: /* client was disconnected or the handshake failed. */
313: ssl.Dispose();
314: client_sock.Close();
315: }
316:
317: /* ssl_ctx.Dispose(); */
318: }
319:
320: /*
321: * do_client()
322: */
323: private void do_client(int build_mode, string[] args)
324: {
325: if (build_mode < axtls.SSL_BUILD_ENABLE_CLIENT)
326: {
327: print_client_options(build_mode, args[1]);
328: }
329:
330: int i = 1, res;
331: int port = 4433;
332: bool quiet = false;
333: string password = null;
334: int reconnect = 0;
335: string private_key_file = null;
336: string hostname = "127.0.0.1";
337:
338: /* organise the cert/ca_cert lists */
339: int cert_index = 0;
340: int ca_cert_index = 0;
341: int cert_size = SSLUtil.MaxCerts();
342: int ca_cert_size = SSLUtil.MaxCACerts();
343: string[] cert = new string[cert_size];
344: string[] ca_cert = new string[ca_cert_size];
345:
346: uint options = axtls.SSL_SERVER_VERIFY_LATER|axtls.SSL_DISPLAY_CERTS;
347: byte[] session_id = null;
348:
349: while (i < args.Length)
350: {
351: if (args[i] == "-connect")
352: {
353: string host_port;
354:
355: if (i >= args.Length-1)
356: {
357: print_client_options(build_mode, args[i]);
358: }
359:
360: host_port = args[++i];
361: int index_colon;
362:
363: if ((index_colon = host_port.IndexOf(':')) < 0)
364: print_client_options(build_mode, args[i]);
365:
366: hostname = new string(host_port.ToCharArray(),
367: 0, index_colon);
368: port = Int32.Parse(new String(host_port.ToCharArray(),
369: index_colon+1, host_port.Length-index_colon-1));
370: }
371: else if (args[i] == "-cert")
372: {
373: if (i >= args.Length-1 || cert_index >= cert_size)
374: {
375: print_client_options(build_mode, args[i]);
376: }
377:
378: cert[cert_index++] = args[++i];
379: }
380: else if (args[i] == "-key")
381: {
382: if (i >= args.Length-1)
383: {
384: print_client_options(build_mode, args[i]);
385: }
386:
387: private_key_file = args[++i];
388: options |= axtls.SSL_NO_DEFAULT_KEY;
389: }
390: else if (args[i] == "-CAfile")
391: {
392: if (i >= args.Length-1 || ca_cert_index >= ca_cert_size)
393: {
394: print_client_options(build_mode, args[i]);
395: }
396:
397: ca_cert[ca_cert_index++] = args[++i];
398: }
399: else if (args[i] == "-verify")
400: {
401: options &= ~(uint)axtls.SSL_SERVER_VERIFY_LATER;
402: }
403: else if (args[i] == "-reconnect")
404: {
405: reconnect = 4;
406: }
407: else if (args[i] == "-quiet")
408: {
409: quiet = true;
410: options &= ~(uint)axtls.SSL_DISPLAY_CERTS;
411: }
412: else if (args[i] == "-pass")
413: {
414: if (i >= args.Length-1)
415: {
416: print_client_options(build_mode, args[i]);
417: }
418:
419: password = args[++i];
420: }
421: else if (build_mode == axtls.SSL_BUILD_FULL_MODE)
422: {
423: if (args[i] == "-debug")
424: {
425: options |= axtls.SSL_DISPLAY_BYTES;
426: }
427: else if (args[i] == "-state")
428: {
429: options |= axtls.SSL_DISPLAY_STATES;
430: }
431: else if (args[i] == "-show-rsa")
432: {
433: options |= axtls.SSL_DISPLAY_RSA;
434: }
435: else
436: print_client_options(build_mode, args[i]);
437: }
438: else /* don't know what this is */
439: print_client_options(build_mode, args[i]);
440:
441: i++;
442: }
443:
444: // IPHostEntry hostInfo = Dns.Resolve(hostname);
445: IPHostEntry hostInfo = Dns.GetHostEntry(hostname);
446: IPAddress[] addresses = hostInfo.AddressList;
447: IPEndPoint ep = new IPEndPoint(addresses[0], port);
448: Socket client_sock = new Socket(AddressFamily.InterNetwork,
449: SocketType.Stream, ProtocolType.Tcp);
450: client_sock.Connect(ep);
451:
452: if (!client_sock.Connected)
453: {
454: Console.WriteLine("could not connect");
455: Environment.Exit(1);
456: }
457:
458: if (!quiet)
459: {
460: Console.WriteLine("CONNECTED");
461: }
462:
463: /**********************************************************************
464: * This is where the interesting stuff happens. Up until now we've
465: * just been setting up sockets etc. Now we do the SSL handshake.
466: **********************************************************************/
467: SSLClient ssl_ctx = new SSLClient(options,
468: axtls.SSL_DEFAULT_CLNT_SESS);
469:
470: if (ssl_ctx == null)
471: {
472: Console.Error.WriteLine("Error: Client context is invalid");
473: Environment.Exit(1);
474: }
475:
476: if (private_key_file != null)
477: {
478: int obj_type = axtls.SSL_OBJ_RSA_KEY;
479:
480: if (private_key_file.EndsWith(".p8"))
481: obj_type = axtls.SSL_OBJ_PKCS8;
482: else if (private_key_file.EndsWith(".p12"))
483: obj_type = axtls.SSL_OBJ_PKCS12;
484:
485: if (ssl_ctx.ObjLoad(obj_type,
486: private_key_file, password) != axtls.SSL_OK)
487: {
488: Console.Error.WriteLine("Private key '" + private_key_file +
489: "' is undefined.");
490: Environment.Exit(1);
491: }
492: }
493:
494: for (i = 0; i < cert_index; i++)
495: {
496: if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CERT,
497: cert[i], null) != axtls.SSL_OK)
498: {
499: Console.WriteLine("Certificate '" + cert[i] +
500: "' is undefined.");
501: Environment.Exit(1);
502: }
503: }
504:
505: for (i = 0; i < ca_cert_index; i++)
506: {
507: if (ssl_ctx.ObjLoad(axtls.SSL_OBJ_X509_CACERT,
508: ca_cert[i], null) != axtls.SSL_OK)
509: {
510: Console.WriteLine("Certificate '" + cert[i] +
511: "' is undefined.");
512: Environment.Exit(1);
513: }
514: }
515:
516: SSL ssl = new SSL(new IntPtr(0)); /* keep compiler happy */
517:
518: /* Try session resumption? */
519: if (reconnect > 0)
520: {
521: while (reconnect-- > 0)
522: {
523: ssl = ssl_ctx.Connect(client_sock, session_id);
524:
525: if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK)
526: {
527: if (!quiet)
528: {
529: SSLUtil.DisplayError(res);
530: }
531:
532: ssl.Dispose();
533: Environment.Exit(1);
534: }
535:
536: display_session_id(ssl);
537: session_id = ssl.GetSessionId();
538:
539: if (reconnect > 0)
540: {
541: ssl.Dispose();
542: client_sock.Close();
543:
544: /* and reconnect */
545: client_sock = new Socket(AddressFamily.InterNetwork,
546: SocketType.Stream, ProtocolType.Tcp);
547: client_sock.Connect(ep);
548: }
549: }
550: }
551: else
552: {
553: ssl = ssl_ctx.Connect(client_sock, null);
554: }
555:
556: /* check the return status */
557: if ((res = ssl.HandshakeStatus()) != axtls.SSL_OK)
558: {
559: if (!quiet)
560: {
561: SSLUtil.DisplayError(res);
562: }
563:
564: Environment.Exit(1);
565: }
566:
567: if (!quiet)
568: {
569: string common_name =
570: ssl.GetCertificateDN(axtls.SSL_X509_CERT_COMMON_NAME);
571:
572: if (common_name != null)
573: {
574: Console.WriteLine("Common Name:\t\t\t" + common_name);
575: }
576:
577: display_session_id(ssl);
578: display_cipher(ssl);
579: }
580:
581: for (;;)
582: {
583: string user_input = Console.ReadLine();
584:
585: if (user_input == null)
586: break;
587:
588: byte[] buf = new byte[user_input.Length+2];
589: buf[buf.Length-2] = (byte)'\n'; /* add the carriage return */
590: buf[buf.Length-1] = 0; /* null terminate */
591:
592: for (i = 0; i < buf.Length-2; i++)
593: {
594: buf[i] = (byte)user_input[i];
595: }
596:
597: if ((res = ssl_ctx.Write(ssl, buf, buf.Length)) < axtls.SSL_OK)
598: {
599: if (!quiet)
600: {
601: SSLUtil.DisplayError(res);
602: }
603:
604: break;
605: }
606: }
607:
608: ssl_ctx.Dispose();
609: }
610:
611: /**
612: * We've had some sort of command-line error. Print out the basic options.
613: */
614: private void print_options(string option)
615: {
616: Console.WriteLine("axssl: Error: '" + option +
617: "' is an invalid command.");
618: Console.WriteLine("usage: axssl.csharp [s_server|" +
619: "s_client|version] [args ...]");
620: Environment.Exit(1);
621: }
622:
623: /**
624: * We've had some sort of command-line error. Print out the server options.
625: */
626: private void print_server_options(int build_mode, string option)
627: {
628: int cert_size = SSLUtil.MaxCerts();
629: int ca_cert_size = SSLUtil.MaxCACerts();
630:
631: Console.WriteLine("unknown option " + option);
632: Console.WriteLine("usage: s_server [args ...]");
633: Console.WriteLine(" -accept arg\t- port to accept on (default " +
634: "is 4433)");
635: Console.WriteLine(" -quiet\t\t- No server output");
636:
637: if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY)
638: {
639: Console.WriteLine(" -cert arg\t- certificate file to add (in " +
640: "addition to default) to chain -");
641: Console.WriteLine("\t\t Can repeat up to " + cert_size + " times");
642: Console.WriteLine(" -key arg\t- Private key file to use");
643: Console.WriteLine(" -pass\t\t- private key file pass phrase source");
644: }
645:
646: if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION)
647: {
648: Console.WriteLine(" -verify\t- turn on peer certificate " +
649: "verification");
650: Console.WriteLine(" -CAfile arg\t- Certificate authority.");
651: Console.WriteLine("\t\t Can repeat up to " +
652: ca_cert_size + "times");
653: }
654:
655: if (build_mode == axtls.SSL_BUILD_FULL_MODE)
656: {
657: Console.WriteLine(" -debug\t\t- Print more output");
658: Console.WriteLine(" -state\t\t- Show state messages");
659: Console.WriteLine(" -show-rsa\t- Show RSA state");
660: }
661:
662: Environment.Exit(1);
663: }
664:
665: /**
666: * We've had some sort of command-line error. Print out the client options.
667: */
668: private void print_client_options(int build_mode, string option)
669: {
670: int cert_size = SSLUtil.MaxCerts();
671: int ca_cert_size = SSLUtil.MaxCACerts();
672:
673: Console.WriteLine("unknown option " + option);
674:
675: if (build_mode >= axtls.SSL_BUILD_ENABLE_CLIENT)
676: {
677: Console.WriteLine("usage: s_client [args ...]");
678: Console.WriteLine(" -connect host:port - who to connect to " +
679: "(default is localhost:4433)");
680: Console.WriteLine(" -verify\t- turn on peer certificate " +
681: "verification");
682: Console.WriteLine(" -cert arg\t- certificate file to use");
683: Console.WriteLine("\t\t Can repeat up to %d times", cert_size);
684: Console.WriteLine(" -key arg\t- Private key file to use");
685: Console.WriteLine(" -CAfile arg\t- Certificate authority.");
686: Console.WriteLine("\t\t Can repeat up to " + ca_cert_size +
687: " times");
688: Console.WriteLine(" -quiet\t\t- No client output");
689: Console.WriteLine(" -pass\t\t- private key file pass " +
690: "phrase source");
691: Console.WriteLine(" -reconnect\t- Drop and re-make the " +
692: "connection with the same Session-ID");
693:
694: if (build_mode == axtls.SSL_BUILD_FULL_MODE)
695: {
696: Console.WriteLine(" -debug\t\t- Print more output");
697: Console.WriteLine(" -state\t\t- Show state messages");
698: Console.WriteLine(" -show-rsa\t- Show RSA state");
699: }
700: }
701: else
702: {
703: Console.WriteLine("Change configuration to allow this feature");
704: }
705:
706: Environment.Exit(1);
707: }
708:
709: /**
710: * Display what cipher we are using
711: */
712: private void display_cipher(SSL ssl)
713: {
714: Console.Write("CIPHER is ");
715:
716: switch (ssl.GetCipherId())
717: {
718: case axtls.SSL_AES128_SHA:
719: Console.WriteLine("AES128-SHA");
720: break;
721:
722: case axtls.SSL_AES256_SHA:
723: Console.WriteLine("AES256-SHA");
724: break;
725:
726: case axtls.SSL_RC4_128_SHA:
727: Console.WriteLine("RC4-SHA");
728: break;
729:
730: case axtls.SSL_RC4_128_MD5:
731: Console.WriteLine("RC4-MD5");
732: break;
733:
734: default:
735: Console.WriteLine("Unknown - " + ssl.GetCipherId());
736: break;
737: }
738: }
739:
740: /**
741: * Display what session id we have.
742: */
743: private void display_session_id(SSL ssl)
744: {
745: byte[] session_id = ssl.GetSessionId();
746:
747: if (session_id.Length > 0)
748: {
749: Console.WriteLine("-----BEGIN SSL SESSION PARAMETERS-----");
750: foreach (byte b in session_id)
751: {
752: Console.Write("{0:x02}", b);
753: }
754:
755: Console.WriteLine("\n-----END SSL SESSION PARAMETERS-----");
756: }
757: }
758: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>