Annotation of embedaddon/axTLS/samples/java/axssl.java, 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 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>