luasec/src/ssl.lua

173 lines
4.3 KiB
Lua
Raw Normal View History

2012-09-02 16:15:49 +02:00
------------------------------------------------------------------------------
2014-01-29 21:43:33 +01:00
-- LuaSec 0.5
-- Copyright (C) 2006-2014 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
2013-03-30 13:21:40 +01:00
module("ssl", package.seeall)
2012-09-02 16:15:49 +02:00
2013-03-30 13:21:40 +01:00
_VERSION = "0.5.PR"
_COPYRIGHT = core.copyright()
2012-09-02 16:22:22 +02:00
2013-03-30 13:21:40 +01:00
-- Export
loadcertificate = x509.load
2012-09-02 16:15:49 +02:00
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
--
--
--
function newcontext(cfg)
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
end
if context.checkkey then
succ = context.checkkey(ctx)
if not succ then return nil, "private key does not match public key" 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
--
--
--
function wrap(sock, cfg)
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(core.invalidfd)
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)