예제 #1
0
파일: buddy.c 프로젝트: dylex/pidgin
static void
silcpurple_buddy_getkey_cb(SilcPurpleBuddyGetkey g,
			 SilcClientCommandReplyContext cmd)
{
	SilcClientEntry client_entry;
	unsigned char *pk;
	SilcUInt32 pk_len;

	/* Get the client entry. */
	client_entry = silc_client_get_client_by_id(g->client, g->conn,
						    &g->client_id);
	if (!client_entry) {
		purple_notify_error(g->client->application, _("Get Public Key"),
				  _("The remote user is not present in the network any more"),
				  NULL);
		silc_free(g);
		return;
	}

	if (!client_entry->public_key) {
		silc_free(g);
		return;
	}

	/* Now verify the public key */
	pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
	silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname,
				   SILC_SOCKET_TYPE_CLIENT,
				   pk, pk_len, SILC_SKE_PK_TYPE_SILC,
				   NULL, NULL);
	silc_free(pk);
	silc_free(g);
}
예제 #2
0
SilcBuffer silc_public_key_payload_encode(SilcPublicKey public_key)
{
  SilcBuffer buffer;
  unsigned char *pk;
  SilcUInt32 pk_len;
  SilcPKCSType type;

  if (!public_key)
    return NULL;

  type = silc_pkcs_get_type(public_key);
  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
  if (!pk)
    return NULL;

  buffer = silc_buffer_alloc_size(4 + pk_len);
  if (!buffer) {
    silc_free(pk);
    return NULL;
  }

  if (silc_buffer_format(buffer,
			 SILC_STR_UI_SHORT(pk_len),
			 SILC_STR_UI_SHORT(type),
			 SILC_STR_DATA(pk, pk_len),
			 SILC_STR_END) < 0) {
    silc_buffer_free(buffer);
    silc_free(pk);
    return NULL;
  }

  silc_free(pk);
  return buffer;
}
예제 #3
0
파일: buddy.c 프로젝트: dylex/pidgin
static void
silcpurple_add_buddy_getkey_cb(SilcPurpleBuddyRes r,
			     SilcClientCommandReplyContext cmd)
{
	SilcClientEntry client_entry;
	unsigned char *pk;
	SilcUInt32 pk_len;

	/* Get the client entry. */
	client_entry = silc_client_get_client_by_id(r->client, r->conn,
						    &r->client_id);
	if (!client_entry || !client_entry->public_key) {
		/* The buddy is offline/nonexistent. We will require user
		   to associate a public key with the buddy or the buddy
		   cannot be added. */
		r->offline = TRUE;
		silcpurple_add_buddy_ask_pk(r);
		return;
	}

	/* Now verify the public key */
	pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
	silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname,
				   SILC_SOCKET_TYPE_CLIENT,
				   pk, pk_len, SILC_SKE_PK_TYPE_SILC,
				   silcpurple_add_buddy_save, r);
	silc_free(pk);
}
예제 #4
0
파일: buddy.c 프로젝트: dylex/pidgin
static void
silcpurple_add_buddy_ask_import(void *user_data, const char *name)
{
	SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data;
	SilcPublicKey public_key;

	/* Load the public key */
	if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) &&
	    !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) {
		silcpurple_add_buddy_ask_pk_cb(r, 0);
		purple_notify_error(r->client->application,
				  _("Add Buddy"), _("Could not load public key"), NULL);
		return;
	}

	/* Now verify the public key */
	r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len);
	silcpurple_verify_public_key(r->client, r->conn, r->b->name,
				   SILC_SOCKET_TYPE_CLIENT,
				   r->offline_pk, r->offline_pk_len,
				   SILC_SKE_PK_TYPE_SILC,
				   silcpurple_add_buddy_save, r);
}
예제 #5
0
파일: chat.c 프로젝트: Lilitana/Pidgin
static void
silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components)
{
	SilcPurple sg = gc->proto_data;
	const char *chname;
	char tmp[256], *tmp2;
	GString *s;
	SilcChannelEntry channel;
	SilcHashTableList htl;
	SilcChannelUser chu;

	if (!components)
		return;

	chname = g_hash_table_lookup(components, "channel");
	if (!chname)
		return;
	channel = silc_client_get_channel(sg->client, sg->conn,
					  (char *)chname);
	if (!channel) {
		silc_client_get_channel_resolve(sg->client, sg->conn,
						(char *)chname,
						silcpurple_chat_getinfo_res,
						components);
		return;
	}

	s = g_string_new("");
	tmp2 = g_markup_escape_text(channel->channel_name, -1);
	g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2);
	g_free(tmp2);
	if (channel->user_list && silc_hash_table_count(channel->user_list))
		g_string_append_printf(s, _("<br><b>User Count:</b> %d"),
				       (int)silc_hash_table_count(channel->user_list));

	silc_hash_table_list(channel->user_list, &htl);
	while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
		if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) {
			tmp2 = g_markup_escape_text(chu->client->nickname, -1);
			g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"),
					       tmp2);
			g_free(tmp2);
			break;
		}
	}
	silc_hash_table_list_reset(&htl);

	if (channel->cipher)
		g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"),
				       channel->cipher);

	if (channel->hmac)
		/* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */
		g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"),
				       channel->hmac);

	if (channel->topic) {
		tmp2 = g_markup_escape_text(channel->topic, -1);
		g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2);
		g_free(tmp2);
	}

	if (channel->mode) {
		g_string_append_printf(s, _("<br><b>Channel Modes:</b> "));
		silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp));
		g_string_append(s, tmp);
	}

	if (channel->founder_key) {
		char *fingerprint, *babbleprint;
		unsigned char *pk;
		SilcUInt32 pk_len;
		pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len);
		if (pk) {
			fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
			babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);

			g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint);
			g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint);

			silc_free(fingerprint);
			silc_free(babbleprint);
			silc_free(pk);
		}
	}

	purple_notify_formatted(gc, NULL, _("Channel Information"), NULL, s->str, NULL, NULL);
	g_string_free(s, TRUE);
}
예제 #6
0
파일: util.c 프로젝트: Draghtnod/pidgin
void silcpurple_show_public_key(SilcPurple sg,
				const char *name, SilcPublicKey public_key,
				GCallback callback, void *context)
{
	SilcPublicKeyIdentifier ident;
	SilcSILCPublicKey silc_pubkey;
	char *fingerprint, *babbleprint;
	unsigned char *pk;
	SilcUInt32 pk_len, key_len = 0;
	GString *s;

	/* We support showing only SILC public keys for now */
	if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
	  return;

	silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
	ident = &silc_pubkey->identifier;
	key_len = silc_pkcs_public_key_get_len(public_key);

	pk = silc_pkcs_public_key_encode(public_key, &pk_len);
	if (!pk)
	  return;
	fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
	babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
	if (!fingerprint || !babbleprint)
	  return;

	s = g_string_new("");
	if (ident->realname)
		/* Hint for translators: Please check the tabulator width here and in
		   the next strings (short strings: 2 tabs, longer strings 1 tab,
		   sum: 3 tabs or 24 characters) */
		g_string_append_printf(s, _("Real Name: \t%s\n"), ident->realname);
	if (ident->username)
		g_string_append_printf(s, _("User Name: \t%s\n"), ident->username);
	if (ident->email)
		g_string_append_printf(s, _("Email: \t\t%s\n"), ident->email);
	if (ident->host)
		g_string_append_printf(s, _("Host Name: \t%s\n"), ident->host);
	if (ident->org)
		g_string_append_printf(s, _("Organization: \t%s\n"), ident->org);
	if (ident->country)
		g_string_append_printf(s, _("Country: \t%s\n"), ident->country);
	g_string_append_printf(s, _("Algorithm: \t%s\n"), silc_pubkey->pkcs->name);
	g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len);
	if (ident->version)
	  g_string_append_printf(s, _("Version: \t%s\n"), ident->version);
	g_string_append_printf(s, "\n");
	g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint);
	g_string_append_printf(s, _("Public Key Babbleprint:\n%s"), babbleprint);

	purple_request_action(sg->gc, _("Public Key Information"),
			      _("Public Key Information"),
			      s->str, 0, purple_connection_get_account(sg->gc),
			      NULL, NULL, context, 1, _("Close"), callback);

	g_string_free(s, TRUE);
	silc_free(fingerprint);
	silc_free(babbleprint);
	silc_free(pk);
}
예제 #7
0
파일: pk.c 프로젝트: Lilitana/Pidgin
void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn,
				  const char *name, SilcConnectionType conn_type,
				  SilcPublicKey public_key,
				  SilcVerifyPublicKey completion, void *context)
{
	PurpleConnection *gc = client->application;
	int i;
	char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
	char *fingerprint, *babbleprint;
	struct passwd *pw;
	struct stat st;
	char *entity = ((conn_type == SILC_CONN_SERVER ||
			 conn_type == SILC_CONN_ROUTER) ?
			"server" : "client");
	PublicKeyVerify verify;
	const char *ip, *hostname;
	SilcUInt16 port;
	unsigned char *pk;
	SilcUInt32 pk_len;

	if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
		purple_notify_error(gc, _("Verify Public Key"),
				    _("Unsupported public key type"), NULL);
		if (completion)
			completion(FALSE, context);
		return;
	}

	pw = getpwuid(getuid());
	if (!pw) {
		if (completion)
			completion(FALSE, context);
		return;
	}

	memset(filename, 0, sizeof(filename));
	memset(filename2, 0, sizeof(filename2));
	memset(file, 0, sizeof(file));

	silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
				    NULL, &hostname, &ip, &port);

	pk = silc_pkcs_public_key_encode(public_key, &pk_len);
	if (!pk) {
		if (completion)
			completion(FALSE, context);
		return;
	}

	if (conn_type == SILC_CONN_SERVER ||
	    conn_type == SILC_CONN_ROUTER) {
		if (!name) {
			g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
				   ip, port);
			g_snprintf(filename, sizeof(filename) - 1,
				   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
				   silcpurple_silcdir(), entity, file);

			g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
				   hostname, port);
			g_snprintf(filename2, sizeof(filename2) - 1,
				   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
				   silcpurple_silcdir(), entity, file);

			ipf = filename;
			hostf = filename2;
		} else {
			g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
				   name, port);
			g_snprintf(filename, sizeof(filename) - 1,
				   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
				   silcpurple_silcdir(), entity, file);

			ipf = filename;
		}
	} else {
		/* Replace all whitespaces with `_'. */
		fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
		for (i = 0; i < strlen(fingerprint); i++)
			if (fingerprint[i] == ' ')
				fingerprint[i] = '_';

		g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
		g_snprintf(filename, sizeof(filename) - 1,
			   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
			   silcpurple_silcdir(), entity, file);
		silc_free(fingerprint);

		ipf = filename;
	}

	verify = silc_calloc(1, sizeof(*verify));
	if (!verify)
		return;
	verify->client = client;
	verify->conn = conn;
	verify->filename = g_strdup(ipf);
	verify->entity = g_strdup(entity);
	verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
			       (name ? g_strdup(name) : g_strdup(hostname))
			       : NULL);
	verify->public_key = silc_pkcs_public_key_copy(public_key);
	verify->completion = completion;
	verify->context = context;
	fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
	babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);

	/* Check whether this key already exists */
	if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) {
		/* Key does not exist, ask user to verify the key and save it */
		silcpurple_verify_ask(name ? name : entity,
				      fingerprint, babbleprint, verify);
		return;
	} else {
		/* The key already exists, verify it. */
		SilcPublicKey public_key;
		unsigned char *encpk;
		SilcUInt32 encpk_len;

		/* Load the key file, try for both IP filename and hostname filename */
		if (!silc_pkcs_load_public_key(ipf, &public_key) &&
		    (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key)))) {
			silcpurple_verify_ask(name ? name : entity,
					    fingerprint, babbleprint, verify);
			return;
		}

		/* Encode the key data */
		encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
		if (!encpk) {
			silcpurple_verify_ask(name ? name : entity,
					    fingerprint, babbleprint, verify);
			return;
		}

		/* Compare the keys */
		if (memcmp(encpk, pk, encpk_len)) {
			/* Ask user to verify the key and save it */
			verify->changed = TRUE;
			silcpurple_verify_ask(name ? name : entity,
					    fingerprint, babbleprint, verify);
			return;
		}

		/* Local copy matched */
		if (completion)
			completion(TRUE, context);
		g_free(verify->filename);
		g_free(verify->entity);
		g_free(verify->entity_name);
		silc_free(verify->fingerprint);
		silc_free(verify->babbleprint);
		silc_pkcs_public_key_free(verify->public_key);
		silc_free(verify);
	}
}
예제 #8
0
파일: buddy.c 프로젝트: dylex/pidgin
static void
silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init)
{
	SilcPurple sg = gc->proto_data;
	SilcClient client = sg->client;
	SilcClientConnection conn = sg->conn;
	SilcPurpleBuddyRes r;
	SilcBuffer attrs;
	const char *filename, *name = b->name;

	r = silc_calloc(1, sizeof(*r));
	if (!r)
		return;
	r->client = client;
	r->conn = conn;
	r->b = b;
	r->init = init;

	/* See if we have this buddy's public key.  If we do use that
	   to search the details. */
	filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");
	if (filename) {
		SilcPublicKey public_key;
		SilcAttributeObjPk userpk;

		if (!silc_pkcs_load_public_key(filename, &public_key,
					       SILC_PKCS_FILE_PEM) &&
		    !silc_pkcs_load_public_key(filename, &public_key,
					       SILC_PKCS_FILE_BIN))
			return;

		/* Get all attributes, and use the public key to search user */
		name = NULL;
		attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
						       SILC_ATTRIBUTE_SERVICE,
						       SILC_ATTRIBUTE_STATUS_MOOD,
						       SILC_ATTRIBUTE_STATUS_FREETEXT,
						       SILC_ATTRIBUTE_STATUS_MESSAGE,
						       SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
						       SILC_ATTRIBUTE_PREFERRED_CONTACT,
						       SILC_ATTRIBUTE_TIMEZONE,
						       SILC_ATTRIBUTE_GEOLOCATION,
#ifdef SILC_ATTRIBUTE_USER_ICON
						       SILC_ATTRIBUTE_USER_ICON,
#endif
						       SILC_ATTRIBUTE_DEVICE_INFO, 0);
		userpk.type = "silc-rsa";
		userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len);
		attrs = silc_attribute_payload_encode(attrs,
						      SILC_ATTRIBUTE_USER_PUBLIC_KEY,
						      SILC_ATTRIBUTE_FLAG_VALID,
						      &userpk, sizeof(userpk));
		silc_free(userpk.data);
		silc_pkcs_public_key_free(public_key);
		r->pubkey_search = TRUE;
	} else {
		/* Get all attributes */
		attrs = silc_client_attributes_request(0);
	}

	/* Resolve */
	silc_client_get_clients_whois(client, conn, name, NULL, attrs,
				      silcpurple_add_buddy_resolved, r);
	silc_buffer_free(attrs);
}
예제 #9
0
파일: buddy.c 프로젝트: dylex/pidgin
static void
silcpurple_add_buddy_resolved(SilcClient client,
			    SilcClientConnection conn,
			    SilcClientEntry *clients,
			    SilcUInt32 clients_count,
			    void *context)
{
	SilcPurpleBuddyRes r = context;
	PurpleBuddy *b = r->b;
	SilcAttributePayload pub;
	SilcAttributeObjPk userpk;
	unsigned char *pk;
	SilcUInt32 pk_len;
	const char *filename;

	filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");

	/* If the buddy is offline/nonexistent, we will require user
	   to associate a public key with the buddy or the buddy
	   cannot be added. */
	if (!clients_count) {
		if (r->init) {
			silc_free(r);
			return;
		}

		r->offline = TRUE;
		/* If the user has already associated a public key, try loading it
		 * before prompting the user to load it again */
		if (filename != NULL)
			silcpurple_add_buddy_ask_import(r, filename);
		else
			silcpurple_add_buddy_ask_pk(r);
		return;
	}

	/* If more than one client was found with nickname, we need to verify
	   from user which one is the correct. */
	if (clients_count > 1 && !r->pubkey_search) {
		if (r->init) {
			silc_free(r);
			return;
		}

		silcpurple_add_buddy_select(r, clients, clients_count);
		return;
	}

	/* If we searched using public keys and more than one entry was found
	   the same person is logged on multiple times. */
	if (clients_count > 1 && r->pubkey_search && b->name) {
		if (r->init) {
			/* Find the entry that closest matches to the
			   buddy nickname. */
			int i;
			for (i = 0; i < clients_count; i++) {
				if (!g_ascii_strncasecmp(b->name, clients[i]->nickname,
						 strlen(b->name))) {
					clients[0] = clients[i];
					break;
				}
			}
		} else {
			/* Verify from user which one is correct */
			silcpurple_add_buddy_select(r, clients, clients_count);
			return;
		}
	}

	/* The client was found.  Now get its public key and verify
	   that before adding the buddy. */
	memset(&userpk, 0, sizeof(userpk));
	b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id));
	r->client_id = *clients[0]->id;

	/* Get the public key from attributes, if not present then
	   resolve it with GETKEY unless we have it cached already. */
	if (clients[0]->attrs && !clients[0]->public_key) {
		pub = silcpurple_get_attr(clients[0]->attrs,
					SILC_ATTRIBUTE_USER_PUBLIC_KEY);
		if (!pub || !silc_attribute_get_object(pub, (void *)&userpk,
						       sizeof(userpk))) {
			/* Get public key with GETKEY */
			silc_client_command_call(client, conn, NULL,
						 "GETKEY", clients[0]->nickname, NULL);
			silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
						    conn->cmd_ident,
						    (SilcCommandCb)silcpurple_add_buddy_getkey_cb,
						    r);
			return;
		}
		if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len,
						 &clients[0]->public_key))
			return;
		silc_free(userpk.data);
	} else if (filename && !clients[0]->public_key) {
		if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key,
					       SILC_PKCS_FILE_PEM) &&
		    !silc_pkcs_load_public_key(filename, &clients[0]->public_key,
					       SILC_PKCS_FILE_BIN)) {
			/* Get public key with GETKEY */
			silc_client_command_call(client, conn, NULL,
						 "GETKEY", clients[0]->nickname, NULL);
			silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
						    conn->cmd_ident,
						    (SilcCommandCb)silcpurple_add_buddy_getkey_cb,
						    r);
			return;
		}
	} else if (!clients[0]->public_key) {
		/* Get public key with GETKEY */
		silc_client_command_call(client, conn, NULL,
					 "GETKEY", clients[0]->nickname, NULL);
		silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
					    conn->cmd_ident,
					    (SilcCommandCb)silcpurple_add_buddy_getkey_cb,
					    r);
		return;
	}

	/* We have the public key, verify it. */
	pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len);
	silcpurple_verify_public_key(client, conn, clients[0]->nickname,
				   SILC_SOCKET_TYPE_CLIENT,
				   pk, pk_len, SILC_SKE_PK_TYPE_SILC,
				   silcpurple_add_buddy_save, r);
	silc_free(pk);
}
예제 #10
0
SilcBuffer silc_client_attributes_process(SilcClient client,
					  SilcClientConnection conn,
					  SilcDList attrs)
{
  SilcBuffer buffer = NULL;
  SilcAttrForeach f;
  SilcAttribute attribute;
  SilcAttributePayload attr;
  SilcAttributeObjPk pk;
  unsigned char sign[2048 + 1];
  SilcUInt32 sign_len;

  SILC_LOG_DEBUG(("Process Requested Attributes"));

  /* If nothing is set by application assume that we don't want to use
     attributes, ignore the request. */
  if (!conn->internal->attrs) {
    SILC_LOG_DEBUG(("User has not set any attributes"));
    return NULL;
  }

  /* Always put our public key. */
  pk.type = "silc-rsa";
  pk.data = silc_pkcs_public_key_encode(conn->public_key, &pk.data_len);
  buffer = silc_attribute_payload_encode(buffer,
					 SILC_ATTRIBUTE_USER_PUBLIC_KEY,
					 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
					 SILC_ATTRIBUTE_FLAG_INVALID,
					 &pk, sizeof(pk));
  silc_free(pk.data);

  /* Go through all requested attributes */
  f.buffer = buffer;
  silc_dlist_start(attrs);
  while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
    /* Put all attributes of this type */
    attribute = silc_attribute_get_attribute(attr);

    /* Ignore signature since we will compute it later */
    if (attribute == SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE)
      continue;

    silc_hash_table_find_foreach(conn->internal->attrs,
				 SILC_32_TO_PTR(attribute),
				 silc_client_attributes_process_foreach,
				 &f);
  }
  buffer = f.buffer;

  /* Finally compute the digital signature of all the data we provided. */
  if (silc_pkcs_sign(conn->private_key, silc_buffer_data(buffer),
		     silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
		     TRUE, conn->internal->sha1hash)) {
    pk.type = NULL;
    pk.data = sign;
    pk.data_len = sign_len;
    buffer =
      silc_attribute_payload_encode(buffer,
				    SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE,
				    SILC_ATTRIBUTE_FLAG_VALID,
				    &pk, sizeof(pk));
  }

  return buffer;
}