mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
400 lines
14 KiB
Diff
400 lines
14 KiB
Diff
commit 07df61b7814db08d81e1ff92f58b24e5d852fdf8
|
|
Author: Martin Basti <mbasti@redhat.com>
|
|
Date: Wed Mar 29 18:53:11 2017 +0200
|
|
|
|
Fix PKCS11 helper
|
|
|
|
Slots in HSM are not assigned statically, we have to chose proper
|
|
slot from token label.
|
|
|
|
Softhsm i2.2.0 changed this behavior and now slots can change over
|
|
time (it is allowed by pkcs11 standard).
|
|
|
|
Changelog:
|
|
* created method get_slot() that returns slot number from
|
|
used label
|
|
* replaces usage of slot in __init__ method of P11_Helper
|
|
with label
|
|
* slot is dynamically detected from token label before
|
|
session is opened
|
|
* pkcs11-util --init-token now uses '--free' instead '--slot'
|
|
which uses first free slot (we don't care about slot numbers
|
|
anymore)
|
|
|
|
https://pagure.io/freeipa/issue/6692
|
|
|
|
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
|
|
|
|
diff --git a/daemons/dnssec/ipa-dnskeysync-replica b/daemons/dnssec/ipa-dnskeysync-replica
|
|
index 69a3a68..3714163 100755
|
|
--- a/daemons/dnssec/ipa-dnskeysync-replica
|
|
+++ b/daemons/dnssec/ipa-dnskeysync-replica
|
|
@@ -15,6 +15,7 @@ import os
|
|
import sys
|
|
|
|
import ipalib
|
|
+from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
|
from ipapython.dn import DN
|
|
from ipapython.ipa_log_manager import root_logger, standard_logging_setup
|
|
from ipapython import ipaldap
|
|
@@ -154,8 +155,7 @@ ldapkeydb = LdapKeyDB(log, ldap,
|
|
DN(('cn', 'keys'), ('cn', 'sec'), ipalib.api.env.container_dns,
|
|
ipalib.api.env.basedn))
|
|
|
|
-# TODO: slot number could be configurable
|
|
-localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, 0,
|
|
+localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, SOFTHSM_DNSSEC_TOKEN_LABEL,
|
|
open(paths.DNSSEC_SOFTHSM_PIN).read())
|
|
|
|
ldap2replica_master_keys_sync(log, ldapkeydb, localhsm)
|
|
diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
|
|
index 385764a..77f8c4d 100755
|
|
--- a/daemons/dnssec/ipa-ods-exporter
|
|
+++ b/daemons/dnssec/ipa-ods-exporter
|
|
@@ -32,6 +32,7 @@ import sqlite3
|
|
import traceback
|
|
|
|
import ipalib
|
|
+from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
|
from ipapython.dn import DN
|
|
from ipapython import ipaldap
|
|
from ipapython import ipautil
|
|
@@ -645,7 +646,7 @@ log.debug('Connected')
|
|
ldapkeydb = LdapKeyDB(log, ldap, DN(('cn', 'keys'), ('cn', 'sec'),
|
|
ipalib.api.env.container_dns,
|
|
ipalib.api.env.basedn))
|
|
-localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, 0,
|
|
+localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, SOFTHSM_DNSSEC_TOKEN_LABEL,
|
|
open(paths.DNSSEC_SOFTHSM_PIN).read())
|
|
|
|
ldap2master_replica_keys_sync(log, ldapkeydb, localhsm)
|
|
diff --git a/ipalib/constants.py b/ipalib/constants.py
|
|
index c423117..43f1f3c 100644
|
|
--- a/ipalib/constants.py
|
|
+++ b/ipalib/constants.py
|
|
@@ -279,3 +279,5 @@ RENEWAL_CA_NAME = 'dogtag-ipa-ca-renew-agent'
|
|
|
|
# regexp definitions
|
|
PATTERN_GROUPUSER_NAME = '^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*[a-zA-Z0-9_.$-]?$'
|
|
+
|
|
+SOFTHSM_DNSSEC_TOKEN_LABEL = u'ipaDNSSEC'
|
|
diff --git a/ipapython/dnssec/localhsm.py b/ipapython/dnssec/localhsm.py
|
|
index 8f18a45..73511e9 100755
|
|
--- a/ipapython/dnssec/localhsm.py
|
|
+++ b/ipapython/dnssec/localhsm.py
|
|
@@ -89,10 +89,11 @@ class Key(collections.MutableMapping):
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
+
|
|
class LocalHSM(AbstractHSM):
|
|
- def __init__(self, library, slot, pin):
|
|
+ def __init__(self, library, label, pin):
|
|
self.cache_replica_pubkeys = None
|
|
- self.p11 = _ipap11helper.P11_Helper(slot, pin, library)
|
|
+ self.p11 = _ipap11helper.P11_Helper(label, pin, library)
|
|
self.log = logging.getLogger()
|
|
|
|
def __del__(self):
|
|
diff --git a/ipapython/p11helper.py b/ipapython/p11helper.py
|
|
index 5ff9ccc..f193ea7 100644
|
|
--- a/ipapython/p11helper.py
|
|
+++ b/ipapython/p11helper.py
|
|
@@ -30,6 +30,7 @@ struct _CK_VERSION
|
|
};
|
|
|
|
typedef unsigned long CK_SLOT_ID;
|
|
+typedef CK_SLOT_ID *CK_SLOT_ID_PTR;
|
|
|
|
typedef unsigned long CK_SESSION_HANDLE;
|
|
|
|
@@ -43,6 +44,13 @@ typedef unsigned long CK_KEY_TYPE;
|
|
|
|
typedef unsigned long CK_ATTRIBUTE_TYPE;
|
|
|
|
+typedef unsigned long ck_flags_t;
|
|
+
|
|
+typedef unsigned char CK_BBOOL;
|
|
+
|
|
+typedef unsigned long int CK_ULONG;
|
|
+typedef CK_ULONG *CK_ULONG_PTR;
|
|
+
|
|
struct _CK_ATTRIBUTE
|
|
{
|
|
CK_ATTRIBUTE_TYPE type;
|
|
@@ -59,6 +67,31 @@ struct _CK_MECHANISM
|
|
unsigned long ulParameterLen;
|
|
};
|
|
|
|
+struct _CK_TOKEN_INFO
|
|
+{
|
|
+ unsigned char label[32];
|
|
+ unsigned char manufacturer_id[32];
|
|
+ unsigned char model[16];
|
|
+ unsigned char serial_number[16];
|
|
+ ck_flags_t flags;
|
|
+ unsigned long max_session_count;
|
|
+ unsigned long session_count;
|
|
+ unsigned long max_rw_session_count;
|
|
+ unsigned long rw_session_count;
|
|
+ unsigned long max_pin_len;
|
|
+ unsigned long min_pin_len;
|
|
+ unsigned long total_public_memory;
|
|
+ unsigned long free_public_memory;
|
|
+ unsigned long total_private_memory;
|
|
+ unsigned long free_private_memory;
|
|
+ struct _CK_VERSION hardware_version;
|
|
+ struct _CK_VERSION firmware_version;
|
|
+ unsigned char utc_time[16];
|
|
+};
|
|
+
|
|
+typedef struct _CK_TOKEN_INFO CK_TOKEN_INFO;
|
|
+typedef CK_TOKEN_INFO *CK_TOKEN_INFO_PTR;
|
|
+
|
|
typedef unsigned long CK_RV;
|
|
|
|
typedef ... *CK_NOTIFY;
|
|
@@ -70,9 +103,12 @@ 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_RV (*CK_C_GetSlotList) (CK_BBOOL tokenPresent,
|
|
+ CK_SLOT_ID_PTR pSlotList,
|
|
+ CK_ULONG_PTR pulCount);
|
|
typedef ... *CK_C_GetSlotInfo;
|
|
-typedef ... *CK_C_GetTokenInfo;
|
|
+typedef CK_RV (*CK_C_GetTokenInfo) (CK_SLOT_ID slotID,
|
|
+ CK_TOKEN_INFO_PTR pInfo);
|
|
typedef ... *CK_C_WaitForSlotEvent;
|
|
typedef ... *CK_C_GetMechanismList;
|
|
typedef ... *CK_C_GetMechanismInfo;
|
|
@@ -255,10 +291,7 @@ struct _CK_FUNCTION_LIST
|
|
|
|
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;
|
|
|
|
@@ -387,6 +420,7 @@ CKM_AES_KEY_GEN = 0x1080
|
|
CKR_OK = 0
|
|
CKR_ATTRIBUTE_TYPE_INVALID = 0x12
|
|
CKR_USER_NOT_LOGGED_IN = 0x101
|
|
+CKR_BUFFER_TOO_SMALL = 0x150
|
|
|
|
CK_BYTE = _ffi.typeof('CK_BYTE')
|
|
CK_BBOOL = _ffi.typeof('CK_BBOOL')
|
|
@@ -403,6 +437,10 @@ CK_MECHANISM = _ffi.typeof('CK_MECHANISM')
|
|
|
|
CK_FUNCTION_LIST_PTR = _ffi.typeof('CK_FUNCTION_LIST_PTR')
|
|
|
|
+CK_SLOT_ID = _ffi.typeof('CK_SLOT_ID')
|
|
+
|
|
+CK_TOKEN_INFO = _ffi.typeof('CK_TOKEN_INFO')
|
|
+
|
|
NULL_PTR = NULL
|
|
|
|
|
|
@@ -796,11 +834,10 @@ class P11_Helper(object):
|
|
# Object not found
|
|
return False
|
|
|
|
- def __init__(self, slot, user_pin, library_path):
|
|
+ def __init__(self, token_label, 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
|
|
@@ -808,7 +845,7 @@ class P11_Helper(object):
|
|
# Parse method args
|
|
if isinstance(user_pin, unicode):
|
|
user_pin = user_pin.encode()
|
|
- self.slot = slot
|
|
+ self.token_label = token_label
|
|
|
|
try:
|
|
pGetFunctionList, module_handle = loadLibrary(library_path)
|
|
@@ -829,9 +866,16 @@ class P11_Helper(object):
|
|
check_return_value(rv, "initialize")
|
|
|
|
#
|
|
+ # Get Slot
|
|
+ #
|
|
+ slot = self.get_slot()
|
|
+ if slot is None:
|
|
+ raise Error("No slot for label {} found".format(self.token_label))
|
|
+
|
|
+ #
|
|
# Start session
|
|
#
|
|
- rv = self.p11.C_OpenSession(self.slot,
|
|
+ rv = self.p11.C_OpenSession(slot,
|
|
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL,
|
|
NULL, self.session_ptr)
|
|
check_return_value(rv, "open session")
|
|
@@ -842,6 +886,49 @@ class P11_Helper(object):
|
|
rv = self.p11.C_Login(self.session, CKU_USER, user_pin, len(user_pin))
|
|
check_return_value(rv, "log in")
|
|
|
|
+ def get_slot(self):
|
|
+ """Get slot where then token is located
|
|
+ :return: slot number or None when slot not found
|
|
+ """
|
|
+ object_count_ptr = new_ptr(CK_ULONG)
|
|
+
|
|
+ # get slots ID
|
|
+ slots = None
|
|
+ for _i in range(0, 10):
|
|
+ # try max N times, then die to avoid infinite iteration
|
|
+ rv = self.p11.C_GetSlotList(CK_TRUE, NULL, object_count_ptr)
|
|
+ check_return_value(rv, "get slots IDs - prepare")
|
|
+
|
|
+ result_ids_ptr = new_array(CK_SLOT_ID, object_count_ptr[0])
|
|
+
|
|
+ rv = self.p11.C_GetSlotList(
|
|
+ CK_TRUE, result_ids_ptr, object_count_ptr)
|
|
+ if rv == CKR_BUFFER_TOO_SMALL:
|
|
+ continue
|
|
+ check_return_value(rv, "get slots IDs")
|
|
+ slots = result_ids_ptr
|
|
+ break # we have slots !!!
|
|
+
|
|
+ if slots is None:
|
|
+ raise Error("Failed to get slots")
|
|
+
|
|
+ for slot in slots:
|
|
+ token_info_ptr = new_ptr(CK_TOKEN_INFO)
|
|
+ rv = self.p11.C_GetTokenInfo(slot, token_info_ptr)
|
|
+ check_return_value(rv, 'get token info')
|
|
+
|
|
+ # softhsm always returns label 32 bytes long with padding made of
|
|
+ # white spaces (#32), so we have to rstrip() padding and compare
|
|
+ # Label was created by softhsm-util so it is not our fault that
|
|
+ # there are #32 as padding (cffi initializes structures with
|
|
+ # zeroes)
|
|
+ # In case that this is not valid anymore, keep in mind backward
|
|
+ # compatibility
|
|
+
|
|
+ if self.token_label == char_array_to_unicode(
|
|
+ token_info_ptr[0].label, 32).rstrip():
|
|
+ return slot
|
|
+
|
|
def finalize(self):
|
|
"""
|
|
Finalize operations with pkcs11 library
|
|
@@ -868,7 +955,6 @@ class P11_Helper(object):
|
|
|
|
self.p11_ptr[0] = NULL
|
|
self.session_ptr[0] = 0
|
|
- self.slot = 0
|
|
self.module_handle = None
|
|
|
|
#################################################################
|
|
diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py
|
|
index fadaf21..d9dfda9 100644
|
|
--- a/ipaserver/install/dnskeysyncinstance.py
|
|
+++ b/ipaserver/install/dnskeysyncinstance.py
|
|
@@ -26,10 +26,9 @@ from ipaplatform.constants import constants
|
|
from ipaplatform.paths import paths
|
|
from ipalib import errors, api
|
|
from ipalib.constants import CACERT
|
|
+from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
|
from ipaserver.install.bindinstance import dns_container_exists
|
|
|
|
-softhsm_token_label = u'ipaDNSSEC'
|
|
-softhsm_slot = 0
|
|
replica_keylabel_template = u"dnssec-replica:%s"
|
|
|
|
|
|
@@ -289,8 +288,8 @@ class DNSKeySyncInstance(service.Service):
|
|
command = [
|
|
paths.SOFTHSM2_UTIL,
|
|
'--init-token',
|
|
- '--slot', str(softhsm_slot),
|
|
- '--label', softhsm_token_label,
|
|
+ '--free', # use random free slot
|
|
+ '--label', SOFTHSM_DNSSEC_TOKEN_LABEL,
|
|
'--pin', pin,
|
|
'--so-pin', pin_so,
|
|
]
|
|
@@ -309,7 +308,8 @@ class DNSKeySyncInstance(service.Service):
|
|
pin = f.read()
|
|
|
|
os.environ["SOFTHSM2_CONF"] = paths.DNSSEC_SOFTHSM2_CONF
|
|
- p11 = _ipap11helper.P11_Helper(softhsm_slot, pin, paths.LIBSOFTHSM2_SO)
|
|
+ p11 = _ipap11helper.P11_Helper(
|
|
+ SOFTHSM_DNSSEC_TOKEN_LABEL, pin, paths.LIBSOFTHSM2_SO)
|
|
|
|
try:
|
|
# generate replica keypair
|
|
diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py
|
|
index f0c512b..1aac24a 100644
|
|
--- a/ipaserver/install/opendnssecinstance.py
|
|
+++ b/ipaserver/install/opendnssecinstance.py
|
|
@@ -18,10 +18,9 @@ from ipaplatform import services
|
|
from ipaplatform.constants import constants
|
|
from ipaplatform.paths import paths
|
|
from ipalib import errors, api
|
|
-from ipaserver.install import dnskeysyncinstance
|
|
+from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
|
|
|
KEYMASTER = u'dnssecKeyMaster'
|
|
-softhsm_slot = 0
|
|
|
|
|
|
def get_dnssec_key_masters(conn):
|
|
@@ -72,7 +71,7 @@ class OpenDNSSECInstance(service.Service):
|
|
self.ods_gid = None
|
|
self.conf_file_dict = {
|
|
'SOFTHSM_LIB': paths.LIBSOFTHSM2_SO,
|
|
- 'TOKEN_LABEL': dnskeysyncinstance.softhsm_token_label,
|
|
+ 'TOKEN_LABEL': SOFTHSM_DNSSEC_TOKEN_LABEL,
|
|
'KASP_DB': paths.OPENDNSSEC_KASP_DB,
|
|
'ODS_USER': constants.ODS_USER,
|
|
'ODS_GROUP': constants.ODS_GROUP,
|
|
@@ -247,7 +246,8 @@ class OpenDNSSECInstance(service.Service):
|
|
pin = f.read()
|
|
|
|
os.environ["SOFTHSM2_CONF"] = paths.DNSSEC_SOFTHSM2_CONF
|
|
- p11 = p11helper.P11_Helper(softhsm_slot, pin, paths.LIBSOFTHSM2_SO)
|
|
+ p11 = p11helper.P11_Helper(
|
|
+ SOFTHSM_DNSSEC_TOKEN_LABEL, pin, paths.LIBSOFTHSM2_SO)
|
|
try:
|
|
# generate master key
|
|
root_logger.debug("Creating master key")
|
|
diff --git a/ipatests/test_ipapython/test_ipap11helper.py b/ipatests/test_ipapython/test_ipap11helper.py
|
|
index 2c8fd28..5659d60 100644
|
|
--- a/ipatests/test_ipapython/test_ipap11helper.py
|
|
+++ b/ipatests/test_ipapython/test_ipap11helper.py
|
|
@@ -55,12 +55,12 @@ def p11(request):
|
|
with open('softhsm2.conf', 'w') as cfg:
|
|
cfg.write(CONFIG_DATA % token_path)
|
|
os.environ['SOFTHSM2_CONF'] = os.path.join(token_path, 'softhsm2.conf')
|
|
- subprocess.check_call([SOFTHSM2_UTIL, '--init-token', '--slot', '0',
|
|
+ subprocess.check_call([SOFTHSM2_UTIL, '--init-token', '--free',
|
|
'--label', 'test', '--pin', '1234', '--so-pin',
|
|
'1234'])
|
|
|
|
try:
|
|
- p11 = _ipap11helper.P11_Helper(0, "1234", LIBSOFTHSM)
|
|
+ p11 = _ipap11helper.P11_Helper('test', "1234", LIBSOFTHSM)
|
|
except _ipap11helper.Error:
|
|
pytest.fail('Failed to initialize the helper object.', pytrace=False)
|
|
|
|
@@ -70,6 +70,8 @@ def p11(request):
|
|
except _ipap11helper.Error:
|
|
pytest.fail('Failed to finalize the helper object.', pytrace=False)
|
|
finally:
|
|
+ subprocess.call(
|
|
+ [SOFTHSM2_UTIL, '--delete-token', '--label', 'test'])
|
|
del os.environ['SOFTHSM2_CONF']
|
|
|
|
request.addfinalizer(fin)
|