| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- //
- // Copyright (c) 2007, Cameron Rich
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the distribution.
- // * Neither the name of the axTLS project nor the names of its
- // contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- //
- //
- // Demonstrate the use of the axTLS library in Lua with a set of
- // command-line parameters similar to openssl. In fact, openssl clients
- // should be able to communicate with axTLS servers and visa-versa.
- //
- // This code has various bits enabled depending on the configuration. To enable
- // the most interesting version, compile with the 'full mode' enabled.
- //
- // To see what options you have, run the following:
- // > [lua] axssl s_server -?
- // > [lua] axssl s_client -?
- //
- // The axtls/axtls shared libraries must be in the same directory or be found
- // by the OS.
- //
- //
- local vargv_len = vargv.len();
- // print version?
- if (vargv_len == 1 && vargv[0] == "version"){
- print("axssl.nut " + axtls.ssl_version());
- os.exit(1);
- }
- //
- // We've had some sort of command-line error. Print out the basic options.
- //
- function print_options(option){
- print("axssl: Error: '" + option + "' is an invalid command.");
- print("usage: axssl [s_server|s_client|version] [args ...]");
- os.exit(1);
- }
- //
- // We've had some sort of command-line error. Print out the server options.
- //
- function print_server_options(build_mode, option){
- local cert_size = axtls.get_config(axtls.SSL_MAX_CERT_CFG_OFFSET);
- local ca_cert_size = axtls.get_config(
- axtls.SSL_MAX_CA_CERT_CFG_OFFSET);
- print("unknown option " + option)
- print("usage: s_server [args ...]");
- print(" -accept\t- port to accept on (default is 4433)");
- print(" -quiet\t\t- No server output");
- if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY) {
- print(" -cert arg\t- certificate file to add (in addition to default) to chain -");
- print("\t\t Can repeat up to " + cert_size + " times");
- print(" -key arg\t- Private key file to use - default DER format");
- print(" -pass\t\t- private key file pass phrase source");
- }
- if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION){
- print(" -verify\t- turn on peer certificate verification");
- print(" -CAfile arg\t- Certificate authority - default DER format");
- print("\t\t Can repeat up to " + ca_cert_size + " times");
- }
- if (build_mode == axtls.SSL_BUILD_FULL_MODE) {
- print(" -debug\t\t- Print more output");
- print(" -state\t\t- Show state messages");
- print(" -show-rsa\t- Show RSA state");
- }
- os.exit(1);
- }
- //
- // We've had some sort of command-line error. Print out the client options.
- //
- function print_client_options(build_mode, option){
- local cert_size = axtls.get_config(axtls.SSL_MAX_CERT_CFG_OFFSET);
- local ca_cert_size = axtls.get_config(
- axtls.SSL_MAX_CA_CERT_CFG_OFFSET);
- print("unknown option " + option);
- if (build_mode >= axtls.SSL_BUILD_ENABLE_CLIENT ){
- print("usage: s_client [args ...]");
- print(" -connect host:port - who to connect to (default is localhost:4433)");
- print(" -verify\t- turn on peer certificate verification");
- print(" -cert arg\t- certificate file to use - default DER format");
- print(" -key arg\t- Private key file to use - default DER format");
- print("\t\t Can repeat up to " + cert_size + " times");
- print(" -CAfile arg\t- Certificate authority - default DER format");
- print("\t\t Can repeat up to " + ca_cert_size + "times");
- print(" -quiet\t\t- No client output");
- print(" -pass\t\t- private key file pass phrase source");
- print(" -reconnect\t- Drop and re-make the connection with the same Session-ID");
- if (build_mode == axtls.SSL_BUILD_FULL_MODE){
- print(" -debug\t\t- Print more output");
- print(" -state\t\t- Show state messages");
- print(" -show-rsa\t- Show RSA state");
- }
- }
- else print("Change configuration to allow this feature");
- os.exit(1);
- }
- // Implement the SSL server logic.
- function do_server(build_mode){
- local i = 1;
- local v;
- local port = 4433;
- local options = axtls.SSL_DISPLAY_CERTS;
- local quiet = false;
- local password = "";
- local private_key_file = null;
- local cert_size = axtls.get_config(axtls.SSL_MAX_CERT_CFG_OFFSET);
- local ca_cert_size = axtls.get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET);
- local cert = [];
- local ca_cert = [];
- while (i < vargv_len) {
- if (vargv[i] == "-accept"){
- if (i >= (vargv_len-1)){
- print_server_options(build_mode, arg[i]);
- }
- ++i;
- port = vargv[i];
- }
- else if (vargv[i] == "-quiet"){
- quiet = true;
- options = options & (~axtls.SSL_DISPLAY_CERTS);
- }
- else if (build_mode >= axtls.SSL_BUILD_SERVER_ONLY){
- if (vargv[i] == "-cert"){
- if (i >= (vargv_len-1) || cert.len() >= cert_size){
- print_server_options(build_mode, vargv[i]);
- }
- ++i;
- cert.push(vargv[i]);
- }
- else if (vargv[i] == "-key"){
- if (i >= (vargv_len-1)){
- print_server_options(build_mode, vargv[i]);
- }
- ++i;
- private_key_file = vargv[i];
- options = options | axtls.SSL_NO_DEFAULT_KEY;
- }
- else if (vargv[i] == "-pass"){
- if (i >= (vargv_len-1)){
- print_server_options(build_mode, vargv[i]);
- }
- ++i;
- password = vargv[i];
- }
- else if (build_mode >= axtls.SSL_BUILD_ENABLE_VERIFICATION){
- if (vargv[i] == "-verify"){
- options = options | axtls.SSL_CLIENT_AUTHENTICATION;
- }
- else if (vargv[i] == "-CAfile"){
- if (i >= (vargv_len-1) || ca_cert.len() >= ca_cert_size){
- print_server_options(build_mode, vargv[i]);
- }
- ++i;
- ca_cert.push(vargv[i]);
- }
- else if (build_mode == axtls.SSL_BUILD_FULL_MODE){
- if (vargv[i] == "-debug"){
- options = options | axtls.SSL_DISPLAY_BYTES;
- }
- else if (vargv[i] == "-state") options = options | axtls.SSL_DISPLAY_STATES;
- else if (vargv[i] == "-show-rsa") options = options | axtls.SSL_DISPLAY_RSA;
- else print_server_options(build_mode, vargv[i]);
- }
- else print_server_options(build_mode, vargv[i]);
- }
- else print_server_options(build_mode, vargv[i]);
- }
- else print_server_options(build_mode, vargv[i]);
- ++i;
- }
- // Create socket for incoming connections
- local server_sock = socket.tcp();
- //server_sock.bind("*", port);
- server_sock.setoption("reuseaddr", true);
- server_sock.bind("*", port);
- server_sock.listen();
- //////////////////////////////////////////////////////////////////////////-
- // This is where the interesting stuff happens. Up until now we've
- // just been setting up sockets etc. Now we do the SSL handshake.
- //////////////////////////////////////////////////////////////////////////-
- local ssl_ctx = axtls.ssl_ctx(options, axtls.SSL_DEFAULT_SVR_SESS);
- if (ssl_ctx == null) throw("Error: Server context is invalid");
- if (private_key_file != null){
- local obj_type = axtls.SSL_OBJ_RSA_KEY;
- if (private_key_file.find(".p8") >= 0 ) obj_type = axtls.SSL_OBJ_PKCS8;
- else if (private_key_file.find(".p12") >= 0) obj_type = axtls.SSL_OBJ_PKCS12;
- if (ssl_ctx.ssl_obj_load(obj_type, private_key_file,
- password) != axtls.SSL_OK)
- throw("Private key '" + private_key_file + "' is undefined.");
- }
- foreach(v in cert) {
- if (ssl_ctx.ssl_obj_load(axtls.SSL_OBJ_X509_CERT, v, "") !=
- axtls.SSL_OK)
- throw("Certificate '" + v + "' is undefined.");
- }
- foreach(v in ca_cert){
- if (ssl_ctx.ssl_obj_load(axtls.SSL_OBJ_X509_CACERT, v, "") !=
- axtls.SSL_OK)
- throwr("Certificate '" + v + "' is undefined.");
- }
- while (true){
- if (!quiet) print("ACCEPT");
- local client_sock = server_sock.accept();
- local ssl = ssl_ctx.server_new(client_sock.getfd());
- // do the actual SSL handshake
- local connected = false;
- local res;
- while (true){
- socket.select([client_sock], []);
- res = ssl.read();
- if(type(res) == "string"){
- foreach(v in res) print1(v);
- }
- else
- {
- if (res == axtls.SSL_OK){ // connection established and ok
- if (ssl.handshake_status() == axtls.SSL_OK){
- if (!quiet && !connected){
- display_session_id(ssl);
- display_cipher(ssl);
- }
- connected = true;
- }
- }
- else if (res < axtls.SSL_OK){
- if (!quiet) axtls.display_error(res);
- break;
- }
- }
- }
- // client was disconnected or the handshake failed.
- print("CONNECTION CLOSED");
- ssl.free();
- client_sock.close();
- }
- ssl_ctx.free();
- }
- //
- // Implement the SSL client logic.
- //
- function do_client(build_mode){
- local i = 1;
- local v;
- local port = 4433;
- local options = axtls.SSL_SERVER_VERIFY_LATER | axtls.SSL_DISPLAY_CERTS;
- local private_key_file = null;
- local reconnect = 0;
- local quiet = false;
- local password = "";
- local session_id = [];
- local host = "127.0.0.1";
- local cert_size = axtls.get_config(axtls.SSL_MAX_CERT_CFG_OFFSET);
- local ca_cert_size = axtls.get_config(axtls.SSL_MAX_CA_CERT_CFG_OFFSET);
- local cert = [];
- local ca_cert = [];
- while (i < vargv_len){
- if (vargv[i] == "-connect"){
- if (i >= (vargv_len-1)) print_client_options(build_mode, vargv[i]);
- ++i;
- local str = vargv[i];
- local t = str.find(":");
- host = str.substr(0, t);
- port = str.substr(t+1);
- }
- else if (vargv[i] == "-cert"){
- if (i >= (vargv_len-1) || cert.len() >= cert_size) print_client_options(build_mode, vargv[i]) ;
- ++i;
- cert.push(vargv[i]);
- }
- else if (vargv[i] == "-key"){
- if (i >= (vargv_len-1)) print_client_options(build_mode, vargv[i]);
- ++i;
- private_key_file = vargv[i];
- options = options | axtls.SSL_NO_DEFAULT_KEY;
- }
- else if (vargv[i] == "-CAfile"){
- if (i >= vargv_len || ca_cert.len() >= ca_cert_size) print_client_options(build_mode, vargv[i]) ;
- ++i;
- ca_cert.push(vargv[i]);
- }
- else if (vargv[i] == "-verify") options = options & (~axtls.SSL_SERVER_VERIFY_LATER);
- else if (vargv[i] == "-reconnect") reconnect = 4;
- else if (vargv[i] == "-quiet") {
- quiet = true;
- options = options & (~axtls.SSL_DISPLAY_CERTS);
- }
- else if (vargv[i] == "-pass") {
- if (i >= (vargv_len-1)) print_server_options(build_mode, vargv[i]);
- ++i;
- password = vargv[i];
- }
- else if (build_mode == axtls.SSL_BUILD_FULL_MODE){
- if (vargv[i] == "-debug") options = options | axtls.SSL_DISPLAY_BYTES;
- else if (vargv[i] == "-state") options = options | axtls.SSL_DISPLAY_STATES;
- else if (vargv[i] == "-show-rsa") options = options | axtls.SSL_DISPLAY_RSA;
- else // don't know what this is
- print_client_options(build_mode, vargv[i]);
- }
- else // don't know what this is
- print_client_options(build_mode, vargv[i]);
- ++i;
- }
- local client_sock = socket.tcp();
- client_sock.connect(host, port);
- local ssl;
- local res;
- if (!quiet) print("CONNECTED");
- //////////////////////////////////////////////////////////////////////////-
- // This is where the interesting stuff happens. Up until now we've
- // just been setting up sockets etc. Now we do the SSL handshake.
- //////////////////////////////////////////////////////////////////////////-
- local ssl_ctx = axtls.ssl_ctx(options, axtls.SSL_DEFAULT_CLNT_SESS);
- if (ssl_ctx == null) throw("Error: Client context is invalid");
- if (private_key_file != null){
- local obj_type = axtls.SSL_OBJ_RSA_KEY;
- if (private_key_file.endswith(".p8")) obj_type = axtls.SSL_OBJ_PKCS8;
- else if (private_key_file.endswith(".p12")) obj_type = axtls.SSL_OBJ_PKCS12 ;
- if (ssl_ctx.obj_load(obj_type, private_key_file,
- password) != axtls.SSL_OK)
- throw("Private key '" + private_key_file + "' is undefined.");
- }
- foreach(v in cert) {
- if (ssl_ctx.obj_load(axtls.SSL_OBJ_X509_CERT, v, "") !=
- axtls.SSL_OK)
- throw("Certificate '" + v + "' is undefined.");
- }
- foreach(v in ca_cert) {
- if (ssl_ctx.obj_load(axtls.SSL_OBJ_X509_CACERT, v, "") !=
- axtls.SSL_OK)
- throwr("Certificate '" + v + "' is undefined.");
- }
- // Try session resumption?
- if (reconnect != 0){
- session_id = null;
- local sess_id_size = 0;
- while (reconnect > 0){
- reconnect = reconnect - 1;
- ssl = ssl_ctx.client_new(client_sock.getfd(), session_id, sess_id_size);
- res = ssl.handshake_status();
- if (res != axtls.SSL_OK){
- if (!quiet) axtls.display_error(res);
- ssl.free();
- os.exit(1);
- }
- display_session_id(ssl);
- session_id = ssl.get_session_id();
- sess_id_size = ssl.get_session_id_size();
- if (reconnect > 0) {
- ssl.free();
- client_sock.close();
- client_sock = socket.tcp();
- client_sock.connect(host, port);
- }
- }
- }
- else
- {
- ssl = ssl_ctx.client_new(client_sock.getfd());
- }
- // check the return status
- res = ssl.handshake_status();
- if (res != axtls.SSL_OK){
- if (!quiet) axtls.display_error(res);
- os.exit(1);
- }
- if (!quiet){
- local common_name = ssl.get_cert_dn(axtls.SSL_X509_CERT_COMMON_NAME);
- if (common_name != null) print("Common Name:\t\t\t" + common_name);
- display_session_id(ssl);
- display_cipher(ssl);
- }
- res = ssl.write("Hello World !");
- res = ssl.write("Again we are here !");
- res = ssl.write("Comming back !");
- res = ssl.write("Bye !");
- while (true){
- local line = stdin.read_line();
- if (line == null) break;
-
- line += "\r\x00";
- res = ssl.write(line, line.len());
- if (res < axtls.SSL_OK){
- if (!quiet) axtls.display_error(res);
- break;
- }
- }
-
- ssl_ctx.free();
- client_sock.close();
- }
- //
- // Display what cipher we are using
- //
- function display_cipher(ssl){
- print1("CIPHER is ");
- local cipher_id = ssl.get_cipher_id();
- switch(cipher_id){
- case axtls.SSL_AES128_SHA: print("AES128-SHA"); break;
- case axtls.SSL_AES256_SHA: print("AES256-SHA"); break;
- case axtls.SSL_RC4_128_SHA: print("RC4-SHA"); break;
- case axtls.SSL_RC4_128_MD5: print("RC4-MD5"); break;
- default:
- print("Unknown - " + cipher_id);
- }
- }
- //
- // Display what session id we have.
- //
- function display_session_id(ssl){
- local session_id = ssl.get_session_id();
- local v;
- if (session_id.len() > 0){
- print("////-BEGIN SSL SESSION PARAMETERS////-");
- foreach(v in session_id) print1(format("%02x", v));
- print("\n////-END SSL SESSION PARAMETERS////-");
- }
- }
- //
- // Main entry point. Doesn't do much except works out whether we are a client
- // or a server.
- //
- if (vargv_len == 0 || (vargv[0] != "s_server" && vargv[0] != "s_client")){
- print_options(vargv_len > 0 && vargv[0] || "");
- }
- local build_mode = axtls.get_config(axtls.SSL_BUILD_MODE);
- local xx = vargv[0] == "s_server" && do_server(build_mode) || do_client(build_mode);
- os.exit(0);
|