Exemplo n.º 1
0
static gboolean
generate_hashed_items (GkmSecretCollection *collection, EggBuffer *buffer)
{
	GHashTable *attributes;
	const gchar *value;
	GList *items, *l;
	guint32 id, type;

	items = gkm_secret_collection_get_items (collection);
	egg_buffer_add_uint32 (buffer, g_list_length (items));

	for (l = items; l; l = g_list_next (l)) {

		value = gkm_secret_object_get_identifier (l->data);
		if (!convert_to_integer (value, &id)) {
			g_warning ("trying to save a non-numeric item identifier '%s' into "
			           "the keyring file format which only supports numeric.", value);
			continue;
		}
		egg_buffer_add_uint32 (buffer, id);

		value = gkm_secret_item_get_schema (l->data);
		type = gkm_secret_compat_parse_item_type (value);
		egg_buffer_add_uint32 (buffer, type);

		attributes = gkm_secret_item_get_fields (l->data);
		buffer_add_attributes (buffer, attributes, TRUE);
	}

	g_list_free (items);
	return !egg_buffer_has_error (buffer);
}
int
gkm_rpc_message_write_attribute_buffer (GkmRpcMessage *msg, CK_ATTRIBUTE_PTR arr,
                                        CK_ULONG num)
{
	CK_ATTRIBUTE_PTR attr;
	CK_ULONG i;

	assert (!num || arr);
	assert (msg);

	/* Make sure this is in the rigth order */
	assert (!msg->signature || gkm_rpc_message_verify_part (msg, "fA"));

	/* Write the number of items */
	egg_buffer_add_uint32 (&msg->buffer, num);

	for (i = 0; i < num; ++i) {
		attr = &(arr[i]);

		/* The attribute type */
		egg_buffer_add_uint32 (&msg->buffer, attr->type);

		/* And the attribute buffer length */
		egg_buffer_add_uint32 (&msg->buffer, attr->pValue ? attr->ulValueLen : 0);
	}

	return !egg_buffer_has_error (&msg->buffer);
}
Exemplo n.º 3
0
static void
buffer_add_attribute (EggBuffer *buffer, GHashTable *attributes, const gchar *key)
{
	guint32 number;

	buffer_add_utf8_string (buffer, key);

	/*
	 * COMPATIBILITY:
	 *
	 * Our new Secrets API doesn't support integer attributes. However, to have
	 * compatibility with old keyring code reading this file, we need to set
	 * the uint32 type attribute appropriately where expected.
	 *
	 * If there's an extra compat-uint32 attribute and the name of this attribute
	 * is contained in that list, then write as a uint32.
	 */

	/* Determine if it's a uint32 compatible value, and store as such if it is */
	if (gkm_secret_fields_get_compat_uint32 (attributes, key, &number)) {
		egg_buffer_add_uint32 (buffer, 1);
		egg_buffer_add_uint32 (buffer, number);

	/* A normal string attribute */
	} else {
		egg_buffer_add_uint32 (buffer, 0);
		buffer_add_utf8_string (buffer, gkm_secret_fields_get (attributes, key));
	}
}
gboolean
gkd_ssh_agent_proto_write_public_v1 (EggBuffer *resp, GckAttributes *attrs)
{
	const GckAttribute *attr;
	gulong bits;

	g_assert (resp);
	g_assert (attrs);

	/* This is always an RSA key. */

	/* Write out the number of bits of the key */
	if (!gck_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits))
		g_return_val_if_reached (FALSE);
	egg_buffer_add_uint32 (resp, bits);

	/* Write out the exponent */
	attr = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
	g_return_val_if_fail (attr, FALSE);

	if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr))
		return FALSE;

	/* Write out the modulus */
	attr = gck_attributes_find (attrs, CKA_MODULUS);
	g_return_val_if_fail (attr, FALSE);

	if (!gkd_ssh_agent_proto_write_mpi_v1 (resp, attr))
		return FALSE;

	return TRUE;
}
static gpointer
run_client_thread (gpointer data)
{
	gint *socket = data;
	GkdSshAgentCall call;
	EggBuffer req;
	EggBuffer resp;
	guchar op;

	g_assert (GP11_IS_MODULE (pkcs11_module));

	memset (&call, 0, sizeof (call));
	call.sock = g_atomic_int_get (socket);
	g_assert (call.sock != -1);

	egg_buffer_init_full (&req, 128, egg_secure_realloc);
	egg_buffer_init_full (&resp, 128, (EggBufferAllocator)g_realloc);
	call.req = &req;
	call.resp = &resp;
	call.module = g_object_ref (pkcs11_module);

	for (;;) {

		egg_buffer_reset (call.req);

		/* 1. Read in the request */
		if (!read_packet_with_size (&call))
			break;

		/* 2. Now decode the operation */
		if (!egg_buffer_get_byte (call.req, 4, NULL, &op))
			break;
		if (op >= GKD_SSH_OP_MAX)
			break;
		g_assert (gkd_ssh_agent_operations[op]);

		/* 3. Execute the right operation */
		egg_buffer_reset (call.resp);
		egg_buffer_add_uint32 (call.resp, 0);
		if (!(gkd_ssh_agent_operations[op]) (&call))
			break;
		if (!egg_buffer_set_uint32 (call.resp, 0, call.resp->len - 4))
			break;

		/* 4. Write the reply back out */
		if (!write_all (call.sock, call.resp->buf, call.resp->len))
			break;
	}

	egg_buffer_uninit (&req);
	egg_buffer_uninit (&resp);
	g_object_unref (call.module);

	close (call.sock);
	g_atomic_int_set (socket, -1);

	return NULL;
}
int
gkm_rpc_message_write_ulong_buffer (GkmRpcMessage *msg, CK_ULONG count)
{
	assert (msg);

	/* Make sure this is in the right order */
	assert (!msg->signature || gkm_rpc_message_verify_part (msg, "fu"));
	return egg_buffer_add_uint32 (&msg->buffer, count);
}
Exemplo n.º 7
0
static gboolean
generate_encrypted_data (EggBuffer *buffer, GkmSecretCollection *collection,
                         GkmSecretData *data)
{
	GkmSecretObject *obj;
	GkmSecretItem *item;
	GList *items, *l;
	GHashTable *attributes;
	const gchar *label;
	GkmSecret *secret;
	GList *acl;
	int i;

	g_assert (buffer);
	g_assert (GKM_IS_SECRET_COLLECTION (collection));
	g_assert (GKM_IS_SECRET_DATA (data));

	/* Make sure we're using non-pageable memory */
	egg_buffer_set_allocator (buffer, egg_secure_realloc);

	items = gkm_secret_collection_get_items (collection);
	for (l = items; l && !egg_buffer_has_error(buffer); l = g_list_next (l)) {
		item = GKM_SECRET_ITEM (l->data);
		obj = GKM_SECRET_OBJECT (l->data);

		label = gkm_secret_object_get_label (obj);
		buffer_add_utf8_string (buffer, label);

		secret = gkm_secret_data_get_secret (data, gkm_secret_object_get_identifier (obj));
		buffer_add_secret (buffer, secret);

		if (!buffer_add_time (buffer, gkm_secret_object_get_created (obj)) ||
		    !buffer_add_time (buffer, gkm_secret_object_get_modified (obj)))
			break;

		/* reserved: */
		if (!buffer_add_utf8_string (buffer, NULL))
			break;
		for (i = 0; i < 4; i++)
			egg_buffer_add_uint32 (buffer, 0);

		attributes = gkm_secret_item_get_fields (item);
		if (!buffer_add_attributes (buffer, attributes, FALSE))
			break;

		acl = g_object_get_data (G_OBJECT (item), "compat-acl");
		if (!generate_acl_data (buffer, acl))
			break;
	}

	g_list_free (items);

	/* Iteration completed prematurely == fail */
	return (l == NULL);
}
Exemplo n.º 8
0
static gboolean
buffer_add_attributes (EggBuffer *buffer, GHashTable *attributes, gboolean hashed)
{
	GList *names, *l;

	g_assert (buffer);

	if (attributes == NULL) {
		egg_buffer_add_uint32 (buffer, 0);
	} else {
		names = gkm_secret_fields_get_names (attributes);
		egg_buffer_add_uint32 (buffer, g_list_length (names));
		for (l = names; l; l = g_list_next (l)) {
			if (hashed)
				buffer_add_hashed_attribute (buffer, attributes, l->data);
			else
				buffer_add_attribute (buffer, attributes, l->data);
		}
		g_list_free (names);
	}

	return !egg_buffer_has_error (buffer);
}
int
gkm_rpc_message_write_attribute_array (GkmRpcMessage *msg,
                                       CK_ATTRIBUTE_PTR arr, CK_ULONG num)
{
	CK_ULONG i;
	CK_ATTRIBUTE_PTR attr;
	unsigned char validity;

	assert (!num || arr);
	assert (msg);

	/* Make sure this is in the rigth order */
	assert (!msg->signature || gkm_rpc_message_verify_part (msg, "aA"));

	/* Write the number of items */
	egg_buffer_add_uint32 (&msg->buffer, num);

	for (i = 0; i < num; ++i) {
		attr = &(arr[i]);

		/* The attribute type */
		egg_buffer_add_uint32 (&msg->buffer, attr->type);

		/* Write out the attribute validity */
		validity = (((CK_LONG)attr->ulValueLen) == -1) ? 0 : 1;
		egg_buffer_add_byte (&msg->buffer, validity);

		/* The attribute length and value */
		if (validity) {
			egg_buffer_add_uint32 (&msg->buffer, attr->ulValueLen);
			egg_buffer_add_byte_array (&msg->buffer, attr->pValue, attr->ulValueLen);
		}
	}

	return !egg_buffer_has_error (&msg->buffer);
}
Exemplo n.º 10
0
static gboolean
generate_acl_data (EggBuffer *buffer, GList *acl)
{
	GList *l;
	GkmSecretAccess *ac;

	egg_buffer_add_uint32 (buffer, g_list_length (acl));

	for (l = acl; l != NULL; l = l->next) {
		ac = l->data;

		egg_buffer_add_uint32 (buffer, ac->types_allowed);
		if (!buffer_add_utf8_string (buffer, ac->display_name) ||
		    !buffer_add_utf8_string (buffer, ac->pathname))
			return FALSE;

		/* Reserved: */
		if (!buffer_add_utf8_string (buffer, NULL))
			return FALSE;
		egg_buffer_add_uint32 (buffer, 0);
	}

	return TRUE;
}
Exemplo n.º 11
0
static void
buffer_add_hashed_attribute (EggBuffer *buffer, GHashTable *attributes, const gchar *key)
{
	guint32 number;
	gchar *value;

	buffer_add_utf8_string (buffer, key);

	/* See comments in buffer_add_attribute. */

	/* Determine if it's a uint32 compatible value, and store as such if it is */
	if (gkm_secret_fields_get_compat_hashed_uint32 (attributes, key, &number)) {
		egg_buffer_add_uint32 (buffer, 1);
		egg_buffer_add_uint32 (buffer, number);

	/* A standard string attribute */
	} else {
		if (!gkm_secret_fields_get_compat_hashed_string (attributes, key, &value))
			g_return_if_reached ();
		egg_buffer_add_uint32 (buffer, 0);
		buffer_add_utf8_string (buffer, value);
		g_free (value);
	}
}
int
gkm_rpc_message_write_byte_array (GkmRpcMessage *msg, CK_BYTE_PTR arr, CK_ULONG num)
{
	assert (msg);

	/* Make sure this is in the right order */
	assert (!msg->signature || gkm_rpc_message_verify_part (msg, "ay"));

	/* No array, no data, just length */
	if (!arr) {
		egg_buffer_add_byte (&msg->buffer, 0);
		egg_buffer_add_uint32 (&msg->buffer, num);
	} else {
		egg_buffer_add_byte (&msg->buffer, 1);
		egg_buffer_add_byte_array (&msg->buffer, arr, num);
	}

	return !egg_buffer_has_error (&msg->buffer);
}
int
gkm_rpc_message_write_ulong_array (GkmRpcMessage *msg, CK_ULONG_PTR array, CK_ULONG n_array)
{
	CK_ULONG i;

	assert (msg);

	/* Check that we're supposed to have this at this point */
	assert (!msg->signature || gkm_rpc_message_verify_part (msg, "au"));

	/* We send a byte which determines whether there's actual data present or not */
	egg_buffer_add_byte (&msg->buffer, array ? 1 : 0);
	egg_buffer_add_uint32 (&msg->buffer, n_array);

	/* Now send the data if valid */
	if (array) {
		for (i = 0; i < n_array; ++i)
			egg_buffer_add_uint64 (&msg->buffer, array[i]);
	}

	return !egg_buffer_has_error (&msg->buffer);
}
int
gkm_rpc_message_prep (GkmRpcMessage *msg, int call_id, GkmRpcMessageType type)
{
	int len;

	assert (type);
	assert (call_id >= GKM_RPC_CALL_ERROR);
	assert (call_id < GKM_RPC_CALL_MAX);

	gkm_rpc_message_reset (msg);

	if (call_id != GKM_RPC_CALL_ERROR) {

		/* The call id and signature */
		if (type == GKM_RPC_REQUEST)
			msg->signature = gkm_rpc_calls[call_id].request;
		else if (type == GKM_RPC_RESPONSE)
			msg->signature = gkm_rpc_calls[call_id].response;
		else
			assert (0 && "invalid message type");
		assert (msg->signature);
		msg->sigverify = msg->signature;
	}

	msg->call_id = call_id;
	msg->call_type = type;

	/* Encode the two of them */
	egg_buffer_add_uint32 (&msg->buffer, call_id);
	if (msg->signature) {
		len = strlen (msg->signature);
		egg_buffer_add_byte_array (&msg->buffer, (unsigned char*)msg->signature, len);
	}

	msg->parsed = 0;
	return !egg_buffer_has_error (&msg->buffer);
}
Exemplo n.º 15
0
GkmDataResult
gkm_secret_binary_write (GkmSecretCollection *collection, GkmSecretData *sdata,
                         gpointer *data, gsize *n_data)
{
	GkmSecretObject *obj;
	EggBuffer to_encrypt;
	GkmSecret *master;
        guchar digest[16];
        EggBuffer buffer;
        gint hash_iterations;
        gint lock_timeout;
        guchar salt[8];
	guint flags = 0;
	int i;

	g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (collection), GKM_DATA_FAILURE);
	g_return_val_if_fail (GKM_IS_SECRET_DATA (sdata), GKM_DATA_LOCKED);
	g_return_val_if_fail (data && n_data, GKM_DATA_FAILURE);
	g_return_val_if_fail (gcry_md_get_algo_dlen (GCRY_MD_MD5) == sizeof (digest), GKM_DATA_FAILURE);

	obj = GKM_SECRET_OBJECT (collection);

	egg_buffer_init_full (&buffer, 256, g_realloc);

	/* Prepare the keyring for encryption */
	hash_iterations = g_random_int_range (1000, 4096);
	gcry_create_nonce (salt, sizeof (salt));

	egg_buffer_append (&buffer, (guchar*)KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN);
	egg_buffer_add_byte (&buffer, 0); /* Major version */
	egg_buffer_add_byte (&buffer, 0); /* Minor version */
	egg_buffer_add_byte (&buffer, 0); /* crypto (0 == AES) */
	egg_buffer_add_byte (&buffer, 0); /* hash (0 == MD5) */

	buffer_add_utf8_string (&buffer, gkm_secret_object_get_label (obj));
	buffer_add_time (&buffer, gkm_secret_object_get_modified (obj));
	buffer_add_time (&buffer, gkm_secret_object_get_created (obj));

	lock_timeout = gkm_secret_collection_get_lock_idle (collection);
	if (lock_timeout) {
		flags |= LOCK_ON_IDLE_FLAG;
	} else {
		lock_timeout = gkm_secret_collection_get_lock_after (collection);
		if (lock_timeout)
			flags |= LOCK_AFTER_FLAG;
	}

	egg_buffer_add_uint32 (&buffer, flags);

	egg_buffer_add_uint32 (&buffer, lock_timeout);
	egg_buffer_add_uint32 (&buffer, hash_iterations);
	egg_buffer_append (&buffer, salt, 8);

	/* Reserved: */
	for (i = 0; i < 4; i++)
		egg_buffer_add_uint32 (&buffer, 0);

	/* Hashed items: */
	generate_hashed_items (collection, &buffer);

	/* Encrypted data. Use non-pageable memory */
	egg_buffer_init_full (&to_encrypt, 4096, egg_secure_realloc);

	egg_buffer_append (&to_encrypt, (guchar*)digest, 16); /* Space for hash */

	if (!generate_encrypted_data (&to_encrypt, collection, sdata)) {
		egg_buffer_uninit (&to_encrypt);
		egg_buffer_uninit (&buffer);
		return GKM_DATA_FAILURE;
	}

	/* Pad with zeros to multiple of 16 bytes */
	while (to_encrypt.len % 16 != 0)
		egg_buffer_add_byte (&to_encrypt, 0);

	gcry_md_hash_buffer (GCRY_MD_MD5, (void*)digest,
			     (guchar*)to_encrypt.buf + 16, to_encrypt.len - 16);
	memcpy (to_encrypt.buf, digest, 16);

	/* If no master password is set, we shouldn't be writing binary... */
	master = gkm_secret_data_get_master (sdata);
	g_return_val_if_fail (master, GKM_DATA_FAILURE);

	if (!encrypt_buffer (&to_encrypt, master, salt, hash_iterations)) {
		egg_buffer_uninit (&buffer);
		egg_buffer_uninit (&to_encrypt);
		return GKM_DATA_FAILURE;
	}

	if (egg_buffer_has_error (&to_encrypt) || egg_buffer_has_error (&buffer)) {
		egg_buffer_uninit (&buffer);
		egg_buffer_uninit (&to_encrypt);
		return GKM_DATA_FAILURE;
	}

	egg_buffer_add_uint32 (&buffer, to_encrypt.len);
	egg_buffer_append (&buffer, to_encrypt.buf, to_encrypt.len);
	egg_buffer_uninit (&to_encrypt);
	*data = egg_buffer_uninit_steal (&buffer, n_data);

	return GKM_DATA_SUCCESS;
}