Repository: privacyidea/privacyidea

Issue:
More log output for CKR_SESSION_HANDLE_INVALID
Sometimes we receive a `CKR_SESSION_HANDLE_INVALID` and we reinitialize the HSM connection.

The session handle to be invalid is a decision of the HSM, so we do not really control this. However, we could add some additional information, to understand why or that a session handle is becoming invalid (like due timeouts)

To do so, the AESHardwareSecurityModule can store to values:

During init of the HSM
(https://github.com/privacyidea/privacyidea/blob/740e6b92acfcc333a2f1ae05880b1a3cfb3a4e13/privacyidea/lib/security/aeshsm.py#L101)
we can store a timestamp `self.session_start_time`.
Each time the session is used (usually for decryption, sometimes for encryption) we could update the value `self.session_last_used-_time`.

During reinitialization we then could output these values to provide a better understanding to the administrator.


Discussion:

Resolving patch:
diff --git a/privacyidea/lib/security/aeshsm.py b/privacyidea/lib/security/aeshsm.py
--- a/privacyidea/lib/security/aeshsm.py
+++ b/privacyidea/lib/security/aeshsm.py
@@ -94,6 +94,8 @@ def __init__(self, config=None):
         self.max_retries = config.get("max_retries", MAX_RETRIES)
         log.debug("Setting max retries: {0!s}".format(self.max_retries))
         self.session = None
+        self.session_start_time = datetime.datetime.now()
+        self.session_lastused_time = datetime.datetime.now()
         self.key_handles = {}
 
         self.initialize_hsm()
@@ -147,8 +149,14 @@ def _login(self):
         slotinfo = self.pkcs11.getSlotInfo(self.slot)
         log.debug("Setting up '{}'".format(slotinfo.slotDescription))
 
+        # Before starting the session, we log the old session time usage
+        log.debug("Starting new session now. The old session started {0!s} seconds ago.".format(
+            datetime.datetime.now() - self.session_start_time))
+        log.debug("Starting new session now. The old session was used {0!s} seconds ago.".format(
+            datetime.datetime.now() - self.session_lastused_time))
         # If the HSM is not connected at this point, it will fail
         self.session = self.pkcs11.openSession(slot=self.slot)
+        self.session_start_time = datetime.datetime.now()
 
         log.debug("Logging on to '{}'".format(slotinfo.slotDescription))
         self.session.login(self.password)
@@ -175,6 +183,7 @@ def random(self, length):
         while True:
             try:
                 r_integers = self.session.generateRandom(length)
+                self.session_lastused_time = datetime.datetime.now()
                 break
             except PyKCS11.PyKCS11Error as exx:
                 log.warning(u"Generate Random failed: {0!s}".format(exx))
@@ -202,6 +211,7 @@ def encrypt(self, data, iv, key_id=SecurityModule.TOKEN_KEY):
             try:
                 k = self.key_handles[key_id]
                 r = self.session.encrypt(k, bytes(data), m)
+                self.session_lastused_time = datetime.datetime.now()
                 break
             except PyKCS11.PyKCS11Error as exx:
                 log.warning(u"Encryption failed: {0!s}".format(exx))
@@ -229,6 +239,7 @@ def decrypt(self, enc_data, iv, key_id=SecurityModule.TOKEN_KEY):
             try:
                 k = self.key_handles[key_id]
                 r = self.session.decrypt(k, bytes(enc_data), m)
+                self.session_lastused_time = datetime.datetime.now()
                 break
             except PyKCS11.PyKCS11Error as exx:
                 log.warning(u"Decryption retry: {0!s}".format(exx))


Test patch: