luasec/src/ssl.lua

180 lines
4.6 KiB
Lua
Raw Normal View History

2012-09-02 16:15:49 +02:00
------------------------------------------------------------------------------
2015-08-21 16:21:16 +02:00
-- LuaSec 0.6a
-- Copyright (C) 2006-2015 Bruno Silvestre
2012-09-02 16:15:49 +02:00
--
------------------------------------------------------------------------------
2013-03-30 13:21:40 +01:00
local core = require("ssl.core")
local context = require("ssl.context")
local x509 = require("ssl.x509")
2012-09-02 16:15:49 +02:00
2015-02-12 19:29:02 +01:00
local unpack = table.unpack or unpack
2013-03-30 13:21:40 +01:00
-- We must prevent the contexts to be collected before the connections,
-- otherwise the C registry will be cleared.
local registry = setmetatable({}, {__mode="k"})
2012-09-02 16:22:22 +02:00
2012-09-02 16:15:49 +02:00
--
--
--
local function optexec(func, param, ctx)
if param then
if type(param) == "table" then
return func(ctx, unpack(param))
else
return func(ctx, param)
end
end
return true
end
--
--
--
2015-02-06 21:07:29 +01:00
local function newcontext(cfg)
2012-09-02 16:15:49 +02:00
local succ, msg, ctx
-- Create the context
ctx, msg = context.create(cfg.protocol)
if not ctx then return nil, msg end
-- Mode
succ, msg = context.setmode(ctx, cfg.mode)
if not succ then return nil, msg end
-- Load the key
2012-09-02 16:22:22 +02:00
if cfg.key then
2013-03-30 13:21:40 +01:00
if cfg.password and
type(cfg.password) ~= "function" and
type(cfg.password) ~= "string"
then
return nil, "invalid password type"
end
2012-09-02 16:22:22 +02:00
succ, msg = context.loadkey(ctx, cfg.key, cfg.password)
if not succ then return nil, msg end
end
2012-09-02 16:15:49 +02:00
-- Load the certificate
2012-09-02 16:22:22 +02:00
if cfg.certificate then
succ, msg = context.loadcert(ctx, cfg.certificate)
if not succ then return nil, msg end
if cfg.key and context.checkkey then
succ = context.checkkey(ctx)
if not succ then return nil, "private key does not match public key" end
end
end
2012-09-02 16:15:49 +02:00
-- Load the CA certificates
if cfg.cafile or cfg.capath then
succ, msg = context.locations(ctx, cfg.cafile, cfg.capath)
if not succ then return nil, msg end
end
2013-03-30 13:21:40 +01:00
-- Set SSL ciphers
if cfg.ciphers then
succ, msg = context.setcipher(ctx, cfg.ciphers)
if not succ then return nil, msg end
end
2012-09-02 16:15:49 +02:00
-- Set the verification options
succ, msg = optexec(context.setverify, cfg.verify, ctx)
if not succ then return nil, msg end
-- Set SSL options
succ, msg = optexec(context.setoptions, cfg.options, ctx)
if not succ then return nil, msg end
-- Set the depth for certificate verification
if cfg.depth then
succ, msg = context.setdepth(ctx, cfg.depth)
if not succ then return nil, msg end
end
-- NOTE: Setting DH parameters and elliptic curves needs to come after
-- setoptions(), in case the user has specified the single_{dh,ecdh}_use
-- options.
2013-03-30 13:21:40 +01:00
-- Set DH parameters
if cfg.dhparam then
if type(cfg.dhparam) ~= "function" then
return nil, "invalid DH parameter type"
end
context.setdhparam(ctx, cfg.dhparam)
end
-- Set elliptic curve
if cfg.curve then
succ, msg = context.setcurve(ctx, cfg.curve)
if not succ then return nil, msg end
end
-- Set extra verification options
if cfg.verifyext and ctx.setverifyext then
succ, msg = optexec(ctx.setverifyext, cfg.verifyext, ctx)
if not succ then return nil, msg end
end
2012-09-02 16:15:49 +02:00
return ctx
end
--
--
--
2015-02-06 21:07:29 +01:00
local function wrap(sock, cfg)
2012-09-02 16:15:49 +02:00
local ctx, msg
if type(cfg) == "table" then
ctx, msg = newcontext(cfg)
if not ctx then return nil, msg end
else
ctx = cfg
end
local s, msg = core.create(ctx)
if s then
core.setfd(s, sock:getfd())
sock:setfd(-1)
2013-03-30 13:21:40 +01:00
registry[s] = ctx
2012-09-02 16:15:49 +02:00
return s
end
return nil, msg
end
2013-03-30 13:21:40 +01:00
--
-- Extract connection information.
--
local function info(ssl, field)
local str, comp, err, protocol
2013-03-30 13:21:40 +01:00
comp, err = core.compression(ssl)
if err then
return comp, err
end
-- Avoid parser
if field == "compression" then
return comp
end
local info = {compression = comp}
str, info.bits, info.algbits, protocol = core.info(ssl)
2013-03-30 13:21:40 +01:00
if str then
info.cipher, info.protocol, info.key,
info.authentication, info.encryption, info.mac =
string.match(str,
"^(%S+)%s+(%S+)%s+Kx=(%S+)%s+Au=(%S+)%s+Enc=(%S+)%s+Mac=(%S+)")
info.export = (string.match(str, "%sexport%s*$") ~= nil)
end
if protocol then
info.protocol = protocol
end
2013-03-30 13:21:40 +01:00
if field then
return info[field]
end
-- Empty?
return ( (next(info)) and info )
end
--
-- Set method for SSL connections.
--
core.setmethod("info", info)
2015-02-06 21:07:29 +01:00
--------------------------------------------------------------------------------
-- Export module
--
local _M = {
2015-08-21 16:21:16 +02:00
_VERSION = "0.6a",
2015-02-06 21:07:29 +01:00
_COPYRIGHT = core.copyright(),
loadcertificate = x509.load,
newcontext = newcontext,
wrap = wrap,
}
return _M