axssl.lua 19 KB

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