summaryrefslogtreecommitdiffstats
path: root/openssl-model.lua
diff options
context:
space:
mode:
authorTed Trask <ttrask01@yahoo.com>2008-05-20 20:56:05 +0000
committerTed Trask <ttrask01@yahoo.com>2008-05-20 20:56:05 +0000
commitf67066bd64784cb5182d6ded1847bcdd09a77d32 (patch)
treec332c805622794c407a8b0d09fb21f774f086497 /openssl-model.lua
parentaf360b084b8b5c787a0141cba65191d13e2a4aa4 (diff)
downloadacf-openssl-f67066bd64784cb5182d6ded1847bcdd09a77d32.tar.bz2
acf-openssl-f67066bd64784cb5182d6ded1847bcdd09a77d32.tar.xz
Continuing to work on openssl. Not done yet.
git-svn-id: svn://svn.alpinelinux.org/acf/openssl/trunk@1127 ab2d0c66-481e-0410-8bed-d214d4d58bed
Diffstat (limited to 'openssl-model.lua')
-rw-r--r--openssl-model.lua232
1 files changed, 218 insertions, 14 deletions
diff --git a/openssl-model.lua b/openssl-model.lua
index bbb5f60..a80ade4 100644
--- a/openssl-model.lua
+++ b/openssl-model.lua
@@ -1,36 +1,240 @@
module(..., package.seeall)
+require("html")
+
+-- 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 configfile = "/etc/ssl/openssl.cnf"
+local requestdir = "/etc/ssl/req/"
-- list of request entries that can be edited
-local distinguished_names = { "countryName", "stateOrProvinceName", "localityName", "organizationName", "organizationalUnitName", "commonName", "emailAddress" }
+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", "policy" }
-local validate_distinguished_names = function(clientdata)
- local config = getopts.getoptsfromfile(configfile)
+-- Validate the values of distinguished names using the min/max found in the config file
+local validate_distinguished_names = function(values, inputconfig)
+ local config = inputconfig or getopts.getoptsfromfile(configfile)
local distinguished_name = config.req.distinguished_name or ""
+ local success = true
for i, name in ipairs(distinguished_names) do
- if config[distinguished_name][name.."_min"] then
+ 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) 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
+ end
+ return success, values
end
-getdefaults = function()
+-- Write distinguished name defaults to config file
+local write_distinguished_names = function(values, inputconfig)
+ local file = fs.read_file(configfile)
+ local config = inputconfig 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)
+end
+
+local create_subject_string = function(values)
+ local outstr = {}
+ for i,name in ipairs(distinguished_names) do
+ outstr[#outstr + 1] = (name.short or name.name) .. "=" .. values.value[name.name].value
+ end
+ outstr[#outstr + 1] = "password="..values.value.password.value
+ return "/"..table.concat(outstr, "/")
+end
+
+-- Find the sections of the config file that define ca's (ca -name option)
+local find_ca_sections = function(inputconfig)
+ local config = inputconfig 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 not config[section][entry] then
+ success = false
+ break
+ end
+ end
+ if success then
+ cert_types[#cert_types + 1] = section
+ end
+ end
+
+ return cert_types
+end
+
+local handle_req_clientdata = function(clientdata, defaults, config)
+
+ -- Next, put the user values into the table
+ for name,value in pairs(clientdata) do
+ if defaults.value[name] then
+ defaults.value[name].value = value
+ end
+ end
+
+ -- Next, validate the values
+ local success
+ success, defaults = validate_distinguished_names(defaults, config)
+
+ 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
+
+ return success, defaults, config
+end
+
+-- FIXME we need to make sure necessary files / directories / private key are there
+verifyopenssl = function()
+ local retval = false
+ if fs.is_file(configfile) then
+ retval=true
+ end
+ return retval
+end
+
+getreqdefaults = function(inputconfig)
local defaults = cfe({ type="group", value={} })
- local config = getopts.getoptsfromfile(configfile)
+ local config = inputconfig 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] = cfe({ label=name,
- value=config[distinguished_name][name .. "_default"] or "",
- descr=config[distinguished_name][name] })
- end
+ 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] })
+ end
+
+ -- Add in the ca type default
+ defaults.value.certtype = cfe({ type="select", label="Certificate Type",
+ value=config.ca.default_ca, option=find_ca_sections(config) })
+
+ return defaults
+end
+
+setreqdefaults = function(clientdata)
+ -- First, get the defaults
+ local config = getopts.getoptsfromfile(configfile)
+ local defaults = getreqdefaults()
+
+ -- Then, copy in user values and validate
+ local success, defaults, config = handle_req_clientdata(clientdata, defaults, config)
+
+ -- Finally, write the values to the config file
+ if success then
+ write_distinguished_names(defaults, config)
+
+ getopts.setoptsinfile(configfile, "ca", "default_ca", defaults.value.certtype.value)
+ end
+
+ if not success then
+ defaults.errtxt = "Failed to set defaults"
+ end
return defaults
end
-setdefaults = function(clientdata)
- -- validate values
- validate_distinguished_names(clientdata)
+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(clientdata, user)
+ -- First, get the defaults
+ local config = getopts.getoptsfromfile(configfile)
+ local defaults = getnewrequest(config)
+
+ -- Then, copy in user values and validate
+ local success, defaults, config = handle_req_clientdata(clientdata, defaults, config)
+
+ -- 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
+
+ if success then
+ -- FIXME check to make sure same certificate or request doesn't already exist
+ end
+
+ if success then
+ -- Submit the request
+ local reqname = requestdir..user.."."..defaults.value.certtype.value.."."..defaults.value.commonName.value
+ 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
+ end
+
+ if not success 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=c}
+ end
+ return cfe({ type="list", value=list, label="List of pending requests" })
end