URL: https://github.com/freeipa/freeipa/pull/1289
Author: tiran
 Title: #1289: Python 3 support for DNSSEC
Action: opened

PR body:
"""
https://pagure.io/freeipa/issue/4985
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1289/head:pr1289
git checkout pr1289
From b64dc9a4e8e4b835ad7fd80adcbd17ee60ce7423 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Mon, 26 Jun 2017 14:23:44 +0200
Subject: [PATCH 1/6] py3: ipa-dnskeysyncd: fix bytes issues

LDAP client returns values as bytes, thus ipa-dnskeysyncd must work with
bytes properly.

https://pagure.io/freeipa/issue/4985
---
 ipaserver/dnssec/keysyncer.py | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/ipaserver/dnssec/keysyncer.py b/ipaserver/dnssec/keysyncer.py
index c3af9156bc..958ebb353a 100644
--- a/ipaserver/dnssec/keysyncer.py
+++ b/ipaserver/dnssec/keysyncer.py
@@ -46,7 +46,7 @@ def _get_objclass(self, attrs):
 
         Given set of attributes has to have exactly one supported object class.
         """
-        supported_objclasses = set(['idnszone', 'idnsseckey', 'ipk11publickey'])
+        supported_objclasses = {b'idnszone', b'idnsseckey', b'ipk11publickey'}
         present_objclasses = set([o.lower() for o in attrs[OBJCLASS_ATTR]]).intersection(supported_objclasses)
         assert len(present_objclasses) == 1, attrs[OBJCLASS_ATTR]
         return present_objclasses.pop()
@@ -55,44 +55,44 @@ def __get_signing_attr(self, attrs):
         """Get SIGNING_ATTR from dictionary with LDAP zone attributes.
 
         Returned value is normalized to TRUE or FALSE, defaults to FALSE."""
-        values = attrs.get(SIGNING_ATTR, ['FALSE'])
+        values = attrs.get(SIGNING_ATTR, [b'FALSE'])
         assert len(values) == 1, '%s is expected to be single-valued' \
             % SIGNING_ATTR
         return values[0].upper()
 
     def __is_dnssec_enabled(self, attrs):
         """Test if LDAP DNS zone with given attributes is DNSSEC enabled."""
-        return self.__get_signing_attr(attrs) == 'TRUE'
+        return self.__get_signing_attr(attrs) == b'TRUE'
 
     def __is_replica_pubkey(self, attrs):
         vals = attrs.get('ipk11label', [])
         if len(vals) != 1:
             return False
-        return vals[0].startswith('dnssec-replica:')
+        return vals[0].startswith(b'dnssec-replica:')
 
     def application_add(self, uuid, dn, newattrs):
         objclass = self._get_objclass(newattrs)
-        if objclass == 'idnszone':
+        if objclass == b'idnszone':
             self.zone_add(uuid, dn, newattrs)
-        elif objclass == 'idnsseckey':
+        elif objclass == b'idnsseckey':
             self.key_meta_add(uuid, dn, newattrs)
-        elif objclass == 'ipk11publickey' and \
+        elif objclass == b'ipk11publickey' and \
                 self.__is_replica_pubkey(newattrs):
             self.hsm_master_sync()
 
     def application_del(self, uuid, dn, oldattrs):
         objclass = self._get_objclass(oldattrs)
-        if objclass == 'idnszone':
+        if objclass == b'idnszone':
             self.zone_del(uuid, dn, oldattrs)
-        elif objclass == 'idnsseckey':
+        elif objclass == b'idnsseckey':
             self.key_meta_del(uuid, dn, oldattrs)
-        elif objclass == 'ipk11publickey' and \
+        elif objclass == b'ipk11publickey' and \
                 self.__is_replica_pubkey(oldattrs):
             self.hsm_master_sync()
 
     def application_sync(self, uuid, dn, newattrs, oldattrs):
         objclass = self._get_objclass(oldattrs)
-        if objclass == 'idnszone':
+        if objclass == b'idnszone':
             olddn = ldap.dn.str2dn(oldattrs['dn'])
             newdn = ldap.dn.str2dn(newattrs['dn'])
             assert olddn == newdn, 'modrdn operation is not supported'
@@ -105,10 +105,10 @@ def application_sync(self, uuid, dn, newattrs, oldattrs):
                 else:
                     self.zone_del(uuid, olddn, oldattrs)
 
-        elif objclass == 'idnsseckey':
+        elif objclass == b'idnsseckey':
             self.key_metadata_sync(uuid, dn, oldattrs, newattrs)
 
-        elif objclass == 'ipk11publickey' and \
+        elif objclass == b'ipk11publickey' and \
                 self.__is_replica_pubkey(newattrs):
             self.hsm_master_sync()
 

From eeedb5186043524d945fd5fdd15ab6e8e0910e67 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Tue, 4 Jul 2017 16:16:11 +0200
Subject: [PATCH 2/6] py3: bindmgr: fix iteration over bytes

In py3 iteration over bytes returns integers, in py2 interation over
bytes returns string.

https://pagure.io/freeipa/issue/4985
---
 ipaserver/dnssec/bindmgr.py | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/ipaserver/dnssec/bindmgr.py b/ipaserver/dnssec/bindmgr.py
index 7d0b59596e..32975fc543 100644
--- a/ipaserver/dnssec/bindmgr.py
+++ b/ipaserver/dnssec/bindmgr.py
@@ -11,6 +11,8 @@
 import shutil
 import stat
 
+import six
+
 import ipalib.constants
 from ipapython.dn import DN
 from ipapython import ipautil
@@ -141,17 +143,21 @@ def get_zone_dir_name(self, zone):
         escaped = ""
         for label in zone:
             for char in label:
-                c = ord(char)
-                if ((c >= 0x30 and c <= 0x39) or   # digit
-                   (c >= 0x41 and c <= 0x5A) or    # uppercase
-                   (c >= 0x61 and c <= 0x7A) or    # lowercase
-                   c == 0x2D or                    # hyphen
-                   c == 0x5F):                     # underscore
-                    if (c >= 0x41 and c <= 0x5A):  # downcase
-                        c += 0x20
-                    escaped += chr(c)
+                if six.PY2:
+                    # PY3 char is already int
+                    char = ord(char)
+                if (
+                    (char >= 0x30 and char <= 0x39) or  # digit
+                    (char >= 0x41 and char <= 0x5A) or  # uppercase
+                    (char >= 0x61 and char <= 0x7A) or  # lowercase
+                    char == 0x2D or                     # hyphen
+                    char == 0x5F                        # underscore
+                ):
+                    if char >= 0x41 and char <= 0x5A:  # downcase
+                        char += 0x20
+                    escaped += chr(char)
                 else:
-                    escaped += "%%%02X" % c
+                    escaped += "%%%02X" % char
             escaped += '.'
 
         # strip trailing period

From 6717e32de97d8ec747720854d29c9e2a0de7cd34 Mon Sep 17 00:00:00 2001
From: Tomas Krizek <tkri...@redhat.com>
Date: Wed, 23 Aug 2017 14:28:49 +0200
Subject: [PATCH 3/6] py3: bindmgr: fix bytes issues

LDAP client returns values as bytes, thus bindmgr must work with
bytes properly.

https://pagure.io/freeipa/issue/4985

Signed-off-by: Tomas Krizek <tkri...@redhat.com>
---
 ipaserver/dnssec/bindmgr.py | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/ipaserver/dnssec/bindmgr.py b/ipaserver/dnssec/bindmgr.py
index 32975fc543..69dff3deea 100644
--- a/ipaserver/dnssec/bindmgr.py
+++ b/ipaserver/dnssec/bindmgr.py
@@ -56,8 +56,10 @@ def dn2zone_name(self, dn):
         return dns.name.from_text(dn[idx - 1]['idnsname'])
 
     def time_ldap2bindfmt(self, str_val):
+        if isinstance(str_val, bytes):
+            str_val = str_val.decode('utf-8')
         dt = datetime.strptime(str_val, ipalib.constants.LDAP_GENERALIZED_TIME_FORMAT)
-        return dt.strftime(time_bindfmt)
+        return dt.strftime(time_bindfmt).encode('utf-8')
 
     def dates2params(self, ldap_attrs):
         """Convert LDAP timestamps to list of parameters suitable
@@ -106,15 +108,15 @@ def install_key(self, zone, uuid, attrs, workdir):
         """Run dnssec-keyfromlabel on given LDAP object.
         :returns: base file name of output files, e.g. Kaaa.test.+008+19719"""
         logger.info('attrs: %s', attrs)
-        assert attrs.get('idnsseckeyzone', ['FALSE'])[0] == 'TRUE', \
-            'object %s is not a DNS zone key' % attrs['dn']
+        assert attrs.get('idnsseckeyzone', [b'FALSE'])[0] == b'TRUE', \
+            b'object %s is not a DNS zone key' % attrs['dn']
 
-        uri = "%s;pin-source=%s" % (attrs['idnsSecKeyRef'][0], paths.DNSSEC_SOFTHSM_PIN)
+        uri = b"%s;pin-source=%s" % (attrs['idnsSecKeyRef'][0], paths.DNSSEC_SOFTHSM_PIN.encode('utf-8'))
         cmd = [paths.DNSSEC_KEYFROMLABEL, '-K', workdir, '-a', attrs['idnsSecAlgorithm'][0], '-l', uri]
         cmd += self.dates2params(attrs)
-        if attrs.get('idnsSecKeySep', ['FALSE'])[0].upper() == 'TRUE':
+        if attrs.get('idnsSecKeySep', [b'FALSE'])[0].upper() == b'TRUE':
             cmd += ['-f', 'KSK']
-        if attrs.get('idnsSecKeyRevoke', ['FALSE'])[0].upper() == 'TRUE':
+        if attrs.get('idnsSecKeyRevoke', [b'FALSE'])[0].upper() == b'TRUE':
             cmd += ['-R', datetime.now().strftime(time_bindfmt)]
         cmd.append(zone.to_text())
 

From 95b20a498b56e0db1bffe8408a42ef95000d1c86 Mon Sep 17 00:00:00 2001
From: Tomas Krizek <tkri...@redhat.com>
Date: Fri, 25 Aug 2017 15:45:24 +0200
Subject: [PATCH 4/6] py3 dnssec: convert hexlify to str

hexlify returns bytes and needs to be casted to string before
printing it out.

Related: https://pagure.io/freeipa/issue/4985

Signed-off-by: Tomas Krizek <tkri...@redhat.com>
---
 daemons/dnssec/ipa-dnskeysync-replica | 21 ++++++++++++---------
 daemons/dnssec/ipa-ods-exporter       | 17 ++++++++---------
 ipaserver/dnssec/ldapkeydb.py         | 30 ++++++++++++++++++++----------
 ipaserver/dnssec/localhsm.py          | 20 ++++++++++----------
 4 files changed, 50 insertions(+), 38 deletions(-)

diff --git a/daemons/dnssec/ipa-dnskeysync-replica b/daemons/dnssec/ipa-dnskeysync-replica
index 5a64b84cb4..ee641ae508 100755
--- a/daemons/dnssec/ipa-dnskeysync-replica
+++ b/daemons/dnssec/ipa-dnskeysync-replica
@@ -8,7 +8,6 @@ Download keys from LDAP to local HSM.
 This program should be run only on replicas, not on DNSSEC masters.
 """
 
-from binascii import hexlify
 from gssapi.exceptions import GSSError
 import logging
 import os
@@ -24,7 +23,7 @@ from ipaplatform.paths import paths
 from ipaserver.dnssec.abshsm import (sync_pkcs11_metadata,
                                      ldap2p11helper_api_params,
                                      wrappingmech_name2id)
-from ipaserver.dnssec.ldapkeydb import LdapKeyDB
+from ipaserver.dnssec.ldapkeydb import LdapKeyDB, str_hexlify
 from ipaserver.dnssec.localhsm import LocalHSM
 
 logger = logging.getLogger(os.path.basename(__file__))
@@ -36,7 +35,7 @@ WORKDIR = '/tmp'
 def hex_set(s):
     out = set()
     for i in s:
-        out.add("0x%s" % hexlify(i))
+        out.add("0x%s" % str_hexlify(i))
     return out
 
 def update_metadata_set(source_set, target_set):
@@ -72,7 +71,9 @@ def ldap2replica_master_keys_sync(ldapkeydb, localhsm):
                  hex_set(new_keys))
     for mkey_id in new_keys:
         mkey_ldap = ldapkeydb.master_keys[mkey_id]
-        assert mkey_ldap.wrapped_entries, "Master key 0x%s in LDAP is missing key material referenced by ipaSecretKeyRefObject attribute" % hexlify(mkey_id)
+        assert mkey_ldap.wrapped_entries, ("Master key 0x%s in LDAP is " \
+            "missing key material referenced by ipaSecretKeyRefObject " \
+            "attribute") % str_hexlify(mkey_id)
         for wrapped_ldap in mkey_ldap.wrapped_entries:
             unwrapping_key = find_unwrapping_key(
                 localhsm, wrapped_ldap.single_value['ipaWrappingKey'])
@@ -80,14 +81,16 @@ def ldap2replica_master_keys_sync(ldapkeydb, localhsm):
                 break
 
         # TODO: Could it happen in normal cases?
-        assert unwrapping_key is not None, "Local HSM does not contain suitable unwrapping key for master key 0x%s" % hexlify(mkey_id)
+        assert unwrapping_key is not None, ("Local HSM does not contain " \
+            "suitable unwrapping key for master key 0x%s") % \
+            str_hexlify(mkey_id)
 
         params = ldap2p11helper_api_params(mkey_ldap)
         params['data'] = wrapped_ldap.single_value['ipaSecretKey']
         params['unwrapping_key'] = unwrapping_key.handle
         params['wrapping_mech'] = wrappingmech_name2id[wrapped_ldap.single_value['ipaWrappingMech']]
         logger.debug('Importing new master key: 0x%s %s',
-                     hexlify(mkey_id), params)
+                     str_hexlify(mkey_id), params)
         localhsm.p11.import_wrapped_secret_key(**params)
 
     # synchronize metadata about master keys in LDAP
@@ -108,14 +111,14 @@ def ldap2replica_zone_keys_sync(ldapkeydb, localhsm):
     for zkey_id in new_keys:
         zkey_ldap = ldapkeydb.zone_keypairs[zkey_id]
         logger.debug('Looking for unwrapping key "%s" for zone key 0x%s',
-                     zkey_ldap['ipaWrappingKey'], hexlify(zkey_id))
+                     zkey_ldap['ipaWrappingKey'], str_hexlify(zkey_id))
         unwrapping_key = find_unwrapping_key(
             localhsm, zkey_ldap['ipaWrappingKey'])
         assert unwrapping_key is not None, \
                 "Local HSM does not contain suitable unwrapping key for ' \
-                'zone key 0x%s" % hexlify(zkey_id)
+                'zone key 0x%s" % str_hexlify(zkey_id)
 
-        logger.debug('Importing zone key pair 0x%s', hexlify(zkey_id))
+        logger.debug('Importing zone key pair 0x%s', str_hexlify(zkey_id))
         localhsm.import_private_key(zkey_ldap, zkey_ldap['ipaPrivateKey'],
                 unwrapping_key)
         localhsm.import_public_key(zkey_ldap, zkey_ldap['ipaPublicKey'])
diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
index b1e69df864..a37d8d32ff 100755
--- a/daemons/dnssec/ipa-ods-exporter
+++ b/daemons/dnssec/ipa-ods-exporter
@@ -16,7 +16,6 @@ Purpose of this replacement is to upload keys generated by OpenDNSSEC to LDAP.
 """
 from __future__ import print_function
 
-from binascii import hexlify
 from datetime import datetime
 import dateutil.tz
 import dns.dnssec
@@ -38,7 +37,7 @@ from ipapython.dn import DN
 from ipapython import ipaldap
 from ipaplatform.paths import paths
 from ipaserver.dnssec.abshsm import sync_pkcs11_metadata, wrappingmech_name2id
-from ipaserver.dnssec.ldapkeydb import LdapKeyDB
+from ipaserver.dnssec.ldapkeydb import LdapKeyDB, str_hexlify
 from ipaserver.dnssec.localhsm import LocalHSM
 
 logger = logging.getLogger(os.path.basename(__file__))
@@ -299,8 +298,8 @@ def ldap2master_replica_keys_sync(ldapkeydb, localhsm):
         new_key_ldap = ldapkeydb.replica_pubkeys_wrap[key_id]
         logger.debug('label=%s, id=%s, data=%s',
                      new_key_ldap['ipk11label'],
-                     hexlify(new_key_ldap['ipk11id']),
-                     hexlify(new_key_ldap['ipapublickey']))
+                     str_hexlify(new_key_ldap['ipk11id']),
+                     str_hexlify(new_key_ldap['ipapublickey']))
         localhsm.import_public_key(new_key_ldap, new_key_ldap['ipapublickey'])
 
     # set CKA_WRAP = FALSE for all replica keys removed from LDAP
@@ -339,7 +338,7 @@ def master2ldap_master_keys_sync(ldapkeydb, localhsm):
     # synchronize master key metadata to LDAP
     for mkey_id, mkey_local in localhsm.master_keys.items():
         logger.debug('synchronizing master key metadata: 0x%s',
-                     hexlify(mkey_id))
+                     str_hexlify(mkey_id))
         sync_pkcs11_metadata('master2ldap_master', mkey_local, ldapkeydb.master_keys[mkey_id])
 
     # re-wrap all master keys in LDAP with new replica keys (as necessary)
@@ -349,7 +348,7 @@ def master2ldap_master_keys_sync(ldapkeydb, localhsm):
 
     for mkey_id, mkey_ldap in ldapkeydb.master_keys.items():
         logger.debug('processing master key data: 0x%s',
-                     hexlify(mkey_id))
+                     str_hexlify(mkey_id))
 
         # check that all active replicas have own copy of master key
         used_replica_keys = set()
@@ -367,13 +366,13 @@ def master2ldap_master_keys_sync(ldapkeydb, localhsm):
 
         new_replica_keys = enabled_replica_key_ids - used_replica_keys
         logger.debug('master key 0x%s is not wrapped with replica keys %s',
-                     hexlify(mkey_id), hex_set(new_replica_keys))
+                     str_hexlify(mkey_id), hex_set(new_replica_keys))
 
         # wrap master key with new replica keys
         mkey_local = localhsm.find_keys(id=mkey_id).popitem()[1]
         for replica_key_id in new_replica_keys:
             logger.info('adding master key 0x%s wrapped with replica key 0x%s',
-                        hexlify(mkey_id), hexlify(replica_key_id))
+                        str_hexlify(mkey_id), str_hexlify(replica_key_id))
             replica_key = localhsm.replica_pubkeys_wrap[replica_key_id]
             keydata = localhsm.p11.export_wrapped_key(mkey_local.handle,
                     replica_key.handle,
@@ -446,7 +445,7 @@ def master2ldap_zone_keys_purge(ldapkeydb, localhsm):
 def hex_set(s):
     out = set()
     for i in s:
-        out.add("0x%s" % hexlify(i))
+        out.add("0x%s" % str_hexlify(i))
     return out
 
 def receive_systemd_command():
diff --git a/ipaserver/dnssec/ldapkeydb.py b/ipaserver/dnssec/ldapkeydb.py
index 30c21ab5c2..99e8a403b0 100644
--- a/ipaserver/dnssec/ldapkeydb.py
+++ b/ipaserver/dnssec/ldapkeydb.py
@@ -29,7 +29,7 @@
 def uri_escape(val):
     """convert val to %-notation suitable for ID component in URI"""
     assert len(val) > 0, "zero-length URI component detected"
-    hexval = hexlify(val)
+    hexval = str_hexlify(val)
     out = '%'
     # pylint: disable=E1127
     out += '%'.join(hexval[i:i+2] for i in range(0, len(hexval), 2))
@@ -112,6 +112,13 @@ def get_default_attrs(object_classes):
     return result
 
 
+def str_hexlify(data):
+    out = hexlify(data)
+    if isinstance(out, bytes):
+        out = out.decode('utf-8')
+    return out
+
+
 class Key(collections.MutableMapping):
     """abstraction to hide LDAP entry weirdnesses:
         - non-normalized attribute names
@@ -197,7 +204,7 @@ def _delete_key(self):
             "Key._delete_key() called before Key.schedule_deletion()")
         assert self._delentry, "Key._delete_key() called more than once"
         logger.debug('deleting key id 0x%s DN %s from LDAP',
-                     hexlify(self._delentry.single_value['ipk11id']),
+                     str_hexlify(self._delentry.single_value['ipk11id']),
                      self._delentry.dn)
         self.ldap.delete_entry(self._delentry)
         self._delentry = None
@@ -260,8 +267,8 @@ def add_wrapped_data(self, data, wrapping_mech, replica_key_id):
 
         logger.info('adding master key 0x%s wrapped with replica key 0x%s to '
                     '%s',
-                    hexlify(self['ipk11id']),
-                    hexlify(replica_key_id),
+                    str_hexlify(self['ipk11id']),
+                    str_hexlify(replica_key_id),
                     entry_dn)
         self.ldap.add_entry(entry)
         if 'ipaSecretKeyRef' not in self.entry:
@@ -294,7 +301,9 @@ def _get_key_dict(self, key_type, ldap_filter):
 
             assert 'ipk11id' in key, 'key is missing ipk11Id in %s' % key.entry.dn
             key_id = key['ipk11id']
-            assert key_id not in keys, 'duplicate ipk11Id=0x%s in "%s" and "%s"' % (hexlify(key_id), key.entry.dn, keys[key_id].entry.dn)
+            assert key_id not in keys, \
+                'duplicate ipk11Id=0x%s in "%s" and "%s"' % \
+                (str_hexlify(key_id), key.entry.dn, keys[key_id].entry.dn)
             assert 'ipk11label' in key, 'key "%s" is missing ipk11Label' % key.entry.dn
             assert 'objectclass' in key.entry, 'key "%s" is missing objectClass attribute' % key.entry.dn
 
@@ -365,7 +374,8 @@ def import_zone_key(self, pubkey, pubkey_data, privkey,
         new_key.entry['ipaPublicKey'] = pubkey_data
 
         self.ldap.add_entry(new_key.entry)
-        logger.debug('imported zone key id: 0x%s', hexlify(new_key['ipk11id']))
+        logger.debug('imported zone key id: 0x%s',
+                     str_hexlify(new_key['ipk11id']))
 
     @property
     def replica_pubkeys_wrap(self):
@@ -392,7 +402,7 @@ def master_keys(self):
                 'secret key dn="%s" ipk11id=0x%s ipk11label="%s" with ipk11UnWrap = TRUE does not have '\
                 '"%s" key label' % (
                     key.entry.dn,
-                    hexlify(key['ipk11id']),
+                    str_hexlify(key['ipk11id']),
                     str(key['ipk11label']),
                     prefix)
 
@@ -437,19 +447,19 @@ def zone_keypairs(self):
     print('replica public keys: CKA_WRAP = TRUE')
     print('====================================')
     for pubkey_id, pubkey in ldapkeydb.replica_pubkeys_wrap.items():
-        print(hexlify(pubkey_id))
+        print(str_hexlify(pubkey_id))
         pprint(pubkey)
 
     print('')
     print('master keys')
     print('===========')
     for mkey_id, mkey in ldapkeydb.master_keys.items():
-        print(hexlify(mkey_id))
+        print(str_hexlify(mkey_id))
         pprint(mkey)
 
     print('')
     print('zone key pairs')
     print('==============')
     for key_id, key in ldapkeydb.zone_keypairs.items():
-        print(hexlify(key_id))
+        print(str_hexlify(key_id))
         pprint(key)
diff --git a/ipaserver/dnssec/localhsm.py b/ipaserver/dnssec/localhsm.py
index 50a11714ff..7d384da7a9 100755
--- a/ipaserver/dnssec/localhsm.py
+++ b/ipaserver/dnssec/localhsm.py
@@ -5,17 +5,17 @@
 
 from __future__ import print_function
 
-from binascii import hexlify
 import collections
 import os
 from pprint import pprint
 
 from ipaplatform.paths import paths
-
 from ipaserver import p11helper as _ipap11helper
 from ipaserver.dnssec.abshsm import (attrs_name2id, attrs_id2name, AbstractHSM,
                                      keytype_id2name, keytype_name2id,
                                      ldap2p11helper_api_params)
+from ipaserver.dnssec.ldapkeydb import str_hexlify
+
 
 private_key_api_params = set(["label", "id", "data", "unwrapping_key",
     "wrapping_mech", "key_type", "cka_always_authenticate", "cka_copyable",
@@ -44,7 +44,7 @@ def __init__(self, p11, handle):
 
         except _ipap11helper.NotFound:
             raise _ipap11helper.NotFound('key without ipk11label: id 0x%s'
-                    % hexlify(cka_id))
+                    % str_hexlify(cka_id))
 
     def __getitem__(self, key):
         key = key.lower()
@@ -113,7 +113,7 @@ def find_keys(self, **kwargs):
             key = Key(self.p11, h)
             o_id = key['ipk11id']
             assert o_id not in keys, 'duplicate ipk11Id = 0x%s; keys = %s' % (
-                    hexlify(o_id), keys)
+                    str_hexlify(o_id), keys)
             keys[o_id] = key
 
         return keys
@@ -138,7 +138,7 @@ def master_keys(self):
             prefix = 'dnssec-master'
             assert key['ipk11label'] == prefix, \
                 'secret key ipk11id=0x%s ipk11label="%s" with ipk11UnWrap = TRUE does not have '\
-                '"%s" key label' % (hexlify(key['ipk11id']),
+                '"%s" key label' % (str_hexlify(key['ipk11id']),
                         str(key['ipk11label']), prefix)
 
         return keys
@@ -194,33 +194,33 @@ def import_private_key(self, source, data, unwrapping_key):
     print('replica public keys: CKA_WRAP = TRUE')
     print('====================================')
     for pubkey_id, pubkey in localhsm.replica_pubkeys_wrap.items():
-        print(hexlify(pubkey_id))
+        print(str_hexlify(pubkey_id))
         pprint(pubkey)
 
     print('')
     print('replica public keys: all')
     print('========================')
     for pubkey_id, pubkey in localhsm.replica_pubkeys.items():
-        print(hexlify(pubkey_id))
+        print(str_hexlify(pubkey_id))
         pprint(pubkey)
 
     print('')
     print('master keys')
     print('===========')
     for mkey_id, mkey in localhsm.master_keys.items():
-        print(hexlify(mkey_id))
+        print(str_hexlify(mkey_id))
         pprint(mkey)
 
     print('')
     print('zone public keys')
     print('================')
     for key_id, key in localhsm.zone_pubkeys.items():
-        print(hexlify(key_id))
+        print(str_hexlify(key_id))
         pprint(key)
 
     print('')
     print('zone private keys')
     print('=================')
     for key_id, key in localhsm.zone_privkeys.items():
-        print(hexlify(key_id))
+        print(str_hexlify(key_id))
         pprint(key)

From 0cd0a6fa7c1aa0ec0c5541b8490c2d35bd48a2fd Mon Sep 17 00:00:00 2001
From: Tomas Krizek <tkri...@redhat.com>
Date: Mon, 28 Aug 2017 19:39:07 +0200
Subject: [PATCH 5/6] spec: bump python3-pyldap for py3 dnssec

Newer version of python3-pyldap contains a fix necessary for
Python3 porting: https://github.com/pyldap/pyldap/issues/103

Related: https://pagure.io/freeipa/issue/4985

Signed-off-by: Tomas Krizek <tkri...@redhat.com>
---
 freeipa.spec.in | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 33f5474c44..92ad6800e8 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -403,7 +403,7 @@ Requires: %{name}-common = %{version}-%{release}
 Requires: python3-ipaclient = %{version}-%{release}
 Requires: python3-custodia >= 0.3.1
 # we need pre-requires since earlier versions may break upgrade
-Requires(pre): python3-pyldap >= 2.4.35.1-2
+Requires(pre): python3-pyldap >= 2.4.37
 Requires: python3-lxml
 Requires: python3-gssapi >= 1.2.0
 Requires: python3-sssdconfig
@@ -739,7 +739,7 @@ Requires: python3-six
 Requires: python3-jwcrypto >= 0.4.2
 Requires: python3-cffi
 # we need pre-requires since earlier versions may break upgrade
-Requires(pre): python3-pyldap >= 2.4.35.1-2
+Requires(pre): python3-pyldap >= 2.4.37
 Requires: python3-requests
 Requires: python3-dns >= 1.15
 Requires: python3-netifaces >= 0.10.4

From ae330a2fcfd03503a548e587f39ea0f13c219b9b Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Wed, 15 Nov 2017 15:46:33 +0100
Subject: [PATCH 6/6] More DNSSEC house keeping

Related: https://pagure.io/freeipa/issue/4985
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaserver/dnssec/bindmgr.py  | 46 ++++++++++++++++++++++----------------------
 ipaserver/dnssec/localhsm.py | 13 ++++++-------
 2 files changed, 29 insertions(+), 30 deletions(-)

diff --git a/ipaserver/dnssec/bindmgr.py b/ipaserver/dnssec/bindmgr.py
index 69dff3deea..9224c21f28 100644
--- a/ipaserver/dnssec/bindmgr.py
+++ b/ipaserver/dnssec/bindmgr.py
@@ -106,18 +106,27 @@ def ldap_event(self, op, uuid, attrs):
 
     def install_key(self, zone, uuid, attrs, workdir):
         """Run dnssec-keyfromlabel on given LDAP object.
-        :returns: base file name of output files, e.g. Kaaa.test.+008+19719"""
+        :returns: base file name of output files, e.g. Kaaa.test.+008+19719
+        """
         logger.info('attrs: %s', attrs)
         assert attrs.get('idnsseckeyzone', [b'FALSE'])[0] == b'TRUE', \
             b'object %s is not a DNS zone key' % attrs['dn']
 
-        uri = b"%s;pin-source=%s" % (attrs['idnsSecKeyRef'][0], paths.DNSSEC_SOFTHSM_PIN.encode('utf-8'))
-        cmd = [paths.DNSSEC_KEYFROMLABEL, '-K', workdir, '-a', attrs['idnsSecAlgorithm'][0], '-l', uri]
-        cmd += self.dates2params(attrs)
+        uri = b"%s;pin-source=%s" % (
+            attrs['idnsSecKeyRef'][0],
+            paths.DNSSEC_SOFTHSM_PIN.encode('utf-8')
+        )
+        cmd = [
+            paths.DNSSEC_KEYFROMLABEL,
+            '-K', workdir,
+            '-a', attrs['idnsSecAlgorithm'][0],
+            '-l', uri
+        ]
+        cmd.extend(self.dates2params(attrs))
         if attrs.get('idnsSecKeySep', [b'FALSE'])[0].upper() == b'TRUE':
-            cmd += ['-f', 'KSK']
+            cmd.extend(['-f', 'KSK'])
         if attrs.get('idnsSecKeyRevoke', [b'FALSE'])[0].upper() == b'TRUE':
-            cmd += ['-R', datetime.now().strftime(time_bindfmt)]
+            cmd.extend(['-R', datetime.now().strftime(time_bindfmt)])
         cmd.append(zone.to_text())
 
         # keys has to be readable by ODS & named
@@ -142,28 +151,19 @@ def get_zone_dir_name(self, zone):
 
         # strip final (empty) label
         zone = zone.relativize(dns.name.root)
-        escaped = ""
+        escaped = []
         for label in zone:
             for char in label:
-                if six.PY2:
-                    # PY3 char is already int
-                    char = ord(char)
-                if (
-                    (char >= 0x30 and char <= 0x39) or  # digit
-                    (char >= 0x41 and char <= 0x5A) or  # uppercase
-                    (char >= 0x61 and char <= 0x7A) or  # lowercase
-                    char == 0x2D or                     # hyphen
-                    char == 0x5F                        # underscore
-                ):
-                    if char >= 0x41 and char <= 0x5A:  # downcase
-                        char += 0x20
-                    escaped += chr(char)
+                if six.PY3:
+                    char = chr(char)
+                if char.isalnum() or char in "-_":
+                    escaped.append(char.lower())
                 else:
-                    escaped += "%%%02X" % char
-            escaped += '.'
+                    escaped.append("%%%02X" % ord(char))
+            escaped.append('.')
 
         # strip trailing period
-        return escaped[:-1]
+        return ''.join(escaped[:-1])
 
     def sync_zone(self, zone):
         logger.info('Synchronizing zone %s', zone)
diff --git a/ipaserver/dnssec/localhsm.py b/ipaserver/dnssec/localhsm.py
index 7d384da7a9..3dc708f677 100755
--- a/ipaserver/dnssec/localhsm.py
+++ b/ipaserver/dnssec/localhsm.py
@@ -43,8 +43,8 @@ def __init__(self, p11, handle):
             assert len(cka_label) != 0, 'ipk11label length should not be 0'
 
         except _ipap11helper.NotFound:
-            raise _ipap11helper.NotFound('key without ipk11label: id 0x%s'
-                    % str_hexlify(cka_id))
+            raise _ipap11helper.NotFound(
+                'key without ipk11label: id 0x%s' % str_hexlify(cka_id))
 
     def __getitem__(self, key):
         key = key.lower()
@@ -184,7 +184,6 @@ def import_private_key(self, source, data, unwrapping_key):
         return Key(self.p11, h)
 
 
-
 if __name__ == '__main__':
     if 'SOFTHSM2_CONF' not in os.environ:
         os.environ['SOFTHSM2_CONF'] = paths.DNSSEC_SOFTHSM2_CONF
@@ -214,13 +213,13 @@ def import_private_key(self, source, data, unwrapping_key):
     print('')
     print('zone public keys')
     print('================')
-    for key_id, key in localhsm.zone_pubkeys.items():
+    for key_id, zkey in localhsm.zone_pubkeys.items():
         print(str_hexlify(key_id))
-        pprint(key)
+        pprint(zkey)
 
     print('')
     print('zone private keys')
     print('=================')
-    for key_id, key in localhsm.zone_privkeys.items():
+    for key_id, zkey in localhsm.zone_privkeys.items():
         print(str_hexlify(key_id))
-        pprint(key)
+        pprint(zkey)
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to