aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2018-08-16 00:28:54 +0300
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2018-09-01 21:34:45 +0300
commited5d2f170cfcfd565682028a9f44caa6ba1217ef (patch)
tree36d51ec9379bd0256b2600eabdbace145f660ed9
parenta2ffa20983a370206ac84f2a3fef8b9dee4309c1 (diff)
downloaddmvpn-tools-ed5d2f170cfcfd565682028a9f44caa6ba1217ef.tar.bz2
dmvpn-tools-ed5d2f170cfcfd565682028a9f44caa6ba1217ef.tar.xz
separate CRL signing keysv0.4.0
-rwxr-xr-xdmvpn-ca212
-rwxr-xr-xdmvpn-pfx-decode22
-rw-r--r--syntax.txt4
3 files changed, 153 insertions, 85 deletions
diff --git a/dmvpn-ca b/dmvpn-ca
index 79c14c2..cf1692a 100755
--- a/dmvpn-ca
+++ b/dmvpn-ca
@@ -262,9 +262,11 @@ function sign(object, hash_alg, cert, key)
end
function issue_cert(attrs, func)
- local ca = attrs.serial == 0
local key = pkey.new(attrs.params.key)
+ local ca = attrs.usage and attrs.usage.keyCertSign
+ attrs.serial = ca and 0 or next_key('certificate', 'serial')
+
local cert = x509.new()
cert:setVersion(3)
cert:setSerial(attrs.serial)
@@ -278,7 +280,7 @@ function issue_cert(attrs, func)
end
cert:setSubject(dn)
- cert:setBasicConstraints{CA=ca}
+ cert:setBasicConstraints{CA=attrs.usage}
cert:setBasicConstraintsCritical(true)
local issued = cert:getLifetime()
@@ -287,7 +289,8 @@ function issue_cert(attrs, func)
attrs.issued = issued
attrs.expires = expires
- attrs.privateKey = encrypt_key(key, ca)
+ attrs.privateKey = (ca or not attrs.usage) and encrypt_key(key, ca) or
+ key:getPrivateKey()
cert:addExtension(
x509ext.new(
@@ -297,16 +300,15 @@ function issue_cert(attrs, func)
)
)
- if ca then
+ if attrs.usage then
cert:addExtension(
x509ext.new(
'keyUsage',
'DER',
- rfc5280.KeyUsage.encode{
- ['keyCertSign']=true, ['cRLSign']=true
- }
+ rfc5280.KeyUsage.encode(attrs.usage)
)
)
+ attrs.usage = nil
end
local crl_dp = config.crl['dist-point']
@@ -339,6 +341,10 @@ function issue_cert(attrs, func)
return attrs
end
+function issue_ca_cert(usage)
+ return issue_cert{dn=config.ca.dn, params=config.ca, usage=usage}
+end
+
function export_cert(cert)
local password = {}
for i=1,config['password-length'] do
@@ -352,6 +358,9 @@ function export_cert(cert)
local chain = x509ch.new()
chain:add(load_ca_cert())
+
+ if config.db['encrypt-keys'] then chain:add(load_crl_cert()) end
+
chain:add(x509.new(cert.data, 'PEM'))
local file = io.open(
@@ -648,6 +657,10 @@ function get_certs()
end, get_cert_by_serial(serial)
end
+ if arg[1] == 'crl' then
+ return select_certs('site IS NULL AND serial > 0')
+ end
+
return select_certs(
vpnc_filter(scan_vpnc{multiple=true, retired=true}) or
'serial > 0'
@@ -655,6 +668,33 @@ function get_certs()
end
+function try_load_crl_cert()
+ if not config.db['encrypt-keys'] then
+ return table.unpack{load_ca_cert()}
+ end
+
+ if not crl_cert then
+ for row in select_certs(
+ 'site IS NULL and serial > 0', 'serial DESC'
+ ) do
+ if not crl_cert then
+ local cert, key = load_cert(row)
+ if is_valid(row) then
+ crl_cert = cert
+ crl_key = key
+ end
+ end
+ end
+ end
+ return crl_cert, crl_key
+end
+
+function load_crl_cert()
+ local cert, key = try_load_crl_cert()
+ if not cert then error('No valid CRL signing key found') end
+ return cert, key
+end
+
function generate_crl()
local crl = x509crl.new()
crl:setVersion(2)
@@ -678,7 +718,7 @@ function generate_crl()
end
end
- sign(crl, config.crl['hash-alg'])
+ sign(crl, config.crl['hash-alg'], table.unpack{load_crl_cert()})
insert('crl', {serial=new_serial, expires=expires, data=tostring(crl)})
if old_serial then delete('crl', {serial=old_serial}) end
@@ -1047,10 +1087,9 @@ output = scan_choice(
add_subnet('', subnet)
end
- issue_cert{
- dn=config.ca.dn,
- serial=0,
- params=config.ca
+ issue_ca_cert{
+ keyCertSign=true,
+ cRLSign=not config.db['encrypt-keys']
}
end,
show=function()
@@ -1059,78 +1098,94 @@ output = scan_choice(
},
cert={
generate=function()
- local vpnc = vpnc_filter(
+ local crl = arg[1] == 'crl'
+ local vpnc = not crl and vpnc_filter(
scan_vpnc{multiple=true},
's.code',
'v.id'
)
- local filter = vpnc or {}
- filter['s.active'] = '1'
- filter['v.active'] = '1'
-
- local subjects = {}
local dns = {}
-
- for row in select_many(
- 's.code, v.id, s.asn, s.name, v.name',
- 'site s INNER JOIN vpnc v ON s.code = v.site',
- filter,
- 'n'
- ) do
- local attrs = {
- site=row[1],
- vpnc=row[2],
- asn=row[3],
- sname=row[4],
- vname=row[5]
- }
-
- local function insert()
- attrs.params = config[
- attrs.site == '' and
- 'hub' or
- 'spoke'
- ]
-
- attrs.dn = attrs.params.dn:gsub(
- '%$(%u+)',
- {
- ROOT=config.ca.dn,
- SITE=attrs.sname or
- attrs.site,
- NAME=attrs.vname or
- attrs.params[
- 'default-name'
- ]:gsub(
- '$ID',
- attrs.vpnc
- )
- }
- )
-
- table.insert(
- subjects, attrs
- )
+ local gen_crl_cert
+ if not vpnc then
+ gen_crl_cert = not try_load_crl_cert()
+ if gen_crl_cert then
table.insert(
dns,
- {tostring(attrs.dn)}
+ {config.ca.dn}
)
end
+ end
+
+ local subjects = {}
- if vpnc then insert()
+ if not crl then
+ local filter = vpnc or {}
+ filter['s.active'] = '1'
+ filter['v.active'] = '1'
+
+ for row in select_many(
+ 's.code, v.id, s.asn, s.name, v.name',
+ 'site s INNER JOIN vpnc v ON s.code = v.site',
+ filter,
+ 'n'
+ ) do
+ local attrs = {
+ site=row[1],
+ vpnc=row[2],
+ asn=row[3],
+ sname=row[4],
+ vname=row[5]
+ }
+
+ local function insert()
+ attrs.params = config[
+ attrs.site == '' and
+ 'hub' or
+ 'spoke'
+ ]
+
+ attrs.dn = attrs.params.dn:gsub(
+ '%$(%u+)',
+ {
+ ROOT=config.ca.dn,
+ SITE=attrs.sname or
+ attrs.site,
+ NAME=attrs.vname or
+ attrs.params[
+ 'default-name'
+ ]:gsub(
+ '$ID',
+ attrs.vpnc
+ )
+ }
+ )
- else
- local valid
- for cert in select_certs{
- site=row[1], vpnc=row[2]
- } do
- if is_valid(cert) then
- valid = true
- end
+ table.insert(
+ subjects,
+ attrs
+ )
+ table.insert(
+ dns,
+ {tostring(attrs.dn)}
+ )
end
- if not valid then
- insert()
+
+ if vpnc then insert()
+
+ else
+ local valid
+ for cert in select_certs{
+ site=row[1],
+ vpnc=row[2]
+ } do
+ if is_valid(cert) then
+ valid = true
+ end
+ end
+ if not valid then
+ insert()
+ end
end
end
end
@@ -1140,11 +1195,16 @@ output = scan_choice(
local issued = {}
- for _, attrs in ipairs(subjects) do
- attrs.serial = next_key(
- 'certificate', 'serial'
+ if gen_crl_cert then
+ table.insert(
+ issued,
+ issue_ca_cert{
+ cRLSign=true
+ }
)
+ end
+ for _, attrs in ipairs(subjects) do
local asn = attrs.asn
attrs.asn = nil
@@ -1298,8 +1358,8 @@ output = scan_choice(
'serial', 'selector'
)
local cert = get_cert_by_serial(serial)
- if cert.serial == 0 then
- error('Cannot export root certificate')
+ if not cert.site then
+ error('Cannot export CA certificate')
end
export_cert(cert)
end
diff --git a/dmvpn-pfx-decode b/dmvpn-pfx-decode
index eecd3f5..1ec2830 100755
--- a/dmvpn-pfx-decode
+++ b/dmvpn-pfx-decode
@@ -7,6 +7,7 @@ See LICENSE file for license details
dmvpn = require('dmvpn')
pkcs12 = require('openssl.pkcs12')
+rfc5280 = require('asn1.rfc5280')
name = arg[1]
file = io.open(name)
@@ -22,17 +23,24 @@ if not success then
key, cert, chain = pkcs12.parse(data, dmvpn.get_password())
end
-function write_pem_file(dir, data)
- local file = io.open('/etc/swanctl/'..dir..'/dmvpn.pem', 'w')
+function write_pem_file(data, dir, suffix)
+ local file = io.open(
+ '/etc/swanctl/'..dir..'/dmvpn'..(suffix or '')..'.pem', 'w'
+ )
file:write(data)
file:close()
end
-write_pem_file('private', key:toPEM('private'))
-write_pem_file('x509', tostring(cert))
-for i, ca_cert in pairs(chain) do
- assert(i == 1)
- write_pem_file('x509ca', tostring(ca_cert))
+write_pem_file(key:toPEM('private'), 'private')
+write_pem_file(tostring(cert), 'x509')
+for _, ca_cert in pairs(chain) do
+ local suffix
+ local usage = rfc5280.KeyUsage.decode(
+ ca_cert:getExtension('keyUsage'):getData()
+ )
+ if usage.keyCertSign then suffix = ''
+ elseif usage.cRLSign then suffix = '-crl' end
+ if suffix then write_pem_file(tostring(ca_cert), 'x509ca', suffix) end
end
function print_var(name, value)
diff --git a/syntax.txt b/syntax.txt
index f946404..51ff432 100644
--- a/syntax.txt
+++ b/syntax.txt
@@ -26,8 +26,8 @@ dmvpn-ca gre-addr del <addr>
dmvpn-ca root-cert {generate|show}
-dmvpn-ca cert generate [hubs|hub <id>|site <abbr> [vpnc <id>]]
-dmvpn-ca cert {list|show|revoke} [serial <num>|hubs|hub <id>|site <abbr> [vpnc <id>]]
+dmvpn-ca cert generate [hubs|hub <id>|site <abbr> [vpnc <id>]|crl]
+dmvpn-ca cert {list|show|revoke} [serial <num>|hubs|hub <id>|site <abbr> [vpnc <id>]|crl]
dmvpn-ca cert export serial <num>
dmvpn-ca crl {generate|show|export}