mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 15:40:01 -06:00
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>
This commit is contained in:
parent
e88d5e815e
commit
e8f2a415b3
@ -15,6 +15,7 @@ import os
|
||||
import sys
|
||||
|
||||
import ipalib
|
||||
from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
||||
from ipalib.install.kinit import kinit_keytab
|
||||
from ipapython.dn import DN
|
||||
from ipapython.ipa_log_manager import root_logger, standard_logging_setup
|
||||
@ -158,8 +159,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)
|
||||
|
@ -32,6 +32,7 @@ import sqlite3
|
||||
import traceback
|
||||
|
||||
import ipalib
|
||||
from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
||||
from ipalib.install.kinit import kinit_keytab
|
||||
from ipapython.dn import DN
|
||||
from ipapython import ipaldap
|
||||
@ -647,7 +648,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)
|
||||
|
@ -313,3 +313,5 @@ USER_CACHE_PATH = (
|
||||
'.cache'
|
||||
)
|
||||
)
|
||||
|
||||
SOFTHSM_DNSSEC_TOKEN_LABEL = u'ipaDNSSEC'
|
||||
|
@ -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):
|
||||
|
@ -23,10 +23,9 @@ from ipapython import ipautil
|
||||
from ipaplatform.constants import constants
|
||||
from ipaplatform.paths import paths
|
||||
from ipalib import errors, api
|
||||
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"
|
||||
|
||||
|
||||
@ -254,8 +253,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,
|
||||
]
|
||||
@ -274,7 +273,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
|
||||
|
@ -20,10 +20,9 @@ from ipaplatform.constants import constants
|
||||
from ipaplatform.paths import paths
|
||||
from ipalib import errors, api
|
||||
from ipaserver import p11helper
|
||||
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):
|
||||
@ -68,7 +67,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,
|
||||
@ -237,7 +236,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")
|
||||
|
@ -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)
|
||||
@ -828,10 +865,17 @@ class P11_Helper(object):
|
||||
rv = self.p11.C_Initialize(NULL)
|
||||
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
|
||||
|
||||
#################################################################
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user