|
1 /*-------------------------------------------------------------------------- |
|
2 * LuaSec 0.4 |
|
3 * Copyright (C) 2006-2009 Bruno Silvestre |
|
4 * |
|
5 *--------------------------------------------------------------------------*/ |
|
6 |
|
7 #include <string.h> |
|
8 #include <openssl/ssl.h> |
|
9 #include <openssl/err.h> |
|
10 |
|
11 #include <lua.h> |
|
12 #include <lauxlib.h> |
|
13 |
|
14 #include "context.h" |
|
15 |
|
16 struct ssl_option_s { |
|
17 const char *name; |
|
18 unsigned long code; |
|
19 }; |
|
20 typedef struct ssl_option_s ssl_option_t; |
|
21 |
|
22 |
|
23 static ssl_option_t ssl_options[] = { |
|
24 /* OpenSSL 0.9.7 and 0.9.8 */ |
|
25 {"all", SSL_OP_ALL}, |
|
26 {"cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE}, |
|
27 {"dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS}, |
|
28 {"ephemeral_rsa", SSL_OP_EPHEMERAL_RSA}, |
|
29 {"netscape_ca_dn_bug", SSL_OP_NETSCAPE_CA_DN_BUG}, |
|
30 {"netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG}, |
|
31 {"microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER}, |
|
32 {"microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG}, |
|
33 {"msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING}, |
|
34 {"netscape_demo_cipher_change_bug", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG}, |
|
35 {"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG}, |
|
36 {"no_session_resumption_on_renegotiation", |
|
37 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION}, |
|
38 {"no_sslv2", SSL_OP_NO_SSLv2}, |
|
39 {"no_sslv3", SSL_OP_NO_SSLv3}, |
|
40 {"no_tlsv1", SSL_OP_NO_TLSv1}, |
|
41 {"pkcs1_check_1", SSL_OP_PKCS1_CHECK_1}, |
|
42 {"pkcs1_check_2", SSL_OP_PKCS1_CHECK_2}, |
|
43 {"single_dh_use", SSL_OP_SINGLE_DH_USE}, |
|
44 {"ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG}, |
|
45 {"sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG}, |
|
46 {"tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG}, |
|
47 {"tls_d5_bug", SSL_OP_TLS_D5_BUG}, |
|
48 {"tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG}, |
|
49 /* OpenSSL 0.9.8 only */ |
|
50 #if OPENSSL_VERSION_NUMBER > 0x00908000L |
|
51 {"cookie_exchange", SSL_OP_COOKIE_EXCHANGE}, |
|
52 {"no_query_mtu", SSL_OP_NO_QUERY_MTU}, |
|
53 {"single_ecdh_use", SSL_OP_SINGLE_ECDH_USE}, |
|
54 #endif |
|
55 /* OpenSSL 0.9.8f and above */ |
|
56 #if defined(SSL_OP_NO_TICKET) |
|
57 {"no_ticket", SSL_OP_NO_TICKET}, |
|
58 #endif |
|
59 {NULL, 0L} |
|
60 }; |
|
61 |
|
62 /*--------------------------- Auxiliary Functions ----------------------------*/ |
|
63 |
|
64 /** |
|
65 * Return the context. |
|
66 */ |
|
67 static p_context checkctx(lua_State *L, int idx) |
|
68 { |
|
69 return (p_context)luaL_checkudata(L, idx, "SSL:Context"); |
|
70 } |
|
71 |
|
72 /** |
|
73 * Prepare the SSL options flag. |
|
74 */ |
|
75 static int set_option_flag(const char *opt, unsigned long *flag) |
|
76 { |
|
77 ssl_option_t *p; |
|
78 for (p = ssl_options; p->name; p++) { |
|
79 if (!strcmp(opt, p->name)) { |
|
80 *flag |= p->code; |
|
81 return 1; |
|
82 } |
|
83 } |
|
84 return 0; |
|
85 } |
|
86 |
|
87 /** |
|
88 * Find the protocol. |
|
89 */ |
|
90 static SSL_METHOD* str2method(const char *method) |
|
91 { |
|
92 if (!strcmp(method, "sslv3")) return SSLv3_method(); |
|
93 if (!strcmp(method, "tlsv1")) return TLSv1_method(); |
|
94 if (!strcmp(method, "sslv23")) return SSLv23_method(); |
|
95 return NULL; |
|
96 } |
|
97 |
|
98 /** |
|
99 * Prepare the SSL handshake verify flag. |
|
100 */ |
|
101 static int set_verify_flag(const char *str, int *flag) |
|
102 { |
|
103 if (!strcmp(str, "none")) { |
|
104 *flag |= SSL_VERIFY_NONE; |
|
105 return 1; |
|
106 } |
|
107 if (!strcmp(str, "peer")) { |
|
108 *flag |= SSL_VERIFY_PEER; |
|
109 return 1; |
|
110 } |
|
111 if (!strcmp(str, "client_once")) { |
|
112 *flag |= SSL_VERIFY_CLIENT_ONCE; |
|
113 return 1; |
|
114 } |
|
115 if (!strcmp(str, "fail_if_no_peer_cert")) { |
|
116 *flag |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
|
117 return 1; |
|
118 } |
|
119 return 0; |
|
120 } |
|
121 |
|
122 /** |
|
123 * Password callback for reading the private key. |
|
124 */ |
|
125 static int passwd_cb(char *buf, int size, int flag, void *udata) |
|
126 { |
|
127 lua_State *L = (lua_State*)udata; |
|
128 switch (lua_type(L, 3)) { |
|
129 case LUA_TFUNCTION: |
|
130 lua_pushvalue(L, 3); |
|
131 lua_call(L, 0, 1); |
|
132 if (lua_type(L, -1) != LUA_TSTRING) |
|
133 return 0; |
|
134 /* fallback */ |
|
135 case LUA_TSTRING: |
|
136 strncpy(buf, lua_tostring(L, -1), size); |
|
137 buf[size-1] = '\0'; |
|
138 return (int)strlen(buf); |
|
139 } |
|
140 return 0; |
|
141 } |
|
142 |
|
143 /*------------------------------ Lua Functions -------------------------------*/ |
|
144 |
|
145 /** |
|
146 * Create a SSL context. |
|
147 */ |
|
148 static int create(lua_State *L) |
|
149 { |
|
150 p_context ctx; |
|
151 SSL_METHOD *method; |
|
152 |
|
153 method = str2method(luaL_checkstring(L, 1)); |
|
154 if (!method) { |
|
155 lua_pushnil(L); |
|
156 lua_pushstring(L, "invalid protocol"); |
|
157 return 2; |
|
158 } |
|
159 ctx = (p_context) lua_newuserdata(L, sizeof(t_context)); |
|
160 if (!ctx) { |
|
161 lua_pushnil(L); |
|
162 lua_pushstring(L, "error creating context"); |
|
163 return 2; |
|
164 } |
|
165 ctx->context = SSL_CTX_new(method); |
|
166 if (!ctx->context) { |
|
167 lua_pushnil(L); |
|
168 lua_pushstring(L, "error creating context"); |
|
169 return 2; |
|
170 } |
|
171 ctx->mode = MD_CTX_INVALID; |
|
172 /* No session support */ |
|
173 SSL_CTX_set_session_cache_mode(ctx->context, SSL_SESS_CACHE_OFF); |
|
174 luaL_getmetatable(L, "SSL:Context"); |
|
175 lua_setmetatable(L, -2); |
|
176 return 1; |
|
177 } |
|
178 |
|
179 /** |
|
180 * Load the trusting certificates. |
|
181 */ |
|
182 static int load_locations(lua_State *L) |
|
183 { |
|
184 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
185 const char *cafile = luaL_optstring(L, 2, NULL); |
|
186 const char *capath = luaL_optstring(L, 3, NULL); |
|
187 if (SSL_CTX_load_verify_locations(ctx, cafile, capath) != 1) { |
|
188 lua_pushboolean(L, 0); |
|
189 lua_pushfstring(L, "error loading CA locations (%s)", |
|
190 ERR_reason_error_string(ERR_get_error())); |
|
191 return 2; |
|
192 } |
|
193 lua_pushboolean(L, 1); |
|
194 return 1; |
|
195 } |
|
196 |
|
197 /** |
|
198 * Load the certificate file. |
|
199 */ |
|
200 static int load_cert(lua_State *L) |
|
201 { |
|
202 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
203 const char *filename = luaL_checkstring(L, 2); |
|
204 if (SSL_CTX_use_certificate_chain_file(ctx, filename) != 1) { |
|
205 lua_pushboolean(L, 0); |
|
206 lua_pushfstring(L, "error loading certificate (%s)", |
|
207 ERR_reason_error_string(ERR_get_error())); |
|
208 return 2; |
|
209 } |
|
210 lua_pushboolean(L, 1); |
|
211 return 1; |
|
212 } |
|
213 |
|
214 /** |
|
215 * Load the key file -- only in PEM format. |
|
216 */ |
|
217 static int load_key(lua_State *L) |
|
218 { |
|
219 int ret = 1; |
|
220 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
221 const char *filename = luaL_checkstring(L, 2); |
|
222 switch (lua_type(L, 3)) { |
|
223 case LUA_TSTRING: |
|
224 case LUA_TFUNCTION: |
|
225 SSL_CTX_set_default_passwd_cb(ctx, passwd_cb); |
|
226 SSL_CTX_set_default_passwd_cb_userdata(ctx, L); |
|
227 /* fallback */ |
|
228 case LUA_TNIL: |
|
229 if (SSL_CTX_use_PrivateKey_file(ctx, filename, SSL_FILETYPE_PEM) == 1) |
|
230 lua_pushboolean(L, 1); |
|
231 else { |
|
232 ret = 2; |
|
233 lua_pushboolean(L, 0); |
|
234 lua_pushfstring(L, "error loading private key (%s)", |
|
235 ERR_reason_error_string(ERR_get_error())); |
|
236 } |
|
237 SSL_CTX_set_default_passwd_cb(ctx, NULL); |
|
238 SSL_CTX_set_default_passwd_cb_userdata(ctx, NULL); |
|
239 break; |
|
240 default: |
|
241 lua_pushstring(L, "invalid callback value"); |
|
242 lua_error(L); |
|
243 } |
|
244 return ret; |
|
245 } |
|
246 |
|
247 /** |
|
248 * Set the cipher list. |
|
249 */ |
|
250 static int set_cipher(lua_State *L) |
|
251 { |
|
252 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
253 const char *list = luaL_checkstring(L, 2); |
|
254 if (SSL_CTX_set_cipher_list(ctx, list) != 1) { |
|
255 lua_pushboolean(L, 0); |
|
256 lua_pushfstring(L, "error setting cipher list (%s)", |
|
257 ERR_reason_error_string(ERR_get_error())); |
|
258 return 2; |
|
259 } |
|
260 lua_pushboolean(L, 1); |
|
261 return 1; |
|
262 } |
|
263 |
|
264 /** |
|
265 * Set the depth for certificate checking. |
|
266 */ |
|
267 static int set_depth(lua_State *L) |
|
268 { |
|
269 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
270 SSL_CTX_set_verify_depth(ctx, luaL_checkint(L, 2)); |
|
271 lua_pushboolean(L, 1); |
|
272 return 1; |
|
273 } |
|
274 |
|
275 /** |
|
276 * Set the handshake verify options. |
|
277 */ |
|
278 static int set_verify(lua_State *L) |
|
279 { |
|
280 int i; |
|
281 int flag = 0; |
|
282 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
283 int max = lua_gettop(L); |
|
284 /* any flag? */ |
|
285 if (max > 1) { |
|
286 for (i = 2; i <= max; i++) { |
|
287 if (!set_verify_flag(luaL_checkstring(L, i), &flag)) { |
|
288 lua_pushboolean(L, 0); |
|
289 lua_pushstring(L, "invalid verify option"); |
|
290 return 2; |
|
291 } |
|
292 } |
|
293 SSL_CTX_set_verify(ctx, flag, NULL); |
|
294 } |
|
295 lua_pushboolean(L, 1); |
|
296 return 1; |
|
297 } |
|
298 |
|
299 /** |
|
300 * Set the protocol options. |
|
301 */ |
|
302 static int set_options(lua_State *L) |
|
303 { |
|
304 int i; |
|
305 unsigned long flag = 0L; |
|
306 SSL_CTX *ctx = ctx_getcontext(L, 1); |
|
307 int max = lua_gettop(L); |
|
308 /* any option? */ |
|
309 if (max > 1) { |
|
310 for (i = 2; i <= max; i++) { |
|
311 if (!set_option_flag(luaL_checkstring(L, i), &flag)) { |
|
312 lua_pushboolean(L, 0); |
|
313 lua_pushstring(L, "invalid option"); |
|
314 return 2; |
|
315 } |
|
316 } |
|
317 SSL_CTX_set_options(ctx, flag); |
|
318 } |
|
319 lua_pushboolean(L, 1); |
|
320 return 1; |
|
321 } |
|
322 |
|
323 /** |
|
324 * Set the context mode. |
|
325 */ |
|
326 static int set_mode(lua_State *L) |
|
327 { |
|
328 p_context ctx = checkctx(L, 1); |
|
329 const char *str = luaL_checkstring(L, 2); |
|
330 if (!strcmp("server", str)) { |
|
331 ctx->mode = MD_CTX_SERVER; |
|
332 lua_pushboolean(L, 1); |
|
333 return 1; |
|
334 } |
|
335 if(!strcmp("client", str)) { |
|
336 ctx->mode = MD_CTX_CLIENT; |
|
337 lua_pushboolean(L, 1); |
|
338 return 1; |
|
339 } |
|
340 lua_pushboolean(L, 0); |
|
341 lua_pushstring(L, "invalid mode"); |
|
342 return 1; |
|
343 } |
|
344 |
|
345 /** |
|
346 * Return a pointer to SSL_CTX structure. |
|
347 */ |
|
348 static int raw_ctx(lua_State *L) |
|
349 { |
|
350 p_context ctx = checkctx(L, 1); |
|
351 lua_pushlightuserdata(L, (void*)ctx->context); |
|
352 return 1; |
|
353 } |
|
354 |
|
355 /** |
|
356 * Package functions |
|
357 */ |
|
358 static luaL_Reg funcs[] = { |
|
359 {"create", create}, |
|
360 {"locations", load_locations}, |
|
361 {"loadcert", load_cert}, |
|
362 {"loadkey", load_key}, |
|
363 {"setcipher", set_cipher}, |
|
364 {"setdepth", set_depth}, |
|
365 {"setverify", set_verify}, |
|
366 {"setoptions", set_options}, |
|
367 {"setmode", set_mode}, |
|
368 {"rawcontext", raw_ctx}, |
|
369 {NULL, NULL} |
|
370 }; |
|
371 |
|
372 /*-------------------------------- Metamethods -------------------------------*/ |
|
373 |
|
374 /** |
|
375 * Collect SSL context -- GC metamethod. |
|
376 */ |
|
377 static int meth_destroy(lua_State *L) |
|
378 { |
|
379 p_context ctx = checkctx(L, 1); |
|
380 if (ctx->context) { |
|
381 SSL_CTX_free(ctx->context); |
|
382 ctx->context = NULL; |
|
383 } |
|
384 return 0; |
|
385 } |
|
386 |
|
387 /** |
|
388 * Object information -- tostring metamethod. |
|
389 */ |
|
390 static int meth_tostring(lua_State *L) |
|
391 { |
|
392 p_context ctx = checkctx(L, 1); |
|
393 lua_pushfstring(L, "SSL context: %p", ctx); |
|
394 return 1; |
|
395 } |
|
396 |
|
397 /** |
|
398 * Context metamethods. |
|
399 */ |
|
400 static luaL_Reg meta[] = { |
|
401 {"__gc", meth_destroy}, |
|
402 {"__tostring", meth_tostring}, |
|
403 {NULL, NULL} |
|
404 }; |
|
405 |
|
406 |
|
407 /*----------------------------- Public Functions ---------------------------*/ |
|
408 |
|
409 /** |
|
410 * Retrieve the SSL context from the Lua stack. |
|
411 */ |
|
412 SSL_CTX* ctx_getcontext(lua_State *L, int idx) |
|
413 { |
|
414 p_context ctx = checkctx(L, idx); |
|
415 return ctx->context; |
|
416 } |
|
417 |
|
418 /** |
|
419 * Retrieve the mode from the context in the Lua stack. |
|
420 */ |
|
421 char ctx_getmode(lua_State *L, int idx) |
|
422 { |
|
423 p_context ctx = checkctx(L, idx); |
|
424 return ctx->mode; |
|
425 } |
|
426 |
|
427 /*------------------------------ Initialization ------------------------------*/ |
|
428 |
|
429 /** |
|
430 * Registre the module. |
|
431 */ |
|
432 int luaopen_ssl_context(lua_State *L) |
|
433 { |
|
434 luaL_newmetatable(L, "SSL:Context"); |
|
435 luaL_register(L, NULL, meta); |
|
436 luaL_register(L, "ssl.context", funcs); |
|
437 return 1; |
|
438 } |