diff options
author | Jan Cholasta <jcholast@redhat.com> | 2016-11-22 17:55:10 +0100 |
---|---|---|
committer | Martin Basti <mbasti@redhat.com> | 2016-11-29 14:50:51 +0100 |
commit | a1f260d021bf5d018e634438fde6b7c81ebbbcef (patch) | |
tree | 29f979f42913f804514f92ada0cb953fdb6d095f /ipapython | |
parent | 8e5d2c7014ff6371a3b306e666c301aea1f7a488 (diff) | |
download | freeipa-a1f260d021bf5d018e634438fde6b7c81ebbbcef.tar.gz freeipa-a1f260d021bf5d018e634438fde6b7c81ebbbcef.tar.xz freeipa-a1f260d021bf5d018e634438fde6b7c81ebbbcef.zip |
ipapython: move dnssec, p11helper and secrets to ipaserver
The dnssec and secrets subpackages and the p11helper module depend on
ipaplatform.
Move them to ipaserver as they are used only on the server.
https://fedorahosted.org/freeipa/ticket/6474
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
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', - ], - }, ) |