Blob Blame History Raw
commit 93588f53d918fe6c7452da076b95081fb6aa9aef
Author: Ingo Franzki <ifranzki@linux.ibm.com>
Date:   Wed Jun 30 13:18:39 2021 +0200

    COMMON: Prevent unsavable operation state to be exported
    
    Tokens using OpenSSL 3.0 to implement digest operations (SHA, MD5) are no
    longer able to store its digest state in the session context in a way
    that it could be exported via C_GetOperationState(). OpenSSL 3.0 does not
    provide support to get the digest state. A token must therefore place
    pointers to OpenSSL digest contexts into the session state structure.
    Such a state can not be externalized through C_GetOperationState().
    
    Also see the discussion in OpenSSL issue "Digest State Serialization":
    https://github.com/openssl/openssl/issues/14222
    
    Allow a token to mark an operation context as 'not saveable', which will
    cause C_GetOperationState() to return CKR_STATE_UNSAVEABLE if it is tried
    to save such a state.
    
    Also, such operation contexts can not simply be freed that way the common
    code performs that. Allow a token to use a custom context free function,
    to cleanup such complex context structures.
    
    Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>

diff --git a/usr/lib/common/decr_mgr.c b/usr/lib/common/decr_mgr.c
index 9842302b..fea6c99e 100644
--- a/usr/lib/common/decr_mgr.c
+++ b/usr/lib/common/decr_mgr.c
@@ -620,7 +620,8 @@ done:
 
 //
 //
-CK_RV decr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx)
+CK_RV decr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                       ENCR_DECR_CONTEXT *ctx)
 {
     if (!ctx) {
         TRACE_ERROR("Invalid function argument.\n");
@@ -635,6 +636,7 @@ CK_RV decr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx)
     ctx->init_pending = FALSE;
     ctx->context_len = 0;
     ctx->pkey_active = FALSE;
+    ctx->state_unsaveable = FALSE;
 
     if (ctx->mech.pParameter) {
         free(ctx->mech.pParameter);
@@ -642,9 +644,14 @@ CK_RV decr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx)
     }
 
     if (ctx->context) {
-        free(ctx->context);
+        if (ctx->context_free_func != NULL)
+            ctx->context_free_func(tokdata, sess, ctx->context,
+                                   ctx->context_len);
+        else
+            free(ctx->context);
         ctx->context = NULL;
     }
+    ctx->context_free_func = NULL;
 
     return CKR_OK;
 }
diff --git a/usr/lib/common/dig_mgr.c b/usr/lib/common/dig_mgr.c
index 77cb60a1..222eee75 100644
--- a/usr/lib/common/dig_mgr.c
+++ b/usr/lib/common/dig_mgr.c
@@ -63,7 +63,7 @@ CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
         ctx->context = NULL;
         rc = sha_init(tokdata, sess, ctx, mech);
         if (rc != CKR_OK) {
-            digest_mgr_cleanup(ctx);    // to de-initialize context above
+            digest_mgr_cleanup(tokdata, sess, ctx);    // to de-initialize context above
             TRACE_ERROR("Failed to init sha context.\n");
             return rc;
         }
@@ -76,7 +76,7 @@ CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
         ctx->context_len = sizeof(MD2_CONTEXT);
         ctx->context = (CK_BYTE *) malloc(sizeof(MD2_CONTEXT));
         if (!ctx->context) {
-            digest_mgr_cleanup(ctx);    // to de-initialize context above
+            digest_mgr_cleanup(tokdata, sess, ctx);    // to de-initialize context above
             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
             return CKR_HOST_MEMORY;
         }
@@ -90,7 +90,7 @@ CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
           ctx->context = NULL;
           rc = md5_init(tokdata, sess, ctx, mech);
           if (rc != CKR_OK) {
-              digest_mgr_cleanup(ctx);    // to de-initialize context above
+              digest_mgr_cleanup(tokdata, sess, ctx);    // to de-initialize context above
               TRACE_ERROR("Failed to init md5 context.\n");
               return rc;
           }
@@ -103,7 +103,7 @@ CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
     if (mech->ulParameterLen > 0 && mech->pParameter != NULL) {
         ptr = (CK_BYTE *) malloc(mech->ulParameterLen);
         if (!ptr) {
-            digest_mgr_cleanup(ctx);    // to de-initialize context above
+            digest_mgr_cleanup(tokdata, sess, ctx);    // to de-initialize context above
             TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
             return CKR_HOST_MEMORY;
         }
@@ -122,7 +122,8 @@ CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
 
 //
 //
-CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx)
+CK_RV digest_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                         DIGEST_CONTEXT *ctx)
 {
     if (!ctx) {
         TRACE_ERROR("Invalid function argument.\n");
@@ -134,6 +135,7 @@ CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx)
     ctx->multi = FALSE;
     ctx->active = FALSE;
     ctx->context_len = 0;
+    ctx->state_unsaveable = FALSE;
 
     if (ctx->mech.pParameter) {
         free(ctx->mech.pParameter);
@@ -141,9 +143,14 @@ CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx)
     }
 
     if (ctx->context != NULL) {
-        free(ctx->context);
+        if (ctx->context_free_func != NULL)
+            ctx->context_free_func(tokdata, sess, ctx->context,
+                                   ctx->context_len);
+        else
+            free(ctx->context);
         ctx->context = NULL;
     }
+    ctx->context_free_func = NULL;
 
     return CKR_OK;
 }
@@ -232,7 +239,7 @@ out:
         // unless it returns CKR_BUFFER_TOO_SMALL or is a successful call (i.e.,
         // one which returns CKR_OK) to determine the length of the buffer
         // needed to hold the message digest."
-        digest_mgr_cleanup(ctx);
+        digest_mgr_cleanup(tokdata, sess, ctx);
     }
 
     return rc;
@@ -301,7 +308,7 @@ CK_RV digest_mgr_digest_update(STDLL_TokData_t *tokdata,
 
 out:
     if (rc != CKR_OK) {
-        digest_mgr_cleanup(ctx);
+        digest_mgr_cleanup(tokdata, sess, ctx);
         // "A call to C_DigestUpdate which results in an error
         // terminates the current digest operation."
     }
@@ -373,7 +380,7 @@ CK_RV digest_mgr_digest_key(STDLL_TokData_t *tokdata,
 
 out:
     if (rc != CKR_OK) {
-        digest_mgr_cleanup(ctx);
+        digest_mgr_cleanup(tokdata, sess, ctx);
     }
 
     object_put(tokdata, key_obj, TRUE);
@@ -451,7 +458,7 @@ out:
         // operation unless it returns CKR_BUFFER_TOO_SMALL or is a successful
         // call (i.e., one which returns CKR_OK) to determine the length of the
         // buffer needed to hold the message digest."
-        digest_mgr_cleanup(ctx);
+        digest_mgr_cleanup(tokdata, sess, ctx);
     }
 
     return rc;
diff --git a/usr/lib/common/encr_mgr.c b/usr/lib/common/encr_mgr.c
index 3e85ceab..7f7dfbae 100644
--- a/usr/lib/common/encr_mgr.c
+++ b/usr/lib/common/encr_mgr.c
@@ -617,7 +617,8 @@ done:
 
 //
 //
-CK_RV encr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx)
+CK_RV encr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                       ENCR_DECR_CONTEXT *ctx)
 {
     if (!ctx) {
         TRACE_ERROR("Invalid function argument.\n");
@@ -632,6 +633,7 @@ CK_RV encr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx)
     ctx->init_pending = FALSE;
     ctx->context_len = 0;
     ctx->pkey_active = FALSE;
+    ctx->state_unsaveable = FALSE;
 
     if (ctx->mech.pParameter) {
         free(ctx->mech.pParameter);
@@ -639,9 +641,14 @@ CK_RV encr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx)
     }
 
     if (ctx->context) {
-        free(ctx->context);
+        if (ctx->context_free_func != NULL)
+            ctx->context_free_func(tokdata, sess, ctx->context,
+                                   ctx->context_len);
+        else
+            free(ctx->context);
         ctx->context = NULL;
     }
+    ctx->context_free_func = NULL;
 
     return CKR_OK;
 }
@@ -1204,8 +1211,8 @@ done:
         free(decr_data);
     }
 
-    decr_mgr_cleanup(decr_ctx);
-    encr_mgr_cleanup(encr_ctx);
+    decr_mgr_cleanup(tokdata, sess, decr_ctx);
+    encr_mgr_cleanup(tokdata, sess, encr_ctx);
 
     return rc;
 }
diff --git a/usr/lib/common/h_extern.h b/usr/lib/common/h_extern.h
index 5e251d95..47b96ba0 100644
--- a/usr/lib/common/h_extern.h
+++ b/usr/lib/common/h_extern.h
@@ -1790,7 +1790,8 @@ CK_RV encr_mgr_init(STDLL_TokData_t *tokdata,
                     CK_ULONG operation,
                     CK_MECHANISM *mech, CK_OBJECT_HANDLE key_handle);
 
-CK_RV encr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx);
+CK_RV encr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                       ENCR_DECR_CONTEXT *ctx);
 
 CK_RV encr_mgr_encrypt(STDLL_TokData_t *tokdata,
                        SESSION *sess, CK_BBOOL length_only,
@@ -1825,7 +1826,8 @@ CK_RV decr_mgr_init(STDLL_TokData_t *tokdata,
                     CK_ULONG operation,
                     CK_MECHANISM *mech, CK_OBJECT_HANDLE key_handle);
 
-CK_RV decr_mgr_cleanup(ENCR_DECR_CONTEXT *ctx);
+CK_RV decr_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                       ENCR_DECR_CONTEXT *ctx);
 
 CK_RV decr_mgr_decrypt(STDLL_TokData_t *tokdata,
                        SESSION *sess, CK_BBOOL length_only,
@@ -1866,7 +1868,8 @@ CK_RV decr_mgr_update_des3_cbc(STDLL_TokData_t *tokdata, SESSION *sess,
 
 // digest manager routines
 //
-CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx);
+CK_RV digest_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                         DIGEST_CONTEXT *ctx);
 
 CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
                       SESSION *sess,
@@ -1955,7 +1958,8 @@ CK_RV sign_mgr_init(STDLL_TokData_t *tokdata,
                     CK_MECHANISM *mech,
                     CK_BBOOL recover_mode, CK_OBJECT_HANDLE key_handle);
 
-CK_RV sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx);
+CK_RV sign_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                       SIGN_VERIFY_CONTEXT *ctx);
 
 CK_RV sign_mgr_sign(STDLL_TokData_t *tokdata,
                     SESSION *sess,
@@ -1992,7 +1996,8 @@ CK_RV verify_mgr_init(STDLL_TokData_t *tokdata,
                       CK_MECHANISM *mech,
                       CK_BBOOL recover_mode, CK_OBJECT_HANDLE key_handle);
 
-CK_RV verify_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx);
+CK_RV verify_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                         SIGN_VERIFY_CONTEXT *ctx);
 
 CK_RV verify_mgr_verify(STDLL_TokData_t *tokdata,
                         SESSION *sess,
@@ -2036,10 +2041,11 @@ CK_BBOOL session_mgr_so_session_exists(STDLL_TokData_t *tokdata);
 CK_BBOOL session_mgr_user_session_exists(STDLL_TokData_t *tokdata);
 CK_BBOOL session_mgr_public_session_exists(STDLL_TokData_t *tokdata);
 
-CK_RV session_mgr_get_op_state(SESSION *sess, CK_BBOOL length_only,
+CK_RV session_mgr_get_op_state(SESSION *sess,
+                               CK_BBOOL length_only,
                                CK_BYTE *data, CK_ULONG *data_len);
 
-CK_RV session_mgr_set_op_state(SESSION *sess,
+CK_RV session_mgr_set_op_state(STDLL_TokData_t *tokdata, SESSION *sess,
                                CK_OBJECT_HANDLE encr_key,
                                CK_OBJECT_HANDLE auth_key, CK_BYTE *data,
                                CK_ULONG data_len);
diff --git a/usr/lib/common/host_defs.h b/usr/lib/common/host_defs.h
index c0b5c83d..41fdb657 100644
--- a/usr/lib/common/host_defs.h
+++ b/usr/lib/common/host_defs.h
@@ -21,27 +21,36 @@
 
 #include "local_types.h"
 
+struct _SESSION;
+
+typedef void (*context_free_func_t)(STDLL_TokData_t *tokdata, struct _SESSION *sess,
+                                    CK_BYTE *context, CK_ULONG context_len);
+
 typedef struct _ENCR_DECR_CONTEXT {
     CK_OBJECT_HANDLE key;
     CK_MECHANISM mech;
     CK_BYTE *context;
     CK_ULONG context_len;
+    context_free_func_t context_free_func;
     CK_BBOOL multi;
     CK_BBOOL active;
     CK_BBOOL init_pending;      // indicate init request pending
     CK_BBOOL multi_init;        // multi field is initialized
                                 // on first call *after* init
     CK_BBOOL pkey_active;
+    CK_BBOOL state_unsaveable;
 } ENCR_DECR_CONTEXT;
 
 typedef struct _DIGEST_CONTEXT {
     CK_MECHANISM mech;
     CK_BYTE *context;
     CK_ULONG context_len;
+    context_free_func_t context_free_func;
     CK_BBOOL multi;
     CK_BBOOL active;
     CK_BBOOL multi_init;        // multi field is initialized
                                 // on first call *after* init
+    CK_BBOOL state_unsaveable;
 } DIGEST_CONTEXT;
 
 typedef struct _SIGN_VERIFY_CONTEXT {
@@ -49,6 +58,7 @@ typedef struct _SIGN_VERIFY_CONTEXT {
     CK_MECHANISM mech;          // current sign mechanism
     CK_BYTE *context;           // temporary work area
     CK_ULONG context_len;
+    context_free_func_t context_free_func;
     CK_BBOOL multi;             // is this a multi-part operation?
     CK_BBOOL recover;           // are we in recover mode?
     CK_BBOOL active;
@@ -56,6 +66,7 @@ typedef struct _SIGN_VERIFY_CONTEXT {
     CK_BBOOL multi_init;        // multi field is initialized
                                 // on first call *after* init
     CK_BBOOL pkey_active;
+    CK_BBOOL state_unsaveable;
 } SIGN_VERIFY_CONTEXT;
 
 
diff --git a/usr/lib/common/key_mgr.c b/usr/lib/common/key_mgr.c
index d9cd1f2f..aea74b7c 100644
--- a/usr/lib/common/key_mgr.c
+++ b/usr/lib/common/key_mgr.c
@@ -1011,7 +1011,7 @@ CK_RV key_mgr_wrap_key(STDLL_TokData_t *tokdata,
         OPENSSL_cleanse(data, data_len);
         free(data);
     }
-    encr_mgr_cleanup(ctx);
+    encr_mgr_cleanup(tokdata, sess, ctx);
     free(ctx);
 
 done:
@@ -1259,7 +1259,7 @@ CK_RV key_mgr_unwrap_key(STDLL_TokData_t *tokdata,
                           FALSE,
                           ctx, wrapped_key, wrapped_key_len, data, &data_len);
 
-    decr_mgr_cleanup(ctx);
+    decr_mgr_cleanup(tokdata, sess, ctx);
     free(ctx);
     ctx = NULL;
 
@@ -1345,7 +1345,7 @@ done:
         free(data);
     }
     if (ctx != NULL) {
-        decr_mgr_cleanup(ctx);
+        decr_mgr_cleanup(tokdata, sess, ctx);
         free(ctx);
     }
 
diff --git a/usr/lib/common/lock_sess_mgr.c b/usr/lib/common/lock_sess_mgr.c
index 0c7dbedf..0609a6c9 100644
--- a/usr/lib/common/lock_sess_mgr.c
+++ b/usr/lib/common/lock_sess_mgr.c
@@ -276,32 +276,62 @@ CK_RV session_mgr_close_session(STDLL_TokData_t *tokdata,
     if (sess->find_list)
         free(sess->find_list);
 
-    if (sess->encr_ctx.context)
-        free(sess->encr_ctx.context);
+    if (sess->encr_ctx.context) {
+        if (sess->encr_ctx.context_free_func != NULL)
+            sess->encr_ctx.context_free_func(tokdata, sess,
+                                             sess->encr_ctx.context,
+                                             sess->encr_ctx.context_len);
+        else
+            free(sess->encr_ctx.context);
+    }
 
     if (sess->encr_ctx.mech.pParameter)
         free(sess->encr_ctx.mech.pParameter);
 
-    if (sess->decr_ctx.context)
-        free(sess->decr_ctx.context);
+    if (sess->decr_ctx.context) {
+        if (sess->decr_ctx.context_free_func != NULL)
+            sess->decr_ctx.context_free_func(tokdata, sess,
+                                             sess->decr_ctx.context,
+                                             sess->decr_ctx.context_len);
+        else
+            free(sess->decr_ctx.context);
+    }
 
     if (sess->decr_ctx.mech.pParameter)
         free(sess->decr_ctx.mech.pParameter);
 
-    if (sess->digest_ctx.context)
-        free(sess->digest_ctx.context);
+    if (sess->digest_ctx.context) {
+        if (sess->digest_ctx.context_free_func != NULL)
+            sess->digest_ctx.context_free_func(tokdata, sess,
+                                               sess->digest_ctx.context,
+                                               sess->digest_ctx.context_len);
+        else
+            free(sess->digest_ctx.context);
+    }
 
     if (sess->digest_ctx.mech.pParameter)
         free(sess->digest_ctx.mech.pParameter);
 
-    if (sess->sign_ctx.context)
-        free(sess->sign_ctx.context);
+    if (sess->sign_ctx.context) {
+        if (sess->sign_ctx.context_free_func != NULL)
+            sess->sign_ctx.context_free_func(tokdata, sess,
+                                             sess->sign_ctx.context,
+                                             sess->sign_ctx.context_len);
+        else
+            free(sess->sign_ctx.context);
+    }
 
     if (sess->sign_ctx.mech.pParameter)
         free(sess->sign_ctx.mech.pParameter);
 
-    if (sess->verify_ctx.context)
-        free(sess->verify_ctx.context);
+    if (sess->verify_ctx.context) {
+        if (sess->verify_ctx.context_free_func != NULL)
+            sess->verify_ctx.context_free_func(tokdata, sess,
+                                               sess->verify_ctx.context,
+                                               sess->verify_ctx.context_len);
+        else
+            free(sess->verify_ctx.context);
+    }
 
     if (sess->verify_ctx.mech.pParameter)
         free(sess->verify_ctx.mech.pParameter);
@@ -354,32 +384,62 @@ void session_free(STDLL_TokData_t *tokdata, void *node_value,
     if (sess->find_list)
         free(sess->find_list);
 
-    if (sess->encr_ctx.context)
-        free(sess->encr_ctx.context);
+    if (sess->encr_ctx.context) {
+        if (sess->encr_ctx.context_free_func != NULL)
+            sess->encr_ctx.context_free_func(tokdata, sess,
+                                             sess->encr_ctx.context,
+                                             sess->encr_ctx.context_len);
+        else
+            free(sess->encr_ctx.context);
+    }
 
     if (sess->encr_ctx.mech.pParameter)
         free(sess->encr_ctx.mech.pParameter);
 
-    if (sess->decr_ctx.context)
-        free(sess->decr_ctx.context);
+    if (sess->decr_ctx.context) {
+        if (sess->decr_ctx.context_free_func != NULL)
+            sess->decr_ctx.context_free_func(tokdata, sess,
+                                             sess->decr_ctx.context,
+                                             sess->decr_ctx.context_len);
+        else
+            free(sess->decr_ctx.context);
+    }
 
     if (sess->decr_ctx.mech.pParameter)
         free(sess->decr_ctx.mech.pParameter);
 
-    if (sess->digest_ctx.context)
-        free(sess->digest_ctx.context);
+    if (sess->digest_ctx.context) {
+        if (sess->digest_ctx.context_free_func != NULL)
+            sess->digest_ctx.context_free_func(tokdata, sess,
+                                               sess->digest_ctx.context,
+                                               sess->digest_ctx.context_len);
+        else
+            free(sess->digest_ctx.context);
+    }
 
     if (sess->digest_ctx.mech.pParameter)
         free(sess->digest_ctx.mech.pParameter);
 
-    if (sess->sign_ctx.context)
-        free(sess->sign_ctx.context);
+    if (sess->sign_ctx.context) {
+        if (sess->sign_ctx.context_free_func != NULL)
+            sess->sign_ctx.context_free_func(tokdata, sess,
+                                             sess->sign_ctx.context,
+                                             sess->sign_ctx.context_len);
+        else
+            free(sess->sign_ctx.context);
+    }
 
     if (sess->sign_ctx.mech.pParameter)
         free(sess->sign_ctx.mech.pParameter);
 
-    if (sess->verify_ctx.context)
-        free(sess->verify_ctx.context);
+    if (sess->verify_ctx.context) {
+        if (sess->verify_ctx.context_free_func != NULL)
+            sess->verify_ctx.context_free_func(tokdata, sess,
+                                               sess->verify_ctx.context,
+                                               sess->verify_ctx.context_len);
+        else
+            free(sess->verify_ctx.context);
+    }
 
     if (sess->verify_ctx.mech.pParameter)
         free(sess->verify_ctx.mech.pParameter);
@@ -528,6 +588,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     active_ops = 0;
 
     if (sess->encr_ctx.active == TRUE) {
+        if (sess->encr_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -572,6 +636,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->decr_ctx.active == TRUE) {
+        if (sess->decr_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -616,6 +684,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->digest_ctx.active == TRUE) {
+        if (sess->digest_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -660,6 +732,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->sign_ctx.active == TRUE) {
+        if (sess->sign_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -704,6 +780,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->verify_ctx.active == TRUE) {
+        if (sess->verify_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -759,7 +839,7 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
 
 //
 //
-CK_RV session_mgr_set_op_state(SESSION *sess,
+CK_RV session_mgr_set_op_state(STDLL_TokData_t *tokdata, SESSION *sess,
                                CK_OBJECT_HANDLE encr_key,
                                CK_OBJECT_HANDLE auth_key,
                                CK_BYTE *data, CK_ULONG data_len)
@@ -939,19 +1019,19 @@ CK_RV session_mgr_set_op_state(SESSION *sess,
     // state information looks okay.  cleanup the current session state, first
     //
     if (sess->encr_ctx.active)
-        encr_mgr_cleanup(&sess->encr_ctx);
+        encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
 
     if (sess->decr_ctx.active)
-        decr_mgr_cleanup(&sess->decr_ctx);
+        decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
 
     if (sess->digest_ctx.active)
-        digest_mgr_cleanup(&sess->digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &sess->digest_ctx);
 
     if (sess->sign_ctx.active)
-        sign_mgr_cleanup(&sess->sign_ctx);
+        sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
 
     if (sess->verify_ctx.active)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
 
     // copy the new state information
diff --git a/usr/lib/common/mech_aes.c b/usr/lib/common/mech_aes.c
index a117487d..ad6af16b 100644
--- a/usr/lib/common/mech_aes.c
+++ b/usr/lib/common/mech_aes.c
@@ -2740,6 +2740,9 @@ CK_RV aes_cmac_sign(STDLL_TokData_t *tokdata,
         goto done;
     }
 
+    if (((AES_CMAC_CONTEXT *)ctx->context)->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     memcpy(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv, mac_len);
     *out_data_len = mac_len;
 
@@ -2810,6 +2813,9 @@ CK_RV aes_cmac_sign_update(STDLL_TokData_t *tokdata,
             context->len = remain;
 
             context->initialized = CK_TRUE;
+
+            if (context->ctx != NULL)
+                ctx->state_unsaveable = CK_TRUE;
         } else {
             TRACE_DEVEL("Token specific aes cmac failed.\n");
         }
@@ -2873,6 +2879,9 @@ CK_RV aes_cmac_sign_final(STDLL_TokData_t *tokdata,
         goto done;
     }
 
+    if (context->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     memcpy(out_data, context->iv, mac_len);
     *out_data_len = mac_len;
 
@@ -2929,6 +2938,9 @@ CK_RV aes_cmac_verify(STDLL_TokData_t *tokdata,
         return rc;
     }
 
+    if (((AES_CMAC_CONTEXT *)ctx->context)->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     if (CRYPTO_memcmp(out_data, ((AES_CMAC_CONTEXT *) ctx->context)->iv,
                       out_data_len) == 0) {
         return CKR_OK;
@@ -2997,6 +3009,9 @@ CK_RV aes_cmac_verify_update(STDLL_TokData_t *tokdata,
             context->len = remain;
 
             context->initialized = CK_TRUE;
+
+            if (context->ctx != NULL)
+                ctx->state_unsaveable = CK_TRUE;
         } else {
             TRACE_DEVEL("Token specific aes cmac failed.\n");
         }
@@ -3052,6 +3067,9 @@ CK_RV aes_cmac_verify_final(STDLL_TokData_t *tokdata,
     object_put(tokdata, key_obj, TRUE);
     key_obj = NULL;
 
+    if (context->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     if (rc != CKR_OK) {
         TRACE_DEVEL("Token specific aes mac failed.\n");
         return rc;
diff --git a/usr/lib/common/mech_des3.c b/usr/lib/common/mech_des3.c
index 786f9a4a..be8d6075 100644
--- a/usr/lib/common/mech_des3.c
+++ b/usr/lib/common/mech_des3.c
@@ -2380,6 +2380,9 @@ CK_RV des3_cmac_sign(STDLL_TokData_t *tokdata,
     if (rc != CKR_OK)
         TRACE_DEVEL("Token specific des3 cmac failed.\n");
 
+    if (((DES_CMAC_CONTEXT *)ctx->context)->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     memcpy(out_data, ((DES_CMAC_CONTEXT *) ctx->context)->iv, mac_len);
 
     *out_data_len = mac_len;
@@ -2450,6 +2453,9 @@ CK_RV des3_cmac_sign_update(STDLL_TokData_t *tokdata,
             context->len = remain;
 
             context->initialized = CK_TRUE;
+
+            if (context->ctx != NULL)
+                ctx->state_unsaveable = CK_TRUE;
         } else {
             TRACE_DEVEL("Token specific des3 cmac failed.\n");
         }
@@ -2512,6 +2518,9 @@ CK_RV des3_cmac_sign_final(STDLL_TokData_t *tokdata,
         goto done;
     }
 
+    if (context->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     memcpy(out_data, context->iv, mac_len);
 
     *out_data_len = mac_len;
@@ -2565,6 +2574,9 @@ CK_RV des3_cmac_verify(STDLL_TokData_t *tokdata,
     object_put(tokdata, key_obj, TRUE);
     key_obj = NULL;
 
+    if (((DES_CMAC_CONTEXT *)ctx->context)->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     if (CRYPTO_memcmp(out_data, ((DES_CMAC_CONTEXT *) ctx->context)->iv,
                       out_data_len) == 0) {
         return CKR_OK;
@@ -2631,6 +2643,9 @@ CK_RV des3_cmac_verify_update(STDLL_TokData_t *tokdata,
             context->len = remain;
 
             context->initialized = CK_TRUE;
+
+            if (context->ctx != NULL)
+                ctx->state_unsaveable = CK_TRUE;
         } else {
             TRACE_DEVEL("Token specific des3 cmac failed.\n");
         }
@@ -2691,6 +2706,9 @@ CK_RV des3_cmac_verify_final(STDLL_TokData_t *tokdata,
         return rc;
     }
 
+    if (context->ctx != NULL)
+        ctx->state_unsaveable = CK_TRUE;
+
     if (CRYPTO_memcmp(signature, context->iv, signature_len) == 0)
         return CKR_OK;
 
diff --git a/usr/lib/common/mech_ec.c b/usr/lib/common/mech_ec.c
index a0a06302..c338d063 100644
--- a/usr/lib/common/mech_ec.c
+++ b/usr/lib/common/mech_ec.c
@@ -414,7 +414,7 @@ CK_RV ec_hash_sign(STDLL_TokData_t *tokdata,
                            in_data_len, hash, &hash_len);
     if (rc != CKR_OK) {
         TRACE_DEVEL("Digest Mgr Digest failed.\n");
-        digest_mgr_cleanup(&digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &digest_ctx);
         return rc;
     }
 
@@ -434,7 +434,7 @@ CK_RV ec_hash_sign(STDLL_TokData_t *tokdata,
         TRACE_DEVEL("Sign Mgr Sign failed.\n");
 
 error:
-    sign_mgr_cleanup(&sign_ctx);
+    sign_mgr_cleanup(tokdata, sess, &sign_ctx);
 
     return rc;
 }
@@ -485,6 +485,7 @@ CK_RV ec_hash_sign_update(STDLL_TokData_t *tokdata,
             return rc;
         }
         context->flag = TRUE;
+        ctx->state_unsaveable |= context->hash_context.state_unsaveable;
     }
 
     rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
@@ -556,12 +557,12 @@ CK_RV ec_hash_sign_final(STDLL_TokData_t *tokdata,
         TRACE_DEVEL("Sign Mgr Sign failed.\n");
 
     if (length_only == TRUE || rc == CKR_BUFFER_TOO_SMALL) {
-        sign_mgr_cleanup(&sign_ctx);
+        sign_mgr_cleanup(tokdata, sess, &sign_ctx);
         return rc;
     }
 
 done:
-    sign_mgr_cleanup(&sign_ctx);
+    sign_mgr_cleanup(tokdata, sess, &sign_ctx);
 
     return rc;
 }
@@ -627,7 +628,7 @@ CK_RV ec_hash_verify(STDLL_TokData_t *tokdata,
                            in_data_len, hash, &hash_len);
     if (rc != CKR_OK) {
         TRACE_DEVEL("Digest Mgr Digest failed.\n");
-        digest_mgr_cleanup(&digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &digest_ctx);
         return rc;
     }
     // Verify the Signed BER-encoded Data block
@@ -649,7 +650,7 @@ CK_RV ec_hash_verify(STDLL_TokData_t *tokdata,
     if (rc != CKR_OK)
         TRACE_DEVEL("Verify Mgr Verify failed.\n");
 done:
-    sign_mgr_cleanup(&verify_ctx);
+    sign_mgr_cleanup(tokdata, sess, &verify_ctx);
 
     return rc;
 }
@@ -701,6 +702,7 @@ CK_RV ec_hash_verify_update(STDLL_TokData_t *tokdata,
             return rc;
         }
         context->flag = TRUE;
+        ctx->state_unsaveable |= context->hash_context.state_unsaveable;
     }
 
     rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
@@ -768,7 +770,7 @@ CK_RV ec_hash_verify_final(STDLL_TokData_t *tokdata,
     if (rc != CKR_OK)
         TRACE_DEVEL("Verify Mgr Verify failed.\n");
 done:
-    verify_mgr_cleanup(&verify_ctx);
+    verify_mgr_cleanup(tokdata, sess, &verify_ctx);
 
     return rc;
 }
@@ -823,7 +825,7 @@ CK_RV ckm_kdf(STDLL_TokData_t *tokdata, SESSION *sess, CK_ULONG kdf,
                            h_len);
     if (rc != CKR_OK) {
         TRACE_ERROR("digest_mgr_digest failed with rc = %s\n", ock_err(rc));
-        digest_mgr_cleanup(&ctx);
+        digest_mgr_cleanup(tokdata, sess, &ctx);
         return rc;
     }
 
diff --git a/usr/lib/common/mech_md2.c b/usr/lib/common/mech_md2.c
index beb84365..91da6259 100644
--- a/usr/lib/common/mech_md2.c
+++ b/usr/lib/common/mech_md2.c
@@ -245,7 +245,7 @@ CK_RV md2_hmac_sign(STDLL_TokData_t *tokdata,
                                attr->pValue, attr->ulValueLen, hash, &hash_len);
         if (rc != CKR_OK) {
             TRACE_DEVEL("Digest Mgr Digest failed.\n");
-            digest_mgr_cleanup(&digest_ctx);
+            digest_mgr_cleanup(tokdata, sess, &digest_ctx);
             goto done;
         }
         memset(&digest_ctx, 0x0, sizeof(DIGEST_CONTEXT));
diff --git a/usr/lib/common/mech_md5.c b/usr/lib/common/mech_md5.c
index 6b1281de..320e2549 100644
--- a/usr/lib/common/mech_md5.c
+++ b/usr/lib/common/mech_md5.c
@@ -61,7 +61,10 @@ CK_RV sw_md5_hash(DIGEST_CONTEXT *ctx, CK_BYTE *in_data,
     MD5_Final(out_data, (MD5_CTX *)ctx->context);
     *out_data_len = MD5_HASH_SIZE;
 
-    free(ctx->context);
+    if (ctx->context_free_func != NULL)
+        ctx->context_free_func(ctx->context, ctx->context_len);
+    else
+        free(ctx->context);
     ctx->context = NULL;
 
     return CKR_OK;
@@ -86,7 +89,10 @@ CK_RV sw_MD5_Final(DIGEST_CONTEXT *ctx, CK_BYTE *out_data,
     MD5_Final(out_data, (MD5_CTX *)ctx->context);
     *out_data_len = MD5_HASH_SIZE;
 
-    free(ctx->context);
+    if (ctx->context_free_func != NULL)
+        ctx->context_free_func(ctx->context, ctx->context_len);
+    else
+        free(ctx->context);
     ctx->context = NULL;
 
     return CKR_OK;
@@ -267,7 +273,7 @@ CK_RV md5_hmac_sign(STDLL_TokData_t *tokdata,
                                attr->pValue, attr->ulValueLen, hash, &hash_len);
         if (rc != CKR_OK) {
             TRACE_DEVEL("Digest Mgr Digest failed.\n");
-            digest_mgr_cleanup(&digest_ctx);
+            digest_mgr_cleanup(tokdata, sess, &digest_ctx);
             goto done;
         }
 
@@ -413,6 +419,6 @@ CK_RV md5_hmac_verify(STDLL_TokData_t *tokdata, SESSION *sess,
     }
 
 done:
-    sign_mgr_cleanup(&hmac_ctx);
+    sign_mgr_cleanup(tokdata, sess, &hmac_ctx);
     return rc;
 }
diff --git a/usr/lib/common/mech_rsa.c b/usr/lib/common/mech_rsa.c
index e35b383c..0a690e78 100644
--- a/usr/lib/common/mech_rsa.c
+++ b/usr/lib/common/mech_rsa.c
@@ -1476,7 +1476,7 @@ CK_RV rsa_hash_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess,
                            in_data, in_data_len, hash, &hlen);
     if (rc != CKR_OK) {
         TRACE_DEVEL("Digest Mgr Digest failed.\n");
-        digest_mgr_cleanup(&digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &digest_ctx);
         return rc;
     }
 
@@ -1497,7 +1497,7 @@ CK_RV rsa_hash_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess,
         TRACE_DEVEL("Sign Mgr Sign failed.\n");
 
 done:
-    sign_mgr_cleanup(&sign_ctx);
+    sign_mgr_cleanup(tokdata, sess, &sign_ctx);
 
     return rc;
 }
@@ -1546,6 +1546,7 @@ CK_RV rsa_hash_pss_update(STDLL_TokData_t *tokdata, SESSION *sess,
             TRACE_DEVEL("Digest Mgr Init failed.\n");
             return rc;
         }
+        ctx->state_unsaveable |= digest_ctx->state_unsaveable;
     }
 
     rc = digest_mgr_digest_update(tokdata, sess, digest_ctx, in_data,
@@ -1613,7 +1614,7 @@ CK_RV rsa_hash_pss_sign_final(STDLL_TokData_t *tokdata, SESSION *sess,
         TRACE_DEVEL("Sign Mgr Sign failed.\n");
 
 done:
-    sign_mgr_cleanup(&sign_ctx);
+    sign_mgr_cleanup(tokdata, sess, &sign_ctx);
 
     return rc;
 }
@@ -1676,7 +1677,7 @@ CK_RV rsa_hash_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess,
                            in_data_len, hash, &hlen);
     if (rc != CKR_OK) {
         TRACE_DEVEL("Digest Mgr Digest failed.\n");
-        digest_mgr_cleanup(&digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &digest_ctx);
         return rc;
     }
 
@@ -1698,7 +1699,7 @@ CK_RV rsa_hash_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess,
         TRACE_DEVEL("Verify Mgr Verify failed.\n");
 
 done:
-    verify_mgr_cleanup(&verify_ctx);
+    verify_mgr_cleanup(tokdata, sess, &verify_ctx);
 
     return rc;
 }
@@ -1760,7 +1761,7 @@ CK_RV rsa_hash_pss_verify_final(STDLL_TokData_t *tokdata, SESSION *sess,
         TRACE_DEVEL("Verify Mgr Verify failed.\n");
 
 done:
-    verify_mgr_cleanup(&verify_ctx);
+    verify_mgr_cleanup(tokdata, sess, &verify_ctx);
 
     return rc;
 }
@@ -1842,7 +1843,7 @@ CK_RV rsa_hash_pkcs_sign(STDLL_TokData_t *tokdata,
                            in_data_len, hash, &hash_len);
     if (rc != CKR_OK) {
         TRACE_DEVEL("Digest Mgr Digest failed.\n");
-        digest_mgr_cleanup(&digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &digest_ctx);
         return rc;
     }
     // build the BER-encodings
@@ -1885,7 +1886,7 @@ error:
         free(octet_str);
     if (ber_data)
         free(ber_data);
-    sign_mgr_cleanup(&sign_ctx);
+    sign_mgr_cleanup(tokdata, sess, &sign_ctx);
 
     return rc;
 }
@@ -1934,6 +1935,7 @@ CK_RV rsa_hash_pkcs_sign_update(STDLL_TokData_t *tokdata,
             return rc;
         }
         context->flag = TRUE;
+        ctx->state_unsaveable |= context->hash_context.state_unsaveable;
     }
 
     rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
@@ -2021,7 +2023,7 @@ CK_RV rsa_hash_pkcs_verify(STDLL_TokData_t *tokdata,
                            in_data_len, hash, &hash_len);
     if (rc != CKR_OK) {
         TRACE_DEVEL("Digest Mgr Digest failed.\n");
-        digest_mgr_cleanup(&digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &digest_ctx);
         return rc;
     }
     // Build the BER encoding
@@ -2063,7 +2065,7 @@ done:
         free(octet_str);
     if (ber_data)
         free(ber_data);
-    sign_mgr_cleanup(&verify_ctx);
+    sign_mgr_cleanup(tokdata, sess, &verify_ctx);
 
     return rc;
 }
@@ -2111,6 +2113,7 @@ CK_RV rsa_hash_pkcs_verify_update(STDLL_TokData_t *tokdata,
             return rc;
         }
         context->flag = TRUE;
+        ctx->state_unsaveable |= context->hash_context.state_unsaveable;
     }
 
     rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
@@ -2236,7 +2239,7 @@ done:
         free(octet_str);
     if (ber_data)
         free(ber_data);
-    sign_mgr_cleanup(&sign_ctx);
+    sign_mgr_cleanup(tokdata, sess, &sign_ctx);
 
     return rc;
 }
@@ -2347,7 +2350,7 @@ done:
         free(octet_str);
     if (ber_data)
         free(ber_data);
-    verify_mgr_cleanup(&verify_ctx);
+    verify_mgr_cleanup(tokdata, sess, &verify_ctx);
 
     return rc;
 }
diff --git a/usr/lib/common/mech_sha.c b/usr/lib/common/mech_sha.c
index 4037b8f1..0b9b7b28 100644
--- a/usr/lib/common/mech_sha.c
+++ b/usr/lib/common/mech_sha.c
@@ -80,7 +80,10 @@ CK_RV sw_sha1_hash(DIGEST_CONTEXT *ctx, CK_BYTE *in_data,
     SHA1_Final(out_data, (SHA_CTX *)ctx->context);
     *out_data_len = SHA1_HASH_SIZE;
 
-    free(ctx->context);
+    if (ctx->context_free_func != NULL)
+        ctx->context_free_func(ctx->context, ctx->context_len);
+    else
+        free(ctx->context);
     ctx->context = NULL;
 
     return CKR_OK;
@@ -105,7 +108,10 @@ CK_RV sw_sha1_final(DIGEST_CONTEXT *ctx, CK_BYTE *out_data,
     SHA1_Final(out_data, (SHA_CTX *)ctx->context);
     *out_data_len = SHA1_HASH_SIZE;
 
-    free(ctx->context);
+    if (ctx->context_free_func != NULL)
+        ctx->context_free_func(ctx->context, ctx->context_len);
+    else
+        free(ctx->context);
     ctx->context = NULL;
 
     return CKR_OK;
@@ -421,7 +427,7 @@ CK_RV sha_hmac_sign(STDLL_TokData_t *tokdata,
                                attr->pValue, attr->ulValueLen, hash, &hash_len);
         if (rc != CKR_OK) {
             TRACE_DEVEL("Digest Mgr Digest failed.\n");
-            digest_mgr_cleanup(&digest_ctx);
+            digest_mgr_cleanup(tokdata, sess, &digest_ctx);
             goto done;
         }
 
@@ -607,7 +613,7 @@ CK_RV sha_hmac_verify(STDLL_TokData_t *tokdata, SESSION *sess,
     }
 
 done:
-    sign_mgr_cleanup(&hmac_ctx);
+    sign_mgr_cleanup(tokdata, sess, &hmac_ctx);
     return rc;
 }
 
diff --git a/usr/lib/common/mech_ssl3.c b/usr/lib/common/mech_ssl3.c
index 66bdb8f4..566aeee2 100644
--- a/usr/lib/common/mech_ssl3.c
+++ b/usr/lib/common/mech_ssl3.c
@@ -289,6 +289,7 @@ CK_RV ssl3_mac_sign_update(STDLL_TokData_t *tokdata,
             goto done;
         }
         context->flag = TRUE;
+        ctx->state_unsaveable |= context->hash_context.state_unsaveable;
     }
 
 
@@ -485,7 +486,7 @@ CK_RV ssl3_mac_verify(STDLL_TokData_t *tokdata,
         rc = CKR_SIGNATURE_INVALID;
     }
 error:
-    sign_mgr_cleanup(&mac_ctx);
+    sign_mgr_cleanup(tokdata, sess, &mac_ctx);
 
     return rc;
 }
@@ -573,6 +574,7 @@ CK_RV ssl3_mac_verify_update(STDLL_TokData_t *tokdata,
             goto done;
         }
         context->flag = TRUE;
+        ctx->state_unsaveable |= context->hash_context.state_unsaveable;
     }
 
     rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
diff --git a/usr/lib/common/new_host.c b/usr/lib/common/new_host.c
index a3749d26..d01091f9 100644
--- a/usr/lib/common/new_host.c
+++ b/usr/lib/common/new_host.c
@@ -1215,8 +1215,9 @@ CK_RV SC_SetOperationState(STDLL_TokData_t *tokdata,
         goto done;
     }
 
-    rc = session_mgr_set_op_state(sess, hEncryptionKey, hAuthenticationKey,
-                                  pOperationState, ulOperationStateLen);
+    rc = session_mgr_set_op_state(tokdata, sess, hEncryptionKey,
+                                  hAuthenticationKey, pOperationState,
+                                  ulOperationStateLen);
 
     if (rc != CKR_OK)
         TRACE_DEVEL("session_mgr_set_op_state() failed.\n");
@@ -2128,7 +2129,7 @@ CK_RV SC_Encrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_Encrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2187,7 +2188,7 @@ CK_RV SC_EncryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_EncryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2244,7 +2245,7 @@ CK_RV SC_EncryptFinal(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_EncryptFinal: rc = 0x%08lx, sess = %ld\n",
@@ -2361,7 +2362,7 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_Decrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2420,7 +2421,7 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_DecryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2477,7 +2478,7 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_DecryptFinal: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2825,7 +2826,7 @@ CK_RV SC_Sign(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_Sign: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
@@ -2875,7 +2876,7 @@ CK_RV SC_SignUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (rc != CKR_OK && sess != NULL)
-        sign_mgr_cleanup(&sess->sign_ctx);
+        sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
 
     TRACE_INFO("C_SignUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen);
@@ -2930,7 +2931,7 @@ CK_RV SC_SignFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_SignFinal: rc = 0x%08lx, sess = %ld\n",
@@ -3045,7 +3046,7 @@ CK_RV SC_SignRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_SignRecover: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
@@ -3155,7 +3156,7 @@ CK_RV SC_Verify(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_Verify: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen);
@@ -3205,7 +3206,7 @@ CK_RV SC_VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (rc != CKR_OK && sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_VerifyUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen);
@@ -3255,7 +3256,7 @@ CK_RV SC_VerifyFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_VerifyFinal: rc = 0x%08lx, sess = %ld\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle);
@@ -3372,7 +3373,7 @@ CK_RV SC_VerifyRecover(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess != NULL)
-            verify_mgr_cleanup(&sess->verify_ctx);
+            verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
     }
 
     TRACE_INFO("C_VerifyRecover: rc = 0x%08lx, sess = %ld, recover len = %lu, "
diff --git a/usr/lib/common/sess_mgr.c b/usr/lib/common/sess_mgr.c
index e2da6df5..69c3be3b 100644
--- a/usr/lib/common/sess_mgr.c
+++ b/usr/lib/common/sess_mgr.c
@@ -243,32 +243,62 @@ CK_RV session_mgr_close_session(STDLL_TokData_t *tokdata,
     if (sess->find_list)
         free(sess->find_list);
 
-    if (sess->encr_ctx.context)
-        free(sess->encr_ctx.context);
+    if (sess->encr_ctx.context) {
+        if (sess->encr_ctx.context_free_func != NULL)
+            sess->encr_ctx.context_free_func(tokdata, sess,
+                                             sess->encr_ctx.context,
+                                             sess->encr_ctx.context_len);
+        else
+            free(sess->encr_ctx.context);
+    }
 
     if (sess->encr_ctx.mech.pParameter)
         free(sess->encr_ctx.mech.pParameter);
 
-    if (sess->decr_ctx.context)
-        free(sess->decr_ctx.context);
+    if (sess->decr_ctx.context) {
+        if (sess->decr_ctx.context_free_func != NULL)
+            sess->decr_ctx.context_free_func(tokdata, sess,
+                                             sess->decr_ctx.context,
+                                             sess->decr_ctx.context_len);
+        else
+            free(sess->decr_ctx.context);
+    }
 
     if (sess->decr_ctx.mech.pParameter)
         free(sess->decr_ctx.mech.pParameter);
 
-    if (sess->digest_ctx.context)
-        free(sess->digest_ctx.context);
+    if (sess->digest_ctx.context) {
+        if (sess->digest_ctx.context_free_func != NULL)
+            sess->digest_ctx.context_free_func(tokdata, sess,
+                                               sess->digest_ctx.context,
+                                               sess->digest_ctx.context_len);
+        else
+            free(sess->digest_ctx.context);
+    }
 
     if (sess->digest_ctx.mech.pParameter)
         free(sess->digest_ctx.mech.pParameter);
 
-    if (sess->sign_ctx.context)
-        free(sess->sign_ctx.context);
+    if (sess->sign_ctx.context) {
+        if (sess->sign_ctx.context_free_func != NULL)
+            sess->sign_ctx.context_free_func(tokdata, sess,
+                                             sess->sign_ctx.context,
+                                             sess->sign_ctx.context_len);
+        else
+            free(sess->sign_ctx.context);
+    }
 
     if (sess->sign_ctx.mech.pParameter)
         free(sess->sign_ctx.mech.pParameter);
 
-    if (sess->verify_ctx.context)
-        free(sess->verify_ctx.context);
+    if (sess->verify_ctx.context) {
+        if (sess->verify_ctx.context_free_func != NULL)
+            sess->verify_ctx.context_free_func(tokdata, sess,
+                                               sess->verify_ctx.context,
+                                               sess->verify_ctx.context_len);
+        else
+            free(sess->verify_ctx.context);
+    }
 
     if (sess->verify_ctx.mech.pParameter)
         free(sess->verify_ctx.mech.pParameter);
@@ -323,32 +353,62 @@ void session_free(STDLL_TokData_t *tokdata, void *node_value,
     if (sess->find_list)
         free(sess->find_list);
 
-    if (sess->encr_ctx.context)
-        free(sess->encr_ctx.context);
+    if (sess->encr_ctx.context) {
+        if (sess->encr_ctx.context_free_func != NULL)
+            sess->encr_ctx.context_free_func(tokdata, sess,
+                                             sess->encr_ctx.context,
+                                             sess->encr_ctx.context_len);
+        else
+            free(sess->encr_ctx.context);
+    }
 
     if (sess->encr_ctx.mech.pParameter)
         free(sess->encr_ctx.mech.pParameter);
 
-    if (sess->decr_ctx.context)
-        free(sess->decr_ctx.context);
+    if (sess->decr_ctx.context) {
+        if (sess->decr_ctx.context_free_func != NULL)
+            sess->decr_ctx.context_free_func(tokdata, sess,
+                                             sess->decr_ctx.context,
+                                             sess->decr_ctx.context_len);
+        else
+            free(sess->decr_ctx.context);
+    }
 
     if (sess->decr_ctx.mech.pParameter)
         free(sess->decr_ctx.mech.pParameter);
 
-    if (sess->digest_ctx.context)
-        free(sess->digest_ctx.context);
+    if (sess->digest_ctx.context) {
+        if (sess->digest_ctx.context_free_func != NULL)
+            sess->digest_ctx.context_free_func(tokdata, sess,
+                                               sess->digest_ctx.context,
+                                               sess->digest_ctx.context_len);
+        else
+            free(sess->digest_ctx.context);
+    }
 
     if (sess->digest_ctx.mech.pParameter)
         free(sess->digest_ctx.mech.pParameter);
 
-    if (sess->sign_ctx.context)
-        free(sess->sign_ctx.context);
+    if (sess->sign_ctx.context) {
+        if (sess->sign_ctx.context_free_func != NULL)
+            sess->sign_ctx.context_free_func(tokdata, sess,
+                                             sess->sign_ctx.context,
+                                             sess->sign_ctx.context_len);
+        else
+            free(sess->sign_ctx.context);
+    }
 
     if (sess->sign_ctx.mech.pParameter)
         free(sess->sign_ctx.mech.pParameter);
 
-    if (sess->verify_ctx.context)
-        free(sess->verify_ctx.context);
+    if (sess->verify_ctx.context) {
+        if (sess->verify_ctx.context_free_func != NULL)
+            sess->verify_ctx.context_free_func(tokdata, sess,
+                                               sess->verify_ctx.context,
+                                               sess->verify_ctx.context_len);
+        else
+            free(sess->verify_ctx.context);
+    }
 
     if (sess->verify_ctx.mech.pParameter)
         free(sess->verify_ctx.mech.pParameter);
@@ -480,6 +540,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     active_ops = 0;
 
     if (sess->encr_ctx.active == TRUE) {
+        if (sess->encr_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -524,6 +588,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->decr_ctx.active == TRUE) {
+        if (sess->decr_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -568,6 +636,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->digest_ctx.active == TRUE) {
+        if (sess->digest_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -612,6 +684,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->sign_ctx.active == TRUE) {
+        if (sess->sign_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -656,6 +732,10 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
     }
 
     if (sess->verify_ctx.active == TRUE) {
+        if (sess->verify_ctx.state_unsaveable) {
+            TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
+            return CKR_STATE_UNSAVEABLE;
+        }
         active_ops++;
         if (op_data != NULL) {
             TRACE_ERROR("%s\n", ock_err(ERR_STATE_UNSAVEABLE));
@@ -711,7 +791,7 @@ CK_RV session_mgr_get_op_state(SESSION *sess,
 
 //
 //
-CK_RV session_mgr_set_op_state(SESSION *sess,
+CK_RV session_mgr_set_op_state(STDLL_TokData_t *tokdata, SESSION *sess,
                                CK_OBJECT_HANDLE encr_key,
                                CK_OBJECT_HANDLE auth_key,
                                CK_BYTE *data, CK_ULONG data_len)
@@ -891,19 +971,19 @@ CK_RV session_mgr_set_op_state(SESSION *sess,
     // state information looks okay.  cleanup the current session state, first
     //
     if (sess->encr_ctx.active)
-        encr_mgr_cleanup(&sess->encr_ctx);
+        encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
 
     if (sess->decr_ctx.active)
-        decr_mgr_cleanup(&sess->decr_ctx);
+        decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
 
     if (sess->digest_ctx.active)
-        digest_mgr_cleanup(&sess->digest_ctx);
+        digest_mgr_cleanup(tokdata, sess, &sess->digest_ctx);
 
     if (sess->sign_ctx.active)
-        sign_mgr_cleanup(&sess->sign_ctx);
+        sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
 
     if (sess->verify_ctx.active)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
 
     // copy the new state information
diff --git a/usr/lib/common/sign_mgr.c b/usr/lib/common/sign_mgr.c
index c7268e01..74e3a9e0 100644
--- a/usr/lib/common/sign_mgr.c
+++ b/usr/lib/common/sign_mgr.c
@@ -805,7 +805,8 @@ done:
 
 //
 //
-CK_RV sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
+CK_RV sign_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                       SIGN_VERIFY_CONTEXT *ctx)
 {
     if (!ctx) {
         TRACE_ERROR("Invalid function argument.\n");
@@ -821,6 +822,7 @@ CK_RV sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
     ctx->recover = FALSE;
     ctx->context_len = 0;
     ctx->pkey_active = FALSE;
+    ctx->state_unsaveable = FALSE;
 
     if (ctx->mech.pParameter) {
         free(ctx->mech.pParameter);
@@ -828,9 +830,14 @@ CK_RV sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
     }
 
     if (ctx->context) {
-        free(ctx->context);
+        if (ctx->context_free_func != NULL)
+            ctx->context_free_func(tokdata, sess, ctx->context,
+                                   ctx->context_len);
+        else
+            free(ctx->context);
         ctx->context = NULL;
     }
+    ctx->context_free_func = NULL;
 
     return CKR_OK;
 }
diff --git a/usr/lib/common/verify_mgr.c b/usr/lib/common/verify_mgr.c
index c46a9803..b49fbb49 100644
--- a/usr/lib/common/verify_mgr.c
+++ b/usr/lib/common/verify_mgr.c
@@ -798,7 +798,8 @@ done:
 
 //
 //
-CK_RV verify_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
+CK_RV verify_mgr_cleanup(STDLL_TokData_t *tokdata, SESSION *sess,
+                         SIGN_VERIFY_CONTEXT *ctx)
 {
     if (!ctx) {
         TRACE_ERROR("Invalid function argument.\n");
@@ -814,6 +815,7 @@ CK_RV verify_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
     ctx->recover = FALSE;
     ctx->context_len = 0;
     ctx->pkey_active = FALSE;
+    ctx->state_unsaveable = FALSE;
 
     if (ctx->mech.pParameter) {
         free(ctx->mech.pParameter);
@@ -821,9 +823,14 @@ CK_RV verify_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
     }
 
     if (ctx->context) {
-        free(ctx->context);
+        if (ctx->context_free_func != NULL)
+            ctx->context_free_func(tokdata, sess, ctx->context,
+                                   ctx->context_len);
+        else
+            free(ctx->context);
         ctx->context = NULL;
     }
+    ctx->context_free_func = NULL;
 
     return CKR_OK;
 }
diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c
index fb6055e9..49775d0a 100644
--- a/usr/lib/ep11_stdll/ep11_specific.c
+++ b/usr/lib/ep11_stdll/ep11_specific.c
@@ -8091,7 +8091,7 @@ static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session,
         ctx->context_len = ep11_state_l;
         ctx->pkey_active = FALSE;
         if (rc != CKR_OK) {
-            decr_mgr_cleanup(ctx);
+            decr_mgr_cleanup(tokdata, session, ctx);
             rc = ep11_error_to_pkcs11_error(rc, session);
             TRACE_ERROR("%s m_DecryptInit rc=0x%lx blob_len=0x%zx "
                         "mech=0x%lx\n", __func__, rc, blob_len,
@@ -8124,7 +8124,7 @@ static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session,
         ctx->context_len = ep11_state_l;
         ctx->pkey_active = FALSE;
         if (rc != CKR_OK) {
-            encr_mgr_cleanup(ctx);
+            encr_mgr_cleanup(tokdata, session, ctx);
             rc = ep11_error_to_pkcs11_error(rc, session);
             TRACE_ERROR("%s m_EncryptInit rc=0x%lx blob_len=0x%zx "
                         "mech=0x%lx\n", __func__, rc, blob_len,
diff --git a/usr/lib/ep11_stdll/new_host.c b/usr/lib/ep11_stdll/new_host.c
index cd12604e..a0e7517c 100644
--- a/usr/lib/ep11_stdll/new_host.c
+++ b/usr/lib/ep11_stdll/new_host.c
@@ -1223,8 +1223,9 @@ CK_RV SC_SetOperationState(STDLL_TokData_t *tokdata,
         goto done;
     }
 
-    rc = session_mgr_set_op_state(sess, hEncryptionKey, hAuthenticationKey,
-                                  pOperationState, ulOperationStateLen);
+    rc = session_mgr_set_op_state(tokdata, sess, hEncryptionKey,
+                                  hAuthenticationKey, pOperationState,
+                                  ulOperationStateLen);
 
     if (rc != CKR_OK)
         TRACE_DEVEL("session_mgr_set_op_state() failed.\n");
@@ -2160,7 +2161,7 @@ CK_RV SC_Encrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_Encrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2236,7 +2237,7 @@ CK_RV SC_EncryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_EncryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2310,7 +2311,7 @@ CK_RV SC_EncryptFinal(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_EncryptFinal: rc = 0x%08lx, sess = %ld\n",
@@ -2478,7 +2479,7 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_Decrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2554,7 +2555,7 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_DecryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2626,7 +2627,7 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_DecryptFinal: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -3022,7 +3023,7 @@ CK_RV SC_Sign(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_Sign: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
@@ -3104,7 +3105,7 @@ CK_RV SC_SignUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (rc != CKR_OK && sess != NULL)
-        sign_mgr_cleanup(&sess->sign_ctx);
+        sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
 
     TRACE_INFO("C_SignUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen);
@@ -3185,7 +3186,7 @@ CK_RV SC_SignFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_SignFinal: rc = 0x%08lx, sess = %ld\n",
@@ -3406,7 +3407,7 @@ CK_RV SC_Verify(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_Verify: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen);
@@ -3487,7 +3488,7 @@ CK_RV SC_VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (rc != CKR_OK && sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_VerifyUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen);
@@ -3562,7 +3563,7 @@ CK_RV SC_VerifyFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_VerifyFinal: rc = 0x%08lx, sess = %ld\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle);
diff --git a/usr/lib/ica_s390_stdll/ica_specific.c b/usr/lib/ica_s390_stdll/ica_specific.c
index 7a81145d..77876467 100644
--- a/usr/lib/ica_s390_stdll/ica_specific.c
+++ b/usr/lib/ica_s390_stdll/ica_specific.c
@@ -810,8 +810,10 @@ CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx,
     }
 
     /* (re)alloc ctx in one memory area */
-    if (ctx->context)
+    if (ctx->context) {
         free(ctx->context);
+        ctx->context_free_func = NULL;
+    }
     ctx->context_len = 0;
     ctx->context = malloc(ctxsize + devctxsize);
     if (ctx->context == NULL) {
diff --git a/usr/lib/icsf_stdll/new_host.c b/usr/lib/icsf_stdll/new_host.c
index cfef7425..09e9d27a 100644
--- a/usr/lib/icsf_stdll/new_host.c
+++ b/usr/lib/icsf_stdll/new_host.c
@@ -773,8 +773,9 @@ CK_RV SC_SetOperationState(STDLL_TokData_t *tokdata,
     //set the handle into the session.
     sess->handle = sSession->sessionh;
 
-    rc = session_mgr_set_op_state(sess, hEncryptionKey, hAuthenticationKey,
-                                  pOperationState, ulOperationStateLen);
+    rc = session_mgr_set_op_state(tokdata, sess, hEncryptionKey,
+                                  hAuthenticationKey, pOperationState,
+                                  ulOperationStateLen);
 
     if (rc != CKR_OK)
         TRACE_DEVEL("session_mgr_set_op_state() failed.\n");
@@ -1556,7 +1557,7 @@ CK_RV SC_Encrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_Encrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -1612,7 +1613,7 @@ CK_RV SC_EncryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_EncryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -1671,7 +1672,7 @@ CK_RV SC_EncryptFinal(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            encr_mgr_cleanup(&sess->encr_ctx);
+            encr_mgr_cleanup(tokdata, sess, &sess->encr_ctx);
     }
 
     TRACE_INFO("C_EncryptFinal: rc = 0x%08lx, sess = %ld\n",
@@ -1790,7 +1791,7 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_Decrypt: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -1846,7 +1847,7 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_DecryptUpdate: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -1903,7 +1904,7 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) {
         if (sess)
-            decr_mgr_cleanup(&sess->decr_ctx);
+            decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx);
     }
 
     TRACE_INFO("C_DecryptFinal: rc = 0x%08lx, sess = %ld, amount = %lu\n",
@@ -2261,7 +2262,7 @@ CK_RV SC_Sign(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || pSignature)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_Sign: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
@@ -2312,7 +2313,7 @@ CK_RV SC_SignUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
         TRACE_DEVEL("icsftok_sign_update() failed.\n");
 done:
     if (rc != CKR_OK && sess != NULL)
-        sign_mgr_cleanup(&sess->sign_ctx);
+        sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
 
     TRACE_INFO("C_SignUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen);
@@ -2364,7 +2365,7 @@ CK_RV SC_SignFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 done:
     if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || pSignature)) {
         if (sess != NULL)
-            sign_mgr_cleanup(&sess->sign_ctx);
+            sign_mgr_cleanup(tokdata, sess, &sess->sign_ctx);
     }
 
     TRACE_INFO("C_SignFinal: rc = 0x%08lx, sess = %ld\n",
@@ -2517,7 +2518,7 @@ CK_RV SC_Verify(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_Verify: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulDataLen);
@@ -2568,7 +2569,7 @@ CK_RV SC_VerifyUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (rc != CKR_OK && sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_VerifyUpdate: rc = 0x%08lx, sess = %ld, datalen = %lu\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle, ulPartLen);
@@ -2619,7 +2620,7 @@ CK_RV SC_VerifyFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession,
 
 done:
     if (sess != NULL)
-        verify_mgr_cleanup(&sess->verify_ctx);
+        verify_mgr_cleanup(tokdata, sess, &sess->verify_ctx);
 
     TRACE_INFO("C_VerifyFinal: rc = 0x%08lx, sess = %ld\n",
                rc, (sess == NULL) ? -1 : (CK_LONG) sess->handle);