Author: Pekka Riikonen <priikone@silcnet.org> Copyright (C) 2004 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. PURPLE_BEGIN_IGNORE_CAST_ALIGN PURPLE_END_IGNORE_CAST_ALIGN /************************* Public Key Verification ***************************/ SilcClientConnection conn; SilcPublicKey public_key; SilcVerifyPublicKey completion; static void silcpurple_verify_ask(const char *entity, static void silcpurple_verify_cb(PublicKeyVerify verify, gint id) verify->completion(FALSE, verify->context); verify->completion(TRUE, verify->context); /* Save the key for future checking */ silc_pkcs_save_public_key(verify->filename, verify->public_key, g_free(verify->filename); g_free(verify->entity_name); silc_free(verify->fingerprint); silc_free(verify->babbleprint); silc_pkcs_public_key_free(verify->public_key); static void silcpurple_verify_details_cb(PublicKeyVerify verify) /* What a hack. We have to display the accept dialog _again_ because Purple closes the dialog after you press the button. Purple should have option for the dialogs whether the buttons close them silcpurple_verify_ask(verify->entity, verify->fingerprint, verify->babbleprint, verify); static void silcpurple_verify_details(PublicKeyVerify verify, gint id) PurpleConnection *gc = verify->client->application; SilcPurple sg = purple_connection_get_protocol_data(gc); silcpurple_show_public_key(sg, verify->entity_name, verify->public_key, G_CALLBACK(silcpurple_verify_details_cb), static void silcpurple_verify_ask(const char *entity, PurpleConnection *gc = verify->client->application; char tmp[256], tmp2[256]; g_snprintf(tmp, sizeof(tmp), _("Received %s's public key. Your local copy does not match this " "key. Would you still like to accept this public key?"), g_snprintf(tmp, sizeof(tmp), _("Received %s's public key. Would you like to accept this " g_snprintf(tmp2, sizeof(tmp2), _("Fingerprint and babbleprint for the %s key are:\n\n" "%s\n%s\n"), entity, fingerprint, babbleprint); purple_request_action(gc, _("Verify Public Key"), tmp, tmp2, PURPLE_DEFAULT_ACTION_NONE, purple_request_cpar_from_connection(gc), verify, 3, _("Yes"), G_CALLBACK(silcpurple_verify_cb), _("No"), G_CALLBACK(silcpurple_verify_cb), _("_View..."), G_CALLBACK(silcpurple_verify_details)); 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; char file[256], filename[256], filename2[256], *ipf, *hostf = NULL; char *fingerprint, *babbleprint; char *entity = ((conn_type == SILC_CONN_SERVER || conn_type == SILC_CONN_ROUTER) ? const char *ip, *hostname; if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) { purple_notify_error(gc, _("Verify Public Key"), _("Unsupported public key type"), NULL, purple_request_cpar_from_connection(gc)); completion(FALSE, context); completion(FALSE, context); 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); completion(FALSE, context); if (conn_type == SILC_CONN_SERVER || conn_type == SILC_CONN_ROUTER) { g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 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, g_snprintf(filename2, sizeof(filename2) - 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, g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); /* Replace all whitespaces with `_'. */ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); for (i = 0; i < strlen(fingerprint); i++) if (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); verify = silc_calloc(1, sizeof(*verify)); 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)) 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); /* The key already exists, verify it. */ SilcPublicKey public_key; /* 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); /* Encode the key data */ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); if (memcmp(encpk, pk, encpk_len)) { /* Ask user to verify the key and save it */ silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); completion(TRUE, context); g_free(verify->filename); g_free(verify->entity_name); silc_free(verify->fingerprint); silc_free(verify->babbleprint); silc_pkcs_public_key_free(verify->public_key);