comparison libpurple/protocols/silc/pk.c @ 15373:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 32c366eeeb99
comparison
equal deleted inserted replaced
15372:f79e0f4df793 15373:5fe8042783c1
1 /*
2
3 silcgaim_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 "silcgaim.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 silcgaim_verify_ask(const char *entity,
43 const char *fingerprint,
44 const char *babbleprint,
45 PublicKeyVerify verify);
46
47 static void silcgaim_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 silcgaim_verify_details_cb(PublicKeyVerify verify)
71 {
72 /* What a hack. We have to display the accept dialog _again_
73 because Gaim closes the dialog after you press the button. Gaim
74 should have option for the dialogs whether the buttons close them
75 or not. */
76 silcgaim_verify_ask(verify->entity, verify->fingerprint,
77 verify->babbleprint, verify);
78 }
79
80 static void silcgaim_verify_details(PublicKeyVerify verify, gint id)
81 {
82 SilcPublicKey public_key;
83 GaimConnection *gc = verify->client->application;
84 SilcGaim sg = gc->proto_data;
85
86 silc_pkcs_public_key_decode(verify->pk, verify->pk_len,
87 &public_key);
88 silcgaim_show_public_key(sg, verify->entity_name, public_key,
89 G_CALLBACK(silcgaim_verify_details_cb),
90 verify);
91 silc_pkcs_public_key_free(public_key);
92 }
93
94 static void silcgaim_verify_ask(const char *entity,
95 const char *fingerprint,
96 const char *babbleprint,
97 PublicKeyVerify verify)
98 {
99 char tmp[256], tmp2[256];
100
101 if (verify->changed) {
102 g_snprintf(tmp, sizeof(tmp),
103 _("Received %s's public key. Your local copy does not match this "
104 "key. Would you still like to accept this public key?"),
105 entity);
106 } else {
107 g_snprintf(tmp, sizeof(tmp),
108 _("Received %s's public key. Would you like to accept this "
109 "public key?"), entity);
110 }
111 g_snprintf(tmp2, sizeof(tmp2),
112 _("Fingerprint and babbleprint for the %s key are:\n\n"
113 "%s\n%s\n"), entity, fingerprint, babbleprint);
114
115 gaim_request_action(verify->client->application, _("Verify Public Key"), tmp, tmp2,
116 GAIM_DEFAULT_ACTION_NONE, verify, 3,
117 _("Yes"), G_CALLBACK(silcgaim_verify_cb),
118 _("No"), G_CALLBACK(silcgaim_verify_cb),
119 _("_View..."), G_CALLBACK(silcgaim_verify_details));
120 }
121
122 void silcgaim_verify_public_key(SilcClient client, SilcClientConnection conn,
123 const char *name, SilcSocketType conn_type,
124 unsigned char *pk, SilcUInt32 pk_len,
125 SilcSKEPKType pk_type,
126 SilcVerifyPublicKey completion, void *context)
127 {
128 GaimConnection *gc = client->application;
129 int i;
130 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
131 char *fingerprint, *babbleprint;
132 struct passwd *pw;
133 struct stat st;
134 char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
135 conn_type == SILC_SOCKET_TYPE_ROUTER) ?
136 "server" : "client");
137 PublicKeyVerify verify;
138
139 if (pk_type != SILC_SKE_PK_TYPE_SILC) {
140 gaim_notify_error(gc, _("Verify Public Key"),
141 _("Unsupported public key type"), NULL);
142 if (completion)
143 completion(FALSE, context);
144 return;
145 }
146
147 pw = getpwuid(getuid());
148 if (!pw) {
149 if (completion)
150 completion(FALSE, context);
151 return;
152 }
153
154 memset(filename, 0, sizeof(filename));
155 memset(filename2, 0, sizeof(filename2));
156 memset(file, 0, sizeof(file));
157
158 if (conn_type == SILC_SOCKET_TYPE_SERVER ||
159 conn_type == SILC_SOCKET_TYPE_ROUTER) {
160 if (!name) {
161 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
162 conn->sock->ip, conn->sock->port);
163 g_snprintf(filename, sizeof(filename) - 1,
164 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
165 silcgaim_silcdir(), entity, file);
166
167 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
168 conn->sock->hostname, conn->sock->port);
169 g_snprintf(filename2, sizeof(filename2) - 1,
170 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
171 silcgaim_silcdir(), entity, file);
172
173 ipf = filename;
174 hostf = filename2;
175 } else {
176 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
177 name, conn->sock->port);
178 g_snprintf(filename, sizeof(filename) - 1,
179 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
180 silcgaim_silcdir(), entity, file);
181
182 ipf = filename;
183 }
184 } else {
185 /* Replace all whitespaces with `_'. */
186 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
187 for (i = 0; i < strlen(fingerprint); i++)
188 if (fingerprint[i] == ' ')
189 fingerprint[i] = '_';
190
191 g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
192 g_snprintf(filename, sizeof(filename) - 1,
193 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
194 silcgaim_silcdir(), entity, file);
195 silc_free(fingerprint);
196
197 ipf = filename;
198 }
199
200 verify = silc_calloc(1, sizeof(*verify));
201 if (!verify)
202 return;
203 verify->client = client;
204 verify->conn = conn;
205 verify->filename = strdup(ipf);
206 verify->entity = strdup(entity);
207 verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
208 (name ? strdup(name) : strdup(conn->sock->hostname))
209 : NULL);
210 verify->pk = silc_memdup(pk, pk_len);
211 verify->pk_len = pk_len;
212 verify->pk_type = pk_type;
213 verify->completion = completion;
214 verify->context = context;
215 fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
216 babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
217
218 /* Check whether this key already exists */
219 if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) {
220 /* Key does not exist, ask user to verify the key and save it */
221 silcgaim_verify_ask(name ? name : entity,
222 fingerprint, babbleprint, verify);
223 return;
224 } else {
225 /* The key already exists, verify it. */
226 SilcPublicKey public_key;
227 unsigned char *encpk;
228 SilcUInt32 encpk_len;
229
230 /* Load the key file, try for both IP filename and hostname filename */
231 if (!silc_pkcs_load_public_key(ipf, &public_key,
232 SILC_PKCS_FILE_PEM) &&
233 !silc_pkcs_load_public_key(ipf, &public_key,
234 SILC_PKCS_FILE_BIN) &&
235 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
236 SILC_PKCS_FILE_PEM) &&
237 !silc_pkcs_load_public_key(hostf, &public_key,
238 SILC_PKCS_FILE_BIN)))) {
239 silcgaim_verify_ask(name ? name : entity,
240 fingerprint, babbleprint, verify);
241 return;
242 }
243
244 /* Encode the key data */
245 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
246 if (!encpk) {
247 silcgaim_verify_ask(name ? name : entity,
248 fingerprint, babbleprint, verify);
249 return;
250 }
251
252 /* Compare the keys */
253 if (memcmp(encpk, pk, encpk_len)) {
254 /* Ask user to verify the key and save it */
255 verify->changed = TRUE;
256 silcgaim_verify_ask(name ? name : entity,
257 fingerprint, babbleprint, verify);
258 return;
259 }
260
261 /* Local copy matched */
262 if (completion)
263 completion(TRUE, context);
264 silc_free(verify->filename);
265 silc_free(verify->entity);
266 silc_free(verify->entity_name);
267 silc_free(verify->pk);
268 silc_free(verify->fingerprint);
269 silc_free(verify->babbleprint);
270 silc_free(verify);
271 }
272 }