diff options
Diffstat (limited to 'vendor/luasec/src/context.c')
-rw-r--r-- | vendor/luasec/src/context.c | 1099 |
1 files changed, 1099 insertions, 0 deletions
diff --git a/vendor/luasec/src/context.c b/vendor/luasec/src/context.c new file mode 100644 index 00000000..881ebb90 --- /dev/null +++ b/vendor/luasec/src/context.c | |||
@@ -0,0 +1,1099 @@ | |||
1 | /*-------------------------------------------------------------------------- | ||
2 | * LuaSec 1.3.2 | ||
3 | * | ||
4 | * Copyright (C) 2014-2023 Kim Alvefur, Paul Aurich, Tobias Markmann, Matthew Wild | ||
5 | * Copyright (C) 2006-2023 Bruno Silvestre | ||
6 | * | ||
7 | *--------------------------------------------------------------------------*/ | ||
8 | |||
9 | #include <string.h> | ||
10 | |||
11 | #if defined(WIN32) | ||
12 | #include <windows.h> | ||
13 | #endif | ||
14 | |||
15 | #include <openssl/ssl.h> | ||
16 | #include <openssl/err.h> | ||
17 | #include <openssl/x509.h> | ||
18 | #include <openssl/x509v3.h> | ||
19 | #include <openssl/x509_vfy.h> | ||
20 | #include <openssl/dh.h> | ||
21 | |||
22 | #include <lua.h> | ||
23 | #include <lauxlib.h> | ||
24 | |||
25 | #include "compat.h" | ||
26 | #include "context.h" | ||
27 | #include "options.h" | ||
28 | |||
29 | #ifndef OPENSSL_NO_EC | ||
30 | #include <openssl/ec.h> | ||
31 | #include "ec.h" | ||
32 | #endif | ||
33 | |||
34 | /*--------------------------- Auxiliary Functions ----------------------------*/ | ||
35 | |||
36 | /** | ||
37 | * Return the context. | ||
38 | */ | ||
39 | static p_context checkctx(lua_State *L, int idx) | ||
40 | { | ||
41 | return (p_context)luaL_checkudata(L, idx, "SSL:Context"); | ||
42 | } | ||
43 | |||
44 | static p_context testctx(lua_State *L, int idx) | ||
45 | { | ||
46 | return (p_context)luaL_testudata(L, idx, "SSL:Context"); | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * Prepare the SSL options flag. | ||
51 | */ | ||
52 | static int set_option_flag(const char *opt, unsigned long *flag) | ||
53 | { | ||
54 | lsec_ssl_option_t *p; | ||
55 | for (p = lsec_get_ssl_options(); p->name; p++) { | ||
56 | if (!strcmp(opt, p->name)) { | ||
57 | *flag |= p->code; | ||
58 | return 1; | ||
59 | } | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | #ifndef LSEC_API_OPENSSL_1_1_0 | ||
65 | /** | ||
66 | * Find the protocol. | ||
67 | */ | ||
68 | static const SSL_METHOD* str2method(const char *method, int *vmin, int *vmax) | ||
69 | { | ||
70 | (void)vmin; | ||
71 | (void)vmax; | ||
72 | if (!strcmp(method, "any")) return SSLv23_method(); | ||
73 | if (!strcmp(method, "sslv23")) return SSLv23_method(); // deprecated | ||
74 | if (!strcmp(method, "tlsv1")) return TLSv1_method(); | ||
75 | if (!strcmp(method, "tlsv1_1")) return TLSv1_1_method(); | ||
76 | if (!strcmp(method, "tlsv1_2")) return TLSv1_2_method(); | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | #else | ||
81 | |||
82 | /** | ||
83 | * Find the protocol. | ||
84 | */ | ||
85 | static const SSL_METHOD* str2method(const char *method, int *vmin, int *vmax) | ||
86 | { | ||
87 | if (!strcmp(method, "any") || !strcmp(method, "sslv23")) { // 'sslv23' is deprecated | ||
88 | *vmin = 0; | ||
89 | *vmax = 0; | ||
90 | return TLS_method(); | ||
91 | } | ||
92 | else if (!strcmp(method, "tlsv1")) { | ||
93 | *vmin = TLS1_VERSION; | ||
94 | *vmax = TLS1_VERSION; | ||
95 | return TLS_method(); | ||
96 | } | ||
97 | else if (!strcmp(method, "tlsv1_1")) { | ||
98 | *vmin = TLS1_1_VERSION; | ||
99 | *vmax = TLS1_1_VERSION; | ||
100 | return TLS_method(); | ||
101 | } | ||
102 | else if (!strcmp(method, "tlsv1_2")) { | ||
103 | *vmin = TLS1_2_VERSION; | ||
104 | *vmax = TLS1_2_VERSION; | ||
105 | return TLS_method(); | ||
106 | } | ||
107 | #if defined(TLS1_3_VERSION) | ||
108 | else if (!strcmp(method, "tlsv1_3")) { | ||
109 | *vmin = TLS1_3_VERSION; | ||
110 | *vmax = TLS1_3_VERSION; | ||
111 | return TLS_method(); | ||
112 | } | ||
113 | #endif | ||
114 | return NULL; | ||
115 | } | ||
116 | #endif | ||
117 | |||
118 | /** | ||
119 | * Prepare the SSL handshake verify flag. | ||
120 | */ | ||
121 | static int set_verify_flag(const char *str, int *flag) | ||
122 | { | ||
123 | if (!strcmp(str, "none")) { | ||
124 | *flag |= SSL_VERIFY_NONE; | ||
125 | return 1; | ||
126 | } | ||
127 | if (!strcmp(str, "peer")) { | ||
128 | *flag |= SSL_VERIFY_PEER; | ||
129 | return 1; | ||
130 | } | ||
131 | if (!strcmp(str, "client_once")) { | ||
132 | *flag |= SSL_VERIFY_CLIENT_ONCE; | ||
133 | return 1; | ||
134 | } | ||
135 | if (!strcmp(str, "fail_if_no_peer_cert")) { | ||
136 | *flag |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; | ||
137 | return 1; | ||
138 | } | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * Password callback for reading the private key. | ||
144 | */ | ||
145 | static int passwd_cb(char *buf, int size, int flag, void *udata) | ||
146 | { | ||
147 | lua_State *L = (lua_State*)udata; | ||
148 | switch (lua_type(L, 3)) { | ||
149 | case LUA_TFUNCTION: | ||
150 | lua_pushvalue(L, 3); | ||
151 | lua_call(L, 0, 1); | ||
152 | if (lua_type(L, -1) != LUA_TSTRING) { | ||
153 | lua_pop(L, 1); /* Remove the result from the stack */ | ||
154 | return 0; | ||
155 | } | ||
156 | /* fallback */ | ||
157 | case LUA_TSTRING: | ||
158 | strncpy(buf, lua_tostring(L, -1), size); | ||
159 | lua_pop(L, 1); /* Remove the result from the stack */ | ||
160 | buf[size-1] = '\0'; | ||
161 | return (int)strlen(buf); | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * Add an error related to a depth certificate of the chain. | ||
168 | */ | ||
169 | static void add_cert_error(lua_State *L, SSL *ssl, int err, int depth) | ||
170 | { | ||
171 | luaL_getmetatable(L, "SSL:Verify:Registry"); | ||
172 | lua_pushlightuserdata(L, (void*)ssl); | ||
173 | lua_gettable(L, -2); | ||
174 | if (lua_isnil(L, -1)) { | ||
175 | lua_pop(L, 1); | ||
176 | /* Create an error table for this connection */ | ||
177 | lua_newtable(L); | ||
178 | lua_pushlightuserdata(L, (void*)ssl); | ||
179 | lua_pushvalue(L, -2); /* keep the table on stack */ | ||
180 | lua_settable(L, -4); | ||
181 | } | ||
182 | lua_rawgeti(L, -1, depth+1); | ||
183 | /* If the table doesn't exist, create it */ | ||
184 | if (lua_isnil(L, -1)) { | ||
185 | lua_pop(L, 1); /* remove 'nil' from stack */ | ||
186 | lua_newtable(L); | ||
187 | lua_pushvalue(L, -1); /* keep the table on stack */ | ||
188 | lua_rawseti(L, -3, depth+1); | ||
189 | } | ||
190 | lua_pushstring(L, X509_verify_cert_error_string(err)); | ||
191 | lua_rawseti(L, -2, lua_rawlen(L, -2) + 1); | ||
192 | /* Clear the stack */ | ||
193 | lua_pop(L, 3); | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * Call Lua user function to get the DH key. | ||
198 | */ | ||
199 | static DH *dhparam_cb(SSL *ssl, int is_export, int keylength) | ||
200 | { | ||
201 | BIO *bio; | ||
202 | lua_State *L; | ||
203 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); | ||
204 | p_context pctx = (p_context)SSL_CTX_get_app_data(ctx); | ||
205 | |||
206 | L = pctx->L; | ||
207 | |||
208 | /* Get the callback */ | ||
209 | luaL_getmetatable(L, "SSL:DH:Registry"); | ||
210 | lua_pushlightuserdata(L, (void*)ctx); | ||
211 | lua_gettable(L, -2); | ||
212 | |||
213 | /* Invoke the callback */ | ||
214 | lua_pushboolean(L, is_export); | ||
215 | lua_pushnumber(L, keylength); | ||
216 | lua_call(L, 2, 1); | ||
217 | |||
218 | /* Load parameters from returned value */ | ||
219 | if (lua_type(L, -1) != LUA_TSTRING) { | ||
220 | lua_pop(L, 2); /* Remove values from stack */ | ||
221 | return NULL; | ||
222 | } | ||
223 | |||
224 | bio = BIO_new_mem_buf((void*)lua_tostring(L, -1), lua_rawlen(L, -1)); | ||
225 | if (bio) { | ||
226 | pctx->dh_param = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); | ||
227 | BIO_free(bio); | ||
228 | } | ||
229 | |||
230 | lua_pop(L, 2); /* Remove values from stack */ | ||
231 | return pctx->dh_param; | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * Set the "ignore purpose" before to start verifing the certificate chain. | ||
236 | */ | ||
237 | static int cert_verify_cb(X509_STORE_CTX *x509_ctx, void *ptr) | ||
238 | { | ||
239 | int verify; | ||
240 | lua_State *L; | ||
241 | SSL_CTX *ctx = (SSL_CTX*)ptr; | ||
242 | p_context pctx = (p_context)SSL_CTX_get_app_data(ctx); | ||
243 | |||
244 | L = pctx->L; | ||
245 | |||
246 | /* Get verify flags */ | ||
247 | luaL_getmetatable(L, "SSL:Verify:Registry"); | ||
248 | lua_pushlightuserdata(L, (void*)ctx); | ||
249 | lua_gettable(L, -2); | ||
250 | verify = (int)lua_tonumber(L, -1); | ||
251 | |||
252 | lua_pop(L, 2); /* Remove values from stack */ | ||
253 | |||
254 | if (verify & LSEC_VERIFY_IGNORE_PURPOSE) { | ||
255 | /* Set parameters to ignore the server purpose */ | ||
256 | X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(x509_ctx); | ||
257 | if (param) { | ||
258 | X509_VERIFY_PARAM_set_purpose(param, X509_PURPOSE_SSL_SERVER); | ||
259 | X509_VERIFY_PARAM_set_trust(param, X509_TRUST_SSL_SERVER); | ||
260 | } | ||
261 | } | ||
262 | /* Call OpenSSL standard verification function */ | ||
263 | return X509_verify_cert(x509_ctx); | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * This callback implements the "continue on error" flag and log the errors. | ||
268 | */ | ||
269 | static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) | ||
270 | { | ||
271 | int err; | ||
272 | int verify; | ||
273 | SSL *ssl; | ||
274 | SSL_CTX *ctx; | ||
275 | p_context pctx; | ||
276 | lua_State *L; | ||
277 | |||
278 | /* Short-circuit optimization */ | ||
279 | if (preverify_ok) | ||
280 | return 1; | ||
281 | |||
282 | ssl = X509_STORE_CTX_get_ex_data(x509_ctx, | ||
283 | SSL_get_ex_data_X509_STORE_CTX_idx()); | ||
284 | ctx = SSL_get_SSL_CTX(ssl); | ||
285 | pctx = (p_context)SSL_CTX_get_app_data(ctx); | ||
286 | L = pctx->L; | ||
287 | |||
288 | /* Get verify flags */ | ||
289 | luaL_getmetatable(L, "SSL:Verify:Registry"); | ||
290 | lua_pushlightuserdata(L, (void*)ctx); | ||
291 | lua_gettable(L, -2); | ||
292 | verify = (int)lua_tonumber(L, -1); | ||
293 | |||
294 | lua_pop(L, 2); /* Remove values from stack */ | ||
295 | |||
296 | err = X509_STORE_CTX_get_error(x509_ctx); | ||
297 | if (err != X509_V_OK) | ||
298 | add_cert_error(L, ssl, err, X509_STORE_CTX_get_error_depth(x509_ctx)); | ||
299 | |||
300 | return (verify & LSEC_VERIFY_CONTINUE ? 1 : preverify_ok); | ||
301 | } | ||
302 | |||
303 | /*------------------------------ Lua Functions -------------------------------*/ | ||
304 | |||
305 | /** | ||
306 | * Create a SSL context. | ||
307 | */ | ||
308 | static int create(lua_State *L) | ||
309 | { | ||
310 | p_context ctx; | ||
311 | const char *str_method; | ||
312 | const SSL_METHOD *method; | ||
313 | int vmin, vmax; | ||
314 | |||
315 | str_method = luaL_checkstring(L, 1); | ||
316 | method = str2method(str_method, &vmin, &vmax); | ||
317 | if (!method) { | ||
318 | lua_pushnil(L); | ||
319 | lua_pushfstring(L, "invalid protocol (%s)", str_method); | ||
320 | return 2; | ||
321 | } | ||
322 | ctx = (p_context) lua_newuserdata(L, sizeof(t_context)); | ||
323 | if (!ctx) { | ||
324 | lua_pushnil(L); | ||
325 | lua_pushstring(L, "error creating context"); | ||
326 | return 2; | ||
327 | } | ||
328 | memset(ctx, 0, sizeof(t_context)); | ||
329 | ctx->context = SSL_CTX_new(method); | ||
330 | if (!ctx->context) { | ||
331 | lua_pushnil(L); | ||
332 | lua_pushfstring(L, "error creating context (%s)", | ||
333 | ERR_reason_error_string(ERR_get_error())); | ||
334 | return 2; | ||
335 | } | ||
336 | #ifdef LSEC_API_OPENSSL_1_1_0 | ||
337 | SSL_CTX_set_min_proto_version(ctx->context, vmin); | ||
338 | SSL_CTX_set_max_proto_version(ctx->context, vmax); | ||
339 | #endif | ||
340 | ctx->mode = LSEC_MODE_INVALID; | ||
341 | ctx->L = L; | ||
342 | luaL_getmetatable(L, "SSL:Context"); | ||
343 | lua_setmetatable(L, -2); | ||
344 | |||
345 | /* No session support */ | ||
346 | SSL_CTX_set_session_cache_mode(ctx->context, SSL_SESS_CACHE_OFF); | ||
347 | /* Link LuaSec context with the OpenSSL context */ | ||
348 | SSL_CTX_set_app_data(ctx->context, ctx); | ||
349 | |||
350 | return 1; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * Load the trusting certificates. | ||
355 | */ | ||
356 | static int load_locations(lua_State *L) | ||
357 | { | ||
358 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
359 | const char *cafile = luaL_optstring(L, 2, NULL); | ||
360 | const char *capath = luaL_optstring(L, 3, NULL); | ||
361 | if (SSL_CTX_load_verify_locations(ctx, cafile, capath) != 1) { | ||
362 | lua_pushboolean(L, 0); | ||
363 | lua_pushfstring(L, "error loading CA locations (%s)", | ||
364 | ERR_reason_error_string(ERR_get_error())); | ||
365 | return 2; | ||
366 | } | ||
367 | lua_pushboolean(L, 1); | ||
368 | return 1; | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * Load the certificate file. | ||
373 | */ | ||
374 | static int load_cert(lua_State *L) | ||
375 | { | ||
376 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
377 | const char *filename = luaL_checkstring(L, 2); | ||
378 | if (SSL_CTX_use_certificate_chain_file(ctx, filename) != 1) { | ||
379 | lua_pushboolean(L, 0); | ||
380 | lua_pushfstring(L, "error loading certificate (%s)", | ||
381 | ERR_reason_error_string(ERR_get_error())); | ||
382 | return 2; | ||
383 | } | ||
384 | lua_pushboolean(L, 1); | ||
385 | return 1; | ||
386 | } | ||
387 | |||
388 | /** | ||
389 | * Load the key file -- only in PEM format. | ||
390 | */ | ||
391 | static int load_key(lua_State *L) | ||
392 | { | ||
393 | int ret = 1; | ||
394 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
395 | const char *filename = luaL_checkstring(L, 2); | ||
396 | switch (lua_type(L, 3)) { | ||
397 | case LUA_TSTRING: | ||
398 | case LUA_TFUNCTION: | ||
399 | SSL_CTX_set_default_passwd_cb(ctx, passwd_cb); | ||
400 | SSL_CTX_set_default_passwd_cb_userdata(ctx, L); | ||
401 | /* fallback */ | ||
402 | case LUA_TNIL: | ||
403 | if (SSL_CTX_use_PrivateKey_file(ctx, filename, SSL_FILETYPE_PEM) == 1) | ||
404 | lua_pushboolean(L, 1); | ||
405 | else { | ||
406 | ret = 2; | ||
407 | lua_pushboolean(L, 0); | ||
408 | lua_pushfstring(L, "error loading private key (%s)", | ||
409 | ERR_reason_error_string(ERR_get_error())); | ||
410 | } | ||
411 | SSL_CTX_set_default_passwd_cb(ctx, NULL); | ||
412 | SSL_CTX_set_default_passwd_cb_userdata(ctx, NULL); | ||
413 | break; | ||
414 | default: | ||
415 | lua_pushstring(L, "invalid callback value"); | ||
416 | lua_error(L); | ||
417 | } | ||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * Check that the certificate public key matches the private key | ||
423 | */ | ||
424 | |||
425 | static int check_key(lua_State *L) | ||
426 | { | ||
427 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
428 | lua_pushboolean(L, SSL_CTX_check_private_key(ctx)); | ||
429 | return 1; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * Set the cipher list. | ||
434 | */ | ||
435 | static int set_cipher(lua_State *L) | ||
436 | { | ||
437 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
438 | const char *list = luaL_checkstring(L, 2); | ||
439 | if (SSL_CTX_set_cipher_list(ctx, list) != 1) { | ||
440 | lua_pushboolean(L, 0); | ||
441 | lua_pushfstring(L, "error setting cipher list (%s)", ERR_reason_error_string(ERR_get_error())); | ||
442 | return 2; | ||
443 | } | ||
444 | lua_pushboolean(L, 1); | ||
445 | return 1; | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * Set the cipher suites. | ||
450 | */ | ||
451 | static int set_ciphersuites(lua_State *L) | ||
452 | { | ||
453 | #if defined(TLS1_3_VERSION) | ||
454 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
455 | const char *list = luaL_checkstring(L, 2); | ||
456 | if (SSL_CTX_set_ciphersuites(ctx, list) != 1) { | ||
457 | lua_pushboolean(L, 0); | ||
458 | lua_pushfstring(L, "error setting cipher list (%s)", ERR_reason_error_string(ERR_get_error())); | ||
459 | return 2; | ||
460 | } | ||
461 | #endif | ||
462 | lua_pushboolean(L, 1); | ||
463 | return 1; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * Set the depth for certificate checking. | ||
468 | */ | ||
469 | static int set_depth(lua_State *L) | ||
470 | { | ||
471 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
472 | SSL_CTX_set_verify_depth(ctx, (int)luaL_checkinteger(L, 2)); | ||
473 | lua_pushboolean(L, 1); | ||
474 | return 1; | ||
475 | } | ||
476 | |||
477 | /** | ||
478 | * Set the handshake verify options. | ||
479 | */ | ||
480 | static int set_verify(lua_State *L) | ||
481 | { | ||
482 | int i; | ||
483 | const char *str; | ||
484 | int flag = 0; | ||
485 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
486 | int max = lua_gettop(L); | ||
487 | for (i = 2; i <= max; i++) { | ||
488 | str = luaL_checkstring(L, i); | ||
489 | if (!set_verify_flag(str, &flag)) { | ||
490 | lua_pushboolean(L, 0); | ||
491 | lua_pushfstring(L, "invalid verify option (%s)", str); | ||
492 | return 2; | ||
493 | } | ||
494 | } | ||
495 | if (flag) SSL_CTX_set_verify(ctx, flag, NULL); | ||
496 | lua_pushboolean(L, 1); | ||
497 | return 1; | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * Set the protocol options. | ||
502 | */ | ||
503 | static int set_options(lua_State *L) | ||
504 | { | ||
505 | int i; | ||
506 | const char *str; | ||
507 | unsigned long flag = 0L; | ||
508 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
509 | int max = lua_gettop(L); | ||
510 | /* any option? */ | ||
511 | if (max > 1) { | ||
512 | for (i = 2; i <= max; i++) { | ||
513 | str = luaL_checkstring(L, i); | ||
514 | if (!set_option_flag(str, &flag)) { | ||
515 | lua_pushboolean(L, 0); | ||
516 | lua_pushfstring(L, "invalid option (%s)", str); | ||
517 | return 2; | ||
518 | } | ||
519 | } | ||
520 | SSL_CTX_set_options(ctx, flag); | ||
521 | } | ||
522 | lua_pushboolean(L, 1); | ||
523 | return 1; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * Set the context mode. | ||
528 | */ | ||
529 | static int set_mode(lua_State *L) | ||
530 | { | ||
531 | p_context ctx = checkctx(L, 1); | ||
532 | const char *str = luaL_checkstring(L, 2); | ||
533 | if (!strcmp("server", str)) { | ||
534 | ctx->mode = LSEC_MODE_SERVER; | ||
535 | lua_pushboolean(L, 1); | ||
536 | return 1; | ||
537 | } | ||
538 | if (!strcmp("client", str)) { | ||
539 | ctx->mode = LSEC_MODE_CLIENT; | ||
540 | lua_pushboolean(L, 1); | ||
541 | return 1; | ||
542 | } | ||
543 | lua_pushboolean(L, 0); | ||
544 | lua_pushfstring(L, "invalid mode (%s)", str); | ||
545 | return 1; | ||
546 | } | ||
547 | |||
548 | /** | ||
549 | * Configure DH parameters. | ||
550 | */ | ||
551 | static int set_dhparam(lua_State *L) | ||
552 | { | ||
553 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
554 | SSL_CTX_set_tmp_dh_callback(ctx, dhparam_cb); | ||
555 | |||
556 | /* Save callback */ | ||
557 | luaL_getmetatable(L, "SSL:DH:Registry"); | ||
558 | lua_pushlightuserdata(L, (void*)ctx); | ||
559 | lua_pushvalue(L, 2); | ||
560 | lua_settable(L, -3); | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | #if !defined(OPENSSL_NO_EC) | ||
566 | /** | ||
567 | * Set elliptic curve. | ||
568 | */ | ||
569 | static int set_curve(lua_State *L) | ||
570 | { | ||
571 | long ret; | ||
572 | EC_KEY *key = NULL; | ||
573 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
574 | const char *str = luaL_checkstring(L, 2); | ||
575 | |||
576 | SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); | ||
577 | |||
578 | key = lsec_find_ec_key(L, str); | ||
579 | |||
580 | if (!key) { | ||
581 | lua_pushboolean(L, 0); | ||
582 | lua_pushfstring(L, "elliptic curve '%s' not supported", str); | ||
583 | return 2; | ||
584 | } | ||
585 | |||
586 | ret = SSL_CTX_set_tmp_ecdh(ctx, key); | ||
587 | /* SSL_CTX_set_tmp_ecdh takes its own reference */ | ||
588 | EC_KEY_free(key); | ||
589 | |||
590 | if (!ret) { | ||
591 | lua_pushboolean(L, 0); | ||
592 | lua_pushfstring(L, "error setting elliptic curve (%s)", | ||
593 | ERR_reason_error_string(ERR_get_error())); | ||
594 | return 2; | ||
595 | } | ||
596 | |||
597 | lua_pushboolean(L, 1); | ||
598 | return 1; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * Set elliptic curves list. | ||
603 | */ | ||
604 | static int set_curves_list(lua_State *L) | ||
605 | { | ||
606 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
607 | const char *str = luaL_checkstring(L, 2); | ||
608 | |||
609 | SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); | ||
610 | |||
611 | if (SSL_CTX_set1_curves_list(ctx, str) != 1) { | ||
612 | lua_pushboolean(L, 0); | ||
613 | lua_pushfstring(L, "unknown elliptic curve in \"%s\"", str); | ||
614 | return 2; | ||
615 | } | ||
616 | |||
617 | #if defined(LIBRESSL_VERSION_NUMBER) || !defined(LSEC_API_OPENSSL_1_1_0) | ||
618 | (void)SSL_CTX_set_ecdh_auto(ctx, 1); | ||
619 | #endif | ||
620 | |||
621 | lua_pushboolean(L, 1); | ||
622 | return 1; | ||
623 | } | ||
624 | #endif | ||
625 | |||
626 | /** | ||
627 | * Set the protocols a client should send for ALPN. | ||
628 | */ | ||
629 | static int set_alpn(lua_State *L) | ||
630 | { | ||
631 | long ret; | ||
632 | size_t len; | ||
633 | p_context ctx = checkctx(L, 1); | ||
634 | const char *str = luaL_checklstring(L, 2, &len); | ||
635 | |||
636 | ret = SSL_CTX_set_alpn_protos(ctx->context, (const unsigned char*)str, len); | ||
637 | if (ret) { | ||
638 | lua_pushboolean(L, 0); | ||
639 | lua_pushfstring(L, "error setting ALPN (%s)", ERR_reason_error_string(ERR_get_error())); | ||
640 | return 2; | ||
641 | } | ||
642 | lua_pushboolean(L, 1); | ||
643 | return 1; | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * This standard callback calls the server's callback in Lua sapce. | ||
648 | * The server has to return a list in wire-format strings. | ||
649 | * This function uses a helper function to match server and client lists. | ||
650 | */ | ||
651 | static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, | ||
652 | const unsigned char *in, unsigned int inlen, void *arg) | ||
653 | { | ||
654 | int ret; | ||
655 | size_t server_len; | ||
656 | const char *server; | ||
657 | p_context ctx = (p_context)arg; | ||
658 | lua_State *L = ctx->L; | ||
659 | |||
660 | luaL_getmetatable(L, "SSL:ALPN:Registry"); | ||
661 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
662 | lua_gettable(L, -2); | ||
663 | |||
664 | lua_pushlstring(L, (const char*)in, inlen); | ||
665 | |||
666 | lua_call(L, 1, 1); | ||
667 | |||
668 | if (!lua_isstring(L, -1)) { | ||
669 | lua_pop(L, 2); | ||
670 | return SSL_TLSEXT_ERR_NOACK; | ||
671 | } | ||
672 | |||
673 | // Protocol list from server in wire-format string | ||
674 | server = luaL_checklstring(L, -1, &server_len); | ||
675 | ret = SSL_select_next_proto((unsigned char**)out, outlen, (const unsigned char*)server, | ||
676 | server_len, in, inlen); | ||
677 | if (ret != OPENSSL_NPN_NEGOTIATED) { | ||
678 | lua_pop(L, 2); | ||
679 | return SSL_TLSEXT_ERR_NOACK; | ||
680 | } | ||
681 | |||
682 | // Copy the result because lua_pop() can collect the pointer | ||
683 | ctx->alpn = malloc(*outlen); | ||
684 | memcpy(ctx->alpn, (void*)*out, *outlen); | ||
685 | *out = (const unsigned char*)ctx->alpn; | ||
686 | |||
687 | lua_pop(L, 2); | ||
688 | |||
689 | return SSL_TLSEXT_ERR_OK; | ||
690 | } | ||
691 | |||
692 | /** | ||
693 | * Set a callback a server can use to select the next protocol with ALPN. | ||
694 | */ | ||
695 | static int set_alpn_cb(lua_State *L) | ||
696 | { | ||
697 | p_context ctx = checkctx(L, 1); | ||
698 | |||
699 | luaL_getmetatable(L, "SSL:ALPN:Registry"); | ||
700 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
701 | lua_pushvalue(L, 2); | ||
702 | lua_settable(L, -3); | ||
703 | |||
704 | SSL_CTX_set_alpn_select_cb(ctx->context, alpn_cb, ctx); | ||
705 | |||
706 | lua_pushboolean(L, 1); | ||
707 | return 1; | ||
708 | } | ||
709 | |||
710 | #if defined(LSEC_ENABLE_PSK) | ||
711 | /** | ||
712 | * Callback to select the PSK. | ||
713 | */ | ||
714 | static unsigned int server_psk_cb(SSL *ssl, const char *identity, unsigned char *psk, | ||
715 | unsigned int max_psk_len) | ||
716 | { | ||
717 | size_t psk_len; | ||
718 | const char *ret_psk; | ||
719 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); | ||
720 | p_context pctx = (p_context)SSL_CTX_get_app_data(ctx); | ||
721 | lua_State *L = pctx->L; | ||
722 | |||
723 | luaL_getmetatable(L, "SSL:PSK:Registry"); | ||
724 | lua_pushlightuserdata(L, (void*)pctx->context); | ||
725 | lua_gettable(L, -2); | ||
726 | |||
727 | lua_pushstring(L, identity); | ||
728 | lua_pushinteger(L, max_psk_len); | ||
729 | |||
730 | lua_call(L, 2, 1); | ||
731 | |||
732 | if (!lua_isstring(L, -1)) { | ||
733 | lua_pop(L, 2); | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | ret_psk = lua_tolstring(L, -1, &psk_len); | ||
738 | |||
739 | if (psk_len == 0 || psk_len > max_psk_len) | ||
740 | psk_len = 0; | ||
741 | else | ||
742 | memcpy(psk, ret_psk, psk_len); | ||
743 | |||
744 | lua_pop(L, 2); | ||
745 | |||
746 | return psk_len; | ||
747 | } | ||
748 | |||
749 | /** | ||
750 | * Set a PSK callback for server. | ||
751 | */ | ||
752 | static int set_server_psk_cb(lua_State *L) | ||
753 | { | ||
754 | p_context ctx = checkctx(L, 1); | ||
755 | |||
756 | luaL_getmetatable(L, "SSL:PSK:Registry"); | ||
757 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
758 | lua_pushvalue(L, 2); | ||
759 | lua_settable(L, -3); | ||
760 | |||
761 | SSL_CTX_set_psk_server_callback(ctx->context, server_psk_cb); | ||
762 | |||
763 | lua_pushboolean(L, 1); | ||
764 | return 1; | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | * Set the PSK indentity hint. | ||
769 | */ | ||
770 | static int set_psk_identity_hint(lua_State *L) | ||
771 | { | ||
772 | p_context ctx = checkctx(L, 1); | ||
773 | const char *hint = luaL_checkstring(L, 2); | ||
774 | int ret = SSL_CTX_use_psk_identity_hint(ctx->context, hint); | ||
775 | lua_pushboolean(L, ret); | ||
776 | return 1; | ||
777 | } | ||
778 | |||
779 | /* | ||
780 | * Client callback to PSK. | ||
781 | */ | ||
782 | static unsigned int client_psk_cb(SSL *ssl, const char *hint, char *identity, | ||
783 | unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len) | ||
784 | { | ||
785 | size_t psk_len; | ||
786 | size_t identity_len; | ||
787 | const char *ret_psk; | ||
788 | const char *ret_identity; | ||
789 | SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); | ||
790 | p_context pctx = (p_context)SSL_CTX_get_app_data(ctx); | ||
791 | lua_State *L = pctx->L; | ||
792 | |||
793 | luaL_getmetatable(L, "SSL:PSK:Registry"); | ||
794 | lua_pushlightuserdata(L, (void*)pctx->context); | ||
795 | lua_gettable(L, -2); | ||
796 | |||
797 | if (hint) | ||
798 | lua_pushstring(L, hint); | ||
799 | else | ||
800 | lua_pushnil(L); | ||
801 | |||
802 | // Leave space to '\0' | ||
803 | lua_pushinteger(L, max_identity_len-1); | ||
804 | lua_pushinteger(L, max_psk_len); | ||
805 | |||
806 | lua_call(L, 3, 2); | ||
807 | |||
808 | if (!lua_isstring(L, -1) || !lua_isstring(L, -2)) { | ||
809 | lua_pop(L, 3); | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | ret_identity = lua_tolstring(L, -2, &identity_len); | ||
814 | ret_psk = lua_tolstring(L, -1, &psk_len); | ||
815 | |||
816 | if (identity_len >= max_identity_len || psk_len > max_psk_len) | ||
817 | psk_len = 0; | ||
818 | else { | ||
819 | memcpy(identity, ret_identity, identity_len); | ||
820 | identity[identity_len] = 0; | ||
821 | memcpy(psk, ret_psk, psk_len); | ||
822 | } | ||
823 | |||
824 | lua_pop(L, 3); | ||
825 | |||
826 | return psk_len; | ||
827 | } | ||
828 | |||
829 | /** | ||
830 | * Set a PSK callback for client. | ||
831 | */ | ||
832 | static int set_client_psk_cb(lua_State *L) { | ||
833 | p_context ctx = checkctx(L, 1); | ||
834 | |||
835 | luaL_getmetatable(L, "SSL:PSK:Registry"); | ||
836 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
837 | lua_pushvalue(L, 2); | ||
838 | lua_settable(L, -3); | ||
839 | |||
840 | SSL_CTX_set_psk_client_callback(ctx->context, client_psk_cb); | ||
841 | |||
842 | lua_pushboolean(L, 1); | ||
843 | return 1; | ||
844 | } | ||
845 | #endif | ||
846 | |||
847 | #if defined(LSEC_ENABLE_DANE) | ||
848 | /* | ||
849 | * DANE | ||
850 | */ | ||
851 | static int dane_options[] = { | ||
852 | /* TODO move into options.c | ||
853 | * however this symbol is not from openssl/ssl.h but rather from | ||
854 | * openssl/x509_vfy.h | ||
855 | * */ | ||
856 | #ifdef DANE_FLAG_NO_DANE_EE_NAMECHECKS | ||
857 | DANE_FLAG_NO_DANE_EE_NAMECHECKS, | ||
858 | #endif | ||
859 | 0 | ||
860 | }; | ||
861 | static const char *dane_option_names[] = { | ||
862 | #ifdef DANE_FLAG_NO_DANE_EE_NAMECHECKS | ||
863 | "no_ee_namechecks", | ||
864 | #endif | ||
865 | NULL | ||
866 | }; | ||
867 | |||
868 | static int set_dane(lua_State *L) | ||
869 | { | ||
870 | int ret, i; | ||
871 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
872 | ret = SSL_CTX_dane_enable(ctx); | ||
873 | for (i = 2; ret > 0 && i <= lua_gettop(L); i++) { | ||
874 | ret = SSL_CTX_dane_set_flags(ctx, dane_options[luaL_checkoption(L, i, NULL, dane_option_names)]); | ||
875 | } | ||
876 | lua_pushboolean(L, (ret > 0)); | ||
877 | return 1; | ||
878 | } | ||
879 | #endif | ||
880 | |||
881 | /** | ||
882 | * Package functions | ||
883 | */ | ||
884 | static luaL_Reg funcs[] = { | ||
885 | {"create", create}, | ||
886 | {"locations", load_locations}, | ||
887 | {"loadcert", load_cert}, | ||
888 | {"loadkey", load_key}, | ||
889 | {"checkkey", check_key}, | ||
890 | {"setalpn", set_alpn}, | ||
891 | {"setalpncb", set_alpn_cb}, | ||
892 | {"setcipher", set_cipher}, | ||
893 | {"setciphersuites", set_ciphersuites}, | ||
894 | {"setdepth", set_depth}, | ||
895 | {"setdhparam", set_dhparam}, | ||
896 | {"setverify", set_verify}, | ||
897 | {"setoptions", set_options}, | ||
898 | #if defined(LSEC_ENABLE_PSK) | ||
899 | {"setpskhint", set_psk_identity_hint}, | ||
900 | {"setserverpskcb", set_server_psk_cb}, | ||
901 | {"setclientpskcb", set_client_psk_cb}, | ||
902 | #endif | ||
903 | {"setmode", set_mode}, | ||
904 | #if !defined(OPENSSL_NO_EC) | ||
905 | {"setcurve", set_curve}, | ||
906 | {"setcurveslist", set_curves_list}, | ||
907 | #endif | ||
908 | #if defined(LSEC_ENABLE_DANE) | ||
909 | {"setdane", set_dane}, | ||
910 | #endif | ||
911 | {NULL, NULL} | ||
912 | }; | ||
913 | |||
914 | /*-------------------------------- Metamethods -------------------------------*/ | ||
915 | |||
916 | /** | ||
917 | * Collect SSL context -- GC metamethod. | ||
918 | */ | ||
919 | static int meth_destroy(lua_State *L) | ||
920 | { | ||
921 | p_context ctx = checkctx(L, 1); | ||
922 | if (ctx->context) { | ||
923 | /* Clear registries */ | ||
924 | luaL_getmetatable(L, "SSL:DH:Registry"); | ||
925 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
926 | lua_pushnil(L); | ||
927 | lua_settable(L, -3); | ||
928 | luaL_getmetatable(L, "SSL:Verify:Registry"); | ||
929 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
930 | lua_pushnil(L); | ||
931 | lua_settable(L, -3); | ||
932 | luaL_getmetatable(L, "SSL:ALPN:Registry"); | ||
933 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
934 | lua_pushnil(L); | ||
935 | lua_settable(L, -3); | ||
936 | luaL_getmetatable(L, "SSL:PSK:Registry"); | ||
937 | lua_pushlightuserdata(L, (void*)ctx->context); | ||
938 | lua_pushnil(L); | ||
939 | lua_settable(L, -3); | ||
940 | |||
941 | SSL_CTX_free(ctx->context); | ||
942 | ctx->context = NULL; | ||
943 | } | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | /** | ||
948 | * Object information -- tostring metamethod. | ||
949 | */ | ||
950 | static int meth_tostring(lua_State *L) | ||
951 | { | ||
952 | p_context ctx = checkctx(L, 1); | ||
953 | lua_pushfstring(L, "SSL context: %p", ctx); | ||
954 | return 1; | ||
955 | } | ||
956 | |||
957 | /** | ||
958 | * Set extra flags for handshake verification. | ||
959 | */ | ||
960 | static int meth_set_verify_ext(lua_State *L) | ||
961 | { | ||
962 | int i; | ||
963 | const char *str; | ||
964 | int crl_flag = 0; | ||
965 | int lsec_flag = 0; | ||
966 | SSL_CTX *ctx = lsec_checkcontext(L, 1); | ||
967 | int max = lua_gettop(L); | ||
968 | for (i = 2; i <= max; i++) { | ||
969 | str = luaL_checkstring(L, i); | ||
970 | if (!strcmp(str, "lsec_continue")) { | ||
971 | lsec_flag |= LSEC_VERIFY_CONTINUE; | ||
972 | } else if (!strcmp(str, "lsec_ignore_purpose")) { | ||
973 | lsec_flag |= LSEC_VERIFY_IGNORE_PURPOSE; | ||
974 | } else if (!strcmp(str, "crl_check")) { | ||
975 | crl_flag |= X509_V_FLAG_CRL_CHECK; | ||
976 | } else if (!strcmp(str, "crl_check_chain")) { | ||
977 | crl_flag |= X509_V_FLAG_CRL_CHECK_ALL; | ||
978 | } else { | ||
979 | lua_pushboolean(L, 0); | ||
980 | lua_pushfstring(L, "invalid verify option (%s)", str); | ||
981 | return 2; | ||
982 | } | ||
983 | } | ||
984 | /* Set callback? */ | ||
985 | if (lsec_flag) { | ||
986 | SSL_CTX_set_verify(ctx, SSL_CTX_get_verify_mode(ctx), verify_cb); | ||
987 | SSL_CTX_set_cert_verify_callback(ctx, cert_verify_cb, (void*)ctx); | ||
988 | /* Save flag */ | ||
989 | luaL_getmetatable(L, "SSL:Verify:Registry"); | ||
990 | lua_pushlightuserdata(L, (void*)ctx); | ||
991 | lua_pushnumber(L, lsec_flag); | ||
992 | lua_settable(L, -3); | ||
993 | } else { | ||
994 | SSL_CTX_set_verify(ctx, SSL_CTX_get_verify_mode(ctx), NULL); | ||
995 | SSL_CTX_set_cert_verify_callback(ctx, NULL, NULL); | ||
996 | /* Remove flag */ | ||
997 | luaL_getmetatable(L, "SSL:Verify:Registry"); | ||
998 | lua_pushlightuserdata(L, (void*)ctx); | ||
999 | lua_pushnil(L); | ||
1000 | lua_settable(L, -3); | ||
1001 | } | ||
1002 | |||
1003 | /* X509 flag */ | ||
1004 | X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), crl_flag); | ||
1005 | |||
1006 | /* Ok */ | ||
1007 | lua_pushboolean(L, 1); | ||
1008 | return 1; | ||
1009 | } | ||
1010 | |||
1011 | /** | ||
1012 | * Context metamethods. | ||
1013 | */ | ||
1014 | static luaL_Reg meta[] = { | ||
1015 | {"__close", meth_destroy}, | ||
1016 | {"__gc", meth_destroy}, | ||
1017 | {"__tostring", meth_tostring}, | ||
1018 | {NULL, NULL} | ||
1019 | }; | ||
1020 | |||
1021 | /** | ||
1022 | * Index metamethods. | ||
1023 | */ | ||
1024 | static luaL_Reg meta_index[] = { | ||
1025 | {"setverifyext", meth_set_verify_ext}, | ||
1026 | {NULL, NULL} | ||
1027 | }; | ||
1028 | |||
1029 | |||
1030 | /*----------------------------- Public Functions ---------------------------*/ | ||
1031 | |||
1032 | /** | ||
1033 | * Retrieve the SSL context from the Lua stack. | ||
1034 | */ | ||
1035 | SSL_CTX* lsec_checkcontext(lua_State *L, int idx) | ||
1036 | { | ||
1037 | p_context ctx = checkctx(L, idx); | ||
1038 | return ctx->context; | ||
1039 | } | ||
1040 | |||
1041 | SSL_CTX* lsec_testcontext(lua_State *L, int idx) | ||
1042 | { | ||
1043 | p_context ctx = testctx(L, idx); | ||
1044 | return (ctx) ? ctx->context : NULL; | ||
1045 | } | ||
1046 | |||
1047 | /** | ||
1048 | * Retrieve the mode from the context in the Lua stack. | ||
1049 | */ | ||
1050 | int lsec_getmode(lua_State *L, int idx) | ||
1051 | { | ||
1052 | p_context ctx = checkctx(L, idx); | ||
1053 | return ctx->mode; | ||
1054 | } | ||
1055 | |||
1056 | /*-- Compat - Lua 5.1 --*/ | ||
1057 | #if (LUA_VERSION_NUM == 501) | ||
1058 | |||
1059 | void *lsec_testudata (lua_State *L, int ud, const char *tname) { | ||
1060 | void *p = lua_touserdata(L, ud); | ||
1061 | if (p != NULL) { /* value is a userdata? */ | ||
1062 | if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ | ||
1063 | luaL_getmetatable(L, tname); /* get correct metatable */ | ||
1064 | if (!lua_rawequal(L, -1, -2)) /* not the same? */ | ||
1065 | p = NULL; /* value is a userdata with wrong metatable */ | ||
1066 | lua_pop(L, 2); /* remove both metatables */ | ||
1067 | return p; | ||
1068 | } | ||
1069 | } | ||
1070 | return NULL; /* value is not a userdata with a metatable */ | ||
1071 | } | ||
1072 | |||
1073 | #endif | ||
1074 | |||
1075 | /*------------------------------ Initialization ------------------------------*/ | ||
1076 | |||
1077 | /** | ||
1078 | * Registre the module. | ||
1079 | */ | ||
1080 | LSEC_API int luaopen_ssl_context(lua_State *L) | ||
1081 | { | ||
1082 | luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */ | ||
1083 | luaL_newmetatable(L, "SSL:ALPN:Registry"); /* Keep all ALPN callbacks */ | ||
1084 | luaL_newmetatable(L, "SSL:PSK:Registry"); /* Keep all PSK callbacks */ | ||
1085 | luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */ | ||
1086 | luaL_newmetatable(L, "SSL:Context"); | ||
1087 | setfuncs(L, meta); | ||
1088 | |||
1089 | /* Create __index metamethods for context */ | ||
1090 | luaL_newlib(L, meta_index); | ||
1091 | lua_setfield(L, -2, "__index"); | ||
1092 | |||
1093 | lsec_load_curves(L); | ||
1094 | |||
1095 | /* Return the module */ | ||
1096 | luaL_newlib(L, funcs); | ||
1097 | |||
1098 | return 1; | ||
1099 | } | ||