diff options
author | Ted Trask <ttrask01@yahoo.com> | 2008-05-20 20:56:05 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2008-05-20 20:56:05 +0000 |
commit | f67066bd64784cb5182d6ded1847bcdd09a77d32 (patch) | |
tree | c332c805622794c407a8b0d09fb21f774f086497 /openssl-model.lua | |
parent | af360b084b8b5c787a0141cba65191d13e2a4aa4 (diff) | |
download | acf-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.lua | 232 |
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 |