module(..., package.seeall)
require("html")
require("validator")
-- There are two options of how to allow users to specify the type of certificate they want - the request extensions
-- and the ca signing extensions. We have opted for making all requests look the same (same extensions) and defining
-- different ca sections for the different types of certificates. The ca section to use when signing the request is
-- actually stored in the request filename. The request filename is in the following format:
-- 'username'.'ca section name'.'common name'.csr
local packagename = "openssl"
--local configfile = "/etc/ssl/openssl.cnf"
local configfile = "/etc/ssl/openssl-ca-acf.cnf"
local requestdir = "/etc/ssl/req/"
local certdir = "/etc/ssl/cert/"
local openssldir = "/etc/ssl/"
-- Save the config in a variable so isn't loaded each and every time needed
local config = nil
-- list of request entries that can be edited
local distinguished_names = { {name="countryName", label="Country Name", short="C"},
{name="stateOrProvinceName", label="State Or Province Name", short="ST"},
{name="localityName", label="Locality Name", short="L"},
{name="organizationName", label="Organization Name", short="O"},
{name="organizationalUnitName", label="Organizational Unit Name", short="OU"},
{name="commonName", label="Common Name", short="CN"},
{name="emailAddress", label="e-mail Address"} }
-- list of entries that may be found in cert extensions section
local extensions = { "basicConstraints", "nsCertType", "nsComment", "keyUsage", "subjectKeyIdentifier",
"authorityKeyIdentifier", "subjectAltName", "issuerAltName" }
-- list of entries that must be found in ca section
local ca_mandatory_entries = { "new_certs_dir", "certificate", "private_key", "default_md", "database", "serial", "policy" }
-- Create a cfe with the distinguished name defaults
local getdefaults = function()
local defaults = cfe({ type="group", value={} })
config = config or getopts.getoptsfromfile(configfile)
local distinguished_name = config.req.distinguished_name or ""
-- Get the distinguished name defaults
for i, name in ipairs(distinguished_names) do
defaults.value[name.name] = cfe({ label=name.label,
value=config[distinguished_name][name.name .. "_default"]
or config[distinguished_name]["0."..name.name.."_default"] or "",
descr=config[distinguished_name][name.name] or config[distinguished_name]["0."..name.name] })
if defaults.value[name.name].value == "" and name.short then
defaults.value[name.name].value = config[distinguished_name][name.short .. "_default"] or ""
end
end
return defaults
end
-- Validate the values of distinguished names using the min/max found in the config file
local validate_distinguished_names = function(values)
config = config or getopts.getoptsfromfile(configfile)
local distinguished_name = config.req.distinguished_name or ""
local success = true
for i, name in ipairs(distinguished_names) do
if string.find(values.value[name.name].value, "[,/'=]") then
values.value[name.name].errtxt = "Value cannot contain =/,'"
success = false
end
-- check min, but empty is allowed
local min = config[distinguished_name][name.name.."_min"] or config[distinguished_name]["0."..name.name.."_min"]
if min and values.value[name.name] and #values.value[name.name].value < tonumber(min) and #values.value[name.name].value > 0 then
values.value[name.name].errtxt = "Value too short"
success = false
end
local max = config[distinguished_name][name.name.."_max"] or config[distinguished_name]["0."..name.name.."_max"]
if max and values.value[name.name] and #values.value[name.name].value > tonumber(max) then
values.value[name.name].errtxt = "Value too long"
success = false
end
end
return success, values
end
-- Write distinguished name defaults to config file
local write_distinguished_names = function(values)
local file = fs.read_file(configfile)
config = config or getopts.getoptsfromfile(file)
local distinguished_name = config.req.distinguished_name or ""
for i,name in ipairs(distinguished_names) do
wname = name.name.."_default"
if config[distinguished_name]["0."..name.name] then
wname = "0."..wname
end
if values.value[name.name] then
local a,b,c
a,b,c, file = getopts.setoptsinfile(file, distinguished_name, wname, values.value[name.name].value)
end
end
fs.write_file(configfile, file)
config = getopts.getoptsfromfile(file)
end
local create_subject_string = function(values)
local outstr = {}
for i,name in ipairs(distinguished_names) do
if values.value[name.name].value ~= "" then
outstr[#outstr + 1] = (name.short or name.name) .. "=" .. values.value[name.name].value
end
end
return "/"..table.concat(outstr, "/")
end
local getconfigentry = function(section, value)
config = config or getopts.getoptsfromfile(configfile)
local result = config[section][value] or config[""][value] or ""
while string.find(result, "%$[%w_]+") do
local sub = string.match(result, "%$[%w_]+")
result = string.gsub(result, sub, config[section][string.sub(sub,2)] or config[""][string.sub(sub,2)] or "")
end
return result
end
-- Find the sections of the config file that define ca's (ca -name option)
local find_ca_sections = function()
config = config or getopts.getoptsfromfile(configfile)
local cert_types = {}
for section in pairs(config) do
local success = true
for i,entry in ipairs(ca_mandatory_entries) do
if getconfigentry(section,entry) == "" then
success = false
break
end
end
if success then
cert_types[#cert_types + 1] = section
end
end
return cert_types
end
local validate_request = function(defaults)
local success
success, defaults = validate_distinguished_names(defaults)
if defaults.value.certtype then
local foundcert=false
for i,cert in ipairs(defaults.value.certtype.option) do
if defaults.value.certtype.value == cert then
foundcert=true
break
end
end
if not foundcert then
success = false
defaults.value.certtype.errtxt = "Invalid certificate type"
end
end
return success, defaults
end
local copyca = function(cacert, cakey)
config = config or getopts.getoptsfromfile(configfile)
local certpath = getconfigentry(config.ca.default_ca, "certificate")
local cmd = "cp "..cacert.." "..certpath
local f = io.popen(cmd)
f:close()
local keypath = getconfigentry(config.ca.default_ca, "private_key")
local cmd = "cp "..cakey.." "..keypath
local f = io.popen(cmd)
f:close()
end
local checkdir = function(name, path)
local errtxt, cmdline
local filestats = posix.stat(path, "type")
if not filestats or filestats == "" then
errtxt = name.." does not exist"
cmdline = "mkdir -p "..path
elseif filestats ~= "directory" then
errtxt = "UNRECOVERABLE - "..name.." not a directory"
end
return errtxt, cmdline
end
local checkfile = function(name, path, default)
local errtxt, cmdline
local filestats = posix.stat(path, "type")
if not filestats or filestats == "" then
errtxt = name.." does not exist"
if default then
cmdline = "echo "..default.." > "..path
else
cmdline = "touch "..path
end
elseif filestats ~= "regular" then
errtxt = "UNRECOVERABLE - "..name.." not a file"
end
return errtxt, cmdline
end
local hashname = function(name)
local hash = {name:byte(1,-1)}
return table.concat(hash, "-")
end
local unhashname = function(hashstring)
local hash = {}
for char in string.gmatch(hashstring, "([^-]+)-*") do
hash[#hash+1] = char
end
return string.char(unpack(hash))
end
getstatus = function()
require("processinfo")
-- set the working directory once for model
posix.chdir(openssldir)
local value,errtxt=processinfo.package_version(packagename)
local version = cfe({ value=value, errtxt=errtxt, label="Program version" })
local conffile = cfe({ value=configfile, label="Configuration file" })
local cacert = cfe({ label="CA Certificate" })
local cacertcontents = cfe({ type="longtext", label="CA Certificate contents" })
local cakey = cfe({ label="CA Key" })
if not fs.is_file(configfile) then
conffile.errtxt="File not found"
cacert.errtxt="File not defined"
cacertcontents.errtxt=""
cakey.errtxt="File not defined"
else
config = config or getopts.getoptsfromfile(configfile)
if (not config) or (not config.ca) or (not config.ca.default_ca) then
conffile.errtxt="Invalid config file"
cacert.errtxt="File not defined"
cacertcontents.errtxt=""
cakey.errtxt="File not defined"
else
cacert.value = getconfigentry(config.ca.default_ca, "certificate")
if not fs.is_file(cacert.value) then
cacert.errtxt="File not found"
else
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl x509 -in "..cacert.value.." -noout -text"
local f = io.popen(cmd)
cacertcontents.value = f:read("*a")
f:close()
local enddate = string.match(cacertcontents.value, "Not After : (.*)")
local month, day, year = string.match(enddate, "(%a+)%s+(%d+)%s+%S+%s+(%d+)")
local reversemonth = {Jan=1,Feb=2,Mar=3,Apr=4,May=5,Jun=6,Jul=7,Aug=8,Sep=9,Oct=10,Nov=11,Dec=12}
local time = os.time({year=year, month=reversemonth[month], day=day})
if os.time() > time then
time = 0
cacert.errtxt="Certificate expired"
else
time = (time-os.time())/86400
end
cacert.daysremaining=time
end
cakey.value = getconfigentry(config.ca.default_ca, "private_key")
if not fs.is_file(cakey.value) then
cakey.errtxt="File not found"
end
end
end
local environment = checkenvironment()
return cfe({ type="group", value={version=version, conffile=conffile, environment=environment, cacert=cacert, cacertcontents=cacertcontents, cakey=cakey}, label="openssl status" })
end
getreqdefaults = function()
local defaults = getdefaults()
-- Add in the ca type default
defaults.value.certtype = cfe({ type="select", label="Certificate Type",
value=config.ca.default_ca, option=find_ca_sections() })
return defaults
end
setreqdefaults = function(defaults)
local success, defaults = validate_request(defaults)
-- If success, write the values to the config file
if success then
getopts.setoptsinfile(configfile, "ca", "default_ca", defaults.value.certtype.value)
config = nil
write_distinguished_names(defaults)
end
if not success then
defaults.errtxt = "Failed to set defaults"
end
return defaults
end
getnewrequest = function()
local values = getreqdefaults()
-- In addition to the request defaults, we need a password and confirmation
values.value.password = cfe({ label="Password" })
values.value.password_confirm = cfe({ label="Password confirmation" })
return values
end
submitrequest = function(defaults, user)
local success, defaults = validate_request(defaults)
-- Must have a common name
if #defaults.value.commonName.value == 0 then
defaults.value.commonName.errtxt = "Common Name cannot be blank"
success = false
end
-- Check validity of password
if #defaults.value.password.value < 4 then
defaults.value.password.errtxt = "Password too short"
success = false
end
if defaults.value.password.value ~= defaults.value.password_confirm.value then
defaults.value.password_confirm.errtxt = "You entered wrong password/confirmation"
success = false
end
local reqname = requestdir..user.."."..defaults.value.certtype.value.."."..hashname(defaults.value.commonName.value)
if fs.is_file(reqname..".csr") then
defaults.errtxt = "Failed to submit request\nRequest already exists"
success = false
end
if success then
-- Submit the request
local subject = create_subject_string(defaults)
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl req -nodes -new -config "..configfile.." -keyout "..reqname..".pem -out "..reqname..".csr -subj '"..subject.."' 2>&1"
local f = io.popen(cmd)
local cmdresult = f:read("*a")
f:close()
defaults.descr = cmdresult
local certfilestats = posix.stat(reqname..".csr")
local keyfilestats = posix.stat(reqname..".pem")
if not certfilestats or certfilestats.size == 0 or not keyfilestats or keyfilestats.size == 0 then
success = false
cmd = "rm "..reqname..".*"
f = io.popen(cmd)
f:close()
else
fs.write_file(reqname..".pwd", defaults.value.password.value)
end
end
if not success and not defaults.errtxt then
defaults.errtxt = "Failed to submit request"
end
return defaults
end
listrequests = function(user)
user = user or "*"
local list={}
local fh = io.popen("find " .. requestdir .. " -name "..user..".*.csr -maxdepth 1")
for x in fh:lines() do
local name = basename(x,".csr")
local a,b,c = string.match(name, "([^%.]*)%.([^%.]*)%.([^%.]*)")
list[#list + 1] = {name=name, user=a, certtype=b, commonName=unhashname(c)}
end
return cfe({ type="list", value=list, label="List of pending requests" })
end
viewrequest = function(request)
local path = requestdir .. request
local cmd = "openssl req -in "..path..".csr -text -noout"
local f = io.popen(cmd)
local cmdresult = f:read("*a")
f:close()
local a,b,c = string.match(request, "([^%.]*)%.([^%.]*)%.([^%.]*)")
local request = cfe({ type="table", value={name=name, user=a, certtype=b, commonName=c, value=cmdresult}, label="Request" })
return request
end
approverequest = function(request)
local cmdresult = cfe({ value="Failed to approve request", label="Approve result" })
local path = requestdir .. request
if fs.is_file(path..".csr") then
-- Request file exists, so try to sign
local user,certtype,commonName = string.match(request, "([^%.]*)%.([^%.]*)%.([^%.]*)")
-- Add the serial number to the end of the cert file name
local serialpath = getconfigentry(certtype, "serial")
local serialfile = fs.read_file(openssldir..serialpath)
local serial = string.match(serialfile, "%x%x")
local certname = certdir..request.."."..serial
-- Now, sign the certificate
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl ca -config "..configfile.." -in "..path..".csr -out "..certname..".crt -name "..certtype.." -batch 2>&1"
local f = io.popen(cmd)
cmdresult.value = f:read("*a")
f:close()
-- If certificate created, create the wrapped up pkcs12
local filestats = posix.stat(certname..".crt")
if filestats and filestats.size > 0 then
-- We're wrapping up the key, the cert, and the CA cert (and whatever came with it)
cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl pkcs12 -export -inkey "..path..".pem -in "..certname..".crt -out "..certname..".pfx -passout file:"..path..".pwd -certfile "..getconfigentry(certtype, "certificate").." 2>&1"
f = io.popen(cmd)
local newcmdresult = f:read("*a")
f:close()
cmdresult.value = cmdresult.value .. newcmdresult
end
-- Finally, remove the request
filestats = posix.stat(certname..".pfx")
if filestats and filestats.size > 0 then
cmd = "cp "..path..".pwd "..certname..".pwd"
f = io.popen(cmd)
f:close()
cmd = "cp "..path..".pem "..certname..".pem"
f = io.popen(cmd)
f:close()
cmd = "rm "..path..".*"
f = io.popen(cmd)
f:close()
else
-- or failed, remove the cert
cmd = "rm "..certname..".*"
f = io.popen(cmd)
f:close()
end
end
return cmdresult
end
deleterequest = function(request, user)
user = user or ".*"
if (not fs.is_file(requestdir..request..".csr")) or (not string.find(request, "^"..user.."%.")) then
return cfe({ value="Request not found", label="Delete result" })
end
cmd = "rm "..requestdir..request..".*"
f = io.popen(cmd)
f:close()
return cfe({ value="Request deleted", label="Delete result" })
end
listcerts = function(user)
user = user or "*"
local list={}
local fh = io.popen("find " .. certdir .. " -name "..user..".*.pfx -maxdepth 1")
for x in fh:lines() do
local name = basename(x,".pfx")
local a,b,c,d = string.match(name, "([^%.]*)%.([^%.]*)%.([^%.]*).([^%.]*)")
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl x509 -in "..certdir..name..".crt -noout -enddate"
local f = io.popen(cmd)
local enddate = f:read("*a")
enddate = string.match(enddate, "notAfter=(.*)")
f:close()
local month, day, year = string.match(enddate, "(%a+)%s+(%d+)%s+%S+%s+(%d+)")
local reversemonth = {Jan=1,Feb=2,Mar=3,Apr=4,May=5,Jun=6,Jul=7,Aug=8,Sep=9,Oct=10,Nov=11,Dec=12}
local time = os.time({year=year, month=reversemonth[month], day=day})
if os.time() > time then
time = 0
else
time = (time-os.time())/86400
end
list[#list + 1] = {name=name, user=a, certtype=b, commonName=unhashname(c), serial=d, enddate=enddate, daysremaining=time}
end
fh:close()
return cfe({ type="list", value=list, label="List of approved certificates" })
end
viewcert = function(cert)
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl x509 -in "..certdir..cert..".crt -noout -text"
local f = io.popen(cmd)
local cmdresult = f:read("*a")
f:close()
local a,b,c,d = string.match(cert, "([^%.]*)%.([^%.]*)%.([^%.]*).([^%.]*)")
return cfe({ type="table", value={name=name, user=a, certtype=b, commonName=c, serial=d, value=cmdresult}, label="Certificate" })
end
getcert = function(cert)
local f = fs.read_file(certdir..cert..".pfx")
return cfe({ type="raw", value=f, label=cert..".pfx", option="application/x-pkcs12" })
end
revokecert = function(cert)
local cmdresult = cfe({ label="Revoke result" })
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl ca -config "..configfile.." -revoke "..certdir .. cert..".crt -batch 2>&1"
local f = io.popen(cmd)
cmdresult.value = f:read("*a")
f:close()
return cmdresult
end
deletecert = function(cert)
-- The certificate will still be in the ca directories and index.txt, just not available for web interface
cmd = "rm "..certdir..cert..".*"
f = io.popen(cmd)
f:close()
return cfe({ value="Certificate deleted", label="Delete result" })
end
renewcert = function(cert, approve)
local cmdresult = ""
local success = true
local user,certtype,commonName,serialnum = string.match(cert, "([^%.]*)%.([^%.]*)%.([^%.]*).([^%.]*)")
local reqname = requestdir..user.."."..certtype.."."..commonName
if fs.is_file(reqname..".csr") then
cmdresult = "Failed to submit request\nRequest already exists"
success = false
end
if success then
-- Submit the request
-- First, get the subject
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl x509 -in "..certdir..cert..".crt -noout -subject"
local f = io.popen(cmd)
local subject = f:read("*a")
subject = string.match(subject, "subject= ([^\n]*)")
f:close()
-- Next, put the key and password in place
cmd = "cp "..certdir..cert..".pwd "..reqname..".pwd"
f = io.popen(cmd)
f:close()
cmd = "cp "..certdir..cert..".pem "..reqname..".pem"
f = io.popen(cmd)
f:close()
-- Next, submit the request
cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl req -new -config "..configfile.." -key "..reqname..".pem -out "..reqname..".csr -subj '"..subject.."' 2>&1"
f = io.popen(cmd)
cmdresult = f:read("*a")
f:close()
local filestats = posix.stat(reqname..".csr")
if not filestats or filestats.size == 0 then
cmdresult = "Failed to submit request\n"..cmdresult
success = false
cmd = "rm "..reqname..".*"
f = io.popen(cmd)
f:close()
else
cmdresult = "Submitted request"
end
end
if success and approve then
approverequest(basename(reqname))
end
return cfe({ type="boolean", value=cmdresult, label="Renew result" })
end
listrevoked = function()
config = config or getopts.getoptsfromfile(configfile)
local databasepath = getconfigentry(config.ca.default_ca, "database")
local revoked = {}
local database = fs.read_file_as_array(databasepath)
for x,line in ipairs(database) do
if string.sub(line,1,1) == "R" then
revoked[#revoked + 1] = string.match(line, "^%S+%s+%S+%s+%S+%s+(%S+)")
end
end
return cfe({ type="list", value=revoked, label="Revoked serial numbers" })
end
getcrl = function(crltype)
local crlfile = cfe({ type="raw", label="Revoke list", option="application/pkix-crl" })
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl ca -config "..configfile.." -gencrl -out "..openssldir.."ca-crl.crl"
local f = io.popen(cmd)
f:close()
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl crl -in "..openssldir.."ca-crl.crl -out "..openssldir.."ca-der-crl.crl -outform DER"
local f = io.popen(cmd)
f:close()
if crltype == "DER" then
crlfile.label = "ca-der-crl.crl"
crlfile.value = fs.read_file(crlfile.label)
elseif crltype == "PEM" then
crlfile.label = "ca-crl.crl"
crlfile.value = fs.read_file(crlfile.label)
else
crlfile.value = fs.read_file("ca-crl.crl")
end
return crlfile
end
putca = function(file, pword, set)
local ca = cfe({ type="raw", value=0, label="CA Certificate", descr='File must be a password protected ".pfx" file' })
local password = cfe({ label="Certificate Password" })
local retval = cfe({ type="group", value={ca=ca, password=password} })
if file and pword and set then
local success = true
-- Trying to upload a cert/key
-- The way haserl works, file contains the temporary file name
-- First, get the cert
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl pkcs12 -in "..file.." -out "..file.."cert.pem -password pass:"..pword.." -nokeys 2>&1"
local f = io.popen(cmd)
local cmdresult = f:read("*a")
f:close()
local filestats = posix.stat(file.."cert.pem")
if not filestats or filestats.size == 0 then
ca.errtxt = "Could not open certificate\n"..cmdresult
success = false
end
-- Since -cacerts doesn't seem to work, we have to check to make sure we got a CA
if success then
cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl x509 -in "..file.."cert.pem -noout -text"
f = io.popen(cmd)
cmdresult = f:read("*a")
f:close()
if not string.find(cmdresult, "CA:TRUE") then
ca.errtxt = "Could not find CA Certificate"
success = false
end
end
-- Now, get the key
if success then
cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl pkcs12 -in "..file.." -out "..file.."key.pem -password pass:"..pword.." -nocerts -nodes 2>&1"
f = io.popen(cmd)
cmdresult = f:read("*a")
f:close()
filestats = posix.stat(file.."key.pem")
if not filestats or filestats.size == 0 then
ca.errtxt = "Could not find CA key\n"..cmdresult
success = false
end
end
if success then
-- copy the keys
copyca(file.."cert.pem", file.."key.pem")
else
retval.errtxt = "Failed to upload CA certificate"
end
-- Delete the temporary files
cmd = "rm "..file.."*"
f = io.popen(cmd)
f:close()
end
return retval
end
getnewcarequest = function()
request = getdefaults()
-- In addition to the distinguished name defaults, we need days
request.value.days = cfe({ value="365", label="Number of days to certify" })
return request
end
generateca = function(defaults)
local success, defaults = validate_request(defaults)
if not validator.is_integer(defaults.value.days.value) then
defaults.value.days.errtxt = "Must be a number"
success = false
end
if success then
-- Submit the request
local subject = create_subject_string(defaults)
local cmd = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin openssl req -x509 -nodes -new -config "..configfile.." -keyout /tmp/cakey.pem -out /tmp/cacert.pem -subj '"..subject.."' -days "..defaults.value.days.value.." 2>&1"
local f = io.popen(cmd)
local cmdresult = f:read("*a")
f:close()
local certfilestats = posix.stat("/tmp/cacert.pem")
local keyfilestats = posix.stat("/tmp/cakey.pem")
if not certfilestats or certfilestats.size == 0 or not keyfilestats or keyfilestats.size == 0 then
defaults.errtxt = "Failed to generate CA certificate\n"..cmdresult
success = false
end
if success then
-- copy the keys
copyca("/tmp/cacert.pem", "/tmp/cakey.pem")
end
-- Delete the temporary files
cmd = "rm /tmp/ca*.pem"
f = io.popen(cmd)
f:close()
end
if not success and not defaults.errtxt then
defaults.errtxt = "Failed to generate CA certificate"
end
return defaults
end
getconfigfile = function()
local filename = cfe({ value=configfile, label="File Name" })
local filecontent = cfe({ type="longtext", label="Config file" })
local filesize = cfe({ value="0", label="File size" })
local mtime = cfe({ value="---", label="File date" })
if fs.is_file(configfile) then
local filedetails = fs.stat(configfile)
filecontent.value=fs.read_file(configfile)
filesize.value = filedetails.size
mtime.value = filedetails.mtime
else
filename.errtxt = "File not found"
end
return cfe({ type="group", value={filename=filename, filecontent=filecontent, filesize=filesize, mtime=mtime}, label="Config file details" })
end
setconfigfile = function(file)
if file and type(file)=="string" and #file>0 then
fs.write_file(configfile, file)
config = nil
return true
end
return false
end
checkenvironment = function(set)
local errtxt = {}
local cmdline = {}
-- First check for the openssl, req, and cert directories
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("openssl directory", openssldir)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("new certificate directory", certdir)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("request directory", requestdir)
-- Then check for the config file entries
config = config or getopts.getoptsfromfile(configfile)
if config then
local path = getconfigentry(config.ca.default_ca, "new_certs_dir")
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("new_certs_dir", path)
local file = getconfigentry(config.ca.default_ca, "certificate")
path = dirname(file)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("certificate directory", path)
file = getconfigentry(config.ca.default_ca, "private_key")
path = dirname(file)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("private_key directory", path)
file = getconfigentry(config.ca.default_ca, "database")
path = dirname(file)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("database directory", path)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkfile("database", file)
file = getconfigentry(config.ca.default_ca, "serial")
path = dirname(file)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("serial directory", path)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkfile("serial", file, "01")
file = getconfigentry(config.ca.default_ca, "crlnumber")
if file ~= "" then
path = dirname(file)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkdir("crlnumber directory", path)
errtxt[#errtxt+1], cmdline[#cmdline+1] = checkfile("crlnumber", file, "01")
end
else
errtxt[#errtxt+1] = "Configuration invalid"
end
if set then
-- loop through the cmdline and execute
for x,cmd in ipairs(cmdline) do
local f = io.popen(cmd)
f:close()
end
return checkenvironment()
else
errtxt = table.concat(errtxt, '\n')
local value
if errtxt == "" then
errtxt = nil
value = "Environment ready"
else
value = "Environment not ready"
end
return cfe({ value=value, errtxt=errtxt, label="Environment" })
end
end