libpurple/protocols/silc/pk.c

changeset 41832
63f39d354a73
parent 41831
596940e90c68
child 41833
a6a511564c1b
equal deleted inserted replaced
41831:596940e90c68 41832:63f39d354a73
1 /*
2
3 silcpurple_pk.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 - 2007 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 <glib/gi18n-lib.h>
21 #include <glib/gstdio.h>
22
23 #include "glibcompat.h" /* for purple_g_stat on win32 */
24 #include "silcpurple.h"
25
26 /************************* Public Key Verification ***************************/
27
28 typedef struct {
29 SilcClient client;
30 SilcClientConnection conn;
31 char *filename;
32 char *entity;
33 char *entity_name;
34 char *fingerprint;
35 char *babbleprint;
36 SilcPublicKey public_key;
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(verify->filename, verify->public_key,
58 SILC_PKCS_FILE_BASE64);
59 }
60
61 g_free(verify->filename);
62 g_free(verify->entity);
63 g_free(verify->entity_name);
64 silc_free(verify->fingerprint);
65 silc_free(verify->babbleprint);
66 silc_pkcs_public_key_free(verify->public_key);
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 PurpleConnection *gc = verify->client->application;
83 SilcPurple sg = purple_connection_get_protocol_data(gc);
84
85 silcpurple_show_public_key(sg, verify->entity_name, verify->public_key,
86 G_CALLBACK(silcpurple_verify_details_cb),
87 verify);
88 }
89
90 static void silcpurple_verify_ask(const char *entity,
91 const char *fingerprint,
92 const char *babbleprint,
93 PublicKeyVerify verify)
94 {
95 PurpleConnection *gc = verify->client->application;
96 char tmp[256], tmp2[256];
97
98 if (verify->changed) {
99 g_snprintf(tmp, sizeof(tmp),
100 _("Received %s's public key. Your local copy does not match this "
101 "key. Would you still like to accept this public key?"),
102 entity);
103 } else {
104 g_snprintf(tmp, sizeof(tmp),
105 _("Received %s's public key. Would you like to accept this "
106 "public key?"), entity);
107 }
108 g_snprintf(tmp2, sizeof(tmp2),
109 _("Fingerprint and babbleprint for the %s key are:\n\n"
110 "%s\n%s\n"), entity, fingerprint, babbleprint);
111
112 purple_request_action(gc, _("Verify Public Key"), tmp, tmp2,
113 PURPLE_DEFAULT_ACTION_NONE,
114 purple_request_cpar_from_connection(gc), verify, 3,
115 _("Yes"), G_CALLBACK(silcpurple_verify_cb),
116 _("No"), G_CALLBACK(silcpurple_verify_cb),
117 _("_View..."), G_CALLBACK(silcpurple_verify_details));
118 }
119
120 void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn,
121 const char *name, SilcConnectionType conn_type,
122 SilcPublicKey public_key,
123 SilcVerifyPublicKey completion, void *context)
124 {
125 PurpleConnection *gc = client->application;
126 gsize i;
127 char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
128 char *fingerprint, *babbleprint;
129 struct passwd *pw;
130 GStatBuf st;
131 char *entity = ((conn_type == SILC_CONN_SERVER ||
132 conn_type == SILC_CONN_ROUTER) ?
133 "server" : "client");
134 PublicKeyVerify verify;
135 const char *ip, *hostname;
136 SilcUInt16 port;
137 unsigned char *pk;
138 SilcUInt32 pk_len;
139
140 if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
141 purple_notify_error(gc, _("Verify Public Key"),
142 _("Unsupported public key type"), NULL,
143 purple_request_cpar_from_connection(gc));
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 silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
161 NULL, &hostname, &ip, &port);
162
163 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
164 if (!pk) {
165 if (completion)
166 completion(FALSE, context);
167 return;
168 }
169
170 if (conn_type == SILC_CONN_SERVER ||
171 conn_type == SILC_CONN_ROUTER) {
172 if (!name) {
173 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
174 ip, port);
175 g_snprintf(filename, sizeof(filename) - 1,
176 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
177 silcpurple_silcdir(), entity, file);
178
179 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
180 hostname, port);
181 g_snprintf(filename2, sizeof(filename2) - 1,
182 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
183 silcpurple_silcdir(), entity, file);
184
185 ipf = filename;
186 hostf = filename2;
187 } else {
188 g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
189 name, port);
190 g_snprintf(filename, sizeof(filename) - 1,
191 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
192 silcpurple_silcdir(), entity, file);
193
194 ipf = filename;
195 }
196 } else {
197 /* Replace all whitespaces with `_'. */
198 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
199 for (i = 0; i < strlen(fingerprint); i++)
200 if (fingerprint[i] == ' ')
201 fingerprint[i] = '_';
202
203 g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
204 g_snprintf(filename, sizeof(filename) - 1,
205 "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
206 silcpurple_silcdir(), entity, file);
207 silc_free(fingerprint);
208
209 ipf = filename;
210 }
211
212 verify = silc_calloc(1, sizeof(*verify));
213 if (!verify)
214 return;
215 verify->client = client;
216 verify->conn = conn;
217 verify->filename = g_strdup(ipf);
218 verify->entity = g_strdup(entity);
219 verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
220 (name ? g_strdup(name) : g_strdup(hostname))
221 : NULL);
222 verify->public_key = silc_pkcs_public_key_copy(public_key);
223 verify->completion = completion;
224 verify->context = context;
225 fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
226 babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
227
228 /* Check whether this key already exists */
229 if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) {
230 /* Key does not exist, ask user to verify the key and save it */
231 silcpurple_verify_ask(name ? name : entity,
232 fingerprint, babbleprint, verify);
233 return;
234 } else {
235 /* The key already exists, verify it. */
236 SilcPublicKey public_key;
237 unsigned char *encpk;
238 SilcUInt32 encpk_len;
239
240 /* Load the key file, try for both IP filename and hostname filename */
241 if (!silc_pkcs_load_public_key(ipf, &public_key) &&
242 (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key)))) {
243 silcpurple_verify_ask(name ? name : entity,
244 fingerprint, babbleprint, verify);
245 return;
246 }
247
248 /* Encode the key data */
249 encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
250 if (!encpk) {
251 silcpurple_verify_ask(name ? name : entity,
252 fingerprint, babbleprint, verify);
253 return;
254 }
255
256 /* Compare the keys */
257 if (memcmp(encpk, pk, encpk_len)) {
258 /* Ask user to verify the key and save it */
259 verify->changed = TRUE;
260 silcpurple_verify_ask(name ? name : entity,
261 fingerprint, babbleprint, verify);
262 return;
263 }
264
265 /* Local copy matched */
266 if (completion)
267 completion(TRUE, context);
268 g_free(verify->filename);
269 g_free(verify->entity);
270 g_free(verify->entity_name);
271 silc_free(verify->fingerprint);
272 silc_free(verify->babbleprint);
273 silc_pkcs_public_key_free(verify->public_key);
274 silc_free(verify);
275 }
276 }

mercurial