freeipa/ipaserver/dnssec/_ods21.py

118 lines
3.8 KiB
Python
Raw Normal View History

#
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
#
import os
from ipaserver.dnssec._odsbase import AbstractODSDBConnection
from ipaserver.dnssec._odsbase import AbstractODSSignerConn
from ipaserver.dnssec._odsbase import ODS_SE_MAXLINE
from ipaplatform.constants import constants
from ipaplatform.paths import paths
from ipapython import ipautil
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 "
"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']
key['generate'] = ipautil.datetime_from_utctimestamp(
row['inception'],
units=1).replace(tzinfo=None).isoformat(
sep=' ', timespec='seconds')
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:
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:
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()
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)