Return to axssl.lua CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / axTLS / samples / lua |
1.1 ! misho 1: #!/usr/local/bin/lua ! 2: ! 3: -- ! 4: -- Copyright (c) 2007, Cameron Rich ! 5: -- ! 6: -- All rights reserved. ! 7: -- ! 8: -- Redistribution and use in source and binary forms, with or without ! 9: -- modification, are permitted provided that the following conditions are met: ! 10: -- ! 11: -- * Redistributions of source code must retain the above copyright notice, ! 12: -- this list of conditions and the following disclaimer. ! 13: -- * Redistributions in binary form must reproduce the above copyright ! 14: -- notice, this list of conditions and the following disclaimer in the ! 15: -- documentation and/or other materials provided with the distribution. ! 16: -- * Neither the name of the axTLS project nor the names of its ! 17: -- contributors may be used to endorse or promote products derived ! 18: -- from this software without specific prior written permission. ! 19: -- ! 20: -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ! 21: -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ! 22: -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ! 23: -- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ! 24: -- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ! 25: -- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ! 26: -- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ! 27: -- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY ! 28: -- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ! 29: -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ! 30: -- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! 31: -- ! 32: ! 33: -- ! 34: -- Demonstrate the use of the axTLS library in Lua with a set of ! 35: -- command-line parameters similar to openssl. In fact, openssl clients ! 36: -- should be able to communicate with axTLS servers and visa-versa. ! 37: -- ! 38: -- This code has various bits enabled depending on the configuration. To enable ! 39: -- the most interesting version, compile with the 'full mode' enabled. ! 40: -- ! 41: -- To see what options you have, run the following: ! 42: -- > [lua] axssl s_server -? ! 43: -- > [lua] axssl s_client -? ! 44: -- ! 45: -- The axtls/axtlsl shared libraries must be in the same directory or be found ! 46: -- by the OS. ! 47: -- ! 48: -- ! 49: require "bit" ! 50: require("axtlsl") ! 51: local socket = require("socket") ! 52: ! 53: -- print version? ! 54: if #arg == 1 and arg[1] == "version" then ! 55: print("axssl.lua "..axtlsl.ssl_version()) ! 56: os.exit(1) ! 57: end ! 58: ! 59: -- ! 60: -- We've had some sort of command-line error. Print out the basic options. ! 61: -- ! 62: function print_options(option) ! 63: print("axssl: Error: '"..option.."' is an invalid command.") ! 64: print("usage: axssl [s_server|s_client|version] [args ...]") ! 65: os.exit(1) ! 66: end ! 67: ! 68: -- ! 69: -- We've had some sort of command-line error. Print out the server options. ! 70: -- ! 71: function print_server_options(build_mode, option) ! 72: local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) ! 73: local ca_cert_size = axtlsl.ssl_get_config( ! 74: axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) ! 75: ! 76: print("unknown option "..option) ! 77: print("usage: s_server [args ...]") ! 78: print(" -accept\t- port to accept on (default is 4433)") ! 79: print(" -quiet\t\t- No server output") ! 80: ! 81: if build_mode >= axtlsl.SSL_BUILD_SERVER_ONLY then ! 82: print(" -cert arg\t- certificate file to add (in addition to ".. ! 83: "default) to chain -") ! 84: print("\t\t Can repeat up to "..cert_size.." times") ! 85: print(" -key arg\t- Private key file to use - default DER format") ! 86: print(" -pass\t\t- private key file pass phrase source") ! 87: end ! 88: ! 89: if build_mode >= axtlsl.SSL_BUILD_ENABLE_VERIFICATION then ! 90: print(" -verify\t- turn on peer certificate verification") ! 91: print(" -CAfile arg\t- Certificate authority - default DER format") ! 92: print("\t\t Can repeat up to "..ca_cert_size.." times") ! 93: end ! 94: ! 95: if build_mode == axtlsl.SSL_BUILD_FULL_MODE then ! 96: print(" -debug\t\t- Print more output") ! 97: print(" -state\t\t- Show state messages") ! 98: print(" -show-rsa\t- Show RSA state") ! 99: end ! 100: ! 101: os.exit(1) ! 102: end ! 103: ! 104: -- ! 105: -- We've had some sort of command-line error. Print out the client options. ! 106: -- ! 107: function print_client_options(build_mode, option) ! 108: local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) ! 109: local ca_cert_size = axtlsl.ssl_get_config( ! 110: axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) ! 111: ! 112: print("unknown option "..option) ! 113: ! 114: if build_mode >= axtlsl.SSL_BUILD_ENABLE_CLIENT then ! 115: print("usage: s_client [args ...]") ! 116: print(" -connect host:port - who to connect to (default ".. ! 117: "is localhost:4433)") ! 118: print(" -verify\t- turn on peer certificate verification") ! 119: print(" -cert arg\t- certificate file to use - default DER format") ! 120: print(" -key arg\t- Private key file to use - default DER format") ! 121: print("\t\t Can repeat up to "..cert_size.." times") ! 122: print(" -CAfile arg\t- Certificate authority - default DER format") ! 123: print("\t\t Can repeat up to "..ca_cert_size.."times") ! 124: print(" -quiet\t\t- No client output") ! 125: print(" -pass\t\t- private key file pass phrase source") ! 126: print(" -reconnect\t- Drop and re-make the connection ".. ! 127: "with the same Session-ID") ! 128: ! 129: if build_mode == axtlsl.SSL_BUILD_FULL_MODE then ! 130: print(" -debug\t\t- Print more output") ! 131: print(" -state\t\t- Show state messages") ! 132: print(" -show-rsa\t- Show RSA state") ! 133: end ! 134: else ! 135: print("Change configuration to allow this feature") ! 136: end ! 137: ! 138: os.exit(1) ! 139: end ! 140: ! 141: -- Implement the SSL server logic. ! 142: function do_server(build_mode) ! 143: local i = 2 ! 144: local v ! 145: local port = 4433 ! 146: local options = axtlsl.SSL_DISPLAY_CERTS ! 147: local quiet = false ! 148: local password = "" ! 149: local private_key_file = nil ! 150: local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) ! 151: local ca_cert_size = axtlsl. ! 152: ssl_get_config(axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) ! 153: local cert = {} ! 154: local ca_cert = {} ! 155: ! 156: while i <= #arg do ! 157: if arg[i] == "-accept" then ! 158: if i >= #arg then ! 159: print_server_options(build_mode, arg[i]) ! 160: end ! 161: ! 162: i = i + 1 ! 163: port = arg[i] ! 164: elseif arg[i] == "-quiet" then ! 165: quiet = true ! 166: options = bit.band(options, bit.bnot(axtlsl.SSL_DISPLAY_CERTS)) ! 167: elseif build_mode >= axtlsl.SSL_BUILD_SERVER_ONLY then ! 168: if arg[i] == "-cert" then ! 169: if i >= #arg or #cert >= cert_size then ! 170: print_server_options(build_mode, arg[i]) ! 171: end ! 172: ! 173: i = i + 1 ! 174: table.insert(cert, arg[i]) ! 175: elseif arg[i] == "-key" then ! 176: if i >= #arg then ! 177: print_server_options(build_mode, arg[i]) ! 178: end ! 179: ! 180: i = i + 1 ! 181: private_key_file = arg[i] ! 182: options = bit.bor(options, axtlsl.SSL_NO_DEFAULT_KEY) ! 183: elseif arg[i] == "-pass" then ! 184: if i >= #arg then ! 185: print_server_options(build_mode, arg[i]) ! 186: end ! 187: ! 188: i = i + 1 ! 189: password = arg[i] ! 190: elseif build_mode >= axtlsl.SSL_BUILD_ENABLE_VERIFICATION then ! 191: if arg[i] == "-verify" then ! 192: options = bit.bor(options, axtlsl.SSL_CLIENT_AUTHENTICATION) ! 193: elseif arg[i] == "-CAfile" then ! 194: if i >= #arg or #ca_cert >= ca_cert_size then ! 195: print_server_options(build_mode, arg[i]) ! 196: end ! 197: ! 198: i = i + 1 ! 199: table.insert(ca_cert, arg[i]) ! 200: elseif build_mode == axtlsl.SSL_BUILD_FULL_MODE then ! 201: if arg[i] == "-debug" then ! 202: options = bit.bor(options, axtlsl.SSL_DISPLAY_BYTES) ! 203: elseif arg[i] == "-state" then ! 204: options = bit.bor(options, axtlsl.SSL_DISPLAY_STATES) ! 205: elseif arg[i] == "-show-rsa" then ! 206: options = bit.bor(options, axtlsl.SSL_DISPLAY_RSA) ! 207: else ! 208: print_server_options(build_mode, arg[i]) ! 209: end ! 210: else ! 211: print_server_options(build_mode, arg[i]) ! 212: end ! 213: else ! 214: print_server_options(build_mode, arg[i]) ! 215: end ! 216: else ! 217: print_server_options(build_mode, arg[i]) ! 218: end ! 219: ! 220: i = i + 1 ! 221: end ! 222: ! 223: -- Create socket for incoming connections ! 224: local server_sock = socket.try(socket.bind("*", port)) ! 225: ! 226: --------------------------------------------------------------------------- ! 227: -- This is where the interesting stuff happens. Up until now we've ! 228: -- just been setting up sockets etc. Now we do the SSL handshake. ! 229: --------------------------------------------------------------------------- ! 230: local ssl_ctx = axtlsl.ssl_ctx_new(options, axtlsl.SSL_DEFAULT_SVR_SESS) ! 231: if ssl_ctx == nil then error("Error: Server context is invalid") end ! 232: ! 233: if private_key_file ~= nil then ! 234: local obj_type = axtlsl.SSL_OBJ_RSA_KEY ! 235: ! 236: if string.find(private_key_file, ".p8") then ! 237: obj_type = axtlsl.SSL_OBJ_PKCS8 ! 238: end ! 239: ! 240: if string.find(private_key_file, ".p12") then ! 241: obj_type = axtlsl.SSL_OBJ_PKCS12 ! 242: end ! 243: ! 244: if axtlsl.ssl_obj_load(ssl_ctx, obj_type, private_key_file, ! 245: password) ~= axtlsl.SSL_OK then ! 246: error("Private key '" .. private_key_file .. "' is undefined.") ! 247: end ! 248: end ! 249: ! 250: for _, v in ipairs(cert) do ! 251: if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CERT, v, "") ~= ! 252: axtlsl.SSL_OK then ! 253: error("Certificate '"..v .. "' is undefined.") ! 254: end ! 255: end ! 256: ! 257: for _, v in ipairs(ca_cert) do ! 258: if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CACERT, v, "") ~= ! 259: axtlsl.SSL_OK then ! 260: error("Certificate '"..v .."' is undefined.") ! 261: end ! 262: end ! 263: ! 264: while true do ! 265: if not quiet then print("ACCEPT") end ! 266: local client_sock = server_sock:accept(); ! 267: local ssl = axtlsl.ssl_server_new(ssl_ctx, client_sock:getfd()) ! 268: ! 269: -- do the actual SSL handshake ! 270: local connected = false ! 271: local res ! 272: local buf ! 273: ! 274: while true do ! 275: socket.select({client_sock}, nil) ! 276: res, buf = axtlsl.ssl_read(ssl) ! 277: ! 278: if res == axtlsl.SSL_OK then -- connection established and ok ! 279: if axtlsl.ssl_handshake_status(ssl) == axtlsl.SSL_OK then ! 280: if not quiet and not connected then ! 281: display_session_id(ssl) ! 282: display_cipher(ssl) ! 283: end ! 284: connected = true ! 285: end ! 286: end ! 287: ! 288: if res > axtlsl.SSL_OK then ! 289: for _, v in ipairs(buf) do ! 290: io.write(string.format("%c", v)) ! 291: end ! 292: elseif res < axtlsl.SSL_OK then ! 293: if not quiet then ! 294: axtlsl.ssl_display_error(res) ! 295: end ! 296: break ! 297: end ! 298: end ! 299: ! 300: -- client was disconnected or the handshake failed. ! 301: print("CONNECTION CLOSED") ! 302: axtlsl.ssl_free(ssl) ! 303: client_sock:close() ! 304: end ! 305: ! 306: axtlsl.ssl_ctx_free(ssl_ctx) ! 307: end ! 308: ! 309: -- ! 310: -- Implement the SSL client logic. ! 311: -- ! 312: function do_client(build_mode) ! 313: local i = 2 ! 314: local v ! 315: local port = 4433 ! 316: local options = ! 317: bit.bor(axtlsl.SSL_SERVER_VERIFY_LATER, axtlsl.SSL_DISPLAY_CERTS) ! 318: local private_key_file = nil ! 319: local reconnect = 0 ! 320: local quiet = false ! 321: local password = "" ! 322: local session_id = {} ! 323: local host = "127.0.0.1" ! 324: local cert_size = axtlsl.ssl_get_config(axtlsl.SSL_MAX_CERT_CFG_OFFSET) ! 325: local ca_cert_size = axtlsl. ! 326: ssl_get_config(axtlsl.SSL_MAX_CA_CERT_CFG_OFFSET) ! 327: local cert = {} ! 328: local ca_cert = {} ! 329: ! 330: while i <= #arg do ! 331: if arg[i] == "-connect" then ! 332: if i >= #arg then ! 333: print_client_options(build_mode, arg[i]) ! 334: end ! 335: ! 336: i = i + 1 ! 337: local t = string.find(arg[i], ":") ! 338: host = string.sub(arg[i], 1, t-1) ! 339: port = string.sub(arg[i], t+1) ! 340: elseif arg[i] == "-cert" then ! 341: if i >= #arg or #cert >= cert_size then ! 342: print_client_options(build_mode, arg[i]) ! 343: end ! 344: ! 345: i = i + 1 ! 346: table.insert(cert, arg[i]) ! 347: elseif arg[i] == "-key" then ! 348: if i >= #arg then ! 349: print_client_options(build_mode, arg[i]) ! 350: end ! 351: ! 352: i = i + 1 ! 353: private_key_file = arg[i] ! 354: options = bit.bor(options, axtlsl.SSL_NO_DEFAULT_KEY) ! 355: elseif arg[i] == "-CAfile" then ! 356: if i >= #arg or #ca_cert >= ca_cert_size then ! 357: print_client_options(build_mode, arg[i]) ! 358: end ! 359: ! 360: i = i + 1 ! 361: table.insert(ca_cert, arg[i]) ! 362: elseif arg[i] == "-verify" then ! 363: options = bit.band(options, ! 364: bit.bnot(axtlsl.SSL_SERVER_VERIFY_LATER)) ! 365: elseif arg[i] == "-reconnect" then ! 366: reconnect = 4 ! 367: elseif arg[i] == "-quiet" then ! 368: quiet = true ! 369: options = bit.band(options, bnot(axtlsl.SSL_DISPLAY_CERTS)) ! 370: elseif arg[i] == "-pass" then ! 371: if i >= #arg then ! 372: print_server_options(build_mode, arg[i]) ! 373: end ! 374: ! 375: i = i + 1 ! 376: password = arg[i] ! 377: elseif build_mode == axtlsl.SSL_BUILD_FULL_MODE then ! 378: if arg[i] == "-debug" then ! 379: options = bit.bor(options, axtlsl.SSL_DISPLAY_BYTES) ! 380: elseif arg[i] == "-state" then ! 381: options = bit.bor(axtlsl.SSL_DISPLAY_STATES) ! 382: elseif arg[i] == "-show-rsa" then ! 383: options = bit.bor(axtlsl.SSL_DISPLAY_RSA) ! 384: else -- don't know what this is ! 385: print_client_options(build_mode, arg[i]) ! 386: end ! 387: else -- don't know what this is ! 388: print_client_options(build_mode, arg[i]) ! 389: end ! 390: ! 391: i = i + 1 ! 392: end ! 393: ! 394: local client_sock = socket.try(socket.connect(host, port)) ! 395: local ssl ! 396: local res ! 397: ! 398: if not quiet then print("CONNECTED") end ! 399: ! 400: --------------------------------------------------------------------------- ! 401: -- This is where the interesting stuff happens. Up until now we've ! 402: -- just been setting up sockets etc. Now we do the SSL handshake. ! 403: --------------------------------------------------------------------------- ! 404: local ssl_ctx = axtlsl.ssl_ctx_new(options, axtlsl.SSL_DEFAULT_CLNT_SESS) ! 405: ! 406: if ssl_ctx == nil then ! 407: error("Error: Client context is invalid") ! 408: end ! 409: ! 410: if private_key_file ~= nil then ! 411: local obj_type = axtlsl.SSL_OBJ_RSA_KEY ! 412: ! 413: if string.find(private_key_file, ".p8") then ! 414: obj_type = axtlsl.SSL_OBJ_PKCS8 ! 415: end ! 416: ! 417: if string.find(private_key_file, ".p12") then ! 418: obj_type = axtlsl.SSL_OBJ_PKCS12 ! 419: end ! 420: ! 421: if axtlsl.ssl_obj_load(ssl_ctx, obj_type, private_key_file, ! 422: password) ~= axtlsl.SSL_OK then ! 423: error("Private key '"..private_key_file.."' is undefined.") ! 424: end ! 425: end ! 426: ! 427: for _, v in ipairs(cert) do ! 428: if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CERT, v, "") ~= ! 429: axtlsl.SSL_OK then ! 430: error("Certificate '"..v .. "' is undefined.") ! 431: end ! 432: end ! 433: ! 434: for _, v in ipairs(ca_cert) do ! 435: if axtlsl.ssl_obj_load(ssl_ctx, axtlsl.SSL_OBJ_X509_CACERT, v, "") ~= ! 436: axtlsl.SSL_OK then ! 437: error("Certificate '"..v .."' is undefined.") ! 438: end ! 439: end ! 440: ! 441: -- Try session resumption? ! 442: if reconnect ~= 0 then ! 443: local session_id = nil ! 444: local sess_id_size = 0 ! 445: ! 446: while reconnect > 0 do ! 447: reconnect = reconnect - 1 ! 448: ssl = axtlsl.ssl_client_new(ssl_ctx, ! 449: client_sock:getfd(), session_id, sess_id_size) ! 450: ! 451: res = axtlsl.ssl_handshake_status(ssl) ! 452: if res ~= axtlsl.SSL_OK then ! 453: if not quiet then axtlsl.ssl_display_error(res) end ! 454: axtlsl.ssl_free(ssl) ! 455: os.exit(1) ! 456: end ! 457: ! 458: display_session_id(ssl) ! 459: session_id = axtlsl.ssl_get_session_id(ssl) ! 460: sess_id_size = axtlsl.ssl_get_session_id_size(ssl) ! 461: ! 462: if reconnect > 0 then ! 463: axtlsl.ssl_free(ssl) ! 464: client_sock:close() ! 465: client_sock = socket.try(socket.connect(host, port)) ! 466: end ! 467: ! 468: end ! 469: else ! 470: ssl = axtlsl.ssl_client_new(ssl_ctx, client_sock:getfd(), nil, 0) ! 471: end ! 472: ! 473: -- check the return status ! 474: res = axtlsl.ssl_handshake_status(ssl) ! 475: if res ~= axtlsl.SSL_OK then ! 476: if not quiet then axtlsl.ssl_display_error(res) end ! 477: os.exit(1) ! 478: end ! 479: ! 480: if not quiet then ! 481: local common_name = axtlsl.ssl_get_cert_dn(ssl, ! 482: axtlsl.SSL_X509_CERT_COMMON_NAME) ! 483: ! 484: if common_name ~= nil then ! 485: print("Common Name:\t\t\t"..common_name) ! 486: end ! 487: ! 488: display_session_id(ssl) ! 489: display_cipher(ssl) ! 490: end ! 491: ! 492: while true do ! 493: local line = io.read() ! 494: if line == nil then break end ! 495: local bytes = {} ! 496: ! 497: for i = 1, #line do ! 498: bytes[i] = line.byte(line, i) ! 499: end ! 500: ! 501: bytes[#line+1] = 10 -- add carriage return, null ! 502: bytes[#line+2] = 0 ! 503: ! 504: res = axtlsl.ssl_write(ssl, bytes, #bytes) ! 505: if res < axtlsl.SSL_OK then ! 506: if not quiet then axtlsl.ssl_display_error(res) end ! 507: break ! 508: end ! 509: end ! 510: ! 511: axtlsl.ssl_ctx_free(ssl_ctx) ! 512: client_sock:close() ! 513: end ! 514: ! 515: -- ! 516: -- Display what cipher we are using ! 517: -- ! 518: function display_cipher(ssl) ! 519: io.write("CIPHER is ") ! 520: local cipher_id = axtlsl.ssl_get_cipher_id(ssl) ! 521: ! 522: if cipher_id == axtlsl.SSL_AES128_SHA then ! 523: print("AES128-SHA") ! 524: elseif cipher_id == axtlsl.SSL_AES256_SHA then ! 525: print("AES256-SHA") ! 526: elseif axtlsl.SSL_RC4_128_SHA then ! 527: print("RC4-SHA") ! 528: elseif axtlsl.SSL_RC4_128_MD5 then ! 529: print("RC4-MD5") ! 530: else ! 531: print("Unknown - "..cipher_id) ! 532: end ! 533: end ! 534: ! 535: -- ! 536: -- Display what session id we have. ! 537: -- ! 538: function display_session_id(ssl) ! 539: local session_id = axtlsl.ssl_get_session_id(ssl) ! 540: local v ! 541: ! 542: if #session_id > 0 then ! 543: print("-----BEGIN SSL SESSION PARAMETERS-----") ! 544: for _, v in ipairs(session_id) do ! 545: io.write(string.format("%02x", v)) ! 546: end ! 547: print("\n-----END SSL SESSION PARAMETERS-----") ! 548: end ! 549: end ! 550: ! 551: -- ! 552: -- Main entry point. Doesn't do much except works out whether we are a client ! 553: -- or a server. ! 554: -- ! 555: if #arg == 0 or (arg[1] ~= "s_server" and arg[1] ~= "s_client") then ! 556: print_options(#arg > 0 and arg[1] or "") ! 557: end ! 558: ! 559: local build_mode = axtlsl.ssl_get_config(axtlsl.SSL_BUILD_MODE) ! 560: _ = arg[1] == "s_server" and do_server(build_mode) or do_client(build_mode) ! 561: os.exit(0) ! 562: