diff --git a/gck-rpc-daemon-standalone.c b/gck-rpc-daemon-standalone.c
index 563f83f5f34d9f8a2da5cd80742e239d97cf2a52..ae10932b2b5a2817ae2b916b5f23b5c53cecba52 100644
--- a/gck-rpc-daemon-standalone.c
+++ b/gck-rpc-daemon-standalone.c
@@ -232,9 +232,9 @@ int main(int argc, char *argv[])
 	   if (sock == -1)
 		   exit(1);
 
-	/* Shut down gracefully on SIGTERM. */
-	if (signal (SIGTERM, termination_handler) == SIG_IGN)
-		signal (SIGTERM, SIG_IGN);
+	   /* Shut down gracefully on SIGTERM. */
+	   if (signal (SIGTERM, termination_handler) == SIG_IGN)
+		   signal (SIGTERM, SIG_IGN);
 
 	   is_running = 1;
 	   while (is_running) {
diff --git a/gck-rpc-dispatch.c b/gck-rpc-dispatch.c
index 902227cf33e31caacb323863ca5e0e1119690857..a0152f3880d011dc94719e4e01b8c574a109d128 100644
--- a/gck-rpc-dispatch.c
+++ b/gck-rpc-dispatch.c
@@ -80,6 +80,9 @@ static DispatchState *pkcs11_dispatchers = NULL;
 /* A mutex to protect the dispatcher list */
 static pthread_mutex_t pkcs11_dispatchers_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+/* To be able to call C_Finalize from call_uninit. */
+static CK_RV rpc_C_Finalize(CallState *);
+
 /* -----------------------------------------------------------------------------
  * LOGGING and DEBUGGING
  */
@@ -180,6 +183,12 @@ static void call_uninit(CallState * cs)
 {
 	assert(cs);
 
+	/* Close any open sessions. Without this, the application won't be able
+	 * to reconnect (possibly after a crash).
+	 */
+	if (cs->req)
+		rpc_C_Finalize(cs);
+
 	call_reset(cs);
 
 	gck_rpc_message_free(cs->req);
@@ -192,9 +201,10 @@ static void call_uninit(CallState * cs)
 
 static CK_RV
 proto_read_byte_buffer(CallState * cs, CK_BYTE_PTR * buffer,
-		       CK_ULONG * n_buffer)
+		       CK_ULONG_PTR * n_buffer)
 {
 	GckRpcMessage *msg;
+	uint8_t flags;
 	uint32_t length;
 
 	assert(cs);
@@ -206,23 +216,27 @@ proto_read_byte_buffer(CallState * cs, CK_BYTE_PTR * buffer,
 	/* Check that we're supposed to be reading this at this point */
 	assert(!msg->signature || gck_rpc_message_verify_part(msg, "fy"));
 
+	if (!egg_buffer_get_byte
+	    (&msg->buffer, msg->parsed, &msg->parsed, &flags))
+		return PARSE_ERROR;
+
 	/* The number of ulongs there's room for on the other end */
 	if (!egg_buffer_get_uint32
 	    (&msg->buffer, msg->parsed, &msg->parsed, &length))
 		return PARSE_ERROR;
 
-	*n_buffer = length;
-	*buffer = NULL;
 
-	/* We go ahead and allocate a buffer even if length is zero. The code used
-	 * to just return CKR_OK without allocating a buffer, but that breaks a
-	 * test case in pkcs11-tool for C_GenerateRandom of 0 bytes. Best to be as
-	 * transparent as possible and let the p11 module decide how to handle it.
-	 */
+	**n_buffer = length;
+	*buffer = NULL_PTR;
 
-	*buffer = call_alloc(cs, length * sizeof(CK_BYTE));
-	if (!*buffer)
-		return CKR_DEVICE_MEMORY;
+	if ((flags & GCK_RPC_BYTE_BUFFER_NULL_COUNT))
+		*n_buffer = NULL_PTR;
+
+	if (! (flags & GCK_RPC_BYTE_BUFFER_NULL_DATA)) {
+		*buffer = call_alloc(cs, length * sizeof(CK_BYTE));
+		if (!*buffer)
+			return CKR_DEVICE_MEMORY;
+	}
 
 	return CKR_OK;
 }
@@ -248,8 +262,13 @@ proto_read_byte_array(CallState * cs, CK_BYTE_PTR * array, CK_ULONG * n_array)
 		return PARSE_ERROR;
 
 	if (!valid) {
+		uint32_t n_size;
+		/* No array, no data, just length */
+		if (!egg_buffer_get_uint32
+		    (&msg->buffer, msg->parsed, &msg->parsed, &n_size))
+			return PARSE_ERROR;
+		*n_array = (size_t) n_size;
 		*array = NULL;
-		*n_array = 0;
 		return CKR_OK;
 	}
 
@@ -264,7 +283,7 @@ proto_read_byte_array(CallState * cs, CK_BYTE_PTR * array, CK_ULONG * n_array)
 }
 
 static CK_RV
-proto_write_byte_array(CallState * cs, CK_BYTE_PTR array, CK_ULONG len,
+proto_write_byte_array(CallState * cs, CK_BYTE_PTR array, CK_ULONG_PTR len,
 		       CK_RV ret)
 {
 	assert(cs);
@@ -286,7 +305,7 @@ proto_write_byte_array(CallState * cs, CK_BYTE_PTR array, CK_ULONG len,
 		return ret;
 	};
 
-	if (!gck_rpc_message_write_byte_array(cs->resp, array, len))
+	if (!gck_rpc_message_write_byte_array(cs->resp, array, len ? *len : 0))
 		return PREP_ERROR;
 
 	return CKR_OK;
@@ -433,7 +452,7 @@ proto_read_attribute_array(CallState * cs, CK_ATTRIBUTE_PTR * result,
 
 	msg = cs->req;
 
-	/* Make sure this is in the rigth order */
+	/* Make sure this is in the right order */
 	assert(!msg->signature || gck_rpc_message_verify_part(msg, "aA"));
 
 	/* Read the number of attributes */
@@ -548,8 +567,8 @@ static CK_RV proto_read_null_string(CallState * cs, CK_UTF8CHAR_PTR * val)
 	    (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data))
 		return PARSE_ERROR;
 
-	/* Allocate a block of memory for it */
-	*val = call_alloc(cs, n_data);
+	/* Allocate a block of memory for it. The +1 accomodates the NULL byte. */
+	*val = call_alloc(cs, n_data + 1);
 	if (!*val)
 		return CKR_DEVICE_MEMORY;
 
@@ -702,6 +721,12 @@ static CK_RV proto_write_session_info(CallState * cs, CK_SESSION_INFO_PTR info)
  * CALL MACROS
  */
 
+#define DECLARE_CK_ULONG_PTR(ck_ulong_ptr_name) \
+	CK_ULONG ck_ulong_ptr_name ## _v ; \
+	CK_ULONG_PTR ck_ulong_ptr_name ; \
+	ck_ulong_ptr_name ## _v = 0; \
+	ck_ulong_ptr_name = &ck_ulong_ptr_name ## _v ;
+
 #define BEGIN_CALL(call_id) \
 	debug ((#call_id ": enter")); \
 	assert (cs); \
@@ -717,7 +742,7 @@ static CK_RV proto_write_session_info(CallState * cs, CK_SESSION_INFO_PTR info)
 
 #define END_CALL \
 	_cleanup: \
-		debug (("ret: %d", _ret)); \
+		debug (("ret: 0x%x", _ret)); \
 		return _ret; \
 	}
 
@@ -733,8 +758,8 @@ static CK_RV proto_write_session_info(CallState * cs, CK_SESSION_INFO_PTR info)
 	_ret = proto_read_null_string (cs, &val); \
 	if (_ret != CKR_OK) goto _cleanup;
 
-#define IN_BYTE_BUFFER(buffer, buffer_len) \
-	_ret = proto_read_byte_buffer (cs, &buffer, &buffer_len); \
+#define IN_BYTE_BUFFER(buffer, buffer_len_ptr) \
+	_ret = proto_read_byte_buffer (cs, &buffer, &buffer_len_ptr); \
 	if (_ret != CKR_OK) goto _cleanup;
 
 #define IN_BYTE_ARRAY(buffer, buffer_len) \
@@ -761,9 +786,9 @@ static CK_RV proto_write_session_info(CallState * cs, CK_SESSION_INFO_PTR info)
 	if (_ret == CKR_OK && !gck_rpc_message_write_ulong (cs->resp, val)) \
 		_ret = PREP_ERROR;
 
-#define OUT_BYTE_ARRAY(array, len) \
+#define OUT_BYTE_ARRAY(array, len_ptr) \
 	/* Note how we filter return codes */ \
-	_ret = proto_write_byte_array (cs, array, len, _ret);
+	_ret = proto_write_byte_array (cs, array, len_ptr, _ret);
 
 #define OUT_ULONG_ARRAY(array, len) \
 	/* Note how we filter return codes */ \
@@ -1122,12 +1147,12 @@ static CK_RV rpc_C_GetOperationState(CallState * cs)
 {
 	CK_SESSION_HANDLE session;
 	CK_BYTE_PTR operation_state;
-	CK_ULONG operation_state_len;
+	DECLARE_CK_ULONG_PTR(operation_state_len);
 
 	BEGIN_CALL(C_GetOperationState);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(operation_state, operation_state_len);
-	PROCESS_CALL((session, operation_state, &operation_state_len));
+	PROCESS_CALL((session, operation_state, operation_state_len));
 	OUT_BYTE_ARRAY(operation_state, operation_state_len);
 	END_CALL;
 }
@@ -1327,14 +1352,14 @@ static CK_RV rpc_C_Encrypt(CallState * cs)
 	CK_BYTE_PTR data;
 	CK_ULONG data_len;
 	CK_BYTE_PTR encrypted_data;
-	CK_ULONG encrypted_data_len;
+	DECLARE_CK_ULONG_PTR(encrypted_data_len);
 
 	BEGIN_CALL(C_Encrypt);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(data, data_len);
 	IN_BYTE_BUFFER(encrypted_data, encrypted_data_len);
 	PROCESS_CALL((session, data, data_len, encrypted_data,
-		      &encrypted_data_len));
+		      encrypted_data_len));
 	OUT_BYTE_ARRAY(encrypted_data, encrypted_data_len);
 	END_CALL;
 }
@@ -1345,14 +1370,14 @@ static CK_RV rpc_C_EncryptUpdate(CallState * cs)
 	CK_BYTE_PTR part;
 	CK_ULONG part_len;
 	CK_BYTE_PTR encrypted_part;
-	CK_ULONG encrypted_part_len;
+	DECLARE_CK_ULONG_PTR(encrypted_part_len);
 
 	BEGIN_CALL(C_EncryptUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(part, part_len);
 	IN_BYTE_BUFFER(encrypted_part, encrypted_part_len);
 	PROCESS_CALL((session, part, part_len, encrypted_part,
-		      &encrypted_part_len));
+		      encrypted_part_len));
 	OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len);
 	END_CALL;
 }
@@ -1361,12 +1386,12 @@ static CK_RV rpc_C_EncryptFinal(CallState * cs)
 {
 	CK_SESSION_HANDLE session;
 	CK_BYTE_PTR last_encrypted_part;
-	CK_ULONG last_encrypted_part_len;
+	DECLARE_CK_ULONG_PTR(last_encrypted_part_len);
 
 	BEGIN_CALL(C_EncryptFinal);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(last_encrypted_part, last_encrypted_part_len);
-	PROCESS_CALL((session, last_encrypted_part, &last_encrypted_part_len));
+	PROCESS_CALL((session, last_encrypted_part, last_encrypted_part_len));
 	OUT_BYTE_ARRAY(last_encrypted_part, last_encrypted_part_len);
 	END_CALL;
 }
@@ -1391,14 +1416,14 @@ static CK_RV rpc_C_Decrypt(CallState * cs)
 	CK_BYTE_PTR encrypted_data;
 	CK_ULONG encrypted_data_len;
 	CK_BYTE_PTR data;
-	CK_ULONG data_len;
+	DECLARE_CK_ULONG_PTR(data_len);
 
 	BEGIN_CALL(C_Decrypt);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(encrypted_data, encrypted_data_len);
 	IN_BYTE_BUFFER(data, data_len);
 	PROCESS_CALL((session, encrypted_data, encrypted_data_len, data,
-		      &data_len));
+		      data_len));
 	OUT_BYTE_ARRAY(data, data_len);
 	END_CALL;
 }
@@ -1409,14 +1434,14 @@ static CK_RV rpc_C_DecryptUpdate(CallState * cs)
 	CK_BYTE_PTR encrypted_part;
 	CK_ULONG encrypted_part_len;
 	CK_BYTE_PTR part;
-	CK_ULONG part_len;
+	DECLARE_CK_ULONG_PTR(part_len);
 
 	BEGIN_CALL(C_DecryptUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(encrypted_part, encrypted_part_len);
 	IN_BYTE_BUFFER(part, part_len);
 	PROCESS_CALL((session, encrypted_part, encrypted_part_len, part,
-		      &part_len));
+		      part_len));
 	OUT_BYTE_ARRAY(part, part_len);
 	END_CALL;
 }
@@ -1425,12 +1450,12 @@ static CK_RV rpc_C_DecryptFinal(CallState * cs)
 {
 	CK_SESSION_HANDLE session;
 	CK_BYTE_PTR last_part;
-	CK_ULONG last_part_len;
+	DECLARE_CK_ULONG_PTR(last_part_len);
 
 	BEGIN_CALL(C_DecryptFinal);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(last_part, last_part_len);
-	PROCESS_CALL((session, last_part, &last_part_len));
+	PROCESS_CALL((session, last_part, last_part_len));
 	OUT_BYTE_ARRAY(last_part, last_part_len);
 	END_CALL;
 }
@@ -1453,13 +1478,13 @@ static CK_RV rpc_C_Digest(CallState * cs)
 	CK_BYTE_PTR data;
 	CK_ULONG data_len;
 	CK_BYTE_PTR digest;
-	CK_ULONG digest_len;
+	DECLARE_CK_ULONG_PTR(digest_len);
 
 	BEGIN_CALL(C_Digest);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(data, data_len);
 	IN_BYTE_BUFFER(digest, digest_len);
-	PROCESS_CALL((session, data, data_len, digest, &digest_len));
+	PROCESS_CALL((session, data, data_len, digest, digest_len));
 	OUT_BYTE_ARRAY(digest, digest_len);
 	END_CALL;
 }
@@ -1493,12 +1518,12 @@ static CK_RV rpc_C_DigestFinal(CallState * cs)
 {
 	CK_SESSION_HANDLE session;
 	CK_BYTE_PTR digest;
-	CK_ULONG digest_len;
+	DECLARE_CK_ULONG_PTR(digest_len);
 
 	BEGIN_CALL(C_DigestFinal);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(digest, digest_len);
-	PROCESS_CALL((session, digest, &digest_len));
+	PROCESS_CALL((session, digest, digest_len));
 	OUT_BYTE_ARRAY(digest, digest_len);
 	END_CALL;
 }
@@ -1523,13 +1548,13 @@ static CK_RV rpc_C_Sign(CallState * cs)
 	CK_BYTE_PTR part;
 	CK_ULONG part_len;
 	CK_BYTE_PTR signature;
-	CK_ULONG signature_len;
+	DECLARE_CK_ULONG_PTR(signature_len);
 
 	BEGIN_CALL(C_Sign);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(part, part_len);
 	IN_BYTE_BUFFER(signature, signature_len);
-	PROCESS_CALL((session, part, part_len, signature, &signature_len));
+	PROCESS_CALL((session, part, part_len, signature, signature_len));
 	OUT_BYTE_ARRAY(signature, signature_len);
 	END_CALL;
 
@@ -1552,12 +1577,12 @@ static CK_RV rpc_C_SignFinal(CallState * cs)
 {
 	CK_SESSION_HANDLE session;
 	CK_BYTE_PTR signature;
-	CK_ULONG signature_len;
+	DECLARE_CK_ULONG_PTR(signature_len);
 
 	BEGIN_CALL(C_SignFinal);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(signature, signature_len);
-	PROCESS_CALL((session, signature, &signature_len));
+	PROCESS_CALL((session, signature, signature_len));
 	OUT_BYTE_ARRAY(signature, signature_len);
 	END_CALL;
 }
@@ -1582,13 +1607,13 @@ static CK_RV rpc_C_SignRecover(CallState * cs)
 	CK_BYTE_PTR data;
 	CK_ULONG data_len;
 	CK_BYTE_PTR signature;
-	CK_ULONG signature_len;
+	DECLARE_CK_ULONG_PTR(signature_len);
 
 	BEGIN_CALL(C_SignRecover);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(data, data_len);
 	IN_BYTE_BUFFER(signature, signature_len);
-	PROCESS_CALL((session, data, data_len, signature, &signature_len));
+	PROCESS_CALL((session, data, data_len, signature, signature_len));
 	OUT_BYTE_ARRAY(signature, signature_len);
 	END_CALL;
 }
@@ -1669,13 +1694,13 @@ static CK_RV rpc_C_VerifyRecover(CallState * cs)
 	CK_BYTE_PTR signature;
 	CK_ULONG signature_len;
 	CK_BYTE_PTR data;
-	CK_ULONG data_len;
+	DECLARE_CK_ULONG_PTR(data_len);
 
 	BEGIN_CALL(C_VerifyRecover);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(signature, signature_len);
 	IN_BYTE_BUFFER(data, data_len);
-	PROCESS_CALL((session, signature, signature_len, data, &data_len));
+	PROCESS_CALL((session, signature, signature_len, data, data_len));
 	OUT_BYTE_ARRAY(data, data_len);
 	END_CALL;
 }
@@ -1686,14 +1711,14 @@ static CK_RV rpc_C_DigestEncryptUpdate(CallState * cs)
 	CK_BYTE_PTR part;
 	CK_ULONG part_len;
 	CK_BYTE_PTR encrypted_part;
-	CK_ULONG encrypted_part_len;
+	DECLARE_CK_ULONG_PTR(encrypted_part_len);
 
 	BEGIN_CALL(C_DigestEncryptUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(part, part_len);
 	IN_BYTE_BUFFER(encrypted_part, encrypted_part_len);
 	PROCESS_CALL((session, part, part_len, encrypted_part,
-		      &encrypted_part_len));
+		      encrypted_part_len));
 	OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len);
 	END_CALL;
 }
@@ -1704,14 +1729,14 @@ static CK_RV rpc_C_DecryptDigestUpdate(CallState * cs)
 	CK_BYTE_PTR encrypted_part;
 	CK_ULONG encrypted_part_len;
 	CK_BYTE_PTR part;
-	CK_ULONG part_len;
+	DECLARE_CK_ULONG_PTR(part_len);
 
 	BEGIN_CALL(C_DecryptDigestUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(encrypted_part, encrypted_part_len);
 	IN_BYTE_BUFFER(part, part_len);
 	PROCESS_CALL((session, encrypted_part, encrypted_part_len, part,
-		      &part_len));
+		      part_len));
 	OUT_BYTE_ARRAY(part, part_len);
 	END_CALL;
 }
@@ -1722,14 +1747,14 @@ static CK_RV rpc_C_SignEncryptUpdate(CallState * cs)
 	CK_BYTE_PTR part;
 	CK_ULONG part_len;
 	CK_BYTE_PTR encrypted_part;
-	CK_ULONG encrypted_part_len;
+	DECLARE_CK_ULONG_PTR(encrypted_part_len);
 
 	BEGIN_CALL(C_SignEncryptUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(part, part_len);
 	IN_BYTE_BUFFER(encrypted_part, encrypted_part_len);
 	PROCESS_CALL((session, part, part_len, encrypted_part,
-		      &encrypted_part_len));
+		      encrypted_part_len));
 	OUT_BYTE_ARRAY(encrypted_part, encrypted_part_len);
 	END_CALL;
 }
@@ -1740,14 +1765,14 @@ static CK_RV rpc_C_DecryptVerifyUpdate(CallState * cs)
 	CK_BYTE_PTR encrypted_part;
 	CK_ULONG encrypted_part_len;
 	CK_BYTE_PTR part;
-	CK_ULONG part_len;
+	DECLARE_CK_ULONG_PTR(part_len);
 
 	BEGIN_CALL(C_DecryptVerifyUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(encrypted_part, encrypted_part_len);
 	IN_BYTE_BUFFER(part, part_len);
 	PROCESS_CALL((session, encrypted_part, encrypted_part_len, part,
-		      &part_len));
+		      part_len));
 	OUT_BYTE_ARRAY(part, part_len);
 	END_CALL;
 }
@@ -1805,7 +1830,7 @@ static CK_RV rpc_C_WrapKey(CallState * cs)
 	CK_OBJECT_HANDLE wrapping_key;
 	CK_OBJECT_HANDLE key;
 	CK_BYTE_PTR wrapped_key;
-	CK_ULONG wrapped_key_len;
+	DECLARE_CK_ULONG_PTR(wrapped_key_len);
 
 	BEGIN_CALL(C_WrapKey);
 	IN_ULONG(session);
@@ -1814,7 +1839,7 @@ static CK_RV rpc_C_WrapKey(CallState * cs)
 	IN_ULONG(key);
 	IN_BYTE_BUFFER(wrapped_key, wrapped_key_len);
 	PROCESS_CALL((session, &mechanism, wrapping_key, key, wrapped_key,
-		      &wrapped_key_len));
+		      wrapped_key_len));
 	OUT_BYTE_ARRAY(wrapped_key, wrapped_key_len);
 	END_CALL;
 }
@@ -1879,12 +1904,12 @@ static CK_RV rpc_C_GenerateRandom(CallState * cs)
 {
 	CK_SESSION_HANDLE session;
 	CK_BYTE_PTR random_data;
-	CK_ULONG random_len;
+	DECLARE_CK_ULONG_PTR(random_len);
 
 	BEGIN_CALL(C_GenerateRandom);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(random_data, random_len);
-	PROCESS_CALL((session, random_data, random_len));
+	PROCESS_CALL((session, random_data, *random_len));
 	OUT_BYTE_ARRAY(random_data, random_len);
 	END_CALL;
 }
diff --git a/gck-rpc-message.c b/gck-rpc-message.c
index 079b21f114bea185dd0e6203e6bb7f4679c447fa..440d88dbdbae992ea942072da563685bc806d2fe 100644
--- a/gck-rpc-message.c
+++ b/gck-rpc-message.c
@@ -334,13 +334,25 @@ int gck_rpc_message_write_ulong(GckRpcMessage * msg, CK_ULONG val)
 	return egg_buffer_add_uint64(&msg->buffer, val);
 }
 
-int gck_rpc_message_write_byte_buffer(GckRpcMessage * msg, CK_ULONG count)
+int gck_rpc_message_write_byte_buffer(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG *count_ptr)
 {
+	uint8_t flags;
 	assert(msg);
 
 	/* Make sure this is in the right order */
 	assert(!msg->signature || gck_rpc_message_verify_part(msg, "fy"));
-	return egg_buffer_add_uint32(&msg->buffer, count);
+
+	flags = 0;
+	if (! arr)
+		flags |= GCK_RPC_BYTE_BUFFER_NULL_DATA;
+	if (! count_ptr)
+		flags |= GCK_RPC_BYTE_BUFFER_NULL_COUNT;
+
+	egg_buffer_add_byte(&msg->buffer, flags);
+
+	egg_buffer_add_uint32(&msg->buffer, count_ptr ? *count_ptr : 0x0);
+
+	return !egg_buffer_has_error(&msg->buffer);
 }
 
 int
diff --git a/gck-rpc-module.c b/gck-rpc-module.c
index 50660636e7ba0dd0360a6e232a69cd35b360a0c5..fe315ac5b3d016ae5f990bc3754de2769a2a5225 100644
--- a/gck-rpc-module.c
+++ b/gck-rpc-module.c
@@ -688,7 +688,10 @@ proto_read_attribute_array(GckRpcMessage * msg, CK_ATTRIBUTE_PTR arr,
 	unsigned char validity;
 	CK_RV ret;
 
-	assert(len);
+	/* Removed assertion. len == 0 is valid for some ret's,
+	 * see proto_write_attribute_array().
+	 * assert(len);
+	 */
 	assert(msg);
 
 	/* Make sure this is in the right order */
@@ -823,12 +826,14 @@ proto_read_byte_array(GckRpcMessage * msg, CK_BYTE_PTR arr,
 
 	/* If not valid, then just the length is encoded, this can signify CKR_BUFFER_TOO_SMALL */
 	if (!valid) {
+		uint32_t t_len;
+
 		if (!egg_buffer_get_uint32
 		    (&msg->buffer, msg->parsed, &msg->parsed,
-		     (uint32_t *) & vlen))
+		     & t_len))
 			return PARSE_ERROR;
 
-		*len = vlen;
+		*len = t_len;
 
 		if (arr)
 			return CKR_BUFFER_TOO_SMALL;
@@ -1051,7 +1056,7 @@ proto_read_sesssion_info(GckRpcMessage * msg, CK_SESSION_INFO_PTR info)
 #define END_CALL \
 	_cleanup: \
 		_ret = call_done (_cs, _ret); \
-		debug (("ret: %d", _ret)); \
+		debug (("ret: 0x%x", _ret)); \
 		return _ret; \
 	}
 
@@ -1068,9 +1073,7 @@ proto_read_sesssion_info(GckRpcMessage * msg, CK_SESSION_INFO_PTR info)
 		{ _ret = CKR_HOST_MEMORY; goto _cleanup; }
 
 #define IN_BYTE_BUFFER(arr, len) \
-	if (len == NULL) \
-		{ _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
-	if (!gck_rpc_message_write_byte_buffer (_cs->req, arr ? *len : 0)) \
+	if (!gck_rpc_message_write_byte_buffer (_cs->req, arr, len))	\
 		{ _ret = CKR_HOST_MEMORY; goto _cleanup; }
 
 #define IN_BYTE_ARRAY(arr, len) \
@@ -1304,8 +1307,8 @@ static CK_RV rpc_C_Finalize(CK_VOID_PTR reserved)
 	CK_RV ret;
 
 	debug(("C_Finalize: enter"));
+	return_val_if_fail(! reserved, CKR_ARGUMENTS_BAD);
 	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
-	return_val_if_fail(!reserved, CKR_ARGUMENTS_BAD);
 
 	pthread_mutex_lock(&init_mutex);
 
@@ -1334,6 +1337,7 @@ static CK_RV rpc_C_Finalize(CK_VOID_PTR reserved)
 
 static CK_RV rpc_C_GetInfo(CK_INFO_PTR info)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(info, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetInfo);
@@ -1352,6 +1356,7 @@ static CK_RV
 rpc_C_GetSlotList(CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
 		  CK_ULONG_PTR count)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(count, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetSlotList);
@@ -1364,6 +1369,7 @@ rpc_C_GetSlotList(CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
 
 static CK_RV rpc_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(info, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetSlotInfo);
@@ -1375,6 +1381,7 @@ static CK_RV rpc_C_GetSlotInfo(CK_SLOT_ID id, CK_SLOT_INFO_PTR info)
 
 static CK_RV rpc_C_GetTokenInfo(CK_SLOT_ID id, CK_TOKEN_INFO_PTR info)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(info, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetTokenInfo);
@@ -1388,6 +1395,7 @@ static CK_RV
 rpc_C_GetMechanismList(CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list,
 		       CK_ULONG_PTR count)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(count, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetMechanismList);
@@ -1403,6 +1411,7 @@ static CK_RV
 rpc_C_GetMechanismInfo(CK_SLOT_ID id, CK_MECHANISM_TYPE type,
 		       CK_MECHANISM_INFO_PTR info)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(info, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetMechanismInfo);
@@ -1417,6 +1426,8 @@ static CK_RV
 rpc_C_InitToken(CK_SLOT_ID id, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len,
 		CK_UTF8CHAR_PTR label)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_InitToken);
 	IN_ULONG(id);
 	IN_BYTE_ARRAY(pin, pin_len);
@@ -1442,7 +1453,10 @@ static CK_RV
 rpc_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
 		  CK_NOTIFY callback, CK_SESSION_HANDLE_PTR session)
 {
-	return_val_if_fail(session, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+	/* It is unnecessarily intrusive to check session here. Leave it to the p11 module.
+	 * return_val_if_fail(session, CKR_ARGUMENTS_BAD);
+	 */
 
 	BEGIN_CALL(C_OpenSession);
 	IN_ULONG(id);
@@ -1454,6 +1468,8 @@ rpc_C_OpenSession(CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
 
 static CK_RV rpc_C_CloseSession(CK_SESSION_HANDLE session)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_CloseSession);
 	IN_ULONG(session);
 	PROCESS_CALL;
@@ -1462,6 +1478,8 @@ static CK_RV rpc_C_CloseSession(CK_SESSION_HANDLE session)
 
 static CK_RV rpc_C_CloseAllSessions(CK_SLOT_ID id)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_CloseAllSessions);
 	IN_ULONG(id);
 	PROCESS_CALL;
@@ -1470,6 +1488,8 @@ static CK_RV rpc_C_CloseAllSessions(CK_SLOT_ID id)
 
 static CK_RV rpc_C_GetFunctionStatus(CK_SESSION_HANDLE session)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_GetFunctionStatus);
 	IN_ULONG(session);
 	PROCESS_CALL;
@@ -1478,6 +1498,8 @@ static CK_RV rpc_C_GetFunctionStatus(CK_SESSION_HANDLE session)
 
 static CK_RV rpc_C_CancelFunction(CK_SESSION_HANDLE session)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_CancelFunction);
 	IN_ULONG(session);
 	PROCESS_CALL;
@@ -1487,6 +1509,7 @@ static CK_RV rpc_C_CancelFunction(CK_SESSION_HANDLE session)
 static CK_RV
 rpc_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(info, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetSessionInfo);
@@ -1499,6 +1522,8 @@ rpc_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info)
 static CK_RV
 rpc_C_InitPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_InitPIN);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(pin, pin_len);
@@ -1511,6 +1536,8 @@ rpc_C_SetPIN(CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR old_pin,
 	     CK_ULONG old_pin_len, CK_UTF8CHAR_PTR new_pin,
 	     CK_ULONG new_pin_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_SetPIN);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(old_pin, old_pin_len);
@@ -1523,7 +1550,7 @@ static CK_RV
 rpc_C_GetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state,
 			CK_ULONG_PTR operation_state_len)
 {
-	return_val_if_fail(operation_state_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_GetOperationState);
 	IN_ULONG(session);
@@ -1539,6 +1566,8 @@ rpc_C_SetOperationState(CK_SESSION_HANDLE session, CK_BYTE_PTR operation_state,
 			CK_OBJECT_HANDLE encryption_key,
 			CK_OBJECT_HANDLE authentication_key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_SetOperationState);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(operation_state, operation_state_len);
@@ -1552,6 +1581,8 @@ static CK_RV
 rpc_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type,
 	    CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_Login);
 	IN_ULONG(session);
 	IN_ULONG(user_type);
@@ -1562,6 +1593,8 @@ rpc_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type,
 
 static CK_RV rpc_C_Logout(CK_SESSION_HANDLE session)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_Logout);
 	IN_ULONG(session);
 	PROCESS_CALL;
@@ -1572,6 +1605,9 @@ static CK_RV
 rpc_C_CreateObject(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR template,
 		   CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+	return_val_if_fail(session != CK_INVALID_HANDLE, CKR_SESSION_HANDLE_INVALID);
+	return_val_if_fail(template, CKR_ARGUMENTS_BAD);
 	return_val_if_fail(new_object, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_CreateObject);
@@ -1587,6 +1623,7 @@ rpc_C_CopyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
 		 CK_ATTRIBUTE_PTR template, CK_ULONG count,
 		 CK_OBJECT_HANDLE_PTR new_object)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(new_object, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_CopyObject);
@@ -1601,6 +1638,8 @@ rpc_C_CopyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
 static CK_RV
 rpc_C_DestroyObject(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_DestroyObject);
 	IN_ULONG(session);
 	IN_ULONG(object);
@@ -1612,6 +1651,7 @@ static CK_RV
 rpc_C_GetObjectSize(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
 		    CK_ULONG_PTR size)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(size, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_GetObjectSize);
@@ -1626,6 +1666,9 @@ static CK_RV
 rpc_C_GetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
 			CK_ATTRIBUTE_PTR template, CK_ULONG count)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+	return_val_if_fail(template, CKR_ARGUMENTS_BAD);
+
 	BEGIN_CALL(C_GetAttributeValue);
 	IN_ULONG(session);
 	IN_ULONG(object);
@@ -1639,6 +1682,7 @@ static CK_RV
 rpc_C_SetAttributeValue(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
 			CK_ATTRIBUTE_PTR template, CK_ULONG count)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	BEGIN_CALL(C_SetAttributeValue);
 	IN_ULONG(session);
 	IN_ULONG(object);
@@ -1651,6 +1695,8 @@ static CK_RV
 rpc_C_FindObjectsInit(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR template,
 		      CK_ULONG count)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_FindObjectsInit);
 	IN_ULONG(session);
 	IN_ATTRIBUTE_ARRAY(template, count);
@@ -1662,6 +1708,7 @@ static CK_RV
 rpc_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,
 		  CK_ULONG max_count, CK_ULONG_PTR count)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(count, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_FindObjects);
@@ -1675,6 +1722,7 @@ rpc_C_FindObjects(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,
 
 static CK_RV rpc_C_FindObjectsFinal(CK_SESSION_HANDLE session)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	BEGIN_CALL(C_FindObjectsFinal);
 	IN_ULONG(session);
 	PROCESS_CALL;
@@ -1685,6 +1733,8 @@ static CK_RV
 rpc_C_EncryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		  CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_EncryptInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1697,7 +1747,16 @@ static CK_RV
 rpc_C_Encrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
 	      CK_BYTE_PTR encrypted_data, CK_ULONG_PTR encrypted_data_len)
 {
-	return_val_if_fail(encrypted_data_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+	/* From PKCS#11 v2.01 :
+	 *  A call to C_Encrypt always terminates the active encryption 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 ciphertext.
+	 *
+	 * Thus, we can't reject for example NULL encrypted_data_len, since then
+	 * the encryption operation won't be terminated in the real PKCS#11 module.
+	 */
 
 	BEGIN_CALL(C_Encrypt);
 	IN_ULONG(session);
@@ -1713,7 +1772,7 @@ rpc_C_EncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
 		    CK_ULONG part_len, CK_BYTE_PTR encrypted_part,
 		    CK_ULONG_PTR encrypted_part_len)
 {
-	return_val_if_fail(encrypted_part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_EncryptUpdate);
 	IN_ULONG(session);
@@ -1728,7 +1787,7 @@ static CK_RV
 rpc_C_EncryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_part,
 		   CK_ULONG_PTR last_part_len)
 {
-	return_val_if_fail(last_part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_EncryptFinal);
 	IN_ULONG(session);
@@ -1742,6 +1801,8 @@ static CK_RV
 rpc_C_DecryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		  CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_DecryptInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1754,7 +1815,7 @@ static CK_RV
 rpc_C_Decrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_data,
 	      CK_ULONG enc_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len)
 {
-	return_val_if_fail(data_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_Decrypt);
 	IN_ULONG(session);
@@ -1770,7 +1831,7 @@ rpc_C_DecryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_part,
 		    CK_ULONG enc_part_len, CK_BYTE_PTR part,
 		    CK_ULONG_PTR part_len)
 {
-	return_val_if_fail(part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_DecryptUpdate);
 	IN_ULONG(session);
@@ -1785,7 +1846,7 @@ static CK_RV
 rpc_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_part,
 		   CK_ULONG_PTR last_part_len)
 {
-	return_val_if_fail(last_part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_DecryptFinal);
 	IN_ULONG(session);
@@ -1798,6 +1859,7 @@ rpc_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_part,
 static CK_RV
 rpc_C_DigestInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	BEGIN_CALL(C_DigestInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1809,7 +1871,7 @@ static CK_RV
 rpc_C_Digest(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
 	     CK_BYTE_PTR digest, CK_ULONG_PTR digest_len)
 {
-	return_val_if_fail(digest_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_Digest);
 	IN_ULONG(session);
@@ -1824,6 +1886,8 @@ static CK_RV
 rpc_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
 		   CK_ULONG part_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_DigestUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(part, part_len);
@@ -1833,6 +1897,8 @@ rpc_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
 
 static CK_RV rpc_C_DigestKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_DigestKey);
 	IN_ULONG(session);
 	IN_ULONG(key);
@@ -1844,7 +1910,7 @@ static CK_RV
 rpc_C_DigestFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR digest,
 		  CK_ULONG_PTR digest_len)
 {
-	return_val_if_fail(digest_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_DigestFinal);
 	IN_ULONG(session);
@@ -1858,6 +1924,7 @@ static CK_RV
 rpc_C_SignInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 	       CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	BEGIN_CALL(C_SignInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1870,7 +1937,7 @@ static CK_RV
 rpc_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
 	   CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
 {
-	return_val_if_fail(signature_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_Sign);
 	IN_ULONG(session);
@@ -1884,6 +1951,7 @@ rpc_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
 static CK_RV
 rpc_C_SignUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 	return_val_if_fail(part_len, CKR_ARGUMENTS_BAD);
 
 	BEGIN_CALL(C_SignUpdate);
@@ -1897,7 +1965,7 @@ static CK_RV
 rpc_C_SignFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
 		CK_ULONG_PTR signature_len)
 {
-	return_val_if_fail(signature_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_SignFinal);
 	IN_ULONG(session);
@@ -1911,6 +1979,8 @@ static CK_RV
 rpc_C_SignRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		      CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_SignRecoverInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1924,7 +1994,7 @@ rpc_C_SignRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR data,
 		  CK_ULONG data_len, CK_BYTE_PTR signature,
 		  CK_ULONG_PTR signature_len)
 {
-	return_val_if_fail(signature_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_SignRecover);
 	IN_ULONG(session);
@@ -1939,6 +2009,8 @@ static CK_RV
 rpc_C_VerifyInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		 CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_VerifyInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1951,6 +2023,8 @@ static CK_RV
 rpc_C_Verify(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
 	     CK_BYTE_PTR signature, CK_ULONG signature_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_Verify);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(data, data_len);
@@ -1963,6 +2037,8 @@ static CK_RV
 rpc_C_VerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
 		   CK_ULONG part_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_VerifyUpdate);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(part, part_len);
@@ -1974,6 +2050,8 @@ static CK_RV
 rpc_C_VerifyFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
 		  CK_ULONG signature_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_VerifyFinal);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(signature, signature_len);
@@ -1985,6 +2063,8 @@ static CK_RV
 rpc_C_VerifyRecoverInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 			CK_OBJECT_HANDLE key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_VerifyRecoverInit);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -1998,7 +2078,7 @@ rpc_C_VerifyRecover(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
 		    CK_ULONG signature_len, CK_BYTE_PTR data,
 		    CK_ULONG_PTR data_len)
 {
-	return_val_if_fail(data_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_VerifyRecover);
 	IN_ULONG(session);
@@ -2014,7 +2094,7 @@ rpc_C_DigestEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
 			  CK_ULONG part_len, CK_BYTE_PTR enc_part,
 			  CK_ULONG_PTR enc_part_len)
 {
-	return_val_if_fail(enc_part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_DigestEncryptUpdate);
 	IN_ULONG(session);
@@ -2030,7 +2110,7 @@ rpc_C_DecryptDigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_part,
 			  CK_ULONG enc_part_len, CK_BYTE_PTR part,
 			  CK_ULONG_PTR part_len)
 {
-	return_val_if_fail(part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_DecryptDigestUpdate);
 	IN_ULONG(session);
@@ -2046,7 +2126,7 @@ rpc_C_SignEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
 			CK_ULONG part_len, CK_BYTE_PTR enc_part,
 			CK_ULONG_PTR enc_part_len)
 {
-	return_val_if_fail(enc_part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_SignEncryptUpdate);
 	IN_ULONG(session);
@@ -2062,7 +2142,7 @@ rpc_C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR enc_part,
 			  CK_ULONG enc_part_len, CK_BYTE_PTR part,
 			  CK_ULONG_PTR part_len)
 {
-	return_val_if_fail(part_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_DecryptVerifyUpdate);
 	IN_ULONG(session);
@@ -2078,6 +2158,8 @@ rpc_C_GenerateKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		  CK_ATTRIBUTE_PTR template, CK_ULONG count,
 		  CK_OBJECT_HANDLE_PTR key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_GenerateKey);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -2094,6 +2176,14 @@ rpc_C_GenerateKeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		      CK_OBJECT_HANDLE_PTR pub_key,
 		      CK_OBJECT_HANDLE_PTR priv_key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+	return_val_if_fail(session != CK_INVALID_HANDLE, CKR_SESSION_HANDLE_INVALID);
+	return_val_if_fail(mechanism, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pub_template, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(priv_template, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pub_key, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(priv_key, CKR_ARGUMENTS_BAD);
+
 	BEGIN_CALL(C_GenerateKeyPair);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -2110,7 +2200,7 @@ rpc_C_WrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 	      CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
 	      CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len)
 {
-	return_val_if_fail(wrapped_key_len, CKR_ARGUMENTS_BAD);
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
 
 	BEGIN_CALL(C_WrapKey);
 	IN_ULONG(session);
@@ -2129,6 +2219,8 @@ rpc_C_UnwrapKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR template,
 		CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_UnwrapKey);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -2145,6 +2237,8 @@ rpc_C_DeriveKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 		CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR template,
 		CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_DeriveKey);
 	IN_ULONG(session);
 	IN_MECHANISM(mechanism);
@@ -2158,6 +2252,8 @@ rpc_C_DeriveKey(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
 static CK_RV
 rpc_C_SeedRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seed_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+
 	BEGIN_CALL(C_SeedRandom);
 	IN_ULONG(session);
 	IN_BYTE_ARRAY(seed, seed_len);
@@ -2169,6 +2265,9 @@ static CK_RV
 rpc_C_GenerateRandom(CK_SESSION_HANDLE session, CK_BYTE_PTR random_data,
 		     CK_ULONG random_len)
 {
+	return_val_if_fail(pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+	return_val_if_fail(random_data, CKR_ARGUMENTS_BAD);
+
 	BEGIN_CALL(C_GenerateRandom);
 	IN_ULONG(session);
 	IN_BYTE_BUFFER(random_data, &random_len);
diff --git a/gck-rpc-private.h b/gck-rpc-private.h
index 22f897a3260e0833acfcd841f2426051cc151b59..02c1e9d2a591c22793ac8cabe8c02ccc8967aa05 100644
--- a/gck-rpc-private.h
+++ b/gck-rpc-private.h
@@ -216,7 +216,7 @@ static const GckRpcCall gck_rpc_calls[] = {
 #endif
 
 #define GCK_RPC_HANDSHAKE \
-	"PRIVATE-GNOME-KEYRING-PKCS11-PROTOCOL-V-1"
+	"PRIVATE-GNOME-KEYRING-PKCS11-PROTOCOL-V-2"
 #define GCK_RPC_HANDSHAKE_LEN \
 	(sizeof (GCK_RPC_HANDSHAKE) - 1)
 
@@ -237,6 +237,9 @@ typedef struct _GckRpcMessage {
 	const char *sigverify;
 } GckRpcMessage;
 
+#define GCK_RPC_BYTE_BUFFER_NULL_DATA	1
+#define GCK_RPC_BYTE_BUFFER_NULL_COUNT	2
+
 GckRpcMessage *gck_rpc_message_new(EggBufferAllocator allocator);
 
 void gck_rpc_message_free(GckRpcMessage * msg);
@@ -266,7 +269,7 @@ int gck_rpc_message_write_zero_string(GckRpcMessage * msg,
 int gck_rpc_message_write_space_string(GckRpcMessage * msg,
 				       CK_UTF8CHAR * buffer, CK_ULONG length);
 
-int gck_rpc_message_write_byte_buffer(GckRpcMessage * msg, CK_ULONG count);
+int gck_rpc_message_write_byte_buffer(GckRpcMessage * msg, CK_BYTE_PTR arr, CK_ULONG *count_ptr);
 
 int gck_rpc_message_write_byte_array(GckRpcMessage * msg,
 				     CK_BYTE_PTR arr, CK_ULONG num);