Rework LuCI build system
[project/luci.git] / libs / luci-lib-nixio / axTLS / samples / csharp / axssl.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  * 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 }