diff options
Diffstat (limited to 'ipapython')
-rw-r--r-- | ipapython/dnssec/__init__.py | 0 | ||||
-rw-r--r-- | ipapython/dnssec/abshsm.py | 184 | ||||
-rw-r--r-- | ipapython/dnssec/bindmgr.py | 217 | ||||
-rw-r--r-- | ipapython/dnssec/keysyncer.py | 191 | ||||
-rw-r--r-- | ipapython/dnssec/ldapkeydb.py | 450 | ||||
-rwxr-xr-x | ipapython/dnssec/localhsm.py | 227 | ||||
-rw-r--r-- | ipapython/dnssec/odsmgr.py | 210 | ||||
-rw-r--r-- | ipapython/dnssec/syncrepl.py | 115 | ||||
-rw-r--r-- | ipapython/dnssec/temp.py | 22 | ||||
-rw-r--r-- | ipapython/p11helper.py | 1772 | ||||
-rw-r--r-- | ipapython/secrets/__init__.py | 0 | ||||
-rw-r--r-- | ipapython/secrets/client.py | 109 | ||||
-rw-r--r-- | ipapython/secrets/common.py | 45 | ||||
-rw-r--r-- | ipapython/secrets/kem.py | 228 | ||||
-rw-r--r-- | ipapython/secrets/store.py | 261 | ||||
-rwxr-xr-x | ipapython/setup.py | 10 |
16 files changed, 0 insertions, 4041 deletions
diff --git a/ipapython/dnssec/__init__.py b/ipapython/dnssec/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ipapython/dnssec/__init__.py +++ /dev/null diff --git a/ipapython/dnssec/abshsm.py b/ipapython/dnssec/abshsm.py deleted file mode 100644 index 1533892f8..000000000 --- a/ipapython/dnssec/abshsm.py +++ /dev/null @@ -1,184 +0,0 @@ -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -from ipapython import p11helper as _ipap11helper - -attrs_id2name = { - #_ipap11helper.CKA_ALLOWED_MECHANISMS: 'ipk11allowedmechanisms', - _ipap11helper.CKA_ALWAYS_AUTHENTICATE: 'ipk11alwaysauthenticate', - _ipap11helper.CKA_ALWAYS_SENSITIVE: 'ipk11alwayssensitive', - #_ipap11helper.CKA_CHECK_VALUE: 'ipk11checkvalue', - _ipap11helper.CKA_COPYABLE: 'ipk11copyable', - _ipap11helper.CKA_DECRYPT: 'ipk11decrypt', - _ipap11helper.CKA_DERIVE: 'ipk11derive', - #_ipap11helper.CKA_DESTROYABLE: 'ipk11destroyable', - _ipap11helper.CKA_ENCRYPT: 'ipk11encrypt', - #_ipap11helper.CKA_END_DATE: 'ipk11enddate', - _ipap11helper.CKA_EXTRACTABLE: 'ipk11extractable', - _ipap11helper.CKA_ID: 'ipk11id', - #_ipap11helper.CKA_KEY_GEN_MECHANISM: 'ipk11keygenmechanism', - _ipap11helper.CKA_KEY_TYPE: 'ipk11keytype', - _ipap11helper.CKA_LABEL: 'ipk11label', - _ipap11helper.CKA_LOCAL: 'ipk11local', - _ipap11helper.CKA_MODIFIABLE: 'ipk11modifiable', - _ipap11helper.CKA_NEVER_EXTRACTABLE: 'ipk11neverextractable', - _ipap11helper.CKA_PRIVATE: 'ipk11private', - #_ipap11helper.CKA_PUBLIC_KEY_INFO: 'ipapublickey', - #_ipap11helper.CKA_PUBLIC_KEY_INFO: 'ipk11publickeyinfo', - _ipap11helper.CKA_SENSITIVE: 'ipk11sensitive', - _ipap11helper.CKA_SIGN: 'ipk11sign', - _ipap11helper.CKA_SIGN_RECOVER: 'ipk11signrecover', - #_ipap11helper.CKA_START_DATE: 'ipk11startdate', - #_ipap11helper.CKA_SUBJECT: 'ipk11subject', - _ipap11helper.CKA_TRUSTED: 'ipk11trusted', - _ipap11helper.CKA_UNWRAP: 'ipk11unwrap', - #_ipap11helper.CKA_UNWRAP_TEMPLATE: 'ipk11unwraptemplate', - _ipap11helper.CKA_VERIFY: 'ipk11verify', - _ipap11helper.CKA_VERIFY_RECOVER: 'ipk11verifyrecover', - _ipap11helper.CKA_WRAP: 'ipk11wrap', - #_ipap11helper.CKA_WRAP_TEMPLATE: 'ipk11wraptemplate', - _ipap11helper.CKA_WRAP_WITH_TRUSTED: 'ipk11wrapwithtrusted', -} - -attrs_name2id = {v: k for k, v in attrs_id2name.items()} - -# attribute: -# http://www.freeipa.org/page/V4/PKCS11_in_LDAP/Schema#ipk11KeyType -# -# mapping table: -# http://www.freeipa.org/page/V4/PKCS11_in_LDAP/Schema#CK_MECHANISM_TYPE -keytype_name2id = { - "rsa": _ipap11helper.KEY_TYPE_RSA, - "aes": _ipap11helper.KEY_TYPE_AES, - } - -keytype_id2name = {v: k for k, v in keytype_name2id.items()} - -wrappingmech_name2id = { - "rsaPkcs": _ipap11helper.MECH_RSA_PKCS, - "rsaPkcsOaep": _ipap11helper.MECH_RSA_PKCS_OAEP, - "aesKeyWrap": _ipap11helper.MECH_AES_KEY_WRAP, - "aesKeyWrapPad": _ipap11helper.MECH_AES_KEY_WRAP_PAD - } - -wrappingmech_id2name = {v: k for k, v in wrappingmech_name2id.items()} - - -bool_attr_names = set([ - 'ipk11alwaysauthenticate', - 'ipk11alwayssensitive', - 'ipk11copyable', - 'ipk11decrypt', - 'ipk11derive', - 'ipk11encrypt', - 'ipk11extractable', - 'ipk11local', - 'ipk11modifiable', - 'ipk11neverextractable', - 'ipk11private', - 'ipk11sensitive', - 'ipk11sign', - 'ipk11signrecover', - 'ipk11trusted', - 'ipk11unwrap', - 'ipk11verify', - 'ipk11verifyrecover', - 'ipk11wrap', - 'ipk11wrapwithtrusted', -]) - -modifiable_attrs_id2name = { - _ipap11helper.CKA_DECRYPT: 'ipk11decrypt', - _ipap11helper.CKA_DERIVE: 'ipk11derive', - _ipap11helper.CKA_ENCRYPT: 'ipk11encrypt', - _ipap11helper.CKA_EXTRACTABLE: 'ipk11extractable', - _ipap11helper.CKA_ID: 'ipk11id', - _ipap11helper.CKA_LABEL: 'ipk11label', - _ipap11helper.CKA_SENSITIVE: 'ipk11sensitive', - _ipap11helper.CKA_SIGN: 'ipk11sign', - _ipap11helper.CKA_SIGN_RECOVER: 'ipk11signrecover', - _ipap11helper.CKA_UNWRAP: 'ipk11unwrap', - _ipap11helper.CKA_VERIFY: 'ipk11verify', - _ipap11helper.CKA_VERIFY_RECOVER: 'ipk11verifyrecover', - _ipap11helper.CKA_WRAP: 'ipk11wrap', -} - -modifiable_attrs_name2id = {v: k for k, v in modifiable_attrs_id2name.items()} - -def sync_pkcs11_metadata(log, source, target): - """sync ipk11 metadata from source object to target object""" - - # iterate over list of modifiable PKCS#11 attributes - this prevents us - # from attempting to set read-only attributes like CKA_LOCAL - for attr in modifiable_attrs_name2id: - if attr in source: - if source[attr] != target[attr]: - log.debug('Updating attribute %s from "%s" to "%s"', attr, repr(source[attr]), repr(target[attr])) - target[attr] = source[attr] - -def populate_pkcs11_metadata(source, target): - """populate all ipk11 metadata attributes in target object from source object""" - for attr in attrs_name2id: - if attr in source: - target[attr] = source[attr] - -def ldap2p11helper_api_params(ldap_key): - """prepare dict with metadata parameters suitable for key unwrapping""" - unwrap_params = {} - - # some attributes are just renamed - direct_param_map = { - "ipk11label": "label", - "ipk11id": "id", - "ipk11copyable": "cka_copyable", - "ipk11decrypt": "cka_decrypt", - "ipk11derive": "cka_derive", - "ipk11encrypt": "cka_encrypt", - "ipk11extractable": "cka_extractable", - "ipk11modifiable": "cka_modifiable", - "ipk11private": "cka_private", - "ipk11sensitive": "cka_sensitive", - "ipk11sign": "cka_sign", - "ipk11unwrap": "cka_unwrap", - "ipk11verify": "cka_verify", - "ipk11wrap": "cka_wrap", - "ipk11wrapwithtrusted": "cka_wrap_with_trusted" - } - - for ldap_name, p11h_name in direct_param_map.items(): - if ldap_name in ldap_key: - unwrap_params[p11h_name] = ldap_key[ldap_name] - - # and some others needs conversion - - indirect_param_map = { - "ipk11keytype": ("key_type", keytype_name2id), - "ipawrappingmech": ("wrapping_mech", wrappingmech_name2id), - } - - for ldap_name, rules in indirect_param_map.items(): - p11h_name, mapping = rules - if ldap_name in ldap_key: - unwrap_params[p11h_name] = mapping[ldap_key[ldap_name]] - - return unwrap_params - - -class AbstractHSM(object): - def _filter_replica_keys(self, all_keys): - replica_keys = {} - for key_id, key in all_keys.items(): - if not key['ipk11label'].startswith('dnssec-replica:'): - continue - replica_keys[key_id] = key - return replica_keys - - def _filter_zone_keys(self, all_keys): - zone_keys = {} - for key_id, key in all_keys.items(): - if key['ipk11label'] == u'dnssec-master' \ - or key['ipk11label'].startswith('dnssec-replica:'): - continue - zone_keys[key_id] = key - return zone_keys diff --git a/ipapython/dnssec/bindmgr.py b/ipapython/dnssec/bindmgr.py deleted file mode 100644 index 33d071f45..000000000 --- a/ipapython/dnssec/bindmgr.py +++ /dev/null @@ -1,217 +0,0 @@ -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -from datetime import datetime -import dns.name -import errno -import os -import shutil -import stat - -import ipalib.constants -from ipapython.dn import DN -from ipapython import ipa_log_manager, ipautil -from ipaplatform.paths import paths - -from ipapython.dnssec.temp import TemporaryDirectory - -time_bindfmt = '%Y%m%d%H%M%S' - -# this daemon should run under ods:named user:group -# user has to be ods because ODSMgr.py sends signal to ods-enforcerd -FILE_PERM = (stat.S_IRUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IWUSR) -DIR_PERM = (stat.S_IRWXU | stat.S_IRWXG) - -class BINDMgr(object): - """BIND key manager. It does LDAP->BIND key files synchronization. - - One LDAP object with idnsSecKey object class will produce - single pair of BIND key files. - """ - def __init__(self, api): - self.api = api - self.log = ipa_log_manager.log_mgr.get_logger(self) - self.ldap_keys = {} - self.modified_zones = set() - - def notify_zone(self, zone): - cmd = ['rndc', 'sign', zone.to_text()] - result = ipautil.run(cmd, capture_output=True) - self.log.info('%s', result.output_log) - - def dn2zone_name(self, dn): - """cn=KSK-20140813162153Z-cede9e182fc4af76c4bddbc19123a565,cn=keys,idnsname=test,cn=dns,dc=ipa,dc=example""" - # verify that metadata object is under DNS sub-tree - dn = DN(dn) - container = DN(self.api.env.container_dns, self.api.env.basedn) - idx = dn.rfind(container) - assert idx != -1, 'Metadata object %s is not inside %s' % (dn, container) - assert len(dn[idx - 1]) == 1, 'Multi-valued RDN as zone name is not supported' - return dns.name.from_text(dn[idx - 1]['idnsname']) - - def time_ldap2bindfmt(self, str_val): - dt = datetime.strptime(str_val, ipalib.constants.LDAP_GENERALIZED_TIME_FORMAT) - return dt.strftime(time_bindfmt) - - def dates2params(self, ldap_attrs): - """Convert LDAP timestamps to list of parameters suitable - for dnssec-keyfromlabel utility""" - attr2param = {'idnsseckeypublish': '-P', - 'idnsseckeyactivate': '-A', - 'idnsseckeyinactive': '-I', - 'idnsseckeydelete': '-D'} - - params = [] - for attr, param in attr2param.items(): - params.append(param) - if attr in ldap_attrs: - assert len(ldap_attrs[attr]) == 1, 'Timestamp %s is expected to be single-valued' % attr - params.append(self.time_ldap2bindfmt(ldap_attrs[attr][0])) - else: - params.append('none') - - return params - - def ldap_event(self, op, uuid, attrs): - """Record single LDAP event - key addition, deletion or modification. - - Change is only recorded to memory. - self.sync() has to be called to synchronize change to BIND.""" - assert op == 'add' or op == 'del' or op == 'mod' - zone = self.dn2zone_name(attrs['dn']) - self.modified_zones.add(zone) - zone_keys = self.ldap_keys.setdefault(zone, {}) - if op == 'add': - self.log.info('Key metadata %s added to zone %s' % (attrs['dn'], zone)) - zone_keys[uuid] = attrs - - elif op == 'del': - self.log.info('Key metadata %s deleted from zone %s' % (attrs['dn'], zone)) - zone_keys.pop(uuid) - - elif op == 'mod': - self.log.info('Key metadata %s updated in zone %s' % (attrs['dn'], zone)) - zone_keys[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""" - self.log.info('attrs: %s', attrs) - assert attrs.get('idnsseckeyzone', ['FALSE'])[0] == 'TRUE', \ - 'object %s is not a DNS zone key' % attrs['dn'] - - uri = "%s;pin-source=%s" % (attrs['idnsSecKeyRef'][0], paths.DNSSEC_SOFTHSM_PIN) - cmd = [paths.DNSSEC_KEYFROMLABEL, '-K', workdir, '-a', attrs['idnsSecAlgorithm'][0], '-l', uri] - cmd += self.dates2params(attrs) - if attrs.get('idnsSecKeySep', ['FALSE'])[0].upper() == 'TRUE': - cmd += ['-f', 'KSK'] - if attrs.get('idnsSecKeyRevoke', ['FALSE'])[0].upper() == 'TRUE': - cmd += ['-R', datetime.now().strftime(time_bindfmt)] - cmd.append(zone.to_text()) - - # keys has to be readable by ODS & named - result = ipautil.run(cmd, capture_output=True) - basename = result.output.strip() - private_fn = "%s/%s.private" % (workdir, basename) - os.chmod(private_fn, FILE_PERM) - # this is useful mainly for debugging - with open("%s/%s.uuid" % (workdir, basename), 'w') as uuid_file: - uuid_file.write(uuid) - with open("%s/%s.dn" % (workdir, basename), 'w') as dn_file: - dn_file.write(attrs['dn']) - - def get_zone_dir_name(self, zone): - """Escape zone name to form suitable for file-system. - - This method has to be equivalent to zr_get_zone_path() - in bind-dyndb-ldap/zone_register.c.""" - - if zone == dns.name.root: - return "@" - - # strip final (empty) label - zone = zone.relativize(dns.name.root) - 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) - else: - escaped += "%%%02X" % c - escaped += '.' - - # strip trailing period - return escaped[:-1] - - def sync_zone(self, zone): - self.log.info('Synchronizing zone %s' % zone) - zone_path = os.path.join(paths.BIND_LDAP_DNS_ZONE_WORKDIR, - self.get_zone_dir_name(zone)) - try: - os.makedirs(zone_path) - except OSError as e: - if e.errno != errno.EEXIST: - raise e - - # fix HSM permissions - # TODO: move out - for prefix, dirs, files in os.walk(paths.DNSSEC_TOKENS_DIR, topdown=True): - for name in dirs: - fpath = os.path.join(prefix, name) - self.log.debug('Fixing directory permissions: %s', fpath) - os.chmod(fpath, DIR_PERM | stat.S_ISGID) - for name in files: - fpath = os.path.join(prefix, name) - self.log.debug('Fixing file permissions: %s', fpath) - os.chmod(fpath, FILE_PERM) - # TODO: move out - - with TemporaryDirectory(zone_path) as tempdir: - for uuid, attrs in self.ldap_keys[zone].items(): - self.install_key(zone, uuid, attrs, tempdir) - # keys were generated in a temporary directory, swap directories - target_dir = "%s/keys" % zone_path - try: - shutil.rmtree(target_dir) - except OSError as e: - if e.errno != errno.ENOENT: - raise e - shutil.move(tempdir, target_dir) - os.chmod(target_dir, DIR_PERM) - - self.notify_zone(zone) - - def sync(self, dnssec_zones): - """Synchronize list of zones in LDAP with BIND. - - dnssec_zones lists zones which should be processed. All other zones - will be ignored even though they were modified using ldap_event(). - - This filter is useful in cases where LDAP contains DNS zones which - have old metadata objects and DNSSEC disabled. Such zones must be - ignored to prevent errors while calling dnssec-keyfromlabel or rndc. - """ - self.log.debug('Key metadata in LDAP: %s' % self.ldap_keys) - self.log.debug('Zones modified but skipped during bindmgr.sync: %s', - self.modified_zones - dnssec_zones) - for zone in self.modified_zones.intersection(dnssec_zones): - self.sync_zone(zone) - - self.modified_zones = set() - - def diff_zl(self, s1, s2): - """Compute zones present in s1 but not present in s2. - - Returns: List of (uuid, name) tuples with zones present only in s1.""" - s1_extra = s1.uuids - s2.uuids - removed = [(uuid, name) for (uuid, name) in s1.mapping.items() - if uuid in s1_extra] - return removed diff --git a/ipapython/dnssec/keysyncer.py b/ipapython/dnssec/keysyncer.py deleted file mode 100644 index 20039a068..000000000 --- a/ipapython/dnssec/keysyncer.py +++ /dev/null @@ -1,191 +0,0 @@ -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -import ldap.dn -import os - -import dns.name - -from ipaplatform.paths import paths -from ipapython import ipautil - -from ipapython.dnssec.syncrepl import SyncReplConsumer -from ipapython.dnssec.odsmgr import ODSMgr -from ipapython.dnssec.bindmgr import BINDMgr - -SIGNING_ATTR = 'idnsSecInlineSigning' -OBJCLASS_ATTR = 'objectClass' - - -class KeySyncer(SyncReplConsumer): - def __init__(self, *args, **kwargs): - # hack - self.api = kwargs['ipa_api'] - del kwargs['ipa_api'] - - # DNSSEC master should have OpenDNSSEC installed - # TODO: Is this the best way? - if os.environ.get('ISMASTER', '0') == '1': - self.ismaster = True - self.odsmgr = ODSMgr() - else: - self.ismaster = False - - self.bindmgr = BINDMgr(self.api) - self.init_done = False - self.dnssec_zones = set() - SyncReplConsumer.__init__(self, *args, **kwargs) - - def _get_objclass(self, attrs): - """Get object class. - - Given set of attributes has to have exactly one supported object class. - """ - supported_objclasses = set(['idnszone', 'idnsseckey', '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() - - 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']) - 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' - - def __is_replica_pubkey(self, attrs): - vals = attrs.get('ipk11label', []) - if len(vals) != 1: - return False - return vals[0].startswith('dnssec-replica:') - - def application_add(self, uuid, dn, newattrs): - objclass = self._get_objclass(newattrs) - if objclass == 'idnszone': - self.zone_add(uuid, dn, newattrs) - elif objclass == 'idnsseckey': - self.key_meta_add(uuid, dn, newattrs) - elif objclass == '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': - self.zone_del(uuid, dn, oldattrs) - elif objclass == 'idnsseckey': - self.key_meta_del(uuid, dn, oldattrs) - elif objclass == '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': - olddn = ldap.dn.str2dn(oldattrs['dn']) - newdn = ldap.dn.str2dn(newattrs['dn']) - assert olddn == newdn, 'modrdn operation is not supported' - - oldval = self.__get_signing_attr(oldattrs) - newval = self.__get_signing_attr(newattrs) - if oldval != newval: - if self.__is_dnssec_enabled(newattrs): - self.zone_add(uuid, olddn, newattrs) - else: - self.zone_del(uuid, olddn, oldattrs) - - elif objclass == 'idnsseckey': - self.key_metadata_sync(uuid, dn, oldattrs, newattrs) - - elif objclass == 'ipk11publickey' and \ - self.__is_replica_pubkey(newattrs): - self.hsm_master_sync() - - def syncrepl_refreshdone(self): - self.log.info('Initial LDAP dump is done, sychronizing with ODS and BIND') - self.init_done = True - self.ods_sync() - self.hsm_replica_sync() - self.hsm_master_sync() - self.bindmgr.sync(self.dnssec_zones) - - # idnsSecKey wrapper - # Assumption: metadata points to the same key blob all the time, - # i.e. it is not necessary to re-download blobs because of change in DNSSEC - # metadata - DNSSEC flags or timestamps. - def key_meta_add(self, uuid, dn, newattrs): - self.hsm_replica_sync() - self.bindmgr.ldap_event('add', uuid, newattrs) - self.bindmgr_sync(self.dnssec_zones) - - def key_meta_del(self, uuid, dn, oldattrs): - self.bindmgr.ldap_event('del', uuid, oldattrs) - self.bindmgr_sync(self.dnssec_zones) - self.hsm_replica_sync() - - def key_metadata_sync(self, uuid, dn, oldattrs, newattrs): - self.bindmgr.ldap_event('mod', uuid, newattrs) - self.bindmgr_sync(self.dnssec_zones) - - def bindmgr_sync(self, dnssec_zones): - if self.init_done: - self.bindmgr.sync(dnssec_zones) - - # idnsZone wrapper - def zone_add(self, uuid, dn, newattrs): - zone = dns.name.from_text(newattrs['idnsname'][0]) - if self.__is_dnssec_enabled(newattrs): - self.dnssec_zones.add(zone) - else: - self.dnssec_zones.discard(zone) - - if not self.ismaster: - return - - if self.__is_dnssec_enabled(newattrs): - self.odsmgr.ldap_event('add', uuid, newattrs) - self.ods_sync() - - def zone_del(self, uuid, dn, oldattrs): - zone = dns.name.from_text(oldattrs['idnsname'][0]) - self.dnssec_zones.discard(zone) - - if not self.ismaster: - return - - if self.__is_dnssec_enabled(oldattrs): - self.odsmgr.ldap_event('del', uuid, oldattrs) - self.ods_sync() - - def ods_sync(self): - if not self.ismaster: - return - - if self.init_done: - self.odsmgr.sync() - - # triggered by modification to idnsSecKey objects - def hsm_replica_sync(self): - """Download keys from LDAP to local HSM.""" - if self.ismaster: - return - if not self.init_done: - return - ipautil.run([paths.IPA_DNSKEYSYNCD_REPLICA]) - - # triggered by modification to ipk11PublicKey objects - def hsm_master_sync(self): - """Download replica keys from LDAP to local HSM - & upload master and zone keys to LDAP.""" - if not self.ismaster: - return - if not self.init_done: - return - ipautil.run([paths.ODS_SIGNER, 'ipa-hsm-update']) diff --git a/ipapython/dnssec/ldapkeydb.py b/ipapython/dnssec/ldapkeydb.py deleted file mode 100644 index aa0413934..000000000 --- a/ipapython/dnssec/ldapkeydb.py +++ /dev/null @@ -1,450 +0,0 @@ -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -from __future__ import print_function - -from binascii import hexlify -import collections -from pprint import pprint - -import ipalib -from ipapython.dn import DN -from ipapython import ipaldap -from ipapython import ipa_log_manager - -from ipapython.dnssec.abshsm import ( - attrs_name2id, - AbstractHSM, - bool_attr_names, - populate_pkcs11_metadata) -from ipapython import p11helper as _ipap11helper -import uuid - -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) - out = '%' - # pylint: disable=E1127 - out += '%'.join(hexval[i:i+2] for i in range(0, len(hexval), 2)) - return out - -def ldap_bool(val): - if val == 'TRUE' or val is True: - return True - elif val == 'FALSE' or val is False: - return False - else: - raise AssertionError('invalid LDAP boolean "%s"' % val) - -def get_default_attrs(object_classes): - # object class -> default attribute values mapping - defaults = { - u'ipk11publickey': { - 'ipk11copyable': True, - 'ipk11derive': False, - 'ipk11encrypt': False, - 'ipk11local': True, - 'ipk11modifiable': True, - 'ipk11private': True, - 'ipk11trusted': False, - 'ipk11verify': True, - 'ipk11verifyrecover': True, - 'ipk11wrap': False - }, - u'ipk11privatekey': { - 'ipk11alwaysauthenticate': False, - 'ipk11alwayssensitive': True, - 'ipk11copyable': True, - 'ipk11decrypt': False, - 'ipk11derive': False, - 'ipk11extractable': True, - 'ipk11local': True, - 'ipk11modifiable': True, - 'ipk11neverextractable': False, - 'ipk11private': True, - 'ipk11sensitive': True, - 'ipk11sign': True, - 'ipk11signrecover': True, - 'ipk11unwrap': False, - 'ipk11wrapwithtrusted': False - }, - u'ipk11secretkey': { - 'ipk11alwaysauthenticate': False, - 'ipk11alwayssensitive': True, - 'ipk11copyable': True, - 'ipk11decrypt': False, - 'ipk11derive': False, - 'ipk11encrypt': False, - 'ipk11extractable': True, - 'ipk11local': True, - 'ipk11modifiable': True, - 'ipk11neverextractable': False, - 'ipk11private': True, - 'ipk11sensitive': True, - 'ipk11sign': False, - 'ipk11trusted': False, - 'ipk11unwrap': True, - 'ipk11verify': False, - 'ipk11wrap': True, - 'ipk11wrapwithtrusted': False - } - } - - # get set of supported object classes - present_clss = set() - for cls in object_classes: - present_clss.add(cls.lower()) - present_clss.intersection_update(set(defaults.keys())) - if len(present_clss) <= 0: - raise AssertionError('none of "%s" object classes are supported' % - object_classes) - - result = {} - for cls in present_clss: - result.update(defaults[cls]) - return result - - -class Key(collections.MutableMapping): - """abstraction to hide LDAP entry weirdnesses: - - non-normalized attribute names - - boolean attributes returned as strings - - planned entry deletion prevents subsequent use of the instance - """ - def __init__(self, entry, ldap, ldapkeydb): - self.entry = entry - self._delentry = None # indicates that object was deleted - self.ldap = ldap - self.ldapkeydb = ldapkeydb - self.log = ldap.log.getChild(__name__) - - def __assert_not_deleted(self): - assert self.entry and not self._delentry, ( - "attempt to use to-be-deleted entry %s detected" - % self._delentry.dn) - - def __getitem__(self, key): - self.__assert_not_deleted() - val = self.entry.single_value[key] - if key.lower() in bool_attr_names: - val = ldap_bool(val) - return val - - def __setitem__(self, key, value): - self.__assert_not_deleted() - self.entry[key] = value - - def __delitem__(self, key): - self.__assert_not_deleted() - del self.entry[key] - - def __iter__(self): - """generates list of ipa names of all PKCS#11 attributes present in the object""" - self.__assert_not_deleted() - for ipa_name in list(self.entry.keys()): - lowercase = ipa_name.lower() - if lowercase in attrs_name2id: - yield lowercase - - def __len__(self): - self.__assert_not_deleted() - return len(self.entry) - - def __repr__(self): - if self._delentry: - return 'deleted entry: %s' % repr(self._delentry) - - sanitized = dict(self.entry) - for attr in ['ipaPrivateKey', 'ipaPublicKey', 'ipk11publickeyinfo']: - if attr in sanitized: - del sanitized[attr] - return repr(sanitized) - - def _cleanup_key(self): - """remove default values from LDAP entry""" - default_attrs = get_default_attrs(self.entry['objectclass']) - empty = object() - for attr in default_attrs: - if self.get(attr, empty) == default_attrs[attr]: - del self[attr] - - def _update_key(self): - """remove default values from LDAP entry and write back changes""" - if self._delentry: - self._delete_key() - return - - self._cleanup_key() - - try: - self.ldap.update_entry(self.entry) - except ipalib.errors.EmptyModlist: - pass - - def _delete_key(self): - """remove key metadata entry from LDAP - - After calling this, the python object is no longer valid and all - subsequent method calls on it will fail. - """ - assert not self.entry, ( - "Key._delete_key() called before Key.schedule_deletion()") - assert self._delentry, "Key._delete_key() called more than once" - self.log.debug('deleting key id 0x%s DN %s from LDAP', - hexlify(self._delentry.single_value['ipk11id']), - self._delentry.dn) - self.ldap.delete_entry(self._delentry) - self._delentry = None - self.ldap = None - self.ldapkeydb = None - - def schedule_deletion(self): - """schedule key deletion from LDAP - - Calling schedule_deletion() will make this object incompatible with - normal Key. After that the object must not be read or modified. - Key metadata will be actually deleted when LdapKeyDB.flush() is called. - """ - assert not self._delentry, ( - "Key.schedule_deletion() called more than once") - self._delentry = self.entry - self.entry = None - - -class ReplicaKey(Key): - # TODO: object class assert - def __init__(self, entry, ldap, ldapkeydb): - super(ReplicaKey, self).__init__(entry, ldap, ldapkeydb) - -class MasterKey(Key): - # TODO: object class assert - def __init__(self, entry, ldap, ldapkeydb): - super(MasterKey, self).__init__(entry, ldap, ldapkeydb) - - @property - def wrapped_entries(self): - """LDAP entires with wrapped data - - One entry = one blob + ipaWrappingKey pointer to unwrapping key""" - - keys = [] - if 'ipaSecretKeyRef' not in self.entry: - return keys - - for dn in self.entry['ipaSecretKeyRef']: - try: - obj = self.ldap.get_entry(dn) - keys.append(obj) - except ipalib.errors.NotFound: - continue - - return keys - - def add_wrapped_data(self, data, wrapping_mech, replica_key_id): - wrapping_key_uri = 'pkcs11:id=%s;type=public' \ - % uri_escape(replica_key_id) - # TODO: replace this with 'autogenerate' to prevent collisions - uuid_rdn = DN('ipk11UniqueId=%s' % uuid.uuid1()) - entry_dn = DN(uuid_rdn, self.ldapkeydb.base_dn) - entry = self.ldap.make_entry(entry_dn, - objectClass=['ipaSecretKeyObject', 'ipk11Object'], - ipaSecretKey=data, - ipaWrappingKey=wrapping_key_uri, - ipaWrappingMech=wrapping_mech) - - self.log.info('adding master key 0x%s wrapped with replica key 0x%s to %s', - hexlify(self['ipk11id']), - hexlify(replica_key_id), - entry_dn) - self.ldap.add_entry(entry) - if 'ipaSecretKeyRef' not in self.entry: - self.entry['objectClass'] += ['ipaSecretKeyRefObject'] - self.entry.setdefault('ipaSecretKeyRef', []).append(entry_dn) - - -class LdapKeyDB(AbstractHSM): - def __init__(self, log, ldap, base_dn): - self.ldap = ldap - self.base_dn = base_dn - self.log = log - self.cache_replica_pubkeys_wrap = None - self.cache_masterkeys = None - self.cache_zone_keypairs = None - - def _get_key_dict(self, key_type, ldap_filter): - try: - objs = self.ldap.get_entries(base_dn=self.base_dn, - filter=ldap_filter) - except ipalib.errors.NotFound: - return {} - - keys = {} - for o in objs: - # add default values not present in LDAP - key = key_type(o, self.ldap, self) - default_attrs = get_default_attrs(key.entry['objectclass']) - for attr in default_attrs: - key.setdefault(attr, default_attrs[attr]) - - 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 '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 - - keys[key_id] = key - - self._update_keys() - return keys - - def _update_keys(self): - for cache in [self.cache_masterkeys, self.cache_replica_pubkeys_wrap, - self.cache_zone_keypairs]: - if cache: - for key in cache.values(): - key._update_key() - - def flush(self): - """write back content of caches to LDAP""" - self._update_keys() - self.cache_masterkeys = None - self.cache_replica_pubkeys_wrap = None - self.cache_zone_keypairs = None - - def _import_keys_metadata(self, source_keys): - """import key metadata from Key-compatible objects - - metadata from multiple source keys can be imported into single LDAP - object - - :param: source_keys is iterable of (Key object, PKCS#11 object class)""" - - entry_dn = DN('ipk11UniqueId=autogenerate', self.base_dn) - entry = self.ldap.make_entry(entry_dn, objectClass=['ipk11Object']) - new_key = Key(entry, self.ldap, self) - - for source_key, pkcs11_class in source_keys: - if pkcs11_class == _ipap11helper.KEY_CLASS_SECRET_KEY: - entry['objectClass'].append('ipk11SecretKey') - elif pkcs11_class == _ipap11helper.KEY_CLASS_PUBLIC_KEY: - entry['objectClass'].append('ipk11PublicKey') - elif pkcs11_class == _ipap11helper.KEY_CLASS_PRIVATE_KEY: - entry['objectClass'].append('ipk11PrivateKey') - else: - raise AssertionError('unsupported object class %s' % pkcs11_class) - - populate_pkcs11_metadata(source_key, new_key) - new_key._cleanup_key() - return new_key - - def import_master_key(self, mkey): - new_key = self._import_keys_metadata( - [(mkey, _ipap11helper.KEY_CLASS_SECRET_KEY)]) - self.ldap.add_entry(new_key.entry) - self.log.debug('imported master key metadata: %s', new_key.entry) - - def import_zone_key(self, pubkey, pubkey_data, privkey, - privkey_wrapped_data, wrapping_mech, master_key_id): - new_key = self._import_keys_metadata( - [(pubkey, _ipap11helper.KEY_CLASS_PUBLIC_KEY), - (privkey, _ipap11helper.KEY_CLASS_PRIVATE_KEY)]) - - new_key.entry['objectClass'].append('ipaPrivateKeyObject') - new_key.entry['ipaPrivateKey'] = privkey_wrapped_data - new_key.entry['ipaWrappingKey'] = 'pkcs11:id=%s;type=secret-key' \ - % uri_escape(master_key_id) - new_key.entry['ipaWrappingMech'] = wrapping_mech - - new_key.entry['objectClass'].append('ipaPublicKeyObject') - new_key.entry['ipaPublicKey'] = pubkey_data - - self.ldap.add_entry(new_key.entry) - self.log.debug('imported zone key id: 0x%s', hexlify(new_key['ipk11id'])) - - @property - def replica_pubkeys_wrap(self): - if self.cache_replica_pubkeys_wrap: - return self.cache_replica_pubkeys_wrap - - keys = self._filter_replica_keys( - self._get_key_dict(ReplicaKey, - '(&(objectClass=ipk11PublicKey)(ipk11Wrap=TRUE)(objectClass=ipaPublicKeyObject))')) - - self.cache_replica_pubkeys_wrap = keys - return keys - - @property - def master_keys(self): - if self.cache_masterkeys: - return self.cache_masterkeys - - keys = self._get_key_dict(MasterKey, - '(&(objectClass=ipk11SecretKey)(|(ipk11UnWrap=TRUE)(!(ipk11UnWrap=*)))(ipk11Label=dnssec-master))') - for key in keys.values(): - prefix = 'dnssec-master' - assert key['ipk11label'] == prefix, \ - '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(key['ipk11label']), - prefix) - - self.cache_masterkeys = keys - return keys - - @property - def zone_keypairs(self): - if self.cache_zone_keypairs: - return self.cache_zone_keypairs - - self.cache_zone_keypairs = self._filter_zone_keys( - self._get_key_dict(Key, - '(&(objectClass=ipk11PrivateKey)(objectClass=ipaPrivateKeyObject)(objectClass=ipk11PublicKey)(objectClass=ipaPublicKeyObject))')) - - return self.cache_zone_keypairs - -if __name__ == '__main__': - # this is debugging mode - # print information we think are useful to stdout - # other garbage goes via logger to stderr - ipa_log_manager.standard_logging_setup(debug=True) - log = ipa_log_manager.root_logger - - # IPA framework initialization - ipalib.api.bootstrap(in_server=True, log=None) # no logging to file - ipalib.api.finalize() - - # LDAP initialization - dns_dn = DN(ipalib.api.env.container_dns, ipalib.api.env.basedn) - ldap = ipaldap.LDAPClient(ipalib.api.env.ldap_uri) - log.debug('Connecting to LDAP') - # GSSAPI will be used, used has to be kinited already - ldap.gssapi_bind() - log.debug('Connected') - - ldapkeydb = LdapKeyDB(log, ldap, DN(('cn', 'keys'), ('cn', 'sec'), - ipalib.api.env.container_dns, - ipalib.api.env.basedn)) - - print('replica public keys: CKA_WRAP = TRUE') - print('====================================') - for pubkey_id, pubkey in ldapkeydb.replica_pubkeys_wrap.items(): - print(hexlify(pubkey_id)) - pprint(pubkey) - - print('') - print('master keys') - print('===========') - for mkey_id, mkey in ldapkeydb.master_keys.items(): - print(hexlify(mkey_id)) - pprint(mkey) - - print('') - print('zone key pairs') - print('==============') - for key_id, key in ldapkeydb.zone_keypairs.items(): - print(hexlify(key_id)) - pprint(key) diff --git a/ipapython/dnssec/localhsm.py b/ipapython/dnssec/localhsm.py deleted file mode 100755 index befe08aec..000000000 --- a/ipapython/dnssec/localhsm.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/python2 -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -from __future__ import print_function - -from binascii import hexlify -import collections -import logging -import os -from pprint import pprint - -from ipaplatform.paths import paths - -from ipapython import p11helper as _ipap11helper -from ipapython.dnssec.abshsm import (attrs_name2id, attrs_id2name, AbstractHSM, - keytype_id2name, keytype_name2id, - ldap2p11helper_api_params) - -private_key_api_params = set(["label", "id", "data", "unwrapping_key", - "wrapping_mech", "key_type", "cka_always_authenticate", "cka_copyable", - "cka_decrypt", "cka_derive", "cka_extractable", "cka_modifiable", - "cka_private", "cka_sensitive", "cka_sign", "cka_sign_recover", - "cka_unwrap", "cka_wrap_with_trusted"]) - -public_key_api_params = set(["label", "id", "data", "cka_copyable", - "cka_derive", "cka_encrypt", "cka_modifiable", "cka_private", - "cka_trusted", "cka_verify", "cka_verify_recover", "cka_wrap"]) - -class Key(collections.MutableMapping): - def __init__(self, p11, handle): - self.p11 = p11 - self.handle = handle - # sanity check CKA_ID and CKA_LABEL - try: - cka_id = self.p11.get_attribute(handle, _ipap11helper.CKA_ID) - assert len(cka_id) != 0, 'ipk11id length should not be 0' - except _ipap11helper.NotFound: - raise _ipap11helper.NotFound('key without ipk11id: handle %s' % handle) - - try: - cka_label = self.p11.get_attribute(handle, _ipap11helper.CKA_LABEL) - assert len(cka_label) != 0, 'ipk11label length should not be 0' - - except _ipap11helper.NotFound: - raise _ipap11helper.NotFound('key without ipk11label: id 0x%s' - % hexlify(cka_id)) - - def __getitem__(self, key): - key = key.lower() - try: - value = self.p11.get_attribute(self.handle, attrs_name2id[key]) - if key == 'ipk11keytype': - value = keytype_id2name[value] - return value - except _ipap11helper.NotFound: - raise KeyError() - - def __setitem__(self, key, value): - key = key.lower() - if key == 'ipk11keytype': - value = keytype_name2id[value] - - return self.p11.set_attribute(self.handle, attrs_name2id[key], value) - - def __delitem__(self, key): - raise _ipap11helper.P11HelperException('__delitem__ is not supported') - - def __iter__(self): - """generates list of ipa names of all attributes present in the object""" - for pkcs11_id, ipa_name in attrs_id2name.items(): - try: - self.p11.get_attribute(self.handle, pkcs11_id) - except _ipap11helper.NotFound: - continue - - yield ipa_name - - def __len__(self): - cnt = 0 - for _attr in self: - cnt += 1 - return cnt - - def __str__(self): - return str(dict(self)) - - def __repr__(self): - return self.__str__() - -class LocalHSM(AbstractHSM): - def __init__(self, library, slot, pin): - self.cache_replica_pubkeys = None - self.p11 = _ipap11helper.P11_Helper(slot, pin, library) - self.log = logging.getLogger() - - def __del__(self): - self.p11.finalize() - - def find_keys(self, **kwargs): - """Return dict with Key objects matching given criteria. - - CKA_ID is used as key so all matching objects have to have unique ID.""" - - # this is a hack for old p11-kit URI parser - # see https://bugs.freedesktop.org/show_bug.cgi?id=85057 - if 'uri' in kwargs: - kwargs['uri'] = kwargs['uri'].replace('type=', 'object-type=') - - handles = self.p11.find_keys(**kwargs) - keys = {} - for h in handles: - 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) - keys[o_id] = key - - return keys - - @property - def replica_pubkeys(self): - return self._filter_replica_keys( - self.find_keys(objclass=_ipap11helper.KEY_CLASS_PUBLIC_KEY)) - - @property - def replica_pubkeys_wrap(self): - return self._filter_replica_keys( - self.find_keys(objclass=_ipap11helper.KEY_CLASS_PUBLIC_KEY, - cka_wrap=True)) - - @property - def master_keys(self): - """Get all usable DNSSEC master keys""" - keys = self.find_keys(objclass=_ipap11helper.KEY_CLASS_SECRET_KEY, label=u'dnssec-master', cka_unwrap=True) - - for key in keys.values(): - 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']), - str(key['ipk11label']), prefix) - - return keys - - @property - def active_master_key(self): - """Get one active DNSSEC master key suitable for key wrapping""" - keys = self.find_keys(objclass=_ipap11helper.KEY_CLASS_SECRET_KEY, - label=u'dnssec-master', cka_wrap=True, cka_unwrap=True) - assert len(keys) > 0, "DNSSEC master key with UN/WRAP = TRUE not found" - return keys.popitem()[1] - - @property - def zone_pubkeys(self): - return self._filter_zone_keys( - self.find_keys(objclass=_ipap11helper.KEY_CLASS_PUBLIC_KEY)) - - @property - def zone_privkeys(self): - return self._filter_zone_keys( - self.find_keys(objclass=_ipap11helper.KEY_CLASS_PRIVATE_KEY)) - - - def import_public_key(self, source, data): - params = ldap2p11helper_api_params(source) - # filter out params inappropriate for public keys - for par in set(params).difference(public_key_api_params): - del params[par] - params['data'] = data - - h = self.p11.import_public_key(**params) - return Key(self.p11, h) - - def import_private_key(self, source, data, unwrapping_key): - params = ldap2p11helper_api_params(source) - # filter out params inappropriate for private keys - for par in set(params).difference(private_key_api_params): - del params[par] - params['data'] = data - params['unwrapping_key'] = unwrapping_key.handle - - h = self.p11.import_wrapped_private_key(**params) - return Key(self.p11, h) - - - -if __name__ == '__main__': - if 'SOFTHSM2_CONF' not in os.environ: - os.environ['SOFTHSM2_CONF'] = paths.DNSSEC_SOFTHSM2_CONF - localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, 0, - open(paths.DNSSEC_SOFTHSM_PIN).read()) - - print('replica public keys: CKA_WRAP = TRUE') - print('====================================') - for pubkey_id, pubkey in localhsm.replica_pubkeys_wrap.items(): - print(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)) - pprint(pubkey) - - print('') - print('master keys') - print('===========') - for mkey_id, mkey in localhsm.master_keys.items(): - print(hexlify(mkey_id)) - pprint(mkey) - - print('') - print('zone public keys') - print('================') - for key_id, key in localhsm.zone_pubkeys.items(): - print(hexlify(key_id)) - pprint(key) - - print('') - print('zone private keys') - print('=================') - for key_id, key in localhsm.zone_privkeys.items(): - print(hexlify(key_id)) - pprint(key) diff --git a/ipapython/dnssec/odsmgr.py b/ipapython/dnssec/odsmgr.py deleted file mode 100644 index 0308408e0..000000000 --- a/ipapython/dnssec/odsmgr.py +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/python2 -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -import dns.name -try: - from xml.etree import cElementTree as etree -except ImportError: - from xml.etree import ElementTree as etree - -from ipapython import ipa_log_manager, ipautil - -# hack: zone object UUID is stored as path to imaginary zone file -ENTRYUUID_PREFIX = "/var/lib/ipa/dns/zone/entryUUID/" -ENTRYUUID_PREFIX_LEN = len(ENTRYUUID_PREFIX) - - -class ZoneListReader(object): - def __init__(self): - self.names = set() # dns.name - self.uuids = set() # UUID strings - self.mapping = dict() # {UUID: dns.name} - self.log = ipa_log_manager.log_mgr.get_logger(self) - - def _add_zone(self, name, zid): - """Add zone & UUID to internal structures. - - Zone with given name and UUID must not exist.""" - # detect duplicate zone names - name = dns.name.from_text(name) - assert name not in self.names, \ - 'duplicate name (%s, %s) vs. %s' % (name, zid, self.mapping) - # duplicate non-None zid is not allowed - assert not zid or zid not in self.uuids, \ - 'duplicate UUID (%s, %s) vs. %s' % (name, zid, self.mapping) - - self.names.add(name) - self.uuids.add(zid) - self.mapping[zid] = name - - def _del_zone(self, name, zid): - """Remove zone & UUID from internal structures. - - Zone with given name and UUID must exist. - """ - name = dns.name.from_text(name) - assert zid is not None - assert name in self.names, \ - 'name (%s, %s) does not exist in %s' % (name, zid, self.mapping) - assert zid in self.uuids, \ - 'UUID (%s, %s) does not exist in %s' % (name, zid, self.mapping) - assert zid in self.mapping and name == self.mapping[zid], \ - 'pair {%s: %s} does not exist in %s' % (zid, name, self.mapping) - - self.names.remove(name) - self.uuids.remove(zid) - del self.mapping[zid] - - -class ODSZoneListReader(ZoneListReader): - """One-shot parser for ODS zonelist.xml.""" - def __init__(self, zonelist_text): - super(ODSZoneListReader, self).__init__() - root = etree.fromstring(zonelist_text) - self._parse_zonelist(root) - - def _parse_zonelist(self, root): - """iterate over Zone elements with attribute 'name' and - add IPA zones to self.zones""" - if not root.tag == 'ZoneList': - raise ValueError(root.tag) - for zone_xml in root.findall('./Zone[@name]'): - name, zid = self._parse_ipa_zone(zone_xml) - self._add_zone(name, zid) - - def _parse_ipa_zone(self, zone_xml): - """Extract zone name, input adapter and detect IPA zones. - - IPA zones have contains Adapters/Input/Adapter element with - attribute type = "File" and with value prefixed with ENTRYUUID_PREFIX. - - Returns: - tuple (zone name, ID) - """ - name = zone_xml.get('name') - zids = [] - for in_adapter in zone_xml.findall( - './Adapters/Input/Adapter[@type="File"]'): - path = in_adapter.text - if path.startswith(ENTRYUUID_PREFIX): - # strip prefix from path - zids.append(path[ENTRYUUID_PREFIX_LEN:]) - - if len(zids) != 1: - raise ValueError('only IPA zones are supported: {}'.format( - etree.tostring(zone_xml))) - - return name, zids[0] - - -class LDAPZoneListReader(ZoneListReader): - def __init__(self): - super(LDAPZoneListReader, self).__init__() - - def process_ipa_zone(self, op, uuid, zone_ldap): - assert (op == 'add' or op == 'del'), 'unsupported op %s' % op - assert uuid is not None - assert 'idnsname' in zone_ldap, \ - 'LDAP zone UUID %s without idnsName' % uuid - assert len(zone_ldap['idnsname']) == 1, \ - 'LDAP zone UUID %s with len(idnsname) != 1' % uuid - - if op == 'add': - self._add_zone(zone_ldap['idnsname'][0], uuid) - elif op == 'del': - self._del_zone(zone_ldap['idnsname'][0], uuid) - - -class ODSMgr(object): - """OpenDNSSEC zone manager. It does LDAP->ODS synchronization. - - Zones with idnsSecInlineSigning attribute = TRUE in LDAP are added - or deleted from ODS as necessary. ODS->LDAP key synchronization - has to be solved seperatelly. - """ - def __init__(self): - self.log = ipa_log_manager.log_mgr.get_logger(self) - self.zl_ldap = LDAPZoneListReader() - - def ksmutil(self, params): - """Call ods-ksmutil with given parameters and return stdout. - - Raises CalledProcessError if returncode != 0. - """ - cmd = ['ods-ksmutil'] + params - result = ipautil.run(cmd, capture_output=True) - return result.output - - def get_ods_zonelist(self): - stdout = self.ksmutil(['zonelist', 'export']) - reader = ODSZoneListReader(stdout) - return reader - - def add_ods_zone(self, uuid, name): - zone_path = '%s%s' % (ENTRYUUID_PREFIX, uuid) - cmd = ['zone', 'add', '--zone', str(name), '--input', zone_path] - output = self.ksmutil(cmd) - self.log.info(output) - self.notify_enforcer() - - def del_ods_zone(self, name): - # ods-ksmutil blows up if zone name has period at the end - name = name.relativize(dns.name.root) - # detect if name is root zone - if name == dns.name.empty: - name = dns.name.root - cmd = ['zone', 'delete', '--zone', str(name)] - output = self.ksmutil(cmd) - self.log.info(output) - self.notify_enforcer() - self.cleanup_signer(name) - - def notify_enforcer(self): - cmd = ['notify'] - output = self.ksmutil(cmd) - self.log.info(output) - - def cleanup_signer(self, zone_name): - cmd = ['ods-signer', 'ldap-cleanup', str(zone_name)] - output = ipautil.run(cmd, capture_output=True) - self.log.info(output) - - def ldap_event(self, op, uuid, attrs): - """Record single LDAP event - zone addition or deletion. - - Change is only recorded to memory. - self.sync() have to be called to synchronize change to ODS.""" - assert op == 'add' or op == 'del' - self.zl_ldap.process_ipa_zone(op, uuid, attrs) - self.log.debug("LDAP zones: %s", self.zl_ldap.mapping) - - def sync(self): - """Synchronize list of zones in LDAP with ODS.""" - zl_ods = self.get_ods_zonelist() - self.log.debug("ODS zones: %s", zl_ods.mapping) - removed = self.diff_zl(zl_ods, self.zl_ldap) - self.log.info("Zones removed from LDAP: %s", removed) - added = self.diff_zl(self.zl_ldap, zl_ods) - self.log.info("Zones added to LDAP: %s", added) - for (uuid, name) in removed: - self.del_ods_zone(name) - for (uuid, name) in added: - self.add_ods_zone(uuid, name) - - def diff_zl(self, s1, s2): - """Compute zones present in s1 but not present in s2. - - Returns: List of (uuid, name) tuples with zones present only in s1.""" - s1_extra = s1.uuids - s2.uuids - removed = [(uuid, name) for (uuid, name) in s1.mapping.items() - if uuid in s1_extra] - return removed - - -if __name__ == '__main__': - ipa_log_manager.standard_logging_setup(debug=True) - ods = ODSMgr() - reader = ods.get_ods_zonelist() - ipa_log_manager.root_logger.info('ODS zones: %s', reader.mapping) diff --git a/ipapython/dnssec/syncrepl.py b/ipapython/dnssec/syncrepl.py deleted file mode 100644 index e197670ad..000000000 --- a/ipapython/dnssec/syncrepl.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# -""" -This script implements a syncrepl consumer which syncs data from server -to a local dict. -""" - -# Import the python-ldap modules -import ldap -# Import specific classes from python-ldap -from ldap.cidict import cidict -from ldap.ldapobject import ReconnectLDAPObject -from ldap.syncrepl import SyncreplConsumer - -from ipapython import ipa_log_manager - - -class SyncReplConsumer(ReconnectLDAPObject, SyncreplConsumer): - """ - Syncrepl Consumer interface - """ - - def __init__(self, *args, **kwargs): - self.log = ipa_log_manager.log_mgr.get_logger(self) - # Initialise the LDAP Connection first - ldap.ldapobject.ReconnectLDAPObject.__init__(self, *args, **kwargs) - # Now prepare the data store - self.__data = cidict() - self.__data['uuids'] = cidict() - # We need this for later internal use - self.__presentUUIDs = cidict() - - def close_db(self): - # This is useless for dict - pass - - def syncrepl_get_cookie(self): - if 'cookie' in self.__data: - cookie = self.__data['cookie'] - self.log.debug('Current cookie is: %s', cookie) - return cookie - else: - self.log.debug('Current cookie is: None (not received yet)') - - def syncrepl_set_cookie(self, cookie): - self.log.debug('New cookie is: %s', cookie) - self.__data['cookie'] = cookie - - def syncrepl_entry(self, dn, attributes, uuid): - attributes = cidict(attributes) - # First we determine the type of change we have here - # (and store away the previous data for later if needed) - previous_attributes = cidict() - if uuid in self.__data['uuids']: - change_type = 'modify' - previous_attributes = self.__data['uuids'][uuid] - else: - change_type = 'add' - # Now we store our knowledge of the existence of this entry - # (including the DN as an attribute for convenience) - attributes['dn'] = dn - self.__data['uuids'][uuid] = attributes - # Debugging - self.log.debug('Detected %s of entry: %s %s', change_type, dn, uuid) - if change_type == 'modify': - self.application_sync(uuid, dn, attributes, previous_attributes) - else: - self.application_add(uuid, dn, attributes) - - def syncrepl_delete(self, uuids): - # Make sure we know about the UUID being deleted, just in case... - uuids = [uuid for uuid in uuids if uuid in self.__data['uuids']] - # Delete all the UUID values we know of - for uuid in uuids: - attributes = self.__data['uuids'][uuid] - dn = attributes['dn'] - self.log.debug('Detected deletion of entry: %s %s', dn, uuid) - self.application_del(uuid, dn, attributes) - del self.__data['uuids'][uuid] - - def syncrepl_present(self, uuids, refreshDeletes=False): - # If we have not been given any UUID values, - # then we have received all the present controls... - if uuids is None: - # We only do things if refreshDeletes is false - # as the syncrepl extension will call syncrepl_delete instead - # when it detects a delete notice - if refreshDeletes is False: - deletedEntries = [uuid for uuid in self.__data['uuids'].keys() - if uuid not in self.__presentUUIDs] - self.syncrepl_delete(deletedEntries) - # Phase is now completed, reset the list - self.__presentUUIDs = {} - else: - # Note down all the UUIDs we have been sent - for uuid in uuids: - self.__presentUUIDs[uuid] = True - - def application_add(self, uuid, dn, attributes): - self.log.info('Performing application add for: %s %s', dn, uuid) - self.log.debug('New attributes: %s', attributes) - return True - - def application_sync(self, uuid, dn, attributes, previous_attributes): - self.log.info('Performing application sync for: %s %s', dn, uuid) - self.log.debug('Old attributes: %s', previous_attributes) - self.log.debug('New attributes: %s', attributes) - return True - - def application_del(self, uuid, dn, previous_attributes): - self.log.info('Performing application delete for: %s %s', dn, uuid) - self.log.debug('Old attributes: %s', previous_attributes) - return True diff --git a/ipapython/dnssec/temp.py b/ipapython/dnssec/temp.py deleted file mode 100644 index e97d3a0b8..000000000 --- a/ipapython/dnssec/temp.py +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -import errno -import shutil -import tempfile - -class TemporaryDirectory(object): - def __init__(self, root): - self.root = root - - def __enter__(self): - self.name = tempfile.mkdtemp(dir=self.root) - return self.name - - def __exit__(self, exc_type, exc_value, traceback): - try: - shutil.rmtree(self.name) - except OSError as e: - if e.errno != errno.ENOENT: - raise diff --git a/ipapython/p11helper.py b/ipapython/p11helper.py deleted file mode 100644 index 5963c6d71..000000000 --- a/ipapython/p11helper.py +++ /dev/null @@ -1,1772 +0,0 @@ -# -# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -# - -import random -import ctypes.util -import binascii - -import six -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa -from cffi import FFI - -if six.PY3: - unicode = str - - -_ffi = FFI() - -_ffi.cdef(''' -/* p11-kit/pkcs11.h */ - -typedef unsigned long CK_FLAGS; - -struct _CK_VERSION -{ - unsigned char major; - unsigned char minor; -}; - -typedef unsigned long CK_SLOT_ID; - -typedef unsigned long CK_SESSION_HANDLE; - -typedef unsigned long CK_USER_TYPE; - -typedef unsigned long CK_OBJECT_HANDLE; - -typedef unsigned long CK_OBJECT_CLASS; - -typedef unsigned long CK_KEY_TYPE; - -typedef unsigned long CK_ATTRIBUTE_TYPE; - -struct _CK_ATTRIBUTE -{ - CK_ATTRIBUTE_TYPE type; - void *pValue; - unsigned long ulValueLen; -}; - -typedef unsigned long CK_MECHANISM_TYPE; - -struct _CK_MECHANISM -{ - CK_MECHANISM_TYPE mechanism; - void *pParameter; - unsigned long ulParameterLen; -}; - -typedef unsigned long CK_RV; - -typedef ... *CK_NOTIFY; - -struct _CK_FUNCTION_LIST; - -typedef CK_RV (*CK_C_Initialize) (void *init_args); -typedef CK_RV (*CK_C_Finalize) (void *pReserved); -typedef ... *CK_C_GetInfo; -typedef ... *CK_C_GetFunctionList; -CK_RV C_GetFunctionList (struct _CK_FUNCTION_LIST **function_list); -typedef ... *CK_C_GetSlotList; -typedef ... *CK_C_GetSlotInfo; -typedef ... *CK_C_GetTokenInfo; -typedef ... *CK_C_WaitForSlotEvent; -typedef ... *CK_C_GetMechanismList; -typedef ... *CK_C_GetMechanismInfo; -typedef ... *CK_C_InitToken; -typedef ... *CK_C_InitPIN; -typedef ... *CK_C_SetPIN; -typedef CK_RV (*CK_C_OpenSession) (CK_SLOT_ID slotID, CK_FLAGS flags, - void *application, CK_NOTIFY notify, - CK_SESSION_HANDLE *session); -typedef CK_RV (*CK_C_CloseSession) (CK_SESSION_HANDLE session); -typedef ... *CK_C_CloseAllSessions; -typedef ... *CK_C_GetSessionInfo; -typedef ... *CK_C_GetOperationState; -typedef ... *CK_C_SetOperationState; -typedef CK_RV (*CK_C_Login) (CK_SESSION_HANDLE session, CK_USER_TYPE user_type, - unsigned char *pin, unsigned long pin_len); -typedef CK_RV (*CK_C_Logout) (CK_SESSION_HANDLE session); -typedef CK_RV (*CK_C_CreateObject) (CK_SESSION_HANDLE session, - struct _CK_ATTRIBUTE *templ, - unsigned long count, - CK_OBJECT_HANDLE *object); -typedef ... *CK_C_CopyObject; -typedef CK_RV (*CK_C_DestroyObject) (CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE object); -typedef ... *CK_C_GetObjectSize; -typedef CK_RV (*CK_C_GetAttributeValue) (CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE object, - struct _CK_ATTRIBUTE *templ, - unsigned long count); -typedef CK_RV (*CK_C_SetAttributeValue) (CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE object, - struct _CK_ATTRIBUTE *templ, - unsigned long count); -typedef CK_RV (*CK_C_FindObjectsInit) (CK_SESSION_HANDLE session, - struct _CK_ATTRIBUTE *templ, - unsigned long count); -typedef CK_RV (*CK_C_FindObjects) (CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE *object, - unsigned long max_object_count, - unsigned long *object_count); -typedef CK_RV (*CK_C_FindObjectsFinal) (CK_SESSION_HANDLE session); -typedef ... *CK_C_EncryptInit; -typedef ... *CK_C_Encrypt; -typedef ... *CK_C_EncryptUpdate; -typedef ... *CK_C_EncryptFinal; -typedef ... *CK_C_DecryptInit; -typedef ... *CK_C_Decrypt; -typedef ... *CK_C_DecryptUpdate; -typedef ... *CK_C_DecryptFinal; -typedef ... *CK_C_DigestInit; -typedef ... *CK_C_Digest; -typedef ... *CK_C_DigestUpdate; -typedef ... *CK_C_DigestKey; -typedef ... *CK_C_DigestFinal; -typedef ... *CK_C_SignInit; -typedef ... *CK_C_Sign; -typedef ... *CK_C_SignUpdate; -typedef ... *CK_C_SignFinal; -typedef ... *CK_C_SignRecoverInit; -typedef ... *CK_C_SignRecover; -typedef ... *CK_C_VerifyInit; -typedef ... *CK_C_Verify; -typedef ... *CK_C_VerifyUpdate; -typedef ... *CK_C_VerifyFinal; -typedef ... *CK_C_VerifyRecoverInit; -typedef ... *CK_C_VerifyRecover; -typedef ... *CK_C_DigestEncryptUpdate; -typedef ... *CK_C_DecryptDigestUpdate; -typedef ... *CK_C_SignEncryptUpdate; -typedef ... *CK_C_DecryptVerifyUpdate; -typedef CK_RV (*CK_C_GenerateKey) (CK_SESSION_HANDLE session, - struct _CK_MECHANISM *mechanism, - struct _CK_ATTRIBUTE *templ, - unsigned long count, - CK_OBJECT_HANDLE *key); -typedef CK_RV (*CK_C_GenerateKeyPair) (CK_SESSION_HANDLE session, - struct _CK_MECHANISM *mechanism, - struct _CK_ATTRIBUTE * - public_key_template, - unsigned long - public_key_attribute_count, - struct _CK_ATTRIBUTE * - private_key_template, - unsigned long - private_key_attribute_count, - CK_OBJECT_HANDLE *public_key, - CK_OBJECT_HANDLE *private_key); -typedef CK_RV (*CK_C_WrapKey) (CK_SESSION_HANDLE session, - struct _CK_MECHANISM *mechanism, - CK_OBJECT_HANDLE wrapping_key, - CK_OBJECT_HANDLE key, - unsigned char *wrapped_key, - unsigned long *wrapped_key_len); -typedef CK_RV (*CK_C_UnwrapKey) (CK_SESSION_HANDLE session, - struct _CK_MECHANISM *mechanism, - CK_OBJECT_HANDLE unwrapping_key, - unsigned char *wrapped_key, - unsigned long wrapped_key_len, - struct _CK_ATTRIBUTE *templ, - unsigned long attribute_count, - CK_OBJECT_HANDLE *key); -typedef ... *CK_C_DeriveKey; -typedef ... *CK_C_SeedRandom; -typedef ... *CK_C_GenerateRandom; -typedef ... *CK_C_GetFunctionStatus; -typedef ... *CK_C_CancelFunction; - -struct _CK_FUNCTION_LIST -{ - struct _CK_VERSION version; - CK_C_Initialize C_Initialize; - CK_C_Finalize C_Finalize; - CK_C_GetInfo C_GetInfo; - CK_C_GetFunctionList C_GetFunctionList; - CK_C_GetSlotList C_GetSlotList; - CK_C_GetSlotInfo C_GetSlotInfo; - CK_C_GetTokenInfo C_GetTokenInfo; - CK_C_GetMechanismList C_GetMechanismList; - CK_C_GetMechanismInfo C_GetMechanismInfo; - CK_C_InitToken C_InitToken; - CK_C_InitPIN C_InitPIN; - CK_C_SetPIN C_SetPIN; - CK_C_OpenSession C_OpenSession; - CK_C_CloseSession C_CloseSession; - CK_C_CloseAllSessions C_CloseAllSessions; - CK_C_GetSessionInfo C_GetSessionInfo; - CK_C_GetOperationState C_GetOperationState; - CK_C_SetOperationState C_SetOperationState; - CK_C_Login C_Login; - CK_C_Logout C_Logout; - CK_C_CreateObject C_CreateObject; - CK_C_CopyObject C_CopyObject; - CK_C_DestroyObject C_DestroyObject; - CK_C_GetObjectSize C_GetObjectSize; - CK_C_GetAttributeValue C_GetAttributeValue; - CK_C_SetAttributeValue C_SetAttributeValue; - CK_C_FindObjectsInit C_FindObjectsInit; - CK_C_FindObjects C_FindObjects; - CK_C_FindObjectsFinal C_FindObjectsFinal; - CK_C_EncryptInit C_EncryptInit; - CK_C_Encrypt C_Encrypt; - CK_C_EncryptUpdate C_EncryptUpdate; - CK_C_EncryptFinal C_EncryptFinal; - CK_C_DecryptInit C_DecryptInit; - CK_C_Decrypt C_Decrypt; - CK_C_DecryptUpdate C_DecryptUpdate; - CK_C_DecryptFinal C_DecryptFinal; - CK_C_DigestInit C_DigestInit; - CK_C_Digest C_Digest; - CK_C_DigestUpdate C_DigestUpdate; - CK_C_DigestKey C_DigestKey; - CK_C_DigestFinal C_DigestFinal; - CK_C_SignInit C_SignInit; - CK_C_Sign C_Sign; - CK_C_SignUpdate C_SignUpdate; - CK_C_SignFinal C_SignFinal; - CK_C_SignRecoverInit C_SignRecoverInit; - CK_C_SignRecover C_SignRecover; - CK_C_VerifyInit C_VerifyInit; - CK_C_Verify C_Verify; - CK_C_VerifyUpdate C_VerifyUpdate; - CK_C_VerifyFinal C_VerifyFinal; - CK_C_VerifyRecoverInit C_VerifyRecoverInit; - CK_C_VerifyRecover C_VerifyRecover; - CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; - CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; - CK_C_SignEncryptUpdate C_SignEncryptUpdate; - CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; - CK_C_GenerateKey C_GenerateKey; - CK_C_GenerateKeyPair C_GenerateKeyPair; - CK_C_WrapKey C_WrapKey; - CK_C_UnwrapKey C_UnwrapKey; - CK_C_DeriveKey C_DeriveKey; - CK_C_SeedRandom C_SeedRandom; - CK_C_GenerateRandom C_GenerateRandom; - CK_C_GetFunctionStatus C_GetFunctionStatus; - CK_C_CancelFunction C_CancelFunction; - CK_C_WaitForSlotEvent C_WaitForSlotEvent; -}; - -typedef unsigned char CK_BYTE; -typedef unsigned char CK_UTF8CHAR; -typedef unsigned char CK_BBOOL; -typedef unsigned long int CK_ULONG; -typedef CK_BYTE *CK_BYTE_PTR; -typedef CK_ULONG *CK_ULONG_PTR; - -typedef CK_OBJECT_HANDLE *CK_OBJECT_HANDLE_PTR; - -typedef struct _CK_ATTRIBUTE CK_ATTRIBUTE; -typedef struct _CK_ATTRIBUTE *CK_ATTRIBUTE_PTR; - -typedef struct _CK_MECHANISM CK_MECHANISM; - -typedef struct _CK_FUNCTION_LIST *CK_FUNCTION_LIST_PTR; - - -/* p11-kit/uri.h */ - -typedef enum { - DUMMY /* ..., */ -} P11KitUriType; - -typedef ... P11KitUri; - -CK_ATTRIBUTE_PTR p11_kit_uri_get_attributes (P11KitUri *uri, - CK_ULONG *n_attrs); - -int p11_kit_uri_any_unrecognized (P11KitUri *uri); - -P11KitUri* p11_kit_uri_new (void); - -int p11_kit_uri_parse (const char *string, - P11KitUriType uri_type, - P11KitUri *uri); - -void p11_kit_uri_free (P11KitUri *uri); - - -/* p11helper.c */ - -struct ck_rsa_pkcs_oaep_params { - CK_MECHANISM_TYPE hash_alg; - unsigned long mgf; - unsigned long source; - void *source_data; - unsigned long source_data_len; -}; - -typedef struct ck_rsa_pkcs_oaep_params CK_RSA_PKCS_OAEP_PARAMS; -''') - -_libp11_kit = _ffi.dlopen(ctypes.util.find_library('p11-kit')) - - -# utility - -NULL = _ffi.NULL - -unsigned_char = _ffi.typeof('unsigned char') -unsigned_long = _ffi.typeof('unsigned long') - -sizeof = _ffi.sizeof - - -def new_ptr(ctype, *args): - return _ffi.new(_ffi.getctype(ctype, '*'), *args) - - -def new_array(ctype, *args): - return _ffi.new(_ffi.getctype(ctype, '[]'), *args) - - -# p11-kit/pkcs11.h - -CK_SESSION_HANDLE = _ffi.typeof('CK_SESSION_HANDLE') - -CK_OBJECT_HANDLE = _ffi.typeof('CK_OBJECT_HANDLE') - -CKU_USER = 1 - -CKF_RW_SESSION = 0x2 -CKF_SERIAL_SESSION = 0x4 - -CK_OBJECT_CLASS = _ffi.typeof('CK_OBJECT_CLASS') - -CKO_PUBLIC_KEY = 2 -CKO_PRIVATE_KEY = 3 -CKO_SECRET_KEY = 4 -CKO_VENDOR_DEFINED = 0x80000000 - -CK_KEY_TYPE = _ffi.typeof('CK_KEY_TYPE') - -CKK_RSA = 0 -CKK_AES = 0x1f - -CKA_CLASS = 0 -CKA_TOKEN = 1 -CKA_PRIVATE = 2 -CKA_LABEL = 3 -CKA_TRUSTED = 0x86 -CKA_KEY_TYPE = 0x100 -CKA_ID = 0x102 -CKA_SENSITIVE = 0x103 -CKA_ENCRYPT = 0x104 -CKA_DECRYPT = 0x105 -CKA_WRAP = 0x106 -CKA_UNWRAP = 0x107 -CKA_SIGN = 0x108 -CKA_SIGN_RECOVER = 0x109 -CKA_VERIFY = 0x10a -CKA_VERIFY_RECOVER = 0x10b -CKA_DERIVE = 0x10c -CKA_MODULUS = 0x120 -CKA_MODULUS_BITS = 0x121 -CKA_PUBLIC_EXPONENT = 0x122 -CKA_VALUE_LEN = 0x161 -CKA_EXTRACTABLE = 0x162 -CKA_LOCAL = 0x163 -CKA_NEVER_EXTRACTABLE = 0x164 -CKA_ALWAYS_SENSITIVE = 0x165 -CKA_MODIFIABLE = 0x170 -CKA_ALWAYS_AUTHENTICATE = 0x202 -CKA_WRAP_WITH_TRUSTED = 0x210 - -CKM_RSA_PKCS_KEY_PAIR_GEN = 0 -CKM_RSA_PKCS = 1 -CKM_RSA_PKCS_OAEP = 9 -CKM_SHA_1 = 0x220 -CKM_AES_KEY_GEN = 0x1080 - -CKR_OK = 0 -CKR_ATTRIBUTE_TYPE_INVALID = 0x12 -CKR_USER_NOT_LOGGED_IN = 0x101 - -CK_BYTE = _ffi.typeof('CK_BYTE') -CK_BBOOL = _ffi.typeof('CK_BBOOL') -CK_ULONG = _ffi.typeof('CK_ULONG') -CK_BYTE_PTR = _ffi.typeof('CK_BYTE_PTR') -CK_FALSE = 0 -CK_TRUE = 1 - -CK_OBJECT_HANDLE_PTR = _ffi.typeof('CK_OBJECT_HANDLE_PTR') - -CK_ATTRIBUTE = _ffi.typeof('CK_ATTRIBUTE') - -CK_MECHANISM = _ffi.typeof('CK_MECHANISM') - -CK_FUNCTION_LIST_PTR = _ffi.typeof('CK_FUNCTION_LIST_PTR') - -NULL_PTR = NULL - - -# p11-kit/uri.h - -P11_KIT_URI_OK = 0 - -P11_KIT_URI_FOR_OBJECT = 2 - -p11_kit_uri_get_attributes = _libp11_kit.p11_kit_uri_get_attributes - -p11_kit_uri_any_unrecognized = _libp11_kit.p11_kit_uri_any_unrecognized - -p11_kit_uri_new = _libp11_kit.p11_kit_uri_new - -p11_kit_uri_parse = _libp11_kit.p11_kit_uri_parse - -p11_kit_uri_free = _libp11_kit.p11_kit_uri_free - - -# library.c - -def loadLibrary(module): - """Load the PKCS#11 library""" - # Load PKCS #11 library - try: - if module: - # pylint: disable=no-member - pDynLib = _ffi.dlopen(module, _ffi.RTLD_NOW | _ffi.RTLD_LOCAL) - else: - raise Exception() - - except Exception: - # Failed to load the PKCS #11 library - raise - - # Retrieve the entry point for C_GetFunctionList - pGetFunctionList = pDynLib.C_GetFunctionList - if pGetFunctionList == NULL: - raise Exception() - - # Store the handle so we can dlclose it later - - return pGetFunctionList, pDynLib - - -# p11helper.c - -# compat TODO -CKM_AES_KEY_WRAP = 0x2109 -CKM_AES_KEY_WRAP_PAD = 0x210a - -# TODO -CKA_COPYABLE = 0x0017 - -CKG_MGF1_SHA1 = 0x00000001 - -CKZ_DATA_SPECIFIED = 0x00000001 - -CK_RSA_PKCS_OAEP_PARAMS = _ffi.typeof('CK_RSA_PKCS_OAEP_PARAMS') - - -true_ptr = new_ptr(CK_BBOOL, CK_TRUE) -false_ptr = new_ptr(CK_BBOOL, CK_FALSE) - -MAX_TEMPLATE_LEN = 32 - -# -# Constants -# -CONST_RSA_PKCS_OAEP_PARAMS_ptr = new_ptr(CK_RSA_PKCS_OAEP_PARAMS, dict( - hash_alg=CKM_SHA_1, - mgf=CKG_MGF1_SHA1, - source=CKZ_DATA_SPECIFIED, - source_data=NULL, - source_data_len=0, -)) - - -# -# ipap11helper Exceptions -# -class P11HelperException(Exception): - """parent class for all exceptions""" - pass -P11HelperException.__name__ = 'Exception' - - -class Error(P11HelperException): - """general error""" - pass - - -class NotFound(P11HelperException): - """key not found""" - pass - - -class DuplicationError(P11HelperException): - """key already exists""" - pass - - -######################################################################## -# Support functions -# - -def pyobj_to_bool(pyobj): - if pyobj: - return true_ptr - return false_ptr - - -def convert_py2bool(mapping): - return tuple(pyobj_to_bool(py_obj) for py_obj in mapping) - - -def string_to_pybytes_or_none(str, len): - if str == NULL: - return None - return _ffi.buffer(str, len)[:] - - -def unicode_to_char_array(unicode): - """ - Convert a unicode string to the utf8 encoded char array - :param unicode: input python unicode object - """ - try: - utf8_str = unicode.encode('utf-8') - except Exception: - raise Error("Unable to encode UTF-8") - try: - result = new_array(unsigned_char, utf8_str) - except Exception: - raise Error("Unable to get bytes from string") - l = len(utf8_str) - return result, l - - -def char_array_to_unicode(array, l): - """ - Convert utf-8 encoded char array to unicode object - """ - return _ffi.buffer(array, l)[:].decode('utf-8') - - -def int_to_bytes(value): - try: - return binascii.unhexlify('{0:x}'.format(value)) - except (TypeError, binascii.Error): - return binascii.unhexlify('0{0:x}'.format(value)) - - -def bytes_to_int(value): - return int(binascii.hexlify(value), 16) - - -def check_return_value(rv, message): - """ - Tests result value of pkc11 operations - """ - if rv != CKR_OK: - try: - errmsg = "Error at %s: 0x%x\n" % (message, rv) - except Exception: - raise Error("An error occured during error message generation. " - "Please report this problem. Developers will use " - "a crystal ball to find out the root cause.") - else: - raise Error(errmsg) - - -def _fill_template_from_parts(attr, template_len, id, id_len, label, label_len, - class_, cka_wrap, cka_unwrap): - """ - Fill template structure with pointers to attributes passed as independent - variables. - Variables with NULL values will be omitted from template. - - @warning input variables should not be modified when template is in use - """ - cnt = 0 - if label != NULL: - attr[0].type = CKA_LABEL - attr[0].pValue = label - attr[0].ulValueLen = label_len - attr += 1 - cnt += 1 - assert cnt < template_len[0] - if id != NULL: - attr[0].type = CKA_ID - attr[0].pValue = id - attr[0].ulValueLen = id_len - attr += 1 - cnt += 1 - assert cnt < template_len[0] - if cka_wrap != NULL: - attr[0].type = CKA_WRAP - attr[0].pValue = cka_wrap - attr[0].ulValueLen = sizeof(CK_BBOOL) - attr += 1 - cnt += 1 - assert cnt < template_len[0] - if cka_unwrap != NULL: - attr[0].type = CKA_UNWRAP - attr[0].pValue = cka_unwrap - attr[0].ulValueLen = sizeof(CK_BBOOL) - attr += 1 - cnt += 1 - assert cnt < template_len[0] - - if class_ != NULL: - attr[0].type = CKA_CLASS - attr[0].pValue = class_ - attr[0].ulValueLen = sizeof(CK_OBJECT_CLASS) - attr += 1 - cnt += 1 - assert cnt < template_len[0] - template_len[0] = cnt - - -def _parse_uri(uri_str): - """ - Parse string to P11-kit representation of PKCS#11 URI. - """ - uri = p11_kit_uri_new() - if not uri: - raise Error("Cannot initialize URI parser") - - try: - result = p11_kit_uri_parse(uri_str, P11_KIT_URI_FOR_OBJECT, uri) - if result != P11_KIT_URI_OK: - raise Error("Cannot parse URI") - - if p11_kit_uri_any_unrecognized(uri): - raise Error("PKCS#11 URI contains unsupported attributes") - except Error: - p11_kit_uri_free(uri) - raise - - return uri - - -def _set_wrapping_mech_parameters(mech_type, mech): - """ - Function set default param values for wrapping mechanism - :param mech_type: mechanism type - :param mech: filled structure with params based on mech type - - Warning: do not dealloc param values, it is static variables - """ - if mech_type in (CKM_RSA_PKCS, CKM_AES_KEY_WRAP, CKM_AES_KEY_WRAP_PAD): - mech.pParameter = NULL - mech.ulParameterLen = 0 - elif mech_type == CKM_RSA_PKCS_OAEP: - # Use the same configuration as openSSL - # https://www.openssl.org/docs/crypto/RSA_public_encrypt.html - mech.pParameter = CONST_RSA_PKCS_OAEP_PARAMS_ptr - mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS) - else: - raise Error("Unsupported wrapping mechanism") - mech.mechanism = mech_type - - -######################################################################## -# P11_Helper object -# -class P11_Helper(object): - @property - def p11(self): - return self.p11_ptr[0] - - @property - def session(self): - return self.session_ptr[0] - - def _find_key(self, template, template_len): - """ - Find keys matching specified template. - Function returns list of key handles via objects parameter. - - :param template: PKCS#11 template for attribute matching - """ - result_objects = [] - result_object_ptr = new_ptr(CK_OBJECT_HANDLE) - objectCount_ptr = new_ptr(CK_ULONG) - - rv = self.p11.C_FindObjectsInit(self.session, template, template_len) - check_return_value(rv, "Find key init") - - rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1, - objectCount_ptr) - check_return_value(rv, "Find key") - - while objectCount_ptr[0] > 0: - result_objects.append(result_object_ptr[0]) - - rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1, - objectCount_ptr) - check_return_value(rv, "Check for duplicated key") - - rv = self.p11.C_FindObjectsFinal(self.session) - check_return_value(rv, "Find objects final") - - return result_objects - - def _id_exists(self, id, id_len, class_): - """ - Test if object with specified label, id and class exists - - :param id: key ID, (if value is NULL, will not be used to find key) - :param id_len: key ID length - :param class_ key: class - - :return: True if object was found, False if object doesnt exists - """ - object_count_ptr = new_ptr(CK_ULONG) - result_object_ptr = new_ptr(CK_OBJECT_HANDLE) - class_ptr = new_ptr(CK_OBJECT_CLASS, class_) - class_sec_ptr = new_ptr(CK_OBJECT_CLASS, CKO_SECRET_KEY) - - template_pub_priv = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id, id_len), - (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)), - )) - - template_sec = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id, id_len), - (CKA_CLASS, class_sec_ptr, sizeof(CK_OBJECT_CLASS)), - )) - - template_id = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id, id_len), - )) - - # - # Only one secret key with same ID is allowed - # - if class_ == CKO_SECRET_KEY: - rv = self.p11.C_FindObjectsInit(self.session, template_id, 1) - check_return_value(rv, "id, label exists init") - - rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1, - object_count_ptr) - check_return_value(rv, "id, label exists") - - rv = self.p11.C_FindObjectsFinal(self.session) - check_return_value(rv, "id, label exists final") - - if object_count_ptr[0] > 0: - return True - return False - - # - # Public and private keys can share one ID, but - # - - # test if secret key with same ID exists - rv = self.p11.C_FindObjectsInit(self.session, template_sec, 2) - check_return_value(rv, "id, label exists init") - - rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1, - object_count_ptr) - check_return_value(rv, "id, label exists") - - rv = self.p11.C_FindObjectsFinal(self.session) - check_return_value(rv, "id, label exists final") - - if object_count_ptr[0] > 0: - # object found - return True - - # test if pub/private key with same id exists - object_count_ptr[0] = 0 - - rv = self.p11.C_FindObjectsInit(self.session, template_pub_priv, 2) - check_return_value(rv, "id, label exists init") - - rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1, - object_count_ptr) - check_return_value(rv, "id, label exists") - - rv = self.p11.C_FindObjectsFinal(self.session) - check_return_value(rv, "id, label exists final") - - if object_count_ptr[0] > 0: - # Object found - return True - - # Object not found - return False - - def __init__(self, slot, user_pin, library_path): - self.p11_ptr = new_ptr(CK_FUNCTION_LIST_PTR) - self.session_ptr = new_ptr(CK_SESSION_HANDLE) - - self.slot = 0 - self.session_ptr[0] = 0 - self.p11_ptr[0] = NULL - self.module_handle = None - - # Parse method args - if isinstance(user_pin, unicode): - user_pin = user_pin.encode() - self.slot = slot - - try: - pGetFunctionList, module_handle = loadLibrary(library_path) - except Exception: - raise Error("Could not load the library.") - - self.module_handle = module_handle - - # - # Load the function list - # - pGetFunctionList(self.p11_ptr) - - # - # Initialize - # - rv = self.p11.C_Initialize(NULL) - check_return_value(rv, "initialize") - - # - # Start session - # - rv = self.p11.C_OpenSession(self.slot, - CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, - NULL, self.session_ptr) - check_return_value(rv, "open session") - - # - # Login - # - rv = self.p11.C_Login(self.session, CKU_USER, user_pin, len(user_pin)) - check_return_value(rv, "log in") - - def finalize(self): - """ - Finalize operations with pkcs11 library - """ - if self.p11 == NULL: - return - - # - # Logout - # - rv = self.p11.C_Logout(self.session) - check_return_value(rv, "log out") - - # - # End session - # - rv = self.p11.C_CloseSession(self.session) - check_return_value(rv, "close session") - - # - # Finalize - # - self.p11.C_Finalize(NULL) - - self.p11_ptr[0] = NULL - self.session_ptr[0] = 0 - self.slot = 0 - self.module_handle = None - - ################################################################# - # Methods working with keys - # - - def generate_master_key(self, label, id, key_length=16, cka_copyable=True, - cka_decrypt=False, cka_derive=False, - cka_encrypt=False, cka_extractable=True, - cka_modifiable=True, cka_private=True, - cka_sensitive=True, cka_sign=False, - cka_unwrap=True, cka_verify=False, cka_wrap=True, - cka_wrap_with_trusted=False): - """ - Generate master key - - :return: master key handle - """ - if isinstance(id, unicode): - id = id.encode() - - attrs = ( - cka_copyable, - cka_decrypt, - cka_derive, - cka_encrypt, - cka_extractable, - cka_modifiable, - cka_private, - cka_sensitive, - cka_sign, - cka_unwrap, - cka_verify, - cka_wrap, - cka_wrap_with_trusted, - ) - - key_length_ptr = new_ptr(CK_ULONG, key_length) - master_key_ptr = new_ptr(CK_OBJECT_HANDLE) - - label_unicode = label - id_length = len(id) - id_ = new_array(CK_BYTE, id) - # TODO check long overflow - - label, label_length = unicode_to_char_array(label_unicode) - - # TODO param? - mechanism_ptr = new_ptr(CK_MECHANISM, ( - CKM_AES_KEY_GEN, NULL_PTR, 0 - )) - - if key_length not in (16, 24, 32): - raise Error("generate_master_key: key length allowed values are: " - "16, 24 and 32") - - if self._id_exists(id_, id_length, CKO_SECRET_KEY): - raise DuplicationError("Master key with same ID already exists") - - # Process keyword boolean arguments - (_cka_copyable_ptr, cka_decrypt_ptr, cka_derive_ptr, cka_encrypt_ptr, - cka_extractable_ptr, cka_modifiable_ptr, cka_private_ptr, - cka_sensitive_ptr, cka_sign_ptr, cka_unwrap_ptr, cka_verify_ptr, - cka_wrap_ptr, cka_wrap_with_trusted_ptr,) = convert_py2bool(attrs) - - symKeyTemplate = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id_, id_length), - (CKA_LABEL, label, label_length), - (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)), - (CKA_VALUE_LEN, key_length_ptr, sizeof(CK_ULONG)), - # TODO Softhsm doesn't support it - # (CKA_COPYABLE, cka_copyable_ptr, sizeof(CK_BBOOL)), - (CKA_DECRYPT, cka_decrypt_ptr, sizeof(CK_BBOOL)), - (CKA_DERIVE, cka_derive_ptr, sizeof(CK_BBOOL)), - (CKA_ENCRYPT, cka_encrypt_ptr, sizeof(CK_BBOOL)), - (CKA_EXTRACTABLE, cka_extractable_ptr, sizeof(CK_BBOOL)), - (CKA_MODIFIABLE, cka_modifiable_ptr, sizeof(CK_BBOOL)), - (CKA_PRIVATE, cka_private_ptr, sizeof(CK_BBOOL)), - (CKA_SENSITIVE, cka_sensitive_ptr, sizeof(CK_BBOOL)), - (CKA_SIGN, cka_sign_ptr, sizeof(CK_BBOOL)), - (CKA_UNWRAP, cka_unwrap_ptr, sizeof(CK_BBOOL)), - (CKA_VERIFY, cka_verify_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP, cka_wrap_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP_WITH_TRUSTED, cka_wrap_with_trusted_ptr, - sizeof(CK_BBOOL)), - )) - - rv = self.p11.C_GenerateKey(self.session, mechanism_ptr, - symKeyTemplate, - (sizeof(symKeyTemplate) // - sizeof(CK_ATTRIBUTE)), master_key_ptr) - check_return_value(rv, "generate master key") - - return master_key_ptr[0] - - def generate_replica_key_pair(self, label, id, modulus_bits=2048, - pub_cka_copyable=True, pub_cka_derive=False, - pub_cka_encrypt=False, - pub_cka_modifiable=True, - pub_cka_private=True, pub_cka_trusted=False, - pub_cka_verify=False, - pub_cka_verify_recover=False, - pub_cka_wrap=True, - priv_cka_always_authenticate=False, - priv_cka_copyable=True, - priv_cka_decrypt=False, - priv_cka_derive=False, - priv_cka_extractable=False, - priv_cka_modifiable=True, - priv_cka_private=True, - priv_cka_sensitive=True, - priv_cka_sign=False, - priv_cka_sign_recover=False, - priv_cka_unwrap=True, - priv_cka_wrap_with_trusted=False): - """ - Generate replica keys - - :returns: tuple (public_key_handle, private_key_handle) - """ - if isinstance(id, unicode): - id = id.encode() - - attrs_pub = ( - pub_cka_copyable, - pub_cka_derive, - pub_cka_encrypt, - pub_cka_modifiable, - pub_cka_private, - pub_cka_trusted, - pub_cka_verify, - pub_cka_verify_recover, - pub_cka_wrap, - ) - - attrs_priv = ( - priv_cka_always_authenticate, - priv_cka_copyable, - priv_cka_decrypt, - priv_cka_derive, - priv_cka_extractable, - priv_cka_modifiable, - priv_cka_private, - priv_cka_sensitive, - priv_cka_sign, - priv_cka_sign_recover, - priv_cka_unwrap, - priv_cka_wrap_with_trusted, - ) - - label_unicode = label - id_ = new_array(CK_BYTE, id) - id_length = len(id) - - label, label_length = unicode_to_char_array(label_unicode) - - public_key_ptr = new_ptr(CK_OBJECT_HANDLE) - private_key_ptr = new_ptr(CK_OBJECT_HANDLE) - mechanism_ptr = new_ptr(CK_MECHANISM, - (CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0)) - - if self._id_exists(id_, id_length, CKO_PRIVATE_KEY): - raise DuplicationError("Private key with same ID already exists") - - if self._id_exists(id_, id_length, CKO_PUBLIC_KEY): - raise DuplicationError("Public key with same ID already exists") - - modulus_bits_ptr = new_ptr(CK_ULONG, modulus_bits) - - # Process keyword boolean arguments - (_pub_cka_copyable_ptr, pub_cka_derive_ptr, pub_cka_encrypt_ptr, - pub_cka_modifiable_ptr, pub_cka_private_ptr, pub_cka_trusted_ptr, - pub_cka_verify_ptr, pub_cka_verify_recover_ptr, pub_cka_wrap_ptr, - ) = convert_py2bool(attrs_pub) - (priv_cka_always_authenticate_ptr, _priv_cka_copyable_ptr, - priv_cka_decrypt_ptr, priv_cka_derive_ptr, priv_cka_extractable_ptr, - priv_cka_modifiable_ptr, priv_cka_private_ptr, priv_cka_sensitive_ptr, - priv_cka_sign_ptr, _priv_cka_sign_recover_ptr, priv_cka_unwrap_ptr, - priv_cka_wrap_with_trusted_ptr,) = convert_py2bool(attrs_priv) - - # 65537 (RFC 6376 section 3.3.1) - public_exponent = new_array(CK_BYTE, (1, 0, 1)) - publicKeyTemplate = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id_, id_length), - (CKA_LABEL, label, label_length), - (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)), - (CKA_MODULUS_BITS, modulus_bits_ptr, sizeof(CK_ULONG)), - (CKA_PUBLIC_EXPONENT, public_exponent, 3), - # TODO Softhsm doesn't support it - # (CKA_COPYABLE, pub_cka_copyable_p, sizeof(CK_BBOOL)), - (CKA_DERIVE, pub_cka_derive_ptr, sizeof(CK_BBOOL)), - (CKA_ENCRYPT, pub_cka_encrypt_ptr, sizeof(CK_BBOOL)), - (CKA_MODIFIABLE, pub_cka_modifiable_ptr, sizeof(CK_BBOOL)), - (CKA_PRIVATE, pub_cka_private_ptr, sizeof(CK_BBOOL)), - (CKA_TRUSTED, pub_cka_trusted_ptr, sizeof(CK_BBOOL)), - (CKA_VERIFY, pub_cka_verify_ptr, sizeof(CK_BBOOL)), - (CKA_VERIFY_RECOVER, pub_cka_verify_recover_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP, pub_cka_wrap_ptr, sizeof(CK_BBOOL)), - )) - - privateKeyTemplate = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id_, id_length), - (CKA_LABEL, label, label_length), - (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)), - (CKA_ALWAYS_AUTHENTICATE, priv_cka_always_authenticate_ptr, - sizeof(CK_BBOOL)), - # TODO Softhsm doesn't support it - # (CKA_COPYABLE, priv_cka_copyable_ptr, sizeof(CK_BBOOL)), - (CKA_DECRYPT, priv_cka_decrypt_ptr, sizeof(CK_BBOOL)), - (CKA_DERIVE, priv_cka_derive_ptr, sizeof(CK_BBOOL)), - (CKA_EXTRACTABLE, priv_cka_extractable_ptr, sizeof(CK_BBOOL)), - (CKA_MODIFIABLE, priv_cka_modifiable_ptr, sizeof(CK_BBOOL)), - (CKA_PRIVATE, priv_cka_private_ptr, sizeof(CK_BBOOL)), - (CKA_SENSITIVE, priv_cka_sensitive_ptr, sizeof(CK_BBOOL)), - (CKA_SIGN, priv_cka_sign_ptr, sizeof(CK_BBOOL)), - (CKA_SIGN_RECOVER, priv_cka_sign_ptr, sizeof(CK_BBOOL)), - (CKA_UNWRAP, priv_cka_unwrap_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP_WITH_TRUSTED, priv_cka_wrap_with_trusted_ptr, - sizeof(CK_BBOOL)), - )) - - rv = self.p11.C_GenerateKeyPair(self.session, mechanism_ptr, - publicKeyTemplate, - (sizeof(publicKeyTemplate) // - sizeof(CK_ATTRIBUTE)), - privateKeyTemplate, - (sizeof(privateKeyTemplate) // - sizeof(CK_ATTRIBUTE)), - public_key_ptr, - private_key_ptr) - check_return_value(rv, "generate key pair") - - return public_key_ptr[0], private_key_ptr[0] - - def find_keys(self, objclass=CKO_VENDOR_DEFINED, label=None, id=None, - cka_wrap=None, cka_unwrap=None, uri=None): - """ - Find key - """ - if isinstance(id, unicode): - id = id.encode() - if isinstance(uri, unicode): - uri = uri.encode() - - class_ = objclass - class_ptr = new_ptr(CK_OBJECT_CLASS, class_) - ckawrap = NULL - ckaunwrap = NULL - if id is not None: - id_ = new_array(CK_BYTE, id) - id_length = len(id) - else: - id_ = NULL - id_length = 0 - label_unicode, label = label, NULL - cka_wrap_bool = cka_wrap - cka_unwrap_bool = cka_unwrap - label_length = 0 - uri_str = uri - uri = NULL - template = new_array(CK_ATTRIBUTE, MAX_TEMPLATE_LEN) - template_len_ptr = new_ptr(CK_ULONG, MAX_TEMPLATE_LEN) - - # TODO check long overflow - - if label_unicode is not None: - label, label_length = unicode_to_char_array(label_unicode) - - if cka_wrap_bool is not None: - if cka_wrap_bool: - ckawrap = true_ptr - else: - ckawrap = false_ptr - - if cka_unwrap_bool is not None: - if cka_unwrap_bool: - ckaunwrap = true_ptr - else: - ckaunwrap = false_ptr - - if class_ == CKO_VENDOR_DEFINED: - class_ptr = NULL - - try: - if uri_str is None: - _fill_template_from_parts(template, template_len_ptr, id_, - id_length, label, label_length, - class_ptr, ckawrap, ckaunwrap) - else: - uri = _parse_uri(uri_str) - template = (p11_kit_uri_get_attributes(uri, template_len_ptr)) - # Do not deallocate URI while you are using the template. - # Template contains pointers to values inside URI! - - result_list = self._find_key(template, template_len_ptr[0]) - - return result_list - finally: - if uri != NULL: - p11_kit_uri_free(uri) - - def delete_key(self, key_handle): - """ - delete key - """ - # TODO check long overflow - rv = self.p11.C_DestroyObject(self.session, key_handle) - check_return_value(rv, "object deletion") - - def _export_RSA_public_key(self, object): - """ - export RSA public key - """ - class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY) - key_type_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA) - - obj_template = new_array(CK_ATTRIBUTE, ( - (CKA_MODULUS, NULL_PTR, 0), - (CKA_PUBLIC_EXPONENT, NULL_PTR, 0), - (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)), - (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)), - )) - - rv = self.p11.C_GetAttributeValue(self.session, object, obj_template, - (sizeof(obj_template) // - sizeof(CK_ATTRIBUTE))) - check_return_value(rv, "get RSA public key values - prepare") - - # Set proper size for attributes - modulus = new_array(CK_BYTE, - obj_template[0].ulValueLen * sizeof(CK_BYTE)) - obj_template[0].pValue = modulus - exponent = new_array(CK_BYTE, - obj_template[1].ulValueLen * sizeof(CK_BYTE)) - obj_template[1].pValue = exponent - - rv = self.p11.C_GetAttributeValue(self.session, object, obj_template, - (sizeof(obj_template) // - sizeof(CK_ATTRIBUTE))) - check_return_value(rv, "get RSA public key values") - - # Check if the key is RSA public key - if class_ptr[0] != CKO_PUBLIC_KEY: - raise Error("export_RSA_public_key: required public key class") - - if key_type_ptr[0] != CKK_RSA: - raise Error("export_RSA_public_key: required RSA key type") - - try: - n = bytes_to_int(string_to_pybytes_or_none( - modulus, obj_template[0].ulValueLen)) - except Exception: - raise Error("export_RSA_public_key: internal error: unable to " - "convert modulus") - - try: - e = bytes_to_int(string_to_pybytes_or_none( - exponent, obj_template[1].ulValueLen)) - except Exception: - raise Error("export_RSA_public_key: internal error: unable to " - "convert exponent") - - # set modulus and exponent - rsa_ = rsa.RSAPublicNumbers(e, n) - - try: - pkey = rsa_.public_key(default_backend()) - except Exception: - raise Error("export_RSA_public_key: internal error: " - "EVP_PKEY_set1_RSA failed") - - try: - ret = pkey.public_bytes( - format=serialization.PublicFormat.SubjectPublicKeyInfo, - encoding=serialization.Encoding.DER, - ) - except Exception: - ret = None - - return ret - - def export_public_key(self, key_handle): - """ - Export public key - - Export public key in SubjectPublicKeyInfo (RFC5280) DER encoded format - """ - object = key_handle - class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY) - key_type_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA) - # TODO check long overflow - - obj_template = new_array(CK_ATTRIBUTE, ( - (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)), - (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)), - )) - - rv = self.p11.C_GetAttributeValue(self.session, object, obj_template, - (sizeof(obj_template) // - sizeof(CK_ATTRIBUTE))) - check_return_value(rv, "export_public_key: get RSA public key values") - - if class_ptr[0] != CKO_PUBLIC_KEY: - raise Error("export_public_key: required public key class") - - if key_type_ptr[0] == CKK_RSA: - return self._export_RSA_public_key(object) - else: - raise Error("export_public_key: unsupported key type") - - def _import_RSA_public_key(self, label, label_length, id, id_length, pkey, - cka_copyable, cka_derive, cka_encrypt, - cka_modifiable, cka_private, cka_trusted, - cka_verify, cka_verify_recover, cka_wrap): - """ - Import RSA public key - """ - class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY) - keyType_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA) - cka_token = true_ptr - - if not isinstance(pkey, rsa.RSAPublicKey): - raise Error("Required RSA public key") - - rsa_ = pkey.public_numbers() - - # convert BIGNUM to binary array - modulus = new_array(CK_BYTE, int_to_bytes(rsa_.n)) - modulus_len = sizeof(modulus) - 1 - if modulus_len == 0: - raise Error("import_RSA_public_key: BN_bn2bin modulus error") - - exponent = new_array(CK_BYTE, int_to_bytes(rsa_.e)) - exponent_len = sizeof(exponent) - 1 - if exponent_len == 0: - raise Error("import_RSA_public_key: BN_bn2bin exponent error") - - template = new_array(CK_ATTRIBUTE, ( - (CKA_ID, id, id_length), - (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)), - (CKA_KEY_TYPE, keyType_ptr, sizeof(CK_KEY_TYPE)), - (CKA_TOKEN, cka_token, sizeof(CK_BBOOL)), - (CKA_LABEL, label, label_length), - (CKA_MODULUS, modulus, modulus_len), - (CKA_PUBLIC_EXPONENT, exponent, exponent_len), - # TODO Softhsm doesn't support it - # (CKA_COPYABLE, cka_copyable, sizeof(CK_BBOOL)), - (CKA_DERIVE, cka_derive, sizeof(CK_BBOOL)), - (CKA_ENCRYPT, cka_encrypt, sizeof(CK_BBOOL)), - (CKA_MODIFIABLE, cka_modifiable, sizeof(CK_BBOOL)), - (CKA_PRIVATE, cka_private, sizeof(CK_BBOOL)), - (CKA_TRUSTED, cka_trusted, sizeof(CK_BBOOL)), - (CKA_VERIFY, cka_verify, sizeof(CK_BBOOL)), - (CKA_VERIFY_RECOVER, cka_verify_recover, sizeof(CK_BBOOL)), - (CKA_WRAP, cka_wrap, sizeof(CK_BBOOL)), - )) - object_ptr = new_ptr(CK_OBJECT_HANDLE) - - rv = self.p11.C_CreateObject(self.session, template, - (sizeof(template) // - sizeof(CK_ATTRIBUTE)), object_ptr) - check_return_value(rv, "create public key object") - - return object_ptr[0] - - def import_public_key(self, label, id, data, cka_copyable=True, - cka_derive=False, cka_encrypt=False, - cka_modifiable=True, cka_private=True, - cka_trusted=False, cka_verify=True, - cka_verify_recover=True, cka_wrap=False): - """ - Import RSA public key - """ - if isinstance(id, unicode): - id = id.encode() - if isinstance(data, unicode): - data = data.encode() - - label_unicode = label - id_ = new_array(CK_BYTE, id) - id_length = len(id) - - attrs_pub = ( - cka_copyable, - cka_derive, - cka_encrypt, - cka_modifiable, - cka_private, - cka_trusted, - cka_verify, - cka_verify_recover, - cka_wrap, - ) - - label, label_length = unicode_to_char_array(label_unicode) - - if self._id_exists(id_, id_length, CKO_PUBLIC_KEY): - raise DuplicationError("Public key with same ID already exists") - - # Process keyword boolean arguments - (cka_copyable_ptr, cka_derive_ptr, cka_encrypt_ptr, cka_modifiable_ptr, - cka_private_ptr, cka_trusted_ptr, cka_verify_ptr, - cka_verify_recover_ptr, cka_wrap_ptr,) = convert_py2bool(attrs_pub) - - # decode from ASN1 DER - try: - pkey = serialization.load_der_public_key(data, default_backend()) - except Exception: - raise Error("import_public_key: d2i_PUBKEY error") - if isinstance(pkey, rsa.RSAPublicKey): - ret = self._import_RSA_public_key(label, label_length, id_, - id_length, pkey, - cka_copyable_ptr, - cka_derive_ptr, - cka_encrypt_ptr, - cka_modifiable_ptr, - cka_private_ptr, - cka_trusted_ptr, - cka_verify_ptr, - cka_verify_recover_ptr, - cka_wrap_ptr) - elif isinstance(pkey, dsa.DSAPublicKey): - raise Error("DSA is not supported") - elif isinstance(pkey, ec.EllipticCurvePublicKey): - raise Error("EC is not supported") - else: - raise Error("Unsupported key type") - - return ret - - def export_wrapped_key(self, key, wrapping_key, wrapping_mech): - """ - Export wrapped key - """ - object_key = key - object_wrapping_key = wrapping_key - wrapped_key_len_ptr = new_ptr(CK_ULONG, 0) - wrapping_mech_ptr = new_ptr(CK_MECHANISM, (wrapping_mech, NULL, 0)) - # currently we don't support parameter in mechanism - - # TODO check long overflow - # TODO export method - - # fill mech parameters - _set_wrapping_mech_parameters(wrapping_mech_ptr.mechanism, - wrapping_mech_ptr) - - rv = self.p11.C_WrapKey(self.session, wrapping_mech_ptr, - object_wrapping_key, object_key, NULL, - wrapped_key_len_ptr) - check_return_value(rv, "key wrapping: get buffer length") - - wrapped_key = new_array(CK_BYTE, wrapped_key_len_ptr[0]) - - rv = self.p11.C_WrapKey(self.session, wrapping_mech_ptr, - object_wrapping_key, object_key, wrapped_key, - wrapped_key_len_ptr) - check_return_value(rv, "key wrapping: wrapping") - - result = string_to_pybytes_or_none(wrapped_key, wrapped_key_len_ptr[0]) - - return result - - def import_wrapped_secret_key(self, label, id, data, unwrapping_key, - wrapping_mech, key_type, cka_copyable=True, - cka_decrypt=False, cka_derive=False, - cka_encrypt=False, cka_extractable=True, - cka_modifiable=True, cka_private=True, - cka_sensitive=True, cka_sign=False, - cka_unwrap=True, cka_verify=False, - cka_wrap=True, cka_wrap_with_trusted=False): - """ - Import wrapped secret key - """ - if isinstance(id, unicode): - id = id.encode() - if isinstance(data, unicode): - data = data.encode() - - wrapped_key = new_array(CK_BYTE, data) - wrapped_key_len = len(data) - unwrapping_key_object = unwrapping_key - unwrapped_key_object_ptr = new_ptr(CK_OBJECT_HANDLE, 0) - label_unicode = label - id_ = new_array(CK_BYTE, id) - id_length = len(id) - wrapping_mech_ptr = new_ptr(CK_MECHANISM, (wrapping_mech, NULL, 0)) - key_class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_SECRET_KEY) - key_type_ptr = new_ptr(CK_KEY_TYPE, key_type) - - attrs = ( - cka_copyable, - cka_decrypt, - cka_derive, - cka_encrypt, - cka_extractable, - cka_modifiable, - cka_private, - cka_sensitive, - cka_sign, - cka_unwrap, - cka_verify, - cka_wrap, - cka_wrap_with_trusted, - ) - - _set_wrapping_mech_parameters(wrapping_mech_ptr.mechanism, - wrapping_mech_ptr) - - label, label_length = unicode_to_char_array(label_unicode) - - if self._id_exists(id_, id_length, key_class_ptr[0]): - raise DuplicationError("Secret key with same ID already exists") - - # Process keyword boolean arguments - (_cka_copyable_ptr, cka_decrypt_ptr, cka_derive_ptr, cka_encrypt_ptr, - cka_extractable_ptr, cka_modifiable_ptr, cka_private_ptr, - cka_sensitive_ptr, cka_sign_ptr, cka_unwrap_ptr, cka_verify_ptr, - cka_wrap_ptr, cka_wrap_with_trusted_ptr,) = convert_py2bool(attrs) - - template = new_array(CK_ATTRIBUTE, ( - (CKA_CLASS, key_class_ptr, sizeof(CK_OBJECT_CLASS)), - (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)), - (CKA_ID, id_, id_length), - (CKA_LABEL, label, label_length), - (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)), - # TODO Softhsm doesn't support it - # (CKA_COPYABLE, cka_copyable_ptr, sizeof(CK_BBOOL)), - (CKA_DECRYPT, cka_decrypt_ptr, sizeof(CK_BBOOL)), - (CKA_DERIVE, cka_derive_ptr, sizeof(CK_BBOOL)), - (CKA_ENCRYPT, cka_encrypt_ptr, sizeof(CK_BBOOL)), - (CKA_EXTRACTABLE, cka_extractable_ptr, sizeof(CK_BBOOL)), - (CKA_MODIFIABLE, cka_modifiable_ptr, sizeof(CK_BBOOL)), - (CKA_PRIVATE, cka_private_ptr, sizeof(CK_BBOOL)), - (CKA_SENSITIVE, cka_sensitive_ptr, sizeof(CK_BBOOL)), - (CKA_SIGN, cka_sign_ptr, sizeof(CK_BBOOL)), - (CKA_UNWRAP, cka_unwrap_ptr, sizeof(CK_BBOOL)), - (CKA_VERIFY, cka_verify_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP, cka_wrap_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP_WITH_TRUSTED, cka_wrap_with_trusted_ptr, - sizeof(CK_BBOOL)), - )) - - rv = self.p11.C_UnwrapKey(self.session, wrapping_mech_ptr, - unwrapping_key_object, wrapped_key, - wrapped_key_len, template, - sizeof(template) // sizeof(CK_ATTRIBUTE), - unwrapped_key_object_ptr) - check_return_value(rv, "import_wrapped_key: key unwrapping") - - return unwrapped_key_object_ptr[0] - - def import_wrapped_private_key(self, label, id, data, unwrapping_key, - wrapping_mech, key_type, - cka_always_authenticate=False, - cka_copyable=True, cka_decrypt=False, - cka_derive=False, cka_extractable=True, - cka_modifiable=True, cka_private=True, - cka_sensitive=True, cka_sign=True, - cka_sign_recover=True, cka_unwrap=False, - cka_wrap_with_trusted=False): - """ - Import wrapped private key - """ - if isinstance(id, unicode): - id = id.encode() - if isinstance(data, unicode): - data = data.encode() - - wrapped_key = new_array(CK_BYTE, data) - wrapped_key_len = len(data) - unwrapping_key_object = unwrapping_key - unwrapped_key_object_ptr = new_ptr(CK_OBJECT_HANDLE, 0) - label_unicode = label - id_ = new_array(CK_BYTE, id) - id_length = len(id) - wrapping_mech_ptr = new_ptr(CK_MECHANISM, (wrapping_mech, NULL, 0)) - key_class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PRIVATE_KEY) - key_type_ptr = new_ptr(CK_KEY_TYPE, key_type) - - attrs_priv = ( - cka_always_authenticate, - cka_copyable, - cka_decrypt, - cka_derive, - cka_extractable, - cka_modifiable, - cka_private, - cka_sensitive, - cka_sign, - cka_sign_recover, - cka_unwrap, - cka_wrap_with_trusted, - ) - - label, label_length = unicode_to_char_array(label_unicode) - - if self._id_exists(id_, id_length, CKO_SECRET_KEY): - raise DuplicationError("Secret key with same ID already exists") - - # Process keyword boolean arguments - (cka_always_authenticate_ptr, _cka_copyable_ptr, cka_decrypt_ptr, - cka_derive_ptr, cka_extractable_ptr, cka_modifiable_ptr, - cka_private_ptr, cka_sensitive_ptr, cka_sign_ptr, - _cka_sign_recover_ptr, cka_unwrap_ptr, cka_wrap_with_trusted_ptr, - ) = convert_py2bool(attrs_priv) - - template = new_array(CK_ATTRIBUTE, ( - (CKA_CLASS, key_class_ptr, sizeof(CK_OBJECT_CLASS)), - (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)), - (CKA_ID, id_, id_length), - (CKA_LABEL, label, label_length), - (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)), - (CKA_ALWAYS_AUTHENTICATE, cka_always_authenticate_ptr, - sizeof(CK_BBOOL)), - # TODO Softhsm doesn't support it - # (CKA_COPYABLE, cka_copyable_ptr, sizeof(CK_BBOOL)), - (CKA_DECRYPT, cka_decrypt_ptr, sizeof(CK_BBOOL)), - (CKA_DERIVE, cka_derive_ptr, sizeof(CK_BBOOL)), - (CKA_EXTRACTABLE, cka_extractable_ptr, sizeof(CK_BBOOL)), - (CKA_MODIFIABLE, cka_modifiable_ptr, sizeof(CK_BBOOL)), - (CKA_PRIVATE, cka_private_ptr, sizeof(CK_BBOOL)), - (CKA_SENSITIVE, cka_sensitive_ptr, sizeof(CK_BBOOL)), - (CKA_SIGN, cka_sign_ptr, sizeof(CK_BBOOL)), - (CKA_SIGN_RECOVER, cka_sign_ptr, sizeof(CK_BBOOL)), - (CKA_UNWRAP, cka_unwrap_ptr, sizeof(CK_BBOOL)), - (CKA_WRAP_WITH_TRUSTED, cka_wrap_with_trusted_ptr, - sizeof(CK_BBOOL)), - )) - - rv = self.p11.C_UnwrapKey(self.session, wrapping_mech_ptr, - unwrapping_key_object, wrapped_key, - wrapped_key_len, template, - sizeof(template) // sizeof(CK_ATTRIBUTE), - unwrapped_key_object_ptr) - check_return_value(rv, "import_wrapped_key: key unwrapping") - - return unwrapped_key_object_ptr[0] - - def set_attribute(self, key_object, attr, value): - """ - Set object attributes - """ - object = key_object - attribute_ptr = new_ptr(CK_ATTRIBUTE) - - attribute_ptr.type = attr - if attr in (CKA_ALWAYS_AUTHENTICATE, - CKA_ALWAYS_SENSITIVE, - CKA_COPYABLE, - CKA_ENCRYPT, - CKA_EXTRACTABLE, - CKA_DECRYPT, - CKA_DERIVE, - CKA_LOCAL, - CKA_MODIFIABLE, - CKA_NEVER_EXTRACTABLE, - CKA_PRIVATE, - CKA_SENSITIVE, - CKA_SIGN, - CKA_SIGN_RECOVER, - CKA_TOKEN, - CKA_TRUSTED, - CKA_UNWRAP, - CKA_VERIFY, - CKA_VERIFY_RECOVER, - CKA_WRAP, - CKA_WRAP_WITH_TRUSTED): - attribute_ptr.pValue = true_ptr if value else false_ptr - attribute_ptr.ulValueLen = sizeof(CK_BBOOL) - elif attr == CKA_ID: - if not isinstance(value, bytes): - raise Error("Bytestring value expected") - attribute_ptr.pValue = new_array(CK_BYTE, value) - attribute_ptr.ulValueLen = len(value) - elif attr == CKA_LABEL: - if not isinstance(value, unicode): - raise Error("Unicode value expected") - label, label_length = unicode_to_char_array(value) - attribute_ptr.pValue = label - attribute_ptr.ulValueLen = label_length - elif attr == CKA_KEY_TYPE: - if not isinstance(value, int): - raise Error("Integer value expected") - attribute_ptr.pValue = new_ptr(unsigned_long, value) - attribute_ptr.ulValueLen = sizeof(unsigned_long) - else: - raise Error("Unknown attribute") - - template = new_array(CK_ATTRIBUTE, (attribute_ptr[0],)) - - rv = self.p11.C_SetAttributeValue(self.session, object, template, - (sizeof(template) // - sizeof(CK_ATTRIBUTE))) - check_return_value(rv, "set_attribute") - - def get_attribute(self, key_object, attr): - object = key_object - attribute_ptr = new_ptr(CK_ATTRIBUTE) - - attribute_ptr.type = attr - attribute_ptr.pValue = NULL_PTR - attribute_ptr.ulValueLen = 0 - template = new_array(CK_ATTRIBUTE, (attribute_ptr[0],)) - - rv = self.p11.C_GetAttributeValue(self.session, object, template, - (sizeof(template) // - sizeof(CK_ATTRIBUTE))) - if rv == CKR_ATTRIBUTE_TYPE_INVALID or template[0].ulValueLen == -1: - raise NotFound("attribute does not exist") - check_return_value(rv, "get_attribute init") - value = new_array(unsigned_char, template[0].ulValueLen) - template[0].pValue = value - - rv = self.p11.C_GetAttributeValue(self.session, object, template, - (sizeof(template) // - sizeof(CK_ATTRIBUTE))) - check_return_value(rv, "get_attribute") - - if attr in (CKA_ALWAYS_AUTHENTICATE, - CKA_ALWAYS_SENSITIVE, - CKA_COPYABLE, - CKA_ENCRYPT, - CKA_EXTRACTABLE, - CKA_DECRYPT, - CKA_DERIVE, - CKA_LOCAL, - CKA_MODIFIABLE, - CKA_NEVER_EXTRACTABLE, - CKA_PRIVATE, - CKA_SENSITIVE, - CKA_SIGN, - CKA_SIGN_RECOVER, - CKA_TOKEN, - CKA_TRUSTED, - CKA_UNWRAP, - CKA_VERIFY, - CKA_VERIFY_RECOVER, - CKA_WRAP, - CKA_WRAP_WITH_TRUSTED): - ret = bool(_ffi.cast(_ffi.getctype(CK_BBOOL, '*'), value)[0]) - elif attr == CKA_LABEL: - ret = char_array_to_unicode(value, template[0].ulValueLen) - elif attr in (CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_ID): - ret = string_to_pybytes_or_none(value, template[0].ulValueLen) - elif attr == CKA_KEY_TYPE: - ret = _ffi.cast(_ffi.getctype(unsigned_long, '*'), value)[0] - else: - raise Error("Unknown attribute") - - return ret - - -# Key Classes -KEY_CLASS_PUBLIC_KEY = CKO_PUBLIC_KEY -KEY_CLASS_PRIVATE_KEY = CKO_PRIVATE_KEY -KEY_CLASS_SECRET_KEY = CKO_SECRET_KEY - -# Key types -KEY_TYPE_RSA = CKK_RSA -KEY_TYPE_AES = CKK_AES - -# Wrapping mech type -MECH_RSA_PKCS = CKM_RSA_PKCS -MECH_RSA_PKCS_OAEP = CKM_RSA_PKCS_OAEP -MECH_AES_KEY_WRAP = CKM_AES_KEY_WRAP -MECH_AES_KEY_WRAP_PAD = CKM_AES_KEY_WRAP_PAD - - -def generate_master_key(p11, keylabel=u"dnssec-master", key_length=16, - disable_old_keys=True): - assert isinstance(p11, P11_Helper) - - key_id = None - while True: - # check if key with this ID exist in LDAP or softHSM - # id is 16 Bytes long - key_id = "".join(chr(random.randint(0, 255)) for _ in range(0, 16)) - keys = p11.find_keys(KEY_CLASS_SECRET_KEY, - label=keylabel, - id=key_id) - if not keys: - break # we found unique id - - p11.generate_master_key(keylabel, - key_id, - key_length=key_length, - cka_wrap=True, - cka_unwrap=True) - - if disable_old_keys: - # set CKA_WRAP=False for old master keys - master_keys = p11.find_keys(KEY_CLASS_SECRET_KEY, - label=keylabel, - cka_wrap=True) - - for handle in master_keys: - # don't disable wrapping for new key - # compare IDs not handle - if key_id != p11.get_attribute(handle, CKA_ID): - p11.set_attribute(handle, CKA_WRAP, False) diff --git a/ipapython/secrets/__init__.py b/ipapython/secrets/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/ipapython/secrets/__init__.py +++ /dev/null diff --git a/ipapython/secrets/client.py b/ipapython/secrets/client.py deleted file mode 100644 index d9cc7d0f5..000000000 --- a/ipapython/secrets/client.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (C) 2015 IPA Project Contributors, see COPYING for license - -from __future__ import print_function -from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC -from jwcrypto.common import json_decode -from jwcrypto.jwk import JWK -from ipapython.secrets.kem import IPAKEMKeys -from ipapython.secrets.store import iSecStore -from ipaplatform.paths import paths -from base64 import b64encode -import ldapurl -import gssapi -import os -import requests - - -class CustodiaClient(object): - - def _client_keys(self): - return self.ikk.server_keys - - def _server_keys(self, server, realm): - principal = 'host/%s@%s' % (server, realm) - sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG))) - ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC))) - return (sk, ek) - - def _ldap_uri(self, realm): - dashrealm = '-'.join(realm.split('.')) - socketpath = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % (dashrealm,) - return 'ldapi://' + ldapurl.ldapUrlEscape(socketpath) - - def _keystore(self, realm, ldap_uri, auth_type): - config = dict() - if ldap_uri is None: - config['ldap_uri'] = self._ldap_uri(realm) - else: - config['ldap_uri'] = ldap_uri - if auth_type is not None: - config['auth_type'] = auth_type - - return iSecStore(config) - - def __init__( - self, client_service, keyfile, keytab, server, realm, - ldap_uri=None, auth_type=None): - self.client_service = client_service - self.keytab = keytab - - # Init creds immediately to make sure they are valid. Creds - # can also be re-inited by _auth_header to avoid expiry. - # - self.creds = self.init_creds() - - self.service_name = gssapi.Name('HTTP@%s' % (server,), - gssapi.NameType.hostbased_service) - self.server = server - - self.ikk = IPAKEMKeys({'server_keys': keyfile, 'ldap_uri': ldap_uri}) - - self.kemcli = KEMClient(self._server_keys(server, realm), - self._client_keys()) - - self.keystore = self._keystore(realm, ldap_uri, auth_type) - - # FIXME: Remove warnings about missig subjAltName - requests.packages.urllib3.disable_warnings() - - def init_creds(self): - name = gssapi.Name(self.client_service, - gssapi.NameType.hostbased_service) - store = {'client_keytab': self.keytab, - 'ccache': 'MEMORY:Custodia_%s' % b64encode(os.urandom(8))} - return gssapi.Credentials(name=name, store=store, usage='initiate') - - def _auth_header(self): - if not self.creds or self.creds.lifetime < 300: - self.creds = self.init_creds() - ctx = gssapi.SecurityContext(name=self.service_name, creds=self.creds) - authtok = ctx.step() - return {'Authorization': 'Negotiate %s' % b64encode(authtok)} - - def fetch_key(self, keyname, store=True): - - # Prepare URL - url = 'https://%s/ipa/keys/%s' % (self.server, keyname) - - # Prepare signed/encrypted request - encalg = ('RSA-OAEP', 'A256CBC-HS512') - request = self.kemcli.make_request(keyname, encalg=encalg) - - # Prepare Authentication header - headers = self._auth_header() - - # Perform request - r = requests.get(url, headers=headers, - params={'type': 'kem', 'value': request}) - r.raise_for_status() - reply = r.json() - - if 'type' not in reply or reply['type'] != 'kem': - raise RuntimeError('Invlid JSON response type') - - value = self.kemcli.parse_reply(keyname, reply['value']) - - if store: - self.keystore.set('keys/%s' % keyname, value) - else: - return value diff --git a/ipapython/secrets/common.py b/ipapython/secrets/common.py deleted file mode 100644 index 2b906b649..000000000 --- a/ipapython/secrets/common.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) 2015 IPA Project Contributors, see COPYING for license -from __future__ import print_function -import ldap -import ldap.sasl -import ldap.filter - - -class iSecLdap(object): - - def __init__(self, uri, auth_type=None): - self.uri = uri - if auth_type is not None: - self.auth_type = auth_type - else: - if uri.startswith('ldapi'): - self.auth_type = 'EXTERNAL' - else: - self.auth_type = 'GSSAPI' - self._basedn = None - - @property - def basedn(self): - if self._basedn is None: - conn = self.connect() - r = conn.search_s('', ldap.SCOPE_BASE) - self._basedn = r[0][1]['defaultnamingcontext'][0] - return self._basedn - - def connect(self): - conn = ldap.initialize(self.uri) - if self.auth_type == 'EXTERNAL': - auth_tokens = ldap.sasl.external(None) - elif self.auth_type == 'GSSAPI': - auth_tokens = ldap.sasl.sasl({}, 'GSSAPI') - else: - raise ValueError( - 'Invalid authentication type: %s' % self.auth_type) - conn.sasl_interactive_bind_s('', auth_tokens) - return conn - - def build_filter(self, formatstr, args): - escaped_args = dict() - for key, value in args.iteritems(): - escaped_args[key] = ldap.filter.escape_filter_chars(value) - return formatstr.format(**escaped_args) diff --git a/ipapython/secrets/kem.py b/ipapython/secrets/kem.py deleted file mode 100644 index 7f92c9f89..000000000 --- a/ipapython/secrets/kem.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (C) 2015 IPA Project Contributors, see COPYING for license - -from __future__ import print_function -import os - -# pylint: disable=import-error -from six.moves.configparser import ConfigParser -# pylint: enable=import-error - -from ipaplatform.paths import paths -from ipapython.dn import DN -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import rsa, ec -from custodia.message.kem import KEMKeysStore -from custodia.message.kem import KEY_USAGE_SIG, KEY_USAGE_ENC, KEY_USAGE_MAP -from jwcrypto.common import json_decode, json_encode -from jwcrypto.common import base64url_encode -from jwcrypto.jwk import JWK -from ipapython.secrets.common import iSecLdap -from binascii import unhexlify -import ldap - - -IPA_REL_BASE_DN = 'cn=custodia,cn=ipa,cn=etc' -IPA_KEYS_QUERY = '(&(ipaKeyUsage={usage:s})(memberPrincipal={princ:s}))' -RFC5280_USAGE_MAP = {KEY_USAGE_SIG: 'digitalSignature', - KEY_USAGE_ENC: 'dataEncipherment'} - - -class KEMLdap(iSecLdap): - - @property - def keysbase(self): - return '%s,%s' % (IPA_REL_BASE_DN, self.basedn) - - def _encode_int(self, i): - I = hex(i).rstrip("L").lstrip("0x") - return base64url_encode(unhexlify((len(I) % 2) * '0' + I)) - - def _parse_public_key(self, ipa_public_key): - public_key = serialization.load_der_public_key(ipa_public_key, - default_backend()) - num = public_key.public_numbers() - if isinstance(num, rsa.RSAPublicNumbers): - return {'kty': 'RSA', - 'e': self._encode_int(num.e), - 'n': self._encode_int(num.n)} - elif isinstance(num, ec.EllipticCurvePublicNumbers): - if num.curve.name == 'secp256r1': - curve = 'P-256' - elif num.curve.name == 'secp384r1': - curve = 'P-384' - elif num.curve.name == 'secp521r1': - curve = 'P-521' - else: - raise TypeError('Unsupported Elliptic Curve') - return {'kty': 'EC', - 'crv': curve, - 'x': self._encode_int(num.x), - 'y': self._encode_int(num.y)} - else: - raise TypeError('Unknown Public Key type') - - def get_key(self, usage, principal): - conn = self.connect() - scope = ldap.SCOPE_SUBTREE - - ldap_filter = self.build_filter(IPA_KEYS_QUERY, - {'usage': RFC5280_USAGE_MAP[usage], - 'princ': principal}) - r = conn.search_s(self.keysbase, scope, ldap_filter) - if len(r) != 1: - raise ValueError("Incorrect number of results (%d) searching for" - "public key for %s" % (len(r), principal)) - ipa_public_key = r[0][1]['ipaPublicKey'][0] - jwk = self._parse_public_key(ipa_public_key) - jwk['use'] = KEY_USAGE_MAP[usage] - return json_encode(jwk) - - def _format_public_key(self, key): - if isinstance(key, str): - jwkey = json_decode(key) - if 'kty' not in jwkey: - raise ValueError('Invalid key, missing "kty" attribute') - if jwkey['kty'] == 'RSA': - pubnum = rsa.RSAPublicNumbers(jwkey['e'], jwkey['n']) - pubkey = pubnum.public_key(default_backend()) - elif jwkey['kty'] == 'EC': - if jwkey['crv'] == 'P-256': - curve = ec.SECP256R1 - elif jwkey['crv'] == 'P-384': - curve = ec.SECP384R1 - elif jwkey['crv'] == 'P-521': - curve = ec.SECP521R1 - else: - raise TypeError('Unsupported Elliptic Curve') - pubnum = ec.EllipticCurvePublicNumbers( - jwkey['x'], jwkey['y'], curve) - pubkey = pubnum.public_key(default_backend()) - else: - raise ValueError('Unknown key type: %s' % jwkey['kty']) - elif isinstance(key, rsa.RSAPublicKey): - pubkey = key - elif isinstance(key, ec.EllipticCurvePublicKey): - pubkey = key - else: - raise TypeError('Unknown key type: %s' % type(key)) - - return pubkey.public_bytes( - encoding=serialization.Encoding.DER, - format=serialization.PublicFormat.SubjectPublicKeyInfo) - - def set_key(self, usage, principal, key): - """ - Write key for the host or service. - - Service keys are nested one level beneath the 'cn=custodia' - container, in the 'cn=<servicename>' container; this allows - fine-grained control over key management permissions for - specific services. - - The container is assumed to exist. - - """ - public_key = self._format_public_key(key) - conn = self.connect() - servicename, host = principal.split('@')[0].split('/') - name = '%s/%s' % (KEY_USAGE_MAP[usage], host) - service_rdn = ('cn', servicename) if servicename != 'host' else DN() - dn = str(DN(('cn', name), service_rdn, self.keysbase)) - try: - mods = [('objectClass', ['nsContainer', - 'ipaKeyPolicy', - 'ipaPublicKeyObject', - 'groupOfPrincipals']), - ('cn', name), - ('ipaKeyUsage', RFC5280_USAGE_MAP[usage]), - ('memberPrincipal', principal), - ('ipaPublicKey', public_key)] - conn.add_s(dn, mods) - except Exception: # pylint: disable=broad-except - # This may fail if the entry already exists - mods = [(ldap.MOD_REPLACE, 'ipaPublicKey', public_key)] - conn.modify_s(dn, mods) - - -def newServerKeys(path, keyid): - skey = JWK(generate='RSA', use='sig', kid=keyid) - ekey = JWK(generate='RSA', use='enc', kid=keyid) - with open(path, 'w') as f: - os.fchmod(f.fileno(), 0o600) - os.fchown(f.fileno(), 0, 0) - f.write('[%s,%s]' % (skey.export(), ekey.export())) - return [skey.get_op_key('verify'), ekey.get_op_key('encrypt')] - - -class IPAKEMKeys(KEMKeysStore): - """A KEM Keys Store. - - This is a store that holds public keys of registered - clients allowed to use KEM messages. It takes the form - of an authorizer merely for the purpose of attaching - itself to a 'request' so that later on the KEM Parser - can fetch the appropariate key to verify/decrypt an - incoming request and make the payload available. - - The KEM Parser will actually perform additional - authorization checks in this case. - - SimplePathAuthz is extended here as we want to attach the - store only to requests on paths we are configured to - manage. - """ - - def __init__(self, config=None, ipaconf=paths.IPA_DEFAULT_CONF): - super(IPAKEMKeys, self).__init__(config) - conf = ConfigParser() - conf.read(ipaconf) - self.host = conf.get('global', 'host') - self.realm = conf.get('global', 'realm') - self.ldap_uri = config.get('ldap_uri', None) - if self.ldap_uri is None: - self.ldap_uri = conf.get('global', 'ldap_uri', None) - self._server_keys = None - - def find_key(self, kid, usage): - if kid is None: - raise TypeError('Key ID is None, should be a SPN') - conn = KEMLdap(self.ldap_uri) - return conn.get_key(usage, kid) - - def generate_server_keys(self): - self.generate_keys('host') - - def generate_keys(self, servicename): - principal = '%s/%s@%s' % (servicename, self.host, self.realm) - # Neutralize the key with read if any - self._server_keys = None - # Generate private key and store it - pubkeys = newServerKeys(self.config['server_keys'], principal) - # Store public key in LDAP - ldapconn = KEMLdap(self.ldap_uri) - ldapconn.set_key(KEY_USAGE_SIG, principal, pubkeys[0]) - ldapconn.set_key(KEY_USAGE_ENC, principal, pubkeys[1]) - - @property - def server_keys(self): - if self._server_keys is None: - with open(self.config['server_keys']) as f: - jsonkeys = f.read() - dictkeys = json_decode(jsonkeys) - self._server_keys = (JWK(**dictkeys[KEY_USAGE_SIG]), - JWK(**dictkeys[KEY_USAGE_ENC])) - return self._server_keys - - -# Manual testing -if __name__ == '__main__': - IKK = IPAKEMKeys({'paths': '/', - 'server_keys': '/etc/ipa/custodia/server.keys'}) - IKK.generate_server_keys() - print(('SIG', IKK.server_keys[0].export_public())) - print(('ENC', IKK.server_keys[1].export_public())) - print(IKK.find_key('host/%s@%s' % (IKK.host, IKK.realm), - usage=KEY_USAGE_SIG)) - print(IKK.find_key('host/%s@%s' % (IKK.host, IKK.realm), - usage=KEY_USAGE_ENC)) diff --git a/ipapython/secrets/store.py b/ipapython/secrets/store.py deleted file mode 100644 index 30a87d4a5..000000000 --- a/ipapython/secrets/store.py +++ /dev/null @@ -1,261 +0,0 @@ -# Copyright (C) 2015 IPA Project Contributors, see COPYING for license - -from __future__ import print_function -from base64 import b64encode, b64decode -from custodia.store.interface import CSStore -from jwcrypto.common import json_decode, json_encode -from ipaplatform.paths import paths -from ipapython import ipautil -from ipapython.secrets.common import iSecLdap -import ldap -import os -import shutil -import sys -import tempfile - - -class UnknownKeyName(Exception): - pass - - -class DBMAPHandler(object): - - def __init__(self, config, dbmap, nickname): - raise NotImplementedError - - def export_key(self): - raise NotImplementedError - - def import_key(self, value): - raise NotImplementedError - - -def log_error(error): - print(error, file=sys.stderr) - - -def PKI_TOMCAT_password_callback(): - password = None - with open(paths.PKI_TOMCAT_PASSWORD_CONF) as f: - for line in f.readlines(): - key, value = line.strip().split('=') - if key == 'internal': - password = value - break - return password - - -def HTTPD_password_callback(): - with open(paths.ALIAS_PWDFILE_TXT) as f: - password = f.read() - return password - - -class NSSWrappedCertDB(DBMAPHandler): - ''' - Store that extracts private keys from an NSSDB, wrapped with the - private key of the primary CA. - ''' - - def __init__(self, config, dbmap, nickname): - if 'path' not in dbmap: - raise ValueError( - 'Configuration does not provide NSSDB path') - if 'pwcallback' not in dbmap: - raise ValueError( - 'Configuration does not provide Password Calback') - if 'wrap_nick' not in dbmap: - raise ValueError( - 'Configuration does not provide nickname of wrapping key') - self.nssdb_path = dbmap['path'] - self.nssdb_password = dbmap['pwcallback']() - self.wrap_nick = dbmap['wrap_nick'] - self.target_nick = nickname - - def export_key(self): - tdir = tempfile.mkdtemp(dir=paths.TMP) - try: - nsspwfile = os.path.join(tdir, 'nsspwfile') - with open(nsspwfile, 'w+') as f: - f.write(self.nssdb_password) - wrapped_key_file = os.path.join(tdir, 'wrapped_key') - certificate_file = os.path.join(tdir, 'certificate') - ipautil.run([ - paths.PKI, '-d', self.nssdb_path, '-C', nsspwfile, - 'ca-authority-key-export', - '--wrap-nickname', self.wrap_nick, - '--target-nickname', self.target_nick, - '-o', wrapped_key_file]) - ipautil.run([ - paths.CERTUTIL, '-d', self.nssdb_path, - '-L', '-n', self.target_nick, - '-a', '-o', certificate_file]) - with open(wrapped_key_file, 'r') as f: - wrapped_key = f.read() - with open(certificate_file, 'r') as f: - certificate = f.read() - finally: - shutil.rmtree(tdir) - return json_encode({ - 'wrapped_key': b64encode(wrapped_key), - 'certificate': certificate}) - - -class NSSCertDB(DBMAPHandler): - - def __init__(self, config, dbmap, nickname): - if 'type' not in dbmap or dbmap['type'] != 'NSSDB': - raise ValueError('Invalid type "%s",' - ' expected "NSSDB"' % (dbmap['type'],)) - if 'path' not in dbmap: - raise ValueError('Configuration does not provide NSSDB path') - if 'pwcallback' not in dbmap: - raise ValueError('Configuration does not provide Password Calback') - self.nssdb_path = dbmap['path'] - self.nickname = nickname - self.nssdb_password = dbmap['pwcallback']() - - def export_key(self): - tdir = tempfile.mkdtemp(dir=paths.TMP) - try: - nsspwfile = os.path.join(tdir, 'nsspwfile') - with open(nsspwfile, 'w+') as f: - f.write(self.nssdb_password) - pk12pwfile = os.path.join(tdir, 'pk12pwfile') - password = b64encode(os.urandom(16)) - with open(pk12pwfile, 'w+') as f: - f.write(password) - pk12file = os.path.join(tdir, 'pk12file') - ipautil.run([paths.PK12UTIL, - "-d", self.nssdb_path, - "-o", pk12file, - "-n", self.nickname, - "-k", nsspwfile, - "-w", pk12pwfile]) - with open(pk12file, 'r') as f: - data = f.read() - finally: - shutil.rmtree(tdir) - return json_encode({'export password': password, - 'pkcs12 data': b64encode(data)}) - - def import_key(self, value): - v = json_decode(value) - tdir = tempfile.mkdtemp(dir=paths.TMP) - try: - nsspwfile = os.path.join(tdir, 'nsspwfile') - with open(nsspwfile, 'w+') as f: - f.write(self.nssdb_password) - pk12pwfile = os.path.join(tdir, 'pk12pwfile') - with open(pk12pwfile, 'w+') as f: - f.write(v['export password']) - pk12file = os.path.join(tdir, 'pk12file') - with open(pk12file, 'w+') as f: - f.write(b64decode(v['pkcs12 data'])) - ipautil.run([paths.PK12UTIL, - "-d", self.nssdb_path, - "-i", pk12file, - "-n", self.nickname, - "-k", nsspwfile, - "-w", pk12pwfile]) - finally: - shutil.rmtree(tdir) - - -# Exfiltrate the DM password Hash so it can be set in replica's and this -# way let a replica be install without knowing the DM password and yet -# still keep the DM password synchronized across replicas -class DMLDAP(DBMAPHandler): - - def __init__(self, config, dbmap, nickname): - if 'type' not in dbmap or dbmap['type'] != 'DMLDAP': - raise ValueError('Invalid type "%s",' - ' expected "DMLDAP"' % (dbmap['type'],)) - if nickname != 'DMHash': - raise UnknownKeyName("Unknown Key Named '%s'" % nickname) - self.ldap = iSecLdap(config['ldap_uri'], - config.get('auth_type', None)) - - def export_key(self): - conn = self.ldap.connect() - r = conn.search_s('cn=config', ldap.SCOPE_BASE, - attrlist=['nsslapd-rootpw']) - if len(r) != 1: - raise RuntimeError('DM Hash not found!') - return json_encode({'dmhash': r[0][1]['nsslapd-rootpw'][0]}) - - def import_key(self, value): - v = json_decode(value) - conn = self.ldap.connect() - mods = [(ldap.MOD_REPLACE, 'nsslapd-rootpw', str(v['dmhash']))] - conn.modify_s('cn=config', mods) - - -NAME_DB_MAP = { - 'ca': { - 'type': 'NSSDB', - 'path': paths.PKI_TOMCAT_ALIAS_DIR, - 'handler': NSSCertDB, - 'pwcallback': PKI_TOMCAT_password_callback, - }, - 'ca_wrapped': { - 'handler': NSSWrappedCertDB, - 'path': paths.PKI_TOMCAT_ALIAS_DIR, - 'pwcallback': PKI_TOMCAT_password_callback, - 'wrap_nick': 'caSigningCert cert-pki-ca', - }, - 'ra': { - 'type': 'NSSDB', - 'path': paths.HTTPD_ALIAS_DIR, - 'handler': NSSCertDB, - 'pwcallback': HTTPD_password_callback, - }, - 'dm': { - 'type': 'DMLDAP', - 'handler': DMLDAP, - } -} - - -class IPASecStore(CSStore): - - def __init__(self, config=None): - self.config = config - - def _get_handler(self, key): - path = key.split('/', 3) - if len(path) != 3 or path[0] != 'keys': - raise ValueError('Invalid name') - if path[1] not in NAME_DB_MAP: - raise UnknownKeyName("Unknown DB named '%s'" % path[1]) - dbmap = NAME_DB_MAP[path[1]] - return dbmap['handler'](self.config, dbmap, path[2]) - - def get(self, key): - try: - key_handler = self._get_handler(key) - value = key_handler.export_key() - except Exception as e: # pylint: disable=broad-except - log_error('Error retrievieng key "%s": %s' % (key, str(e))) - value = None - return value - - def set(self, key, value, replace=False): - try: - key_handler = self._get_handler(key) - key_handler.import_key(value) - except Exception as e: # pylint: disable=broad-except - log_error('Error storing key "%s": %s' % (key, str(e))) - - def list(self, keyfilter=None): - raise NotImplementedError - - def cut(self, key): - raise NotImplementedError - - def span(self, key): - raise NotImplementedError - - -# backwards compatibility with FreeIPA 4.3 and 4.4. -iSecStore = IPASecStore diff --git a/ipapython/setup.py b/ipapython/setup.py index 087086eee..1abe7b067 100755 --- a/ipapython/setup.py +++ b/ipapython/setup.py @@ -34,8 +34,6 @@ if __name__ == '__main__': package_dir={'ipapython': ''}, packages=[ "ipapython", - "ipapython.dnssec", - "ipapython.secrets", "ipapython.install" ], install_requires=[ @@ -60,12 +58,4 @@ if __name__ == '__main__': extras_require={ ":python_version<'3'": ["enum34"], }, - entry_points={ - 'custodia.authorizers': [ - 'IPAKEMKeys = ipapython.secrets.kem:IPAKEMKeys', - ], - 'custodia.stores': [ - 'IPASecStore = ipapython.secrets.store:IPASecStore', - ], - }, ) |