axssl.nut 17 KB

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