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