gboolean
gkd_ssh_agent_proto_read_mpi_v1 (EggBuffer *req,
                                 gsize *offset,
                                 GckBuilder *attrs,
                                 CK_ATTRIBUTE_TYPE type)
{
	const guchar *data;
	gsize bytes;
	guint16 bits;

	/* Get the number of bits */
	if (!egg_buffer_get_uint16 (req, *offset, offset, &bits))
		return FALSE;

	/* Figure out the number of binary bytes following */
	bytes = (bits + 7) / 8;
	if (bytes > 8 * 1024)
		return FALSE;

	/* Pull these out directly */
	if (req->len < *offset + bytes)
		return FALSE;
	data = req->buf + *offset;
	*offset += bytes;

	gck_builder_add_data (attrs, type, data, bytes);
	return TRUE;
}
static gboolean
iter_get_fields (GVariant *variant,
		 gulong attr_type,
		 GckBuilder *builder)
{
	GString *result;
	const gchar *key, *value;
	GVariantIter iter;

	g_assert (variant != NULL);
	g_assert (builder != NULL);

	g_return_val_if_fail (g_variant_type_is_array (g_variant_get_type (variant)), FALSE);

	result = g_string_new ("");
	g_variant_iter_init (&iter, variant);

	while (g_variant_iter_next (&iter, "{&s&s}", &key, &value)) {
		/* Key */
		g_string_append (result, key);
		g_string_append_c (result, '\0');

		/* Value */
		g_string_append (result, value);
		g_string_append_c (result, '\0');
	}

	gck_builder_add_data (builder, attr_type, (const guchar *)result->str, result->len);
	g_string_free (result, TRUE);
	return TRUE;
}
static gboolean
iter_get_time (GVariant *variant,
	       gulong attr_type,
	       GckBuilder *builder)
{
	time_t time;
	struct tm tm;
	gchar buf[20];
	guint64 value;

	g_assert (variant != NULL);
	g_assert (builder != NULL);

	value = g_variant_get_uint64 (variant);
	if (value == 0) {
		gck_builder_add_empty (builder, attr_type);
		return TRUE;
	}

	time = value;
	if (!gmtime_r (&time, &tm))
		g_return_val_if_reached (FALSE);

	if (!strftime (buf, sizeof (buf), "%Y%m%d%H%M%S00", &tm))
		g_return_val_if_reached (FALSE);

	gck_builder_add_data (builder, attr_type, (const guchar *)buf, 16);
	return TRUE;
}
static gboolean
iter_get_time (DBusMessageIter *iter,
               gulong attr_type,
               GckBuilder *builder)
{
	time_t time;
	struct tm tm;
	gchar buf[20];
	guint64 value;

	g_assert (iter != NULL);
	g_assert (builder != NULL);

	g_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_UINT64, FALSE);
	dbus_message_iter_get_basic (iter, &value);
	if (value == 0) {
		gck_builder_add_empty (builder, attr_type);
		return TRUE;
	}

	time = value;
	if (!gmtime_r (&time, &tm))
		g_return_val_if_reached (FALSE);

	if (!strftime (buf, sizeof (buf), "%Y%m%d%H%M%S00", &tm))
		g_return_val_if_reached (FALSE);

	gck_builder_add_data (builder, attr_type, (const guchar *)buf, 16);
	return TRUE;
}
static void
prepare_generate (SeahorsePkcs11Generate *self)
{
	CK_BYTE rsa_public_exponent[] = { 0x01, 0x00, 0x01 }; /* 65537 in bytes */
	GckBuilder publi = GCK_BUILDER_INIT;
	GckBuilder priva = GCK_BUILDER_INIT;
	const gchar *label;

	g_assert (self->cancellable == NULL);
	g_assert (self->mechanism != NULL);

	gck_builder_add_ulong (&publi, CKA_CLASS, CKO_PUBLIC_KEY);
	gck_builder_add_ulong (&priva, CKA_CLASS, CKO_PRIVATE_KEY);

	gck_builder_add_boolean (&publi, CKA_TOKEN, TRUE);
	gck_builder_add_boolean (&priva, CKA_TOKEN, TRUE);

	gck_builder_add_boolean (&priva, CKA_PRIVATE, TRUE);
	gck_builder_add_boolean (&priva, CKA_SENSITIVE, TRUE);

	label = gtk_entry_get_text (self->label_entry);
	gck_builder_add_string (&publi, CKA_LABEL, label);
	gck_builder_add_string (&priva, CKA_LABEL, label);

	if (self->mechanism->type == CKM_RSA_PKCS_KEY_PAIR_GEN) {
		gck_builder_add_boolean (&publi, CKA_ENCRYPT, TRUE);
		gck_builder_add_boolean (&publi, CKA_VERIFY, TRUE);
		gck_builder_add_boolean (&publi, CKA_WRAP, TRUE);

		gck_builder_add_boolean (&priva, CKA_DECRYPT, TRUE);
		gck_builder_add_boolean (&priva, CKA_SIGN, TRUE);
		gck_builder_add_boolean (&priva, CKA_UNWRAP, TRUE);

		gck_builder_add_data (&publi, CKA_PUBLIC_EXPONENT,
		                      rsa_public_exponent, sizeof (rsa_public_exponent));
		gck_builder_add_ulong (&publi, CKA_MODULUS_BITS,
		                       gtk_spin_button_get_value_as_int (self->bits_entry));

	} else {
		g_warning ("currently no support for this mechanism");
	}

	self->prv_attrs = gck_builder_steal (&priva);
	self->pub_attrs = gck_builder_steal (&publi);

	gck_builder_clear (&publi);
	gck_builder_clear (&priva);
}
static gboolean
iter_get_fields (DBusMessageIter *iter,
                 gulong attr_type,
                 GckBuilder *builder)
{
	DBusMessageIter array;
	DBusMessageIter dict;
	GString *result;
	const gchar *string;

	g_assert (iter != NULL);
	g_assert (builder != NULL);

	result = g_string_new ("");

	g_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY, FALSE);
	dbus_message_iter_recurse (iter, &array);

	while (dbus_message_iter_get_arg_type (&array) == DBUS_TYPE_DICT_ENTRY) {
		dbus_message_iter_recurse (&array, &dict);

		/* Key */
		g_return_val_if_fail (dbus_message_iter_get_arg_type (&dict) == DBUS_TYPE_STRING, FALSE);
		dbus_message_iter_get_basic (&dict, &string);
		g_string_append (result, string);
		g_string_append_c (result, '\0');

		dbus_message_iter_next (&dict);

		/* Value */
		g_return_val_if_fail (dbus_message_iter_get_arg_type (&dict) == DBUS_TYPE_STRING, FALSE);
		dbus_message_iter_get_basic (&dict, &string);
		g_string_append (result, string);
		g_string_append_c (result, '\0');

		dbus_message_iter_next (&array);
	}

	gck_builder_add_data (builder, attr_type, (const guchar *)result->str, result->len);
	g_string_free (result, TRUE);
	return TRUE;
}
gboolean
gkd_ssh_agent_proto_read_mpi (EggBuffer *req, gsize *offset,
                              GckBuilder *builder,
                              CK_ATTRIBUTE_TYPE type)
{
	const guchar *data;
	gsize len;

	if (!egg_buffer_get_byte_array (req, *offset, offset, &data, &len))
		return FALSE;

	/* Convert to unsigned format */
	if (len >= 2 && data[0] == 0 && (data[1] & 0x80)) {
		++data;
		--len;
	}

	gck_builder_add_data (builder, type, data, len);
	return TRUE;
}