This commit is contained in:
Thijs Schreijer 2015-03-08 16:24:44 +01:00
commit 9e93748671
8 changed files with 144 additions and 136 deletions

View File

@ -19,7 +19,8 @@ conn = ssl.wrap(conn, params)
-- Comment the lines to not send a name -- Comment the lines to not send a name
--conn:sni("servera.br") --conn:sni("servera.br")
conn:sni("serveraa.br") --conn:sni("serveraa.br")
conn:sni("serverb.br")
assert(conn:dohandshake()) assert(conn:dohandshake())
-- --

View File

@ -39,10 +39,12 @@ local conn = server:accept()
conn = ssl.wrap(conn, ctx01) conn = ssl.wrap(conn, ctx01)
-- Configure the name map -- Configure the name map
conn:sni({ local sni_map = {
["servera.br"] = ctx01, ["servera.br"] = ctx01,
["serveraa.br"] = ctx02, ["serveraa.br"] = ctx02,
}) }
conn:sni(sni_map, true)
assert(conn:dohandshake()) assert(conn:dohandshake())
-- --

View File

@ -14,7 +14,11 @@
#endif #endif
#if (LUA_VERSION_NUM == 501) #if (LUA_VERSION_NUM == 501)
#define lua_rawlen(L, i) lua_objlen(L, i) #define setfuncs(L, R) luaL_register(L, NULL, R)
#define lua_rawlen(L, i) lua_objlen(L, i)
#define luaL_newlib(L, R) do { lua_newtable(L); luaL_register(L, NULL, R); } while(0)
#else
#define setfuncs(L, R) luaL_setfuncs(L, R, 0)
#endif #endif
#endif #endif

View File

@ -429,7 +429,7 @@ static int set_cipher(lua_State *L)
static int set_depth(lua_State *L) static int set_depth(lua_State *L)
{ {
SSL_CTX *ctx = lsec_checkcontext(L, 1); SSL_CTX *ctx = lsec_checkcontext(L, 1);
SSL_CTX_set_verify_depth(ctx, luaL_checkint(L, 2)); SSL_CTX_set_verify_depth(ctx, (int)luaL_checkinteger(L, 2));
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;
} }
@ -723,39 +723,19 @@ int lsec_getmode(lua_State *L, int idx)
/** /**
* Registre the module. * Registre the module.
*/ */
#if (LUA_VERSION_NUM == 501)
LSEC_API int luaopen_ssl_context(lua_State *L) LSEC_API int luaopen_ssl_context(lua_State *L)
{ {
luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */ luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */
luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */ luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */
luaL_newmetatable(L, "SSL:Context"); luaL_newmetatable(L, "SSL:Context");
luaL_register(L, NULL, meta); setfuncs(L, meta);
/* Create __index metamethods for context */ /* Create __index metamethods for context */
lua_newtable(L); luaL_newlib(L, meta_index);
luaL_register(L, NULL, meta_index);
lua_setfield(L, -2, "__index");
/* Register the module */
luaL_register(L, "ssl.context", funcs);
return 1;
}
#else
LSEC_API int luaopen_ssl_context(lua_State *L)
{
luaL_newmetatable(L, "SSL:DH:Registry"); /* Keep all DH callbacks */
luaL_newmetatable(L, "SSL:Verify:Registry"); /* Keep all verify flags */
luaL_newmetatable(L, "SSL:Context");
luaL_setfuncs(L, meta, 0);
/* Create __index metamethods for context */
lua_newtable(L);
luaL_setfuncs(L, meta_index, 0);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
/* Return the module */ /* Return the module */
lua_newtable(L); luaL_newlib(L, funcs);
luaL_setfuncs(L, funcs, 0);
return 1; return 1;
} }
#endif

View File

@ -12,22 +12,18 @@ local ltn12 = require("ltn12")
local http = require("socket.http") local http = require("socket.http")
local url = require("socket.url") local url = require("socket.url")
local table = require("table") local try = socket.try
local string = require("string")
local try = socket.try --
local type = type -- Module
local pairs = pairs --
local getmetatable = getmetatable local _M = {
_VERSION = "0.5",
module("ssl.https") _COPYRIGHT = "LuaSec 0.5 - Copyright (C) 2009-2014 PUC-Rio",
PORT = 443,
_VERSION = "0.5" }
_COPYRIGHT = "LuaSec 0.5 - Copyright (C) 2009-2014 PUC-Rio"
-- Default settings
PORT = 443
-- TLS configuration
local cfg = { local cfg = {
protocol = "tlsv1", protocol = "tlsv1",
options = "all", options = "all",
@ -40,7 +36,7 @@ local cfg = {
-- Insert default HTTPS port. -- Insert default HTTPS port.
local function default_https_port(u) local function default_https_port(u)
return url.build(url.parse(u, {port = PORT})) return url.build(url.parse(u, {port = _M.PORT}))
end end
-- Convert an URL to a table according to Luasocket needs. -- Convert an URL to a table according to Luasocket needs.
@ -113,7 +109,7 @@ end
-- @param body optional (string) -- @param body optional (string)
-- @return (string if url == string or 1), code, headers, status -- @return (string if url == string or 1), code, headers, status
-- --
function request(url, body) local function request(url, body)
local result_table = {} local result_table = {}
local stringrequest = type(url) == "string" local stringrequest = type(url) == "string"
if stringrequest then if stringrequest then
@ -136,3 +132,11 @@ function request(url, body)
end end
return res, code, headers, status return res, code, headers, status
end end
--------------------------------------------------------------------------------
-- Export module
--
_M.request = request
return _M

105
src/ssl.c
View File

@ -330,7 +330,7 @@ static int meth_setfd(lua_State *L)
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_NEW) if (ssl->state != LSEC_STATE_NEW)
luaL_argerror(L, 1, "invalid SSL object state"); luaL_argerror(L, 1, "invalid SSL object state");
ssl->sock = luaL_checkint(L, 2); ssl->sock = (t_socket)luaL_checkinteger(L, 2);
socket_setnonblocking(&ssl->sock); socket_setnonblocking(&ssl->sock);
SSL_set_fd(ssl->ssl, (int)ssl->sock); SSL_set_fd(ssl->ssl, (int)ssl->sock);
return 0; return 0;
@ -400,24 +400,30 @@ static int meth_want(lua_State *L)
} }
return 1; return 1;
} }
/** /**
* Return the compression method used. * Return the compression method used.
*/ */
static int meth_compression(lua_State *L) static int meth_compression(lua_State *L)
{ {
#if !defined(OPENSSL_NO_COMP)
const COMP_METHOD *comp; const COMP_METHOD *comp;
#endif
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
if (ssl->state != LSEC_STATE_CONNECTED) { if (ssl->state != LSEC_STATE_CONNECTED) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, "closed"); lua_pushstring(L, "closed");
return 2; return 2;
} }
#if !defined(OPENSSL_NO_COMP)
comp = SSL_get_current_compression(ssl->ssl); comp = SSL_get_current_compression(ssl->ssl);
if (comp) if (comp)
lua_pushstring(L, SSL_COMP_get_name(comp)); lua_pushstring(L, SSL_COMP_get_name(comp));
else else
lua_pushnil(L); lua_pushnil(L);
#else
lua_pushnil(L);
#endif
return 1; return 1;
} }
@ -436,7 +442,7 @@ static int meth_getpeercertificate(lua_State *L)
return 2; return 2;
} }
/* Default to the first cert */ /* Default to the first cert */
n = luaL_optint(L, 2, 1); n = (int)luaL_optinteger(L, 2, 1);
/* This function is 1-based, but OpenSSL is 0-based */ /* This function is 1-based, but OpenSSL is 0-based */
--n; --n;
if (n < 0) { if (n < 0) {
@ -660,6 +666,7 @@ static int meth_info(lua_State *L)
static int sni_cb(SSL *ssl, int *ad, void *arg) static int sni_cb(SSL *ssl, int *ad, void *arg)
{ {
int strict;
SSL_CTX *newctx = NULL; SSL_CTX *newctx = NULL;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl); SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
lua_State *L = ((p_context)SSL_CTX_get_app_data(ctx))->L; lua_State *L = ((p_context)SSL_CTX_get_app_data(ctx))->L;
@ -667,41 +674,54 @@ static int sni_cb(SSL *ssl, int *ad, void *arg)
/* No name, use default context */ /* No name, use default context */
if (!name) if (!name)
return SSL_TLSEXT_ERR_NOACK; return SSL_TLSEXT_ERR_NOACK;
/* Search for the name in the map */ /* Retrieve struct from registry */
luaL_getmetatable(L, "SSL:SNI:Registry"); luaL_getmetatable(L, "SSL:SNI:Registry");
lua_pushlightuserdata(L, (void*)ssl); lua_pushlightuserdata(L, (void*)ssl);
lua_gettable(L, -2); lua_gettable(L, -2);
/* Strict search? */
lua_pushstring(L, "strict");
lua_gettable(L, -2);
strict = lua_toboolean(L, -1);
lua_pop(L, 1);
/* Search for the name in the map */
lua_pushstring(L, "map");
lua_gettable(L, -2);
lua_pushstring(L, name); lua_pushstring(L, name);
lua_gettable(L, -2); lua_gettable(L, -2);
if (lua_isuserdata(L, -1)) if (lua_isuserdata(L, -1))
newctx = lsec_checkcontext(L, -1); newctx = lsec_checkcontext(L, -1);
lua_pop(L, 3); lua_pop(L, 4);
/* Found, use this context */
if (newctx) { if (newctx) {
SSL_set_SSL_CTX(ssl, newctx); SSL_set_SSL_CTX(ssl, newctx);
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
/* Not found, but use initial context */
if (!strict)
return SSL_TLSEXT_ERR_OK;
return SSL_TLSEXT_ERR_ALERT_FATAL; return SSL_TLSEXT_ERR_ALERT_FATAL;
} }
static int meth_sni(lua_State *L) static int meth_sni(lua_State *L)
{ {
int strict;
SSL_CTX *aux; SSL_CTX *aux;
const char *name; const char *name;
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection"); p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl->ssl); SSL_CTX *ctx = SSL_get_SSL_CTX(ssl->ssl);
p_context pctx = (p_context)SSL_CTX_get_app_data(ctx); p_context pctx = (p_context)SSL_CTX_get_app_data(ctx);
switch (pctx->mode) { if (pctx->mode == LSEC_MODE_CLIENT) {
case LSEC_MODE_CLIENT:
name = luaL_checkstring(L, 2); name = luaL_checkstring(L, 2);
SSL_set_tlsext_host_name(ssl->ssl, name); SSL_set_tlsext_host_name(ssl->ssl, name);
break; return 0;
case LSEC_MODE_SERVER: } else if (pctx->mode == LSEC_MODE_SERVER) {
luaL_checktype(L, 2, LUA_TTABLE); luaL_checktype(L, 2, LUA_TTABLE);
strict = lua_toboolean(L, 3);
/* Check if the table contains only (string -> context) */ /* Check if the table contains only (string -> context) */
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 2)) { while (lua_next(L, 2)) {
luaL_checkstring(L, 3); luaL_checkstring(L, -2);
aux = lsec_checkcontext(L, 4); aux = lsec_checkcontext(L, -1);
/* Set callback in every context */ /* Set callback in every context */
SSL_CTX_set_tlsext_servername_callback(aux, sni_cb); SSL_CTX_set_tlsext_servername_callback(aux, sni_cb);
/* leave the next key on the stack */ /* leave the next key on the stack */
@ -710,15 +730,31 @@ static int meth_sni(lua_State *L)
/* Save table in the register */ /* Save table in the register */
luaL_getmetatable(L, "SSL:SNI:Registry"); luaL_getmetatable(L, "SSL:SNI:Registry");
lua_pushlightuserdata(L, (void*)ssl->ssl); lua_pushlightuserdata(L, (void*)ssl->ssl);
lua_newtable(L);
lua_pushstring(L, "map");
lua_pushvalue(L, 2); lua_pushvalue(L, 2);
lua_settable(L, -3); lua_settable(L, -3);
lua_pushstring(L, "strict");
lua_pushboolean(L, strict);
lua_settable(L, -3);
lua_settable(L, -3);
/* Set callback in the default context */ /* Set callback in the default context */
SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb); SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb);
break;
} }
return 0; return 0;
} }
static int meth_getsniname(lua_State *L)
{
p_ssl ssl = (p_ssl)luaL_checkudata(L, 1, "SSL:Connection");
const char *name = SSL_get_servername(ssl->ssl, TLSEXT_NAMETYPE_host_name);
if (name)
lua_pushstring(L, name);
else
lua_pushnil(L);
return 1;
}
static int meth_copyright(lua_State *L) static int meth_copyright(lua_State *L)
{ {
lua_pushstring(L, "LuaSec 0.5 - Copyright (C) 2006-2011 Bruno Silvestre" lua_pushstring(L, "LuaSec 0.5 - Copyright (C) 2006-2011 Bruno Silvestre"
@ -742,6 +778,7 @@ static luaL_Reg methods[] = {
{"getpeerchain", meth_getpeerchain}, {"getpeerchain", meth_getpeerchain},
{"getpeerverification", meth_getpeerverification}, {"getpeerverification", meth_getpeerverification},
{"getpeerfinished", meth_getpeerfinished}, {"getpeerfinished", meth_getpeerfinished},
{"getsniname", meth_getsniname},
{"getstats", meth_getstats}, {"getstats", meth_getstats},
{"setstats", meth_setstats}, {"setstats", meth_setstats},
{"dirty", meth_dirty}, {"dirty", meth_dirty},
@ -779,7 +816,6 @@ static luaL_Reg funcs[] = {
/** /**
* Initialize modules. * Initialize modules.
*/ */
#if (LUA_VERSION_NUM == 501)
LSEC_API int luaopen_ssl_core(lua_State *L) LSEC_API int luaopen_ssl_core(lua_State *L)
{ {
/* Initialize SSL */ /* Initialize SSL */
@ -799,49 +835,12 @@ LSEC_API int luaopen_ssl_core(lua_State *L)
/* Register the functions and tables */ /* Register the functions and tables */
luaL_newmetatable(L, "SSL:Connection"); luaL_newmetatable(L, "SSL:Connection");
luaL_register(L, NULL, meta); setfuncs(L, meta);
lua_newtable(L); luaL_newlib(L, methods);
luaL_register(L, NULL, methods);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_register(L, "ssl.core", funcs); luaL_newlib(L, funcs);
lua_pushnumber(L, SOCKET_INVALID);
lua_setfield(L, -2, "invalidfd");
return 1; return 1;
} }
#else
LSEC_API int luaopen_ssl_core(lua_State *L)
{
/* Initialize SSL */
if (!SSL_library_init()) {
lua_pushstring(L, "unable to initialize SSL library");
lua_error(L);
}
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
#if defined(WITH_LUASOCKET)
/* Initialize internal library */
socket_open();
#endif
luaL_newmetatable(L, "SSL:SNI:Registry");
/* Register the functions and tables */
luaL_newmetatable(L, "SSL:Connection");
luaL_setfuncs(L, meta, 0);
lua_newtable(L);
luaL_setfuncs(L, methods, 0);
lua_setfield(L, -2, "__index");
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
lua_pushnumber(L, SOCKET_INVALID);
lua_setfield(L, -2, "invalidfd");
return 1;
}
#endif

View File

@ -8,13 +8,7 @@ local core = require("ssl.core")
local context = require("ssl.context") local context = require("ssl.context")
local x509 = require("ssl.x509") local x509 = require("ssl.x509")
module("ssl", package.seeall) local unpack = table.unpack or unpack
_VERSION = "0.5"
_COPYRIGHT = core.copyright()
-- Export
loadcertificate = x509.load
-- We must prevent the contexts to be collected before the connections, -- We must prevent the contexts to be collected before the connections,
-- otherwise the C registry will be cleared. -- otherwise the C registry will be cleared.
@ -37,7 +31,7 @@ end
-- --
-- --
-- --
function newcontext(cfg) local function newcontext(cfg)
local succ, msg, ctx local succ, msg, ctx
-- Create the context -- Create the context
ctx, msg = context.create(cfg.protocol) ctx, msg = context.create(cfg.protocol)
@ -115,7 +109,7 @@ end
-- --
-- --
-- --
function wrap(sock, cfg) local function wrap(sock, cfg)
local ctx, msg local ctx, msg
if type(cfg) == "table" then if type(cfg) == "table" then
ctx, msg = newcontext(cfg) ctx, msg = newcontext(cfg)
@ -126,7 +120,7 @@ function wrap(sock, cfg)
local s, msg = core.create(ctx) local s, msg = core.create(ctx)
if s then if s then
core.setfd(s, sock:getfd()) core.setfd(s, sock:getfd())
sock:setfd(core.invalidfd) sock:setfd(-1)
registry[s] = ctx registry[s] = ctx
return s return s
end end
@ -170,3 +164,16 @@ end
-- --
core.setmethod("info", info) core.setmethod("info", info)
--------------------------------------------------------------------------------
-- Export module
--
local _M = {
_VERSION = "0.5",
_COPYRIGHT = core.copyright(),
loadcertificate = x509.load,
newcontext = newcontext,
wrap = wrap,
}
return _M

View File

@ -20,6 +20,11 @@
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
@ -88,8 +93,10 @@ static void push_asn1_string(lua_State* L, ASN1_STRING *string, int encode)
{ {
int len; int len;
unsigned char *data; unsigned char *data;
if (!string) if (!string) {
lua_pushnil(L); lua_pushnil(L);
return;
}
switch (encode) { switch (encode) {
case LSEC_AI5_STRING: case LSEC_AI5_STRING:
lua_pushlstring(L, (char*)ASN1_STRING_data(string), lua_pushlstring(L, (char*)ASN1_STRING_data(string),
@ -101,6 +108,8 @@ static void push_asn1_string(lua_State* L, ASN1_STRING *string, int encode)
lua_pushlstring(L, (char*)data, len); lua_pushlstring(L, (char*)data, len);
OPENSSL_free(data); OPENSSL_free(data);
} }
else
lua_pushnil(L);
} }
} }
@ -119,6 +128,31 @@ static int push_asn1_time(lua_State *L, ASN1_UTCTIME *tm)
return 1; return 1;
} }
/**
* Return a human readable IP address.
*/
static void push_asn1_ip(lua_State *L, ASN1_STRING *string)
{
unsigned char *ip = ASN1_STRING_data(string);
char dst[INET6_ADDRSTRLEN];
int typ;
switch(ASN1_STRING_length(string)) {
case 4:
typ = AF_INET;
break;
case 16:
typ = AF_INET6;
break;
default:
lua_pushnil(L);
return;
}
if(inet_ntop(typ, ip, dst, INET6_ADDRSTRLEN))
lua_pushstring(L, dst);
else
lua_pushnil(L);
}
/** /**
* *
*/ */
@ -258,7 +292,7 @@ int meth_extensions(lua_State* L)
case GEN_IPADD: case GEN_IPADD:
lua_pushstring(L, "iPAddress"); lua_pushstring(L, "iPAddress");
push_subtable(L, -2); push_subtable(L, -2);
push_asn1_string(L, general_name->d.iPAddress, px->encode); push_asn1_ip(L, general_name->d.iPAddress);
lua_rawseti(L, -2, lua_rawlen(L, -2)+1); lua_rawseti(L, -2, lua_rawlen(L, -2)+1);
lua_pop(L, 1); lua_pop(L, 1);
break; break;
@ -532,39 +566,16 @@ static luaL_Reg funcs[] = {
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
#if (LUA_VERSION_NUM == 501)
LSEC_API int luaopen_ssl_x509(lua_State *L) LSEC_API int luaopen_ssl_x509(lua_State *L)
{ {
/* Register the functions and tables */ /* Register the functions and tables */
luaL_newmetatable(L, "SSL:Certificate"); luaL_newmetatable(L, "SSL:Certificate");
luaL_register(L, NULL, meta); setfuncs(L, meta);
lua_newtable(L); luaL_newlib(L, methods);
luaL_register(L, NULL, methods);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
luaL_register(L, "ssl.x509", funcs); luaL_newlib(L, funcs);
return 1; return 1;
} }
#else
LSEC_API int luaopen_ssl_x509(lua_State *L)
{
/* Register the functions and tables */
luaL_newmetatable(L, "SSL:Certificate");
luaL_setfuncs(L, meta, 0);
lua_newtable(L);
luaL_setfuncs(L, methods, 0);
lua_setfield(L, -2, "__index");
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
return 1;
}
#endif