Blame SOURCES/opencryptoki-openssl3-93588f53d918fe6c7452da076b95081fb6aa9aef.patch

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