Annotation of embedaddon/axTLS/samples/lua/axssl.lua, revision 1.1.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>