2020-03-05 08:54:40 -06:00
|
|
|
#
|
|
|
|
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
|
|
|
#
|
|
|
|
|
2020-03-12 10:23:03 -05:00
|
|
|
import os
|
2020-03-05 08:54:40 -06:00
|
|
|
|
|
|
|
from ipaserver.dnssec._odsbase import AbstractODSDBConnection
|
|
|
|
from ipaserver.dnssec._odsbase import AbstractODSSignerConn
|
|
|
|
from ipaserver.dnssec._odsbase import ODS_SE_MAXLINE
|
2020-03-12 10:23:03 -05:00
|
|
|
from ipaplatform.constants import constants
|
|
|
|
from ipaplatform.paths import paths
|
|
|
|
from ipapython import ipautil
|
2020-03-05 08:54:40 -06:00
|
|
|
|
|
|
|
CLIENT_OPC_STDOUT = 0
|
|
|
|
CLIENT_OPC_EXIT = 4
|
|
|
|
|
|
|
|
|
|
|
|
class ODSDBConnection(AbstractODSDBConnection):
|
|
|
|
def get_zones(self):
|
|
|
|
cur = self._db.execute("SELECT name from zone")
|
|
|
|
rows = cur.fetchall()
|
|
|
|
return [row['name'] for row in rows]
|
|
|
|
|
|
|
|
def get_zone_id(self, zone_name):
|
|
|
|
cur = self._db.execute(
|
|
|
|
"SELECT id FROM zone WHERE LOWER(name)=LOWER(?)",
|
|
|
|
(zone_name,))
|
|
|
|
rows = cur.fetchall()
|
|
|
|
return [row[0] for row in rows]
|
|
|
|
|
|
|
|
def get_keys_for_zone(self, zone_id):
|
|
|
|
cur = self._db.execute(
|
|
|
|
"SELECT hsmk.locator, hsmk.inception, hsmk.algorithm, "
|
dnssec: fix the key type with OpenDNSSEC 2.1
The database storing the keys with OpenDNSSEC 2.1 has a
different schema from OpenDNSSEC 1.4, and the keytype
(ZSK, KSK) is stored in a different table column: "role"
instead of "keytype".
With OpenDNSSEC 1.4, keytype can be 256 (ZSK) or 257 (KSK), while
with OpenDNSSEC 2.1, role can be 1 (KSK) or 2 (ZSK).
The schema migration can be seen in opendnssec source code:
enforcer/utils/1.4-2.0_db_convert/sqlite_convert.sql
INSERT INTO hsmKey
SELECT DISTINCT REMOTE.keypairs.id, 1, REMOTE.keypairs.policy_id,
REMOTE.keypairs.HSMkey_id, 2, REMOTE.keypairs.size,
REMOTE.keypairs.algorithm, (~(REMOTE.dnsseckeys.keytype)&1)+1,
CASE WHEN REMOTE.keypairs.generate IS NOT NULL THEN
strftime('%s', REMOTE.keypairs.generate)
ELSE strftime("%s", "now") END,
0,
1, --only RSA supported
REMOTE.securitymodules.name,
0 --assume no backup
FROM REMOTE.keypairs
JOIN REMOTE.dnsseckeys
ON REMOTE.keypairs.id = REMOTE.dnsseckeys.keypair_id
JOIN REMOTE.securitymodules
ON REMOTE.securitymodules.id = REMOTE.keypairs.securitymodule_id;
and the schema for the table is defined in enforcer/src/db/kasp.sqlite:
CREATE TABLE HsmKey (
locator VARCHAR(255) NOT NULL,
candidate_for_sharing TINYINT UNSIGNED DEFAULT 0,
bits INT UNSIGNED DEFAULT 2048,
policy VARCHAR(255) DEFAULT 'default',
algorithm INT UNSIGNED DEFAULT 1,
role VARCHAR(3) DEFAULT 'ZSK',
inception INT UNSIGNED,
isrevoked TINYINT UNSIGNED DEFAULT 0,
key_type VARCHAR(255),
repository VARCHAR(255),
backmeup TINYINT UNSIGNED DEFAULT 0,
backedup TINYINT UNSIGNED DEFAULT 0,
requirebackup TINYINT UNSIGNED DEFAULT 0,
id INTEGER PRIMARY KEY AUTOINCREMENT
);
Fixes: https://pagure.io/freeipa/issue/8647
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-01-06 14:05:11 -06:00
|
|
|
"hsmk.role, hsmk.state "
|
2020-03-05 08:54:40 -06:00
|
|
|
"FROM hsmKey AS hsmk "
|
|
|
|
"JOIN keyData AS kd ON hsmk.id = kd.hsmKeyId "
|
|
|
|
"WHERE kd.zoneId = ?", (zone_id,))
|
|
|
|
for row in cur:
|
|
|
|
key = dict()
|
|
|
|
key['HSMkey_id'] = row['locator']
|
2020-06-20 04:03:07 -05:00
|
|
|
key['generate'] = ipautil.datetime_from_utctimestamp(
|
|
|
|
row['inception'],
|
|
|
|
units=1).replace(tzinfo=None).isoformat(
|
|
|
|
sep=' ', timespec='seconds')
|
2020-03-05 08:54:40 -06:00
|
|
|
key['algorithm'] = row['algorithm']
|
|
|
|
key['publish'] = key['generate']
|
|
|
|
key['active'] = None
|
|
|
|
key['retire'] = None
|
|
|
|
key['dead'] = None
|
dnssec: fix the key type with OpenDNSSEC 2.1
The database storing the keys with OpenDNSSEC 2.1 has a
different schema from OpenDNSSEC 1.4, and the keytype
(ZSK, KSK) is stored in a different table column: "role"
instead of "keytype".
With OpenDNSSEC 1.4, keytype can be 256 (ZSK) or 257 (KSK), while
with OpenDNSSEC 2.1, role can be 1 (KSK) or 2 (ZSK).
The schema migration can be seen in opendnssec source code:
enforcer/utils/1.4-2.0_db_convert/sqlite_convert.sql
INSERT INTO hsmKey
SELECT DISTINCT REMOTE.keypairs.id, 1, REMOTE.keypairs.policy_id,
REMOTE.keypairs.HSMkey_id, 2, REMOTE.keypairs.size,
REMOTE.keypairs.algorithm, (~(REMOTE.dnsseckeys.keytype)&1)+1,
CASE WHEN REMOTE.keypairs.generate IS NOT NULL THEN
strftime('%s', REMOTE.keypairs.generate)
ELSE strftime("%s", "now") END,
0,
1, --only RSA supported
REMOTE.securitymodules.name,
0 --assume no backup
FROM REMOTE.keypairs
JOIN REMOTE.dnsseckeys
ON REMOTE.keypairs.id = REMOTE.dnsseckeys.keypair_id
JOIN REMOTE.securitymodules
ON REMOTE.securitymodules.id = REMOTE.keypairs.securitymodule_id;
and the schema for the table is defined in enforcer/src/db/kasp.sqlite:
CREATE TABLE HsmKey (
locator VARCHAR(255) NOT NULL,
candidate_for_sharing TINYINT UNSIGNED DEFAULT 0,
bits INT UNSIGNED DEFAULT 2048,
policy VARCHAR(255) DEFAULT 'default',
algorithm INT UNSIGNED DEFAULT 1,
role VARCHAR(3) DEFAULT 'ZSK',
inception INT UNSIGNED,
isrevoked TINYINT UNSIGNED DEFAULT 0,
key_type VARCHAR(255),
repository VARCHAR(255),
backmeup TINYINT UNSIGNED DEFAULT 0,
backedup TINYINT UNSIGNED DEFAULT 0,
requirebackup TINYINT UNSIGNED DEFAULT 0,
id INTEGER PRIMARY KEY AUTOINCREMENT
);
Fixes: https://pagure.io/freeipa/issue/8647
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-01-06 14:05:11 -06:00
|
|
|
if row['role'] == 2:
|
2020-03-05 08:54:40 -06:00
|
|
|
key['keytype'] = 256
|
dnssec: fix the key type with OpenDNSSEC 2.1
The database storing the keys with OpenDNSSEC 2.1 has a
different schema from OpenDNSSEC 1.4, and the keytype
(ZSK, KSK) is stored in a different table column: "role"
instead of "keytype".
With OpenDNSSEC 1.4, keytype can be 256 (ZSK) or 257 (KSK), while
with OpenDNSSEC 2.1, role can be 1 (KSK) or 2 (ZSK).
The schema migration can be seen in opendnssec source code:
enforcer/utils/1.4-2.0_db_convert/sqlite_convert.sql
INSERT INTO hsmKey
SELECT DISTINCT REMOTE.keypairs.id, 1, REMOTE.keypairs.policy_id,
REMOTE.keypairs.HSMkey_id, 2, REMOTE.keypairs.size,
REMOTE.keypairs.algorithm, (~(REMOTE.dnsseckeys.keytype)&1)+1,
CASE WHEN REMOTE.keypairs.generate IS NOT NULL THEN
strftime('%s', REMOTE.keypairs.generate)
ELSE strftime("%s", "now") END,
0,
1, --only RSA supported
REMOTE.securitymodules.name,
0 --assume no backup
FROM REMOTE.keypairs
JOIN REMOTE.dnsseckeys
ON REMOTE.keypairs.id = REMOTE.dnsseckeys.keypair_id
JOIN REMOTE.securitymodules
ON REMOTE.securitymodules.id = REMOTE.keypairs.securitymodule_id;
and the schema for the table is defined in enforcer/src/db/kasp.sqlite:
CREATE TABLE HsmKey (
locator VARCHAR(255) NOT NULL,
candidate_for_sharing TINYINT UNSIGNED DEFAULT 0,
bits INT UNSIGNED DEFAULT 2048,
policy VARCHAR(255) DEFAULT 'default',
algorithm INT UNSIGNED DEFAULT 1,
role VARCHAR(3) DEFAULT 'ZSK',
inception INT UNSIGNED,
isrevoked TINYINT UNSIGNED DEFAULT 0,
key_type VARCHAR(255),
repository VARCHAR(255),
backmeup TINYINT UNSIGNED DEFAULT 0,
backedup TINYINT UNSIGNED DEFAULT 0,
requirebackup TINYINT UNSIGNED DEFAULT 0,
id INTEGER PRIMARY KEY AUTOINCREMENT
);
Fixes: https://pagure.io/freeipa/issue/8647
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
2021-01-06 14:05:11 -06:00
|
|
|
elif row['role'] == 1:
|
2020-03-05 08:54:40 -06:00
|
|
|
key['keytype'] = 257
|
|
|
|
key['state'] = row['state']
|
|
|
|
yield key
|
|
|
|
|
|
|
|
|
|
|
|
class ODSSignerConn(AbstractODSSignerConn):
|
|
|
|
def read_cmd(self):
|
|
|
|
msg = self._conn.recv(ODS_SE_MAXLINE)
|
|
|
|
_opc = int(msg[0])
|
|
|
|
msglen = int(msg[1]) << 8 + int(msg[2])
|
|
|
|
cmd = msg[3:msglen - 1].strip()
|
|
|
|
return cmd
|
|
|
|
|
|
|
|
def send_reply_and_close(self, reply):
|
|
|
|
prefix = bytearray([CLIENT_OPC_STDOUT, len(reply) >> 8,
|
|
|
|
len(reply) & 255])
|
|
|
|
self._conn.sendall(prefix + reply)
|
|
|
|
# 2nd message: CLIENT_OPC_EXIT, then len, msg len, exit code
|
|
|
|
prefix = bytearray([CLIENT_OPC_EXIT, 0, 1, 0])
|
|
|
|
self._conn.sendall(prefix)
|
|
|
|
self._conn.close()
|
2020-03-12 10:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
class ODSTask():
|
|
|
|
def run_ods_setup(self):
|
|
|
|
"""Initialize a new kasp.db"""
|
|
|
|
cmd = [paths.ODS_ENFORCER_DB_SETUP]
|
|
|
|
return ipautil.run(cmd, stdin="y", runas=constants.ODS_USER)
|
|
|
|
|
|
|
|
def run_ods_notify(self, **kwargs):
|
|
|
|
"""Notify ods-enforcerd to reload its conf."""
|
|
|
|
cmd = [paths.ODS_ENFORCER, 'flush']
|
|
|
|
|
|
|
|
# run commands as ODS user
|
|
|
|
if os.geteuid() == 0:
|
|
|
|
kwargs['runas'] = constants.ODS_USER
|
|
|
|
|
|
|
|
return ipautil.run(cmd, **kwargs)
|
|
|
|
|
|
|
|
def run_ods_policy_import(self, **kwargs):
|
|
|
|
"""Run OpenDNSSEC manager command to import policy."""
|
|
|
|
cmd = [paths.ODS_ENFORCER, 'policy', 'import']
|
|
|
|
|
|
|
|
# run commands as ODS user
|
|
|
|
if os.geteuid() == 0:
|
|
|
|
kwargs['runas'] = constants.ODS_USER
|
|
|
|
ipautil.run(cmd, **kwargs)
|
|
|
|
|
|
|
|
def run_ods_manager(self, params, **kwargs):
|
|
|
|
"""Run OpenDNSSEC manager command (ksmutil, enforcer)
|
|
|
|
|
|
|
|
:param params: parameter for ODS command
|
|
|
|
:param kwargs: additional arguments for ipautil.run()
|
|
|
|
:return: result from ipautil.run()
|
|
|
|
"""
|
|
|
|
assert params[0] != 'setup'
|
|
|
|
|
|
|
|
cmd = [paths.ODS_ENFORCER]
|
|
|
|
cmd.extend(params)
|
|
|
|
|
|
|
|
# run commands as ODS user
|
|
|
|
if os.geteuid() == 0:
|
|
|
|
kwargs['runas'] = constants.ODS_USER
|
|
|
|
|
|
|
|
return ipautil.run(cmd, **kwargs)
|