local require = require -- may be overloaded by regress.require local regress = { openssl = require"openssl", bignum = require"openssl.bignum", kdf = require"openssl.kdf", pkey = require"openssl.pkey", x509 = require"openssl.x509", name = require"openssl.x509.name", altname = require"openssl.x509.altname", store = require"openssl.x509.store", pack = table.pack or function (...) local t = { ... } t.n = select("#", ...) return t end, unpack = table.unpack or unpack, } local emit_progname = os.getenv"REGRESS_PROGNAME" or "regress" local emit_verbose = tonumber(os.getenv"REGRESS_VERBOSE" or 1) local emit_info = {} local emit_ll = 0 local function emit(fmt, ...) local msg = string.format(fmt, ...) for txt, nl in msg:gmatch("([^\n]*)(\n?)") do if emit_ll == 0 and #txt > 0 then io.stderr:write(emit_progname, ": ") emit_ll = #emit_progname + 2 end io.stderr:write(txt, nl) if nl == "\n" then emit_ll = 0 else emit_ll = emit_ll + #txt end end end -- emit local function emitln(fmt, ...) if emit_ll > 0 then emit"\n" end emit(fmt .. "\n", ...) end -- emitln local function emitinfo() for _, txt in ipairs(emit_info) do emitln("%s", txt) end end -- emitinfo function regress.say(...) emitln(...) end -- say function regress.panic(...) emitinfo() emitln(...) os.exit(1) end -- panic function regress.info(...) if emit_verbose > 1 then emitln(...) else emit_info[#emit_info + 1] = string.format(...) if emit_verbose > 0 then if emit_ll > 78 then emit"\n." else emit"." end end end end -- info function regress.check(v, ...) if v then return v, ... else regress.panic(...) end end -- check function regress.export(...) for _, pat in ipairs{ ... } do for k, v in pairs(regress) do if string.match(k, pat) then _G[k] = v end end end return regress end -- export function regress.require(modname) local ok, module = pcall(require, modname) regress.check(ok, "module %s required", modname) return module end -- regress.require local counter = 0 function regress.genkey(type, ca_key, ca_crt) local pkey = regress.require"openssl.pkey" local x509 = regress.require"openssl.x509" local name = regress.require"openssl.x509.name" local altname = regress.require"openssl.x509.altname" local key type = string.upper(type or "RSA") if type == "EC" then key = regress.check(pkey.new{ type = "EC", curve = "prime192v1" }) else key = regress.check(pkey.new{ type = type, bits = 1024 }) end local dn = name.new() dn:add("C", "US") dn:add("ST", "California") dn:add("L", "San Francisco") dn:add("O", "Acme, Inc.") dn:add("CN", string.format("acme%d.inc", counter)) counter = counter + 1 local alt = altname.new() alt:add("DNS", "acme.inc") alt:add("DNS", "localhost") local crt = x509.new() crt:setVersion(3) crt:setSerial(47) crt:setSubject(dn) crt:setIssuer((ca_crt or crt):getSubject()) crt:setSubjectAlt(alt) local issued, expires = crt:getLifetime() crt:setLifetime(issued, expires + 60) crt:setBasicConstraints{ CA = true, pathLen = 2 } crt:setBasicConstraintsCritical(true) crt:setPublicKey(key) crt:sign(ca_key or key) return key, crt end -- regress.genkey local function getsubtable(t, name, ...) name = name or false -- cannot be nil if not t[name] then t[name] = {} end if select('#', ...) > 0 then return getsubtable(t[name], ...) else return t[name] end end -- getsubtable function regress.newsslctx(protocol, accept, keytype) local context = regress.require"openssl.ssl.context" local ctx = context.new(protocol, accept) if keytype or keytype == nil then local key, crt = regress.genkey(keytype) ctx:setCertificate(crt) ctx:setPrivateKey(key) end return ctx end -- require.newsslctx local ctxcache = {} function regress.getsslctx(protocol, accept, keytype) local keycache = getsubtable(ctxcache, protocol, accept) if keytype == nil then keytype = "RSA" end local ctx = keycache[keytype] if not ctx then ctx = regress.newsslctx(protocol, accept, keytype) keycache[keytype] = ctx end return ctx end -- regress.getsslctx return regress