From 5c610ad458e3b15b91d7c0962e41d60e94d76995 Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Thu, 21 Feb 2019 22:14:08 +0200 Subject: dmvpn-ca: help on syntax --- dmvpn-ca | 1271 ++++++++++++++++++++++++++++++++---------------------------- syntax.txt | 35 -- 2 files changed, 682 insertions(+), 624 deletions(-) delete mode 100644 syntax.txt diff --git a/dmvpn-ca b/dmvpn-ca index 20c2e7a..433b57d 100755 --- a/dmvpn-ca +++ b/dmvpn-ca @@ -189,12 +189,16 @@ function select_cert(serial) end +function user_error(msg) error{false, msg} end +function syntax_error(msg) error{true, msg} end + + function toint(s, min, max, desc) local i = tonumber(s) if i and i == math.floor(i) and i >= min and (not max or i <= max) then return i end - if desc then error('Invalid '..desc..': '..s) end + if desc then user_error('Invalid '..desc..': '..s) end end function toid(s) return toint(s, 1, nil, 'ID') end @@ -206,7 +210,7 @@ function detect_afi(s) end function detect_prefix_afi(s) - local function fail() error('Invalid network address: '..s) end + local function fail() user_error('Invalid network address: '..s) end local comps = stringy.split(s, '/') if #comps ~= 2 then fail() end @@ -276,7 +280,7 @@ function issue_cert(attrs, func) local dn = x509n.new() for _, rdn in ipairs(stringy.split(attrs.dn, ',')) do local attr, value = string.match(rdn, '^%s*(%a+)=(.*)$') - if not attr then error('Invalid RDN: '..rdn) end + if not attr then user_error('Invalid RDN: '..rdn) end dn:add(attr, value) end cert:setSubject(dn) @@ -439,7 +443,7 @@ end function scan_next(desc) if #arg == 0 then - if desc then error('Missing '..desc) end + if desc then syntax_error('Missing '..desc) end return end local res = arg[1] @@ -463,7 +467,7 @@ function scan_choice(choices, desc) local token = scan_next(desc) if not token then return end for k, v in pairs(choices) do if token == k then return v end end - error('Invalid '..desc..': '..token) + syntax_error('Invalid '..desc..': '..token) end function scan_param(choices, desc, optional) @@ -474,7 +478,7 @@ function scan_param(choices, desc, optional) for _, v in ipairs(choices) do if k == v then return k, scan_next(k..' specification') end end - error('Invalid '..desc..': '..k) + syntax_error('Invalid '..desc..': '..k) end @@ -483,7 +487,7 @@ function scan_site_code() return scan_next('site code'):upper() end function validate_site(code, retired) code = code:upper() if exists('site', {code=code}, not retired) then return code end - error('Invalid site code: '..code) + user_error('Invalid site code: '..code) end function scan_site(retired) return validate_site(scan_site_code(), retired) end @@ -536,7 +540,7 @@ function scan_vpnc(options) end if res.id and not exists('vpnc', res, not options.retired) then - error('Invalid '..obj..' number: '..res.id) + user_error('Invalid '..obj..' number: '..res.id) end return res @@ -551,7 +555,7 @@ end function scan_finished() - if #arg > 0 then error('Invalid parameter: '..scan_next()) end + if #arg > 0 then syntax_error('Invalid parameter: '..scan_next()) end end @@ -648,7 +652,7 @@ function get_cert_by_serial(serial) serial = toint(serial, 0, nil, 'serial number') local cert = select_cert(serial) - if not cert then error('Invalid serial number') end + if not cert then user_error('Invalid serial number') end return cert end @@ -694,7 +698,7 @@ end function load_crl_cert() local cert, key = try_load_crl_cert() - if not cert then error('No valid CRL signing key found') end + if not cert then user_error('No valid CRL signing key found') end return cert, key end @@ -780,654 +784,743 @@ function confirm(object, action, tbl) end -output = scan_choice( - scan_choice( - { - site={ - add=function() - local site = scan_site_code() - scan_finished() +cert_select_syntax = '[serial |hubs|hub |site [vpnc ]|crl]' - add_site{code=site} - end, - set=function() - local k, v = scan_param( - {'asn', 'name'}, 'attribute' - ) - local site = scan_site() - scan_finished() - - if k == 'asn' then - v = toint( - v, - 0, - math.pow(2, 16) - 1, - 'AS number' - ) - end +commands = { + site={ + add={ + '', + function() + local site = scan_site_code() + scan_finished() - update('site', {[k]=v}, {code=site}) - end, - unset=function() - local k = scan_choice( - {name='name'}, 'attribute' - ) - local site = scan_site() - scan_finished() - - update('site', {[k]=false}, {code=site}) - end, - show=function() - local site = scan_site_filter{ - param='code', retired=true - } - scan_finished() - - return show_site(site or "code > ''") - end, - retire=function() - local site = scan_site() - scan_finished() - confirm( - 'site', - 'retired', - show_site{code=site} - ) - - delete('subnet', {site=site}) - local output = retire_vpnc(site) - update( - 'site', - {active='0'}, - {code=site} + add_site{code=site} + end + }, + set={ + '{asn|name} ', + function() + local k, v = scan_param( + {'asn', 'name'}, 'attribute' + ) + local site = scan_site() + scan_finished() + + if k == 'asn' then + v = toint( + v, + 0, + math.pow(2, 16) - 1, + 'AS number' ) - return output end - }, - subnet={ - add=function() - local addr = scan_subnet() - local site = scan_site_selector() - scan_finished() - - add_subnet(site, addr) - end, - show=function() - local site = scan_site_filter() - scan_finished() - - return show( - 'subnet', - {'site', 'address'}, - site and site_filter(site) or - "site > ''" - ) - end, - del=function() - local addr = scan_subnet() - local filter = site_filter( - scan_site_filter() - ) - scan_finished() - - if not filter then filter = {} end - filter.address = addr - if not exists('subnet', filter) then - error( - 'Address does not exist: '.. - addr - ) - end + update('site', {[k]=v}, {code=site}) + end + }, + unset={ + 'name ', + function() + local k = scan_choice( + {name='name'}, 'attribute' + ) + local site = scan_site() + scan_finished() + + update('site', {[k]=false}, {code=site}) + end + }, + show={ + '[code ]', + function() + local site = scan_site_filter{ + param='code', retired=true + } + scan_finished() - delete('subnet', filter) - end - }, - vpnc={ - create=function() - local site = scan_site_selector() - local _, id = scan_param( - 'id', 'VPNc ID', true + return show_site(site or "code > ''") + end + }, + retire={ + '', + function() + local site = scan_site() + scan_finished() + confirm('site', 'retired', show_site{code=site}) + + delete('subnet', {site=site}) + local output = retire_vpnc(site) + update('site', {active='0'}, {code=site}) + return output + end + } + }, + subnet={ + add={ + ' site ', + function() + local addr = scan_subnet() + local site = scan_site_selector() + scan_finished() + + add_subnet(site, addr) + end + }, + show={ + '[site ]', + function() + local site = scan_site_filter() + scan_finished() + + return show( + 'subnet', + {'site', 'address'}, + site and site_filter(site) or + "site > ''" + ) + end + }, + del={ + ' [site ]', + function() + local addr = scan_subnet() + local filter = site_filter(scan_site_filter()) + scan_finished() + + if not filter then filter = {} end + filter.address = addr + + if not exists('subnet', filter) then + user_error( + 'Address does not exist: '..addr ) - scan_finished() + end - insert( - 'vpnc', - { - site=site, - id=id and toid(id) or - next_key( - 'vpnc', - 'id', - {site=site} - ) - } - ) - end, - set=function() - local _, name = scan_param( - 'name', 'attribute' - ) - local vpnc = scan_vpnc{id_attr='id'} - scan_finished() - - update('vpnc', {name=name}, vpnc) - end, - unset=function() - scan_choice({name=true}, 'attribute') - local vpnc = scan_vpnc{id_attr='id'} - scan_finished() - - update('vpnc', {name=false}, vpnc) - end, - show=function() - local site = scan_site_filter{ - retired=true + delete('subnet', filter) + end + } + }, + vpnc={ + create={ + 'site [id ]', + function() + local site = scan_site_selector() + local _, id = scan_param('id', 'VPNc ID', true) + scan_finished() + + insert( + 'vpnc', + { + site=site, + id=id and toid(id) or + next_key( + 'vpnc', + 'id', + {site=site} + ) } - scan_finished() - - return show_vpnc(site) - end, - retire=function() - local id = toid( - scan_next('VPNc number') - ) - local site = scan_site_selector() - scan_finished() - confirm( - 'VPNc', - 'retired', - show_vpnc({code=site}, id) - ) + ) + end + }, + set={ + 'name site id ', + function() + local _, name = scan_param('name', 'attribute') + local vpnc = scan_vpnc{id_attr='id'} + scan_finished() + + update('vpnc', {name=name}, vpnc) + end + }, + unset={ + 'name site id ', + function() + scan_choice({name=true}, 'attribute') + local vpnc = scan_vpnc{id_attr='id'} + scan_finished() + + update('vpnc', {name=false}, vpnc) + end + }, + show={ + '[site ]', + function() + local site = scan_site_filter{retired=true} + scan_finished() - return retire_vpnc(site, id) - end - }, - ['gre-addr']={ - add=function() - local addr = scan_addr() - local vpnc = scan_vpnc() - scan_finished() - - insert( - 'greAddress', - { - site=vpnc.site, - vpnc=vpnc.id, - family=detect_afi(addr), - address=addr - } - ) - end, - del=function() - local addr = scan_addr() - scan_finished() + return show_vpnc(site) + end + }, + retire={ + ' site ', + function() + local id = toid(scan_next('VPNc number')) + local site = scan_site_selector() + scan_finished() + confirm( + 'VPNc', + 'retired', + show_vpnc({code=site}, id) + ) + + return retire_vpnc(site, id) + end + } + }, + ['gre-addr']={ + add={ + ' {hub |site [vpnc ]}', + function() + local addr = scan_addr() + local vpnc = scan_vpnc() + scan_finished() + + insert( + 'greAddress', + { + site=vpnc.site, + vpnc=vpnc.id, + family=detect_afi(addr), + address=addr + } + ) + end + }, + del={ + '', + function() + local addr = scan_addr() + scan_finished() - delete('greAddress', {address=addr}) - end - }, - hub={ - create=function() - local id = scan_next() - scan_finished() - - insert( - 'vpnc', - { - site='', - id=id and toid(id) or - next_key( - 'vpnc', - 'id', - {site=''} - ) - } - ) - end, - set=function() - local _, name = scan_param( - 'name', 'attribute' - ) - local id = toid(scan_next('hub number')) - scan_finished() + delete('greAddress', {address=addr}) + end + } + }, + hub={ + create={ + '[]', + function() + local id = scan_next() + scan_finished() + + insert( + 'vpnc', + { + site='', + id=id and toid(id) or + next_key( + 'vpnc', + 'id', + {site=''} + ) + } + ) + end + }, + set={ + 'name ', + function() + local _, name = scan_param('name', 'attribute') + local id = toid(scan_next('hub number')) + scan_finished() + + update('vpnc', {name=name}, {site='', id=id}) + end + }, + unset={ + 'name ', + function() + scan_choice({name=true}, 'attribute') + local id = toid(scan_next('hub number')) + scan_finished() + + update('vpnc', {name=false}, {site='', id=id}) + end + }, + show={ + '', + function() + scan_finished() - update( - 'vpnc', - {name=name}, - {site='', id=id} + return show_vpnc{code=''} + end + }, + retire={ + '', + function() + local id = toid(scan_next('hub number')) + scan_finished() + confirm( + 'hub', + 'retired', + show_vpnc({code=''}, id) + ) + + return retire_vpnc('', id) + end + } + }, + ['root-cert']={ + generate={ + '', + function() + scan_finished() + + if stat.stat(config.db.file) then + simple_confirm( + function() + io.write('Current configuration and all keys will be lost.\n') + end ) - end, - unset=function() - scan_choice({name=true}, 'attribute') - local id = toid(scan_next('hub number')) - scan_finished() + end - update( - 'vpnc', - {name=false}, - {site='', id=id} - ) - end, - show=function() - scan_finished() - - return show_vpnc{code=''} - end, - retire=function() - local id = toid(scan_next('hub number')) - scan_finished() - confirm( - 'hub', - 'retired', - show_vpnc({code=''}, id) - ) + os.remove(config.db.file) + for _, statement in ipairs( + { + [[ + CREATE TABLE site ( + code VARCHAR(16) NOT NULL PRIMARY KEY, + asn INTEGER NOT NULL, + name VARCHAR(32), + active CHAR(1) DEFAULT '1' + ) + ]], + [[ + CREATE TABLE subnet ( + site VARCHAR(16) NOT NULL REFERENCES site(code), + family INTEGER NOT NULL, + address CHAR(14) NOT NULL, + PRIMARY KEY(site, family, address) + ) + ]], + [[ + CREATE TABLE vpnc ( + site VARCHAR(16) NOT NULL REFERENCES site(code), + id INTEGER NOT NULL, + name VARCHAR(32), + active CHAR(1) DEFAULT '1', + PRIMARY KEY(site, id) + ) + ]], + [[ + CREATE TABLE greAddress ( + site VARCHAR(16) NOT NULL, + vpnc INTEGER NOT NULL, + family INTEGER NOT NULL, + address CHAR(14) NOT NULL, + PRIMARY KEY(site, vpnc, family), + FOREIGN KEY(site, vpnc) REFERENCES vpnc(site, id), + UNIQUE(family, address) + ) + ]], + [[ + CREATE TABLE certificate ( + serial INTEGER NOT NULL PRIMARY KEY, + site VARCHAR(16), + vpnc INTEGER, + dn VARCHAR(128) NOT NULL, + issued DATETIME NOT NULL, + expires DATETIME NOT NULL, + revoked DATETIME, + privateKey TEXT NOT NULL, + data TEXT NOT NULL, + FOREIGN KEY(site, vpnc) REFERENCES vpnc(site, id) + ) + ]], + [[ + CREATE TABLE crl ( + serial INTEGER NOT NULL PRIMARY KEY, + expires DATETIME NOT NULL, + data TEXT NOT NULL + ) + ]] + } + ) do execute(statement) end - return retire_vpnc('', id) + add_site{code=''} + for _, subnet in ipairs(config.hub.subnets) do + add_subnet('', subnet) end - }, - ['root-cert']={ - generate=function() - scan_finished() - - if stat.stat(config.db.file) then - simple_confirm( - function() - io.write('Current configuration and all keys will be lost.\n') - end + + issue_ca_cert{ + keyCertSign=true, + cRLSign=not config.db['encrypt-keys'] + } + end + }, + show={ + '', + function() + scan_finished() + print_cert(get_cert_by_serial(0)) + end + } + }, + cert={ + generate={ + '[hubs|hub |site [vpnc ]|crl]', + function() + local crl = arg[1] == 'crl' + local vpnc = not crl and vpnc_filter( + scan_vpnc{multiple=true}, + 's.code', + 'v.id' + ) + + local dns = {} + local gen_crl_cert + if not vpnc then + gen_crl_cert = not try_load_crl_cert() + if gen_crl_cert then + table.insert( + dns, {config.ca.dn} ) end + end - os.remove(config.db.file) - for _, statement in ipairs( - { - [[ - CREATE TABLE site ( - code VARCHAR(16) NOT NULL PRIMARY KEY, - asn INTEGER NOT NULL, - name VARCHAR(32), - active CHAR(1) DEFAULT '1' - ) - ]], - [[ - CREATE TABLE subnet ( - site VARCHAR(16) NOT NULL REFERENCES site(code), - family INTEGER NOT NULL, - address CHAR(14) NOT NULL, - PRIMARY KEY(site, family, address) - ) - ]], - [[ - CREATE TABLE vpnc ( - site VARCHAR(16) NOT NULL REFERENCES site(code), - id INTEGER NOT NULL, - name VARCHAR(32), - active CHAR(1) DEFAULT '1', - PRIMARY KEY(site, id) - ) - ]], - [[ - CREATE TABLE greAddress ( - site VARCHAR(16) NOT NULL, - vpnc INTEGER NOT NULL, - family INTEGER NOT NULL, - address CHAR(14) NOT NULL, - PRIMARY KEY(site, vpnc, family), - FOREIGN KEY(site, vpnc) REFERENCES vpnc(site, id), - UNIQUE(family, address) - ) - ]], - [[ - CREATE TABLE certificate ( - serial INTEGER NOT NULL PRIMARY KEY, - site VARCHAR(16), - vpnc INTEGER, - dn VARCHAR(128) NOT NULL, - issued DATETIME NOT NULL, - expires DATETIME NOT NULL, - revoked DATETIME, - privateKey TEXT NOT NULL, - data TEXT NOT NULL, - FOREIGN KEY(site, vpnc) REFERENCES vpnc(site, id) - ) - ]], - [[ - CREATE TABLE crl ( - serial INTEGER NOT NULL PRIMARY KEY, - expires DATETIME NOT NULL, - data TEXT NOT NULL - ) - ]] - } - ) do execute(statement) end + local subjects = {} + + if not crl then + local filter = vpnc or {} + filter['s.active'] = '1' + filter['v.active'] = '1' - add_site{code=''} - for _, subnet in ipairs( - config.hub.subnets + 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 - add_subnet('', subnet) - end + local attrs = { + site=row[1], + vpnc=row[2], + asn=row[3], + sname=row[4], + vname=row[5] + } - issue_ca_cert{ - keyCertSign=true, - cRLSign=not config.db['encrypt-keys'] - } - end, - show=function() - scan_finished() - print_cert(get_cert_by_serial(0)) - end - }, - cert={ - generate=function() - local crl = arg[1] == 'crl' - local vpnc = not crl and vpnc_filter( - scan_vpnc{multiple=true}, - 's.code', - 'v.id' - ) + attrs.params = config[ + attrs.site == '' and + 'hub' or 'spoke' + ] + + local function insert() + 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 + ) + } + ) - local dns = {} - local gen_crl_cert - if not vpnc then - gen_crl_cert = not try_load_crl_cert() - if gen_crl_cert then + table.insert( + subjects, attrs + ) table.insert( dns, - {config.ca.dn} + {tostring(attrs.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 = { + else + local valid + for cert in select_certs{ site=row[1], - vpnc=row[2], - asn=row[3], - sname=row[4], - vname=row[5] - } - - attrs.params = config[ - attrs.site == '' and - 'hub' or - 'spoke' - ] - - local function insert() - 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 - ) - table.insert( - dns, - {tostring(attrs.dn)} - ) - end - - if vpnc then insert() - - else - local valid - for cert in select_certs{ - site=row[1], - vpnc=row[2] - } do - if is_valid( - cert, - attrs.params.renewal - ) then - valid = true - end - end - if not valid then - insert() + vpnc=row[2] + } do + if is_valid( + cert, + attrs.params.renewal + ) then + valid = true end end + if not valid then + insert() + end end end + end - add_header(dns, {'dn'}) - confirm('certificates', 'issued', dns) + add_header(dns, {'dn'}) + confirm('certificates', 'issued', dns) - local issued = {} + local issued = {} - if gen_crl_cert then - table.insert( - issued, - issue_ca_cert{ - cRLSign=true - } - ) - end + 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 + for _, attrs in ipairs(subjects) do + local asn = attrs.asn + attrs.asn = nil - local cert = issue_cert( - attrs, - function(cert, attrs) + local cert = issue_cert( + attrs, + function(cert, attrs) - local function get_subnets() - return select_many( - 'family, address', - 'subnet', - {site=attrs.site}, - 'a' - ) - end + local function get_subnets() + return select_many( + 'family, address', + 'subnet', + {site=attrs.site}, + 'a' + ) + end - local function get_gre_addrs() - return select_many( - 'family, address', - 'greAddress', - {site=attrs.site, vpnc=attrs.vpnc}, - 'a' - ) - end + local function get_gre_addrs() + return select_many( + 'family, address', + 'greAddress', + {site=attrs.site, vpnc=attrs.vpnc}, + 'a' + ) + end + + cert:addExtension( + x509ext.new( + dmvpn.OID_IS_HUB, + 'critical,DER', + asn1.boolean.encode(attrs.site == '') + ) + ) + local hosts = config.hub.hosts + if hosts then cert:addExtension( x509ext.new( - dmvpn.OID_IS_HUB, - 'critical,DER', - asn1.boolean.encode(attrs.site == '') + dmvpn.OID_HUB_HOSTS, + 'DER', + asn1.sequence_of(asn1.ia5string).encode(hosts) ) ) + end - local hosts = config.hub.hosts - if hosts then - cert:addExtension( - x509ext.new( - dmvpn.OID_HUB_HOSTS, - 'DER', - asn1.sequence_of(asn1.ia5string).encode(hosts) - ) - ) - end - - local net_config = {} - local pr_config = {} - for subnet in get_subnets() do - local f = subnet.family - if not pr_config[f] then - pr_config[f] = {} - table.insert( - net_config, - { - addressFamily={afi=f}, - ipAddressChoice={ - addressesOrRanges=pr_config[f] - } - } - ) - end + local net_config = {} + local pr_config = {} + for subnet in get_subnets() do + local f = subnet.family + if not pr_config[f] then + pr_config[f] = {} table.insert( - pr_config[f], - {addressPrefix=subnet.address} - ) - end - if net_config[1] then - cert:addExtension( - x509ext.new( - 'sbgp-ipAddrBlock', - 'critical,DER', - rfc3779.IPAddrBlocks.encode(net_config) - ) - ) - end - - local san - for ga in get_gre_addrs() do - if not san then - san = x509an.new() - end - san:add( - 'IP', - ga.address + net_config, + { + addressFamily={afi=f}, + ipAddressChoice={ + addressesOrRanges=pr_config[f] + } + } ) end - if san then - cert:setSubjectAlt(san) - end - + table.insert( + pr_config[f], + {addressPrefix=subnet.address} + ) + end + if net_config[1] then cert:addExtension( x509ext.new( - 'sbgp-autonomousSysNum', + 'sbgp-ipAddrBlock', 'critical,DER', - rfc3779.ASIdentifiers.encode{ - asnum={asIdsOrRanges={{id=asn}}} - } + rfc3779.IPAddrBlocks.encode(net_config) ) ) end - ) - export_cert(cert) - table.insert(issued, cert) - end - return format_cert_info(issued) - end, - list=function() - local certs = {} - for cert in get_certs() do - table.insert(certs, cert) - end - return format_cert_info(certs) - end, - show=function() - for cert in get_certs() do - print_cert(cert) - end - end, - revoke=function() - local certs = {} - for cert, selector in get_certs() do - local valid = is_valid(cert) - if selector == 'serial' and - not valid then - - error('Certificate already expired or revoked') - end - if valid then - table.insert( - certs, cert + local san + for ga in get_gre_addrs() do + if not san then + san = x509an.new() + end + san:add( + 'IP', + ga.address + ) + end + if san then + cert:setSubjectAlt(san) + end + + cert:addExtension( + x509ext.new( + 'sbgp-autonomousSysNum', + 'critical,DER', + rfc3779.ASIdentifiers.encode{ + asnum={asIdsOrRanges={{id=asn}}} + } + ) ) end - end - confirm( - 'certificates', - 'revoked', - format_cert_info(certs) ) + export_cert(cert) + table.insert(issued, cert) + end - local revoked = {} - for _, cert in ipairs(certs) do - table.insert( - revoked, - revoke{serial=cert.serial}[1] - ) + return format_cert_info(issued) + end + }, + list={ + cert_select_syntax, + function() + local certs = {} + for cert in get_certs() do + table.insert(certs, cert) + end + return format_cert_info(certs) + end + }, + show={ + cert_select_syntax, + function() + for cert in get_certs() do print_cert(cert) end + end + }, + revoke={ + cert_select_syntax, + function() + local certs = {} + for cert, selector in get_certs() do + local valid = is_valid(cert) + if selector == 'serial' and + not valid then + + user_error('Certificate already expired or revoked') end - return format_cert_info(revoked) - end, - export=function() - local _, serial = scan_param( - 'serial', 'selector' - ) - local cert = get_cert_by_serial(serial) - if not cert.site then - error('Cannot export CA certificate') + if valid then + table.insert(certs, cert) end - export_cert(cert) end - }, - crl={ - generate=function() - scan_finished() - io.write(tostring(generate_crl())) - end, - show=function() - scan_finished() - io.write(get_crl():text()) - end, - export=function() - scan_finished() - io.write(tostring(get_crl())) + confirm( + 'certificates', + 'revoked', + format_cert_info(certs) + ) + + local revoked = {} + for _, cert in ipairs(certs) do + table.insert( + revoked, + revoke{serial=cert.serial}[1] + ) end - }, - password={ - set=function() - for row in select_many( - 'serial, privateKey', - 'certificate', - nil, - 'n' - ) do - update( - 'certificate', - {privateKey=encrypt_key(decrypt_key(row[2]), true, 'new')}, - {serial=row[1]} - ) - end + return format_cert_info(revoked) + end + }, + export={ + 'serial ', + function() + local _, serial = scan_param( + 'serial', 'selector' + ) + local cert = get_cert_by_serial(serial) + if not cert.site then + user_error( + 'Cannot export CA certificate' + ) end - } + export_cert(cert) + end + } + }, + crl={ + generate={ + '', + function() + scan_finished() + io.write(tostring(generate_crl())) + end + }, + show={ + '', + function() + scan_finished() + io.write(get_crl():text()) + end }, - 'object type' - ), - 'action' -)() + export={ + '', + function() + scan_finished() + io.write(tostring(get_crl())) + end + } + }, + password={ + set={ + '', + function() + for row in select_many( + 'serial, privateKey', + 'certificate', + nil, + 'n' + ) do + update( + 'certificate', + { + privateKey=encrypt_key( + decrypt_key(row[2]), + true, + 'new' + ) + }, + {serial=row[1]} + ) + end + end + } + } +} + +function scan_command(obj_type) + local prefix = 'dmvpn-ca '..(obj_type and obj_type..' ' or '') + local cmd = scan_next() + local choices = obj_type and commands[obj_type] or commands + local res = choices[cmd] + if res then + if obj_type then return prefix..cmd..' '..res[1], res[2] end + return scan_command(cmd) + end + print('Available commands:') + for k, v in pairs(choices) do + print('\t'..prefix..k..(obj_type and ' '..v[1] or '')) + end +end -if output then print_table(output) end +syntax, func = scan_command() + +if syntax then + status, output = xpcall( + func, + function(err) + if type(err) == 'string' then + return err..'\n'..debug.traceback() + end + return err[2]..(err[1] and '\n\nSyntax: '..syntax or '') + end + ) + if status then + if output then print_table(output) end + if sql then conn:commit() end + else print(output) end +end if sql then - conn:commit() conn:close() sql:close() end + +os.exit(status and 0 or 1) diff --git a/syntax.txt b/syntax.txt deleted file mode 100644 index 51ff432..0000000 --- a/syntax.txt +++ /dev/null @@ -1,35 +0,0 @@ -dmvpn-ca hub create [] -dmvpn-ca hub set name -dmvpn-ca hub unset name -dmvpn-ca hub show -dmvpn-ca hub retire - -dmvpn-ca site add -dmvpn-ca site set {asn|name} -dmvpn-ca site unset name -dmvpn-ca site show [code ] -dmvpn-ca site retire - -dmvpn-ca subnet add site -dmvpn-ca subnet show [site ] -dmvpn-ca subnet del [site ] - -dmvpn-ca vpnc create site [id ] -dmvpn-ca vpnc set name site id -dmvpn-ca vpnc unset name site id -dmvpn-ca vpnc show [site ] -dmvpn-ca vpnc retire site - -dmvpn-ca gre-addr add {hub |site [vpnc ]} -dmvpn-ca gre-addr del - - -dmvpn-ca root-cert {generate|show} - -dmvpn-ca cert generate [hubs|hub |site [vpnc ]|crl] -dmvpn-ca cert {list|show|revoke} [serial |hubs|hub |site [vpnc ]|crl] -dmvpn-ca cert export serial - -dmvpn-ca crl {generate|show|export} - -dmvpn-ca password set -- cgit v1.2.3