comparison libpurple/protocols/silc10/pk.c @ 17567:ba1b50f114f6

Duplicate the current SILC prpl as silc10 for backwards compatibility with SILC Toolkit 1.0
author Stu Tomlinson <stu@nosnilmot.com>
date Sat, 09 Jun 2007 16:39:00 +0000
parents
children 285bb637a2b7
comparison
equal deleted inserted replaced
17566:016eee704a96 17567:ba1b50f114f6
1 /*
2
3 silcpurple_pk.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 Pekka Riikonen
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19
20 #include "silcincludes.h"
21 #include "silcclient.h"
22 #include "silcpurple.h"
23
24 /************************* Public Key Verification ***************************/
25
26 typedef struct {
27 SilcClient client;
28 SilcClientConnection conn;
29 char *filename;
30 char *entity;
31 char *entity_name;
32 char *fingerprint;
33 char *babbleprint;
34 unsigned char *pk;
35 SilcUInt32 pk_len;
36 SilcSKEPKType pk_type;
37 SilcVerifyPublicKey completion;
38 void *context;
39 gboolean changed;
40 } *PublicKeyVerify;
41
42 static void silcpurple_verify_ask(const char *entity,
43 const char *fingerprint,
44 const char *babbleprint,
45 PublicKeyVerify verify);
46
47 static void silcpurple_verify_cb(PublicKeyVerify verify, gint id)
48 {
49 if (id != 2) {
50 if (verify->completion)
51 verify->completion(FALSE, verify->context);
52 } else {
53 if (verify->completion)
54 verify->completion(TRUE, verify->context);
55
56 /* Save the key for future checking */
57 silc_pkcs_save_public_key_data(verify->filename, verify->pk,
58 verify->pk_len, SILC_PKCS_FILE_PEM);
59 }
60
61 silc_free(verify->filename);
62 silc_free(verify->entity);
63 silc_free(verify->entity_name);
64 silc_free(verify->fingerprint);
65 silc_free(verify->babbleprint);
66 silc_free(verify->pk);
67 silc_free(verify);
68 }
69
70 static void silcpurple_verify_details_cb(PublicKeyVerify verify)
71 {
72 /* What a hack. We have to display the accept dialog _again_
73 because Purple closes the dialog after you press the button. Purple
74 should have option for the dialogs whether the buttons close them
75 or not. */
76 silcpurple_verify_ask(verify->entity, verify->fingerprint,
77 verify->babbleprint, verify);
78 }
79
80 static void silcpurple_verify_details(PublicKeyVerify verify, gint id)
81 {
82 SilcPublicKey public_key;
83 PurpleConnection *gc = verify->client->application;
84 SilcPurple sg = gc->proto_data;
85
86 silc_pkcs_public_key_decode(verify->pk, verify->pk_len,
87 &public_key);
88 silcpurple_show_public_key(sg, verify->entity_name, public_key,
89 G_CALLBACK(silcpurple_verify_details_cb),
90 verify);
91 silc_pkcs_public_key_free(public_key);
92 }
93
94 static void silcpurple_verify_ask(const char *entity,
95 const char *fingerprint,
96 const char *babbleprint,
97 PublicKeyVerify verify)
98 {
99 PurpleConnection *gc = verify->client->application;
100 char tmp[256], tmp2[256];
101
102 if (verify->changed) {
103 g_snprintf(tmp, sizeof(tmp),
104 _("Received %s's public key. Your local copy does not match this "
105 "key. Would you still like to accept this public key?"),
106 entity);
107 } else {
108 g_snprintf(tmp, sizeof(tmp),
109 _("Received %s's public key. Would you like to accept this "
110 "public key?"), entity);
111 }
112 g_snprintf(tmp2, sizeof(tmp2),
113 _("Fingerprint and babbleprint for the %s key are:\n\n"
114 "%s\n%s\n"), entity, fingerprint, babbleprint);
115
116 purple_request_action(gc, _("Verify Public Key"), tmp, tmp2,
117 PURPLE_DEFAULT_ACTION_NONE,
118 purple_connection_get_account(gc), entity, NULL, verify, 3,
119 _("Yes"), G_CALLBACK(silcpurple_verify_cb),
120 _("No"), G_CALLBACK(silcpurple_verify_cb),
121 _("_View..."), G_CALLBACK(silcpurple_verify_details));
122 }
123
124 void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn,
125 const char *name, SilcSocketType conn_type,
126 unsigned char *pk, SilcUInt32 pk_len,
127 SilcSKEPKType pk_type,
128 SilcVerifyPublicKey completion, void *context)
129 {
130 PurpleConnection *gc = client->application;
131 int i;
132 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
133 char *fingerprint, *babbleprint;
134 struct passwd *pw;
135 struct stat st;
136 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
137 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
138 "server" : "client");
139 PublicKeyVerify verify;
140
141 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
142 purple_notify_error(gc, _("Verify Public Key"),
143 _("Unsupported public key type"), NULL);
144 if (completion)
145 completion(FALSE, context);
146 return;
147 }
148
149 pw = getpwuid(getuid());
150 if (!pw) {
151 if (completion)
152 completion(FALSE, context);
153 return;
154 }
155
156 memset(filename, 0, sizeof(filename));
157 memset(filename2, 0, sizeof(filename2));
158 memset(file, 0, sizeof(file));
159
160 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
161 conn_type == SILC_SOCKET_TYPE_ROUTER) {
162 if (!name) {
163 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
164 conn->sock->ip, conn->sock->port);
165 g_snprintf(filename, sizeof(filename) - 1,
166 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
167 silcpurple_silcdir(), entity, file);
168
169 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
170 conn->sock->hostname, conn->sock->port);
171 g_snprintf(filename2, sizeof(filename2) - 1,
172 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
173 silcpurple_silcdir(), entity, file);
174
175 ipf = filename;
176 hostf = filename2;
177 } else {
178 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
179 name, conn->sock->port);
180 g_snprintf(filename, sizeof(filename) - 1,
181 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
182 silcpurple_silcdir(), entity, file);
183
184 ipf = filename;
185 }
186 } else {
187 /* Replace all whitespaces with `_'. */
188 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
189 for (i = 0; i < strlen(fingerprint); i++)
190 if (fingerprint[i] == ' ')
191 fingerprint[i] = '_';
192
193 g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
194 g_snprintf(filename, sizeof(filename) - 1,
195 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
196 silcpurple_silcdir(), entity, file);
197 silc_free(fingerprint);
198
199 ipf = filename;
200 }
201
202 verify = silc_calloc(1, sizeof(*verify));
203 if (!verify)
204 return;
205 verify->client = client;
206 verify->conn = conn;
207 verify->filename = strdup(ipf);
208 verify->entity = strdup(entity);
209 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
210 (name ? strdup(name) : strdup(conn->sock->hostname))
211 : NULL);
212 verify->pk = silc_memdup(pk, pk_len);
213 verify->pk_len = pk_len;
214 verify->pk_type = pk_type;
215 verify->completion = completion;
216 verify->context = context;
217 fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
218 babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
219
220 /* Check whether this key already exists */
221 if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) {
222 /* Key does not exist, ask user to verify the key and save it */
223 silcpurple_verify_ask(name ? name : entity,
224 fingerprint, babbleprint, verify);
225 return;
226 } else {
227 /* The key already exists, verify it. */
228 SilcPublicKey public_key;
229 unsigned char *encpk;
230 SilcUInt32 encpk_len;
231
232 /* Load the key file, try for both IP filename and hostname filename */
233 if (!silc_pkcs_load_public_key(ipf, &public_key,
234 SILC_PKCS_FILE_PEM) &&
235 !silc_pkcs_load_public_key(ipf, &public_key,
236 SILC_PKCS_FILE_BIN) &&
237 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
238 SILC_PKCS_FILE_PEM) &&
239 !silc_pkcs_load_public_key(hostf, &public_key,
240 SILC_PKCS_FILE_BIN)))) {
241 silcpurple_verify_ask(name ? name : entity,
242 fingerprint, babbleprint, verify);
243 return;
244 }
245
246 /* Encode the key data */
247 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
248 if (!encpk) {
249 silcpurple_verify_ask(name ? name : entity,
250 fingerprint, babbleprint, verify);
251 return;
252 }
253
254 /* Compare the keys */
255 if (memcmp(encpk, pk, encpk_len)) {
256 /* Ask user to verify the key and save it */
257 verify->changed = TRUE;
258 silcpurple_verify_ask(name ? name : entity,
259 fingerprint, babbleprint, verify);
260 return;
261 }
262
263 /* Local copy matched */
264 if (completion)
265 completion(TRUE, context);
266 silc_free(verify->filename);
267 silc_free(verify->entity);
268 silc_free(verify->entity_name);
269 silc_free(verify->pk);
270 silc_free(verify->fingerprint);
271 silc_free(verify->babbleprint);
272 silc_free(verify);
273 }
274 }