/[pkg-mixmaster]/trunk/Mix2.0/Src/client.c
ViewVC logotype

Contents of /trunk/Mix2.0/Src/client.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 200 - (show annotations) (download)
Wed Aug 28 20:06:48 2002 UTC (10 years, 8 months ago) by rabbi
File MIME type: text/plain
File size: 10089 byte(s)
Initial revision
1
2 /* $Id: client.c,v 1.1 2002/08/28 20:06:49 rabbi Exp $
3 * $Log: client.c,v $
4 * Revision 1.1 2002/08/28 20:06:49 rabbi
5 * Initial revision
6 *
7 * Revision 2.5 1998/04/13 23:22:29 um
8 * re-indented.
9 *
10 * Revision 2.4 1998/03/02 16:37:21 um
11 * fuction getline() replaces fgets() + chop().
12 *
13 * Revision 2.3 1998/02/26 02:25:32 um
14 * Changes for BSAFEeay.
15 *
16 * Revision 2.2 1998/02/17 23:25:41 um
17 * Check R_DecodePEMBlock return values.
18 *
19 * client.c 1997-11-08 um
20 * simple socket protocol completed.
21 *
22 * client.c (from Anonymous)
23 */
24
25
26 /* Protocol description by Lance Cottrell <loki@infonex.com>:
27
28 The users has already authenticated the RSA keys of each remailer
29 in the chain (or at least there is no point in authenticating them more
30 than the sender did). The direction that trust matters is from sending
31 remailer (C) to receiving remailer (S) because the receiving remailer will
32 accept messages from anyone, but the sending remailer wants to ensure that
33 only the next remailer in the chain gets the message.
34
35 Variables: A(foo) means RSA encryption of foo with A RSA key.
36 K1 First half of DH key exchange
37 K DH derived key
38 R1 Random number
39 R1(foo) foo encrypted using R1 as a 3DES key
40 H(foo) SHA hash of foo
41
42
43 C sends S the DH base to be used (each remailer can have a different one).
44
45 C requests key matching key hash in message (request conf if C has key already)
46
47 C sends S S(R1,K1,H(R1,K1))
48
49 S sends C R1(K1,K2,H(K1,K2)) Sending K1 under Key R1
50 authenticates K2
51
52 C sends S K(K2,H(K2)) Allows S to confirm correct key generation.
53
54 Done
55
56 RSA ensures only S can know R1 and K1. If we have the wrong key for S then
57 the user encrypted the message to the wrong person, and security has
58 already been compromised. Key authentication and distribution to the user
59 is not covered by this protocol. I assume that the user has used the
60 correct public key. I simply use the same public key (checked with the
61 fingerprint in the message) that the user encrypted to.
62
63 The purpose of the hashes in each exchange is to prevent substitution of
64 the contents of the packet. While an attacker could not know R1, he might
65 be able to change the values. The hash makes any tampering evident.
66
67 Encrypting with R1 and returning the key half K1 proves to C that the
68 correspondent was able to decrypt the initial message (thus proving
69 possession of S's private key). The final exchange acts only to allow S to
70 confirm that the exchange has gone correctly.*/
71
72
73 #include <stdio.h>
74 #include <string.h>
75 #include <stdlib.h>
76 #include <signal.h>
77 #include <sys/file.h>
78 #include "mix.h"
79 #include "inet.h"
80
81 R_DH_PARAMS DH_params;
82 unsigned char prime[DH_PRIME_LEN (1024)], generator[DH_PRIME_LEN (1024)];
83 unsigned char your_publicDH[DH_PRIME_LEN (1024)];
84 unsigned char my_publicDH[DH_PRIME_LEN (1024)];
85 unsigned char my_privateDH[DH_PRIME_LEN (1024)];
86 unsigned char agreedKey[DH_PRIME_LEN (1024)];
87 unsigned char RND1[16], RND2[16];
88 int my_privateDH_len = 700;
89 R_ENVELOPE_CTX rsa_context;
90 R_RSA_PUBLIC_KEY pubKey, *keyPtr[5];
91 R_DIGEST_CTX digest_context;
92 unsigned int numPubKeys, keylen;
93
94 int
95 read_status (int fd)
96 {
97 int n;
98 char line[256];
99
100 do
101 {
102 n = readline (fd, line, sizeof (line));
103 if (n < 0)
104 return (577);
105 if (line[0] < '0' || line[0] > '9' ||
106 line[1] < '0' || line[1] > '9' ||
107 line[2] < '0' || line[2] > '9')
108 return (576);
109 }
110 while (n > 3 && line[3] == '-');
111 return (0100 * (line[0] - '0') + 0010 * (line[1] - '0') + (line[2] - '0'));
112 }
113
114 int
115 read_message (FILE * fptr, BUFFER * msg, unsigned char *ID)
116 {
117 char line[256], line2[256];
118 int len;
119
120 while (getline (line, sizeof (line), fptr) != NULL)
121 if (streq (line, begin_remailer))
122 break;
123 getline (line, sizeof (line), fptr); /* length of de-armored message */
124 getline (line, sizeof (line), fptr); /* checksum line */
125
126 while (getline (line, sizeof (line), fptr) != NULL)
127 {
128 if (streq (line, end_remailer))
129 break;
130 if (decode_block (line2, &len, line, strlen (line)) != 0)
131 break;
132 add_to_buffer (msg, line2, len);
133 }
134 if (!streq (line, end_remailer))
135 return (0);
136 memcpy (ID, msg->message, 16);
137 return (1);
138 }
139
140
141 int
142 remailer_info (char *address, long unsigned int *portnum)
143 {
144 REMAILER remailer_list[256];
145 int num_remailers;
146 char *ptr;
147 int flag = 0, j;
148
149 num_remailers = read_remailer_list (remailer_list);
150
151 for (j = 1; j <= num_remailers; j++)
152 {
153 ptr = remailer_list[j].name;
154 if (strieq (address, ptr))
155 { /* We have the key */
156 ptr = strchr (remailer_list[j].abilities, 'S');
157 if (ptr)
158 {
159 flag = 1;
160 if (ptr[1] == '=')
161 sscanf (ptr + 2, "%lu", portnum);
162 }
163 break;
164 }
165 }
166 return (flag);
167 }
168
169 int
170 get_greeting (int fd)
171 {
172 return (read_status (fd) & SC_OK);
173 }
174
175 int
176 query_key_ID (int fd, int flag, unsigned char *ID)
177 {
178 char line[256];
179
180 sprintf (line, "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
181 flag ? "SendKey" : "ConfirmKey", /* if we don't have the key, ask for it */
182 ID[0], ID[1], ID[2], ID[3], ID[4], ID[5], ID[6], ID[7],
183 ID[8], ID[9], ID[10], ID[11], ID[12], ID[13], ID[14], ID[15]);
184 if (!writestr (fd, line))
185 return (0);
186 return (read_status (fd));
187 }
188
189 int
190 get_server_key (int fd, unsigned char *IDstr)
191 {
192 return 0; /* read the RSA key */
193 }
194
195 int
196 send_DH_params (int fd)
197 {
198 BUFFER *buff;
199 unsigned char tmp;
200 int i;
201
202 DH_params.prime = prime;
203 DH_params.generator = generator;
204 if (get_DH (&DH_params))
205 return (0);
206
207 buff = new_buffer ();
208 tmp = DH_params.primeLen;
209 add_to_buffer (buff, &tmp, 1);
210 add_to_buffer (buff, DH_params.prime, DH_PRIME_LEN (1024));
211 tmp = DH_params.generatorLen;
212 add_to_buffer (buff, &tmp, 1);
213 add_to_buffer (buff, DH_params.generator, DH_PRIME_LEN (1024));
214
215 i = writebuf (fd, buff);
216 free_buffer (buff);
217 return (i);
218 }
219
220 int
221 get_server_keyhalf (int fd)
222 {
223 return (readn (fd, your_publicDH, DH_PRIME_LEN (1024)) == DH_PRIME_LEN (1024));
224 }
225
226 /* Generate and send public DH value, Encrypted under their public key */
227 int
228 send_keyhalf (int fd)
229 {
230 int len, keylen, numPubKeys, i;
231 unsigned char *key[5], line[1024], iv[8], tmpbyte;
232 BUFFER *buf;
233
234 buf = new_buffer ();
235
236 /* Calculate DH key half */
237 if (R_SetupDHAgreement (my_publicDH, my_privateDH, my_privateDH_len,
238 &DH_params, random_obj))
239 return (0);
240
241 /* Encrypt key half */
242 numPubKeys = 1;
243 keyPtr[0] = &pubKey;
244 our_randombytes (iv, 8);
245 key[0] = malloc (MAX_ENCRYPTED_KEY_LEN);
246 /* This does not secure the key exchange against active attacks! */
247 if (R_SealInit (&rsa_context, key, &keylen, iv, numPubKeys, keyPtr,
248 EA_DES_EDE3_CBC, random_obj))
249 return (0);
250 add_to_buffer (buf, iv, 8);
251 tmpbyte = keylen;
252 add_to_buffer (buf, &tmpbyte, 1);
253 add_to_buffer (buf, key[0], keylen);
254 R_SealUpdate (&rsa_context, line, &len, my_publicDH, DH_PRIME_LEN (1024));
255 add_to_buffer (buf, line, len);
256 R_SealFinal (&rsa_context, line, &len);
257 add_to_buffer (buf, line, len);
258 i = writebuf (fd, buf);
259 free_buffer (buf);
260 return (i);
261 }
262
263 /* encrypt and send message. */
264 int
265 sock_send_message (int fd, BUFFER * msg)
266 {
267 unsigned char iv[8];
268 unsigned char digest[16];
269
270 if (R_ComputeDHAgreedKey (agreedKey, your_publicDH, my_privateDH,
271 my_privateDH_len, &DH_params))
272 return (0);
273
274 add_to_buffer (msg, make_digest (msg, digest), 16);
275
276 /* pad message out to 8 byte block size */
277 if ((msg->length % 8) != 0)
278 pad_buffer (msg, 8 - (msg->length % 8));
279 our_randombytes (iv, 8);
280 crypt_in_buffer (agreedKey, iv, msg, 1);
281 writen (fd, iv, 8);
282 return (writebuf (fd, msg));
283 }
284
285 /* Was the message recieved correctly? */
286 int
287 get_server_confirmation (int fd)
288 {
289 return (read_status (fd) & SC_OK);
290 }
291
292 void
293 send_quit (int fd)
294 {
295 writestr (fd, "Quit\n");
296 }
297
298 int
299 client_protocol (int fd, BUFFER * msg, int key_needed, unsigned char *ID)
300 {
301 int ok;
302
303 ok = get_greeting (fd);
304 if (!ok)
305 return (ok);
306
307 ok = query_key_ID (fd, key_needed, ID);
308 if (!ok)
309 return (ok);
310
311 if (ok >= 0400)
312 return (0);
313
314 if (ok == SC_SERVERKEY)
315 {
316 ok = get_server_key (fd, ID);
317 if (!ok)
318 return (ok);
319 }
320
321 ok = send_DH_params (fd);
322 if (!ok)
323 return (ok);
324
325 ok = send_keyhalf (fd);
326 if (!ok)
327 return (ok);
328
329 ok = get_server_keyhalf (fd);
330 if (!ok)
331 return (ok);
332
333 ok = sock_send_message (fd, msg);
334 if (!ok)
335 return (ok);
336
337 ok = get_server_confirmation (fd);
338 if (!ok)
339 return (ok);
340
341 send_quit (fd);
342 return (1);
343 }
344
345 int
346 attempt_socket (FILE * fptr)
347 /* Return 0 on fail. Leave file ptr after first line */
348 {
349 int sockfd, key_needed, i, j;
350 struct sockaddr_in serv_addr;
351 struct hostent *hp;
352 char address[256], line[256], hostnym[80], *ptr;
353 unsigned char ID[16];
354 long unsigned int portnum = SERV_TCP_PORT;
355 int sent = 0;
356 BUFFER *msg;
357
358 getline (address, 256, fptr); /* read in address */
359
360 while (!streq (line, "END"))
361 getline (line, sizeof (line), fptr);
362
363 if (!remailer_info (address, &portnum))
364 goto fail;
365
366 msg = new_buffer ();
367
368 if (!read_message (fptr, msg, ID))
369 goto fail;
370
371 key_needed = get_pub_key (ID, &pubKey);
372
373 /*
374 * Fill in the structure "serv_addr" with the address of the
375 * server that we want to connect with.
376 */
377
378 ptr = strstr (address, "@");
379 if (!ptr)
380 goto fail;
381 ptr++;
382 i = strlen (ptr);
383 strcpy (hostnym, ptr);
384 for (j = 0; j < i; j++)
385 {
386 if (hostnym[j] <= ' ')
387 hostnym[j] = 0; /* chop of trailing spaces */
388 }
389 bzero ((char *) &serv_addr, sizeof (serv_addr));
390 serv_addr.sin_family = AF_INET;
391 if ((hp = gethostbyname (hostnym)) == NULL)
392 return (1);
393 memcpy (&serv_addr.sin_addr, hp->h_addr, hp->h_length);
394 serv_addr.sin_port = htons (portnum);
395
396 if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
397 goto fail;
398 if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
399 goto fail;
400
401 signal (SIGPIPE, SIG_IGN);
402 sent = client_protocol (sockfd, msg, key_needed, ID);
403
404 fail:
405 if (sockfd > 0)
406 close (sockfd);
407 rewind (fptr);
408 getline (line, sizeof (line), fptr);
409 free_buffer (msg);
410 return (sent);
411 }

  ViewVC Help
Powered by ViewVC 1.1.5