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