/[pkg-mixmaster]/trunk/Mix/Src/pgpdb.c
ViewVC logotype

Contents of /trunk/Mix/Src/pgpdb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 300 - (show annotations) (download)
Wed Oct 2 08:06:49 2002 UTC (10 years, 7 months ago) by weaselp
File MIME type: text/plain
File size: 15524 byte(s)
Forgot to rewind the buffer
1 /* Mixmaster version 3 -- (C) 1999 Anonymizer Inc.
2
3 Mixmaster may be redistributed and modified under certain conditions.
4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5 ANY KIND, either express or implied. See the file COPYRIGHT for
6 details.
7
8 OpenPGP key database
9 $Id: pgpdb.c,v 1.20 2002/10/02 08:06:49 weaselp Exp $ */
10
11
12 #include "mix3.h"
13 #ifdef USE_PGP
14 #include "pgp.h"
15 #include <assert.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <time.h>
19
20 static int pgp_readkeyring(BUFFER *keys, char *filename)
21 {
22 FILE *keyfile;
23 BUFFER *armored, *line, *tmp;
24 int err = -1;
25
26 if ((keyfile = mix_openfile(filename, "rb")) == NULL)
27 return (err);
28
29 armored = buf_new();
30 buf_read(armored, keyfile);
31 fclose(keyfile);
32 if (pgp_ispacket(armored)) {
33 err = 0;
34 buf_move(keys, armored);
35 } else {
36 line = buf_new();
37 tmp = buf_new();
38
39 while (1) {
40 do
41 if (buf_getline(armored, line) == -1) {
42 goto end_greedy_dearmor;
43 }
44 while (!bufleft(line, begin_pgp)) ;
45 buf_clear(tmp);
46 buf_cat(tmp, line);
47 buf_appends(tmp, "\n");
48 do {
49 if (buf_getline(armored, line) == -1) {
50 goto end_greedy_dearmor;
51 }
52 buf_cat(tmp, line);
53 buf_appends(tmp, "\n");
54 } while (!bufleft(line, end_pgp)) ;
55
56 if (pgp_dearmor(tmp, tmp) == 0) {
57 err = ARMORED;
58 buf_cat(keys, tmp);
59 }
60 }
61 end_greedy_dearmor:
62 buf_free(line);
63 buf_free(tmp);
64
65 }
66 buf_free(armored);
67 return (err);
68 }
69
70 KEYRING *pgpdb_open(char *keyring, BUFFER *encryptkey, int writer, int type)
71 {
72 KEYRING *keydb;
73
74 assert(! ((writer) && (type == PGP_TYPE_UNDEFINED)));
75 keydb = pgpdb_new(keyring, -1, encryptkey, type);
76 #ifndef NDEBUG
77 keydb->writer = writer;
78 #endif
79 if (writer)
80 keydb->lock = lockfile(keyring);
81 keydb->filetype = pgp_readkeyring(keydb->db, keyring);
82 #if 0
83 if (keydb->filetype == -1) {
84 pgpdb_close(keydb);
85 return (NULL);
86 }
87 #endif /* if 0 */
88 if (encryptkey && encryptkey->length && pgp_isconventional(keydb->db) &&
89 pgp_decrypt(keydb->db, encryptkey, NULL, NULL, NULL) < 0) {
90 user_delpass();
91 return (NULL);
92 }
93 return (keydb);
94 }
95
96 KEYRING *pgpdb_new(char *keyring, int filetype, BUFFER *encryptkey, int type)
97 {
98 KEYRING *keydb;
99
100 keydb = malloc(sizeof(KEYRING));
101
102 if (keydb == NULL)
103 return NULL;
104 keydb->db = buf_new();
105 keydb->modified = 0;
106 keydb->lock = NULL;
107 keydb->type = type;
108 strncpy(keydb->filename, keyring, sizeof(keydb->filename));
109 keydb->filetype = filetype;
110 if (encryptkey == NULL)
111 keydb->encryptkey = NULL;
112 else {
113 keydb->encryptkey = buf_new();
114 buf_set(keydb->encryptkey, encryptkey);
115 }
116 return (keydb);
117 }
118
119 int pgpdb_close(KEYRING *keydb)
120 {
121 int err = 0;
122
123 if (keydb->modified) {
124 FILE *f;
125 #ifndef ndebug
126 assert(keydb->writer);
127 #endif
128 if (keydb->encryptkey && keydb->encryptkey->length)
129 pgp_encrypt(PGP_NCONVENTIONAL | PGP_NOARMOR, keydb->db,
130 keydb->encryptkey, NULL, NULL, NULL, NULL);
131 assert(keydb->type == PGP_TYPE_PRIVATE || keydb->type == PGP_TYPE_PUBLIC);
132 if (keydb->filetype == ARMORED)
133 pgp_armor(keydb->db, keydb->type == PGP_TYPE_PUBLIC ? PGP_ARMOR_KEY : PGP_ARMOR_SECKEY);
134 if (keydb->filetype == -1 || (f = mix_openfile(keydb->filename,
135 keydb->filetype ==
136 ARMORED ? "w" : "wb"))
137 == NULL)
138 err = -1;
139 else {
140 err = buf_write(keydb->db, f);
141 fclose(f);
142 }
143 }
144 if (keydb->lock)
145 unlockfile(keydb->lock);
146 if (keydb->encryptkey)
147 buf_free(keydb->encryptkey);
148 buf_free(keydb->db);
149 free(keydb);
150 return (err);
151 }
152
153 int pgpdb_getnext(KEYRING *keydb, BUFFER *key, BUFFER *keyid, BUFFER *userid)
154 /* store next key from keydb with specified keyid/userid in key. */
155 {
156 int found = 0;
157 int type;
158 long ptr;
159 int tempbuf = 0;
160 BUFFER *p, *i, *thisid;
161
162 p = buf_new();
163 i = buf_new();
164 thisid = buf_new();
165
166 if (key == NULL) {
167 tempbuf = 1;
168 key = buf_new();
169 }
170 assert(key != keyid);
171 while (!found) {
172 buf_clear(key);
173 type = pgp_getpacket(keydb->db, key);
174 if (type == -1)
175 break;
176 if (type != PGP_PUBKEY && type != PGP_SECKEY)
177 continue;
178 if ((keyid == NULL || keyid->length == 0) &&
179 (userid == NULL || userid->length == 0))
180 found = 1;
181
182 if (keyid && keyid->length > 0) {
183 pgp_keyid(key, thisid);
184 if (buf_eq(keyid, thisid))
185 found = 1;
186 }
187
188 pgp_packet(key, type);
189
190 while ((ptr = keydb->db->ptr, type = pgp_getpacket(keydb->db, p)) > 0) {
191 switch (type) {
192 case PGP_SECKEY:
193 case PGP_PUBKEY:
194 keydb->db->ptr = ptr;
195 goto nextkey;
196 case PGP_PUBSUBKEY:
197 case PGP_SECSUBKEY:
198 if (keyid && keyid->length > 0) {
199 pgp_keyid(p, thisid);
200 if (buf_eq(keyid, thisid))
201 found = 1;
202 }
203 break;
204 case PGP_USERID:
205 #ifdef DEBUG
206 printf("%s\n", p->data);
207 #endif /* DEBUG */
208 if (userid && userid->length > 0 && bufifind(p, userid->data))
209 found = 1;
210 break;
211 }
212 pgp_packet(p, type);
213 buf_cat(key, p);
214 }
215 nextkey:
216 ;
217 }
218 if (tempbuf)
219 buf_free(key);
220 buf_free(p);
221 buf_free(i);
222 buf_free(thisid);
223 return (found ? 0 : -1);
224 }
225
226 int pgpdb_append(KEYRING *keydb, BUFFER *p)
227 {
228 assert(keydb->lock);
229 #ifndef ndebug
230 assert(keydb->writer);
231 #endif
232 buf_cat(keydb->db, p);
233 keydb->modified = 1;
234 return (0);
235 }
236
237 #define pgp_preferredalgo PGP_ES_RSA
238
239 int pgpdb_getkey(int mode, int algo, int *sym, int *mdc, long *expires, BUFFER *key, BUFFER *userid,
240 BUFFER *founduid, BUFFER *keyid, char *keyring, BUFFER *pass)
241 /* FIXME: This could be changed to return the key with the latest expiration date if
242 * a key is not unique */
243 {
244 KEYRING *r;
245 BUFFER *id, *thisid, *thiskey;
246 int thisalgo, algofound = -1, needpass = 0;
247 int found = 0;
248
249 id = buf_new();
250 thisid = buf_new();
251 thiskey = buf_new();
252 if (keyring)
253 r = pgpdb_open(keyring, pass, 0, PGP_TYPE_UNDEFINED);
254 else
255 switch (mode) {
256 case PK_DECRYPT:
257 case PK_SIGN:
258 r = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE);
259 break;
260 case PK_ENCRYPT:
261 case PK_VERIFY:
262 r = pgpdb_open(PGPREMPUBRING, NULL, 0, PGP_TYPE_PUBLIC);
263 if (r != NULL && r->filetype == -1) {
264 pgpdb_close(r);
265 r = pgpdb_open(PGPREMPUBASC, NULL, 0, PGP_TYPE_PUBLIC);
266 }
267 break;
268 default:
269 r = NULL;
270 }
271 if (r == NULL)
272 goto end;
273
274 for (;;) {
275 /* repeat until success or end of key ring */
276 if (pgpdb_getnext(r, thiskey, keyid, userid) == -1)
277 break;
278 if (keyid) /* pgp_getkey has to chose subkey with given keyid */
279 buf_set(thisid, keyid);
280 thisalgo = pgp_getkey(mode, algo, sym, mdc, expires, thiskey, thiskey, thisid, founduid,
281 pass);
282 if (thisalgo == PGP_PASS)
283 needpass = 1;
284 if (thisalgo > 0) {
285 found++;
286 if ((thisalgo == pgp_preferredalgo && algofound != pgp_preferredalgo
287 && algofound > 0)
288 || (thisalgo != pgp_preferredalgo && algofound == pgp_preferredalgo))
289 found--; /* ignore the non-preferred algorithm */
290 if (found <= 1 || (thisalgo == pgp_preferredalgo &&
291 algofound != pgp_preferredalgo && algofound > 0)) {
292 algofound = thisalgo;
293 if (key)
294 buf_move(key, thiskey);
295 buf_set(id, thisid);
296 }
297 }
298 }
299 pgpdb_close(r);
300 end:
301 if (found < 1) {
302 if (needpass)
303 errlog(DEBUGINFO, "Need passphrase!\n");
304 else if (!sym || *sym != PGP_K_IDEA) { /* kludge: try again with 3DES */
305 if (userid)
306 errlog(NOTICE, "Key %b not found!\n", userid);
307 else if (keyid && keyid->length > 7)
308 errlog(NOTICE, "Key %02X%02X%02X%02X not found!\n", keyid->data[4],
309 keyid->data[5], keyid->data[6], keyid->data[7]);
310 }
311 }
312 if (found > 1) {
313 if (userid)
314 errlog(WARNING, "Key %b not unique!\n", userid);
315 else if (keyid && keyid->length > 7)
316 errlog(ERRORMSG, "Key %02X%02X%02X%02X not unique!\n", keyid->data[4],
317 keyid->data[5], keyid->data[6], keyid->data[7]);
318 else
319 errlog(WARNING, "Key not unique!\n");
320 }
321 if (found && keyid) /* return ID of found key */
322 buf_set(keyid, id);
323
324 buf_free(thiskey);
325 buf_free(thisid);
326 buf_free(id);
327 return (algofound);
328 }
329
330 int pgp_keymgt(int force)
331 {
332 FILE *f = NULL;
333 BUFFER *key, *keybak, *userid, *out, *outkey, *outtxt, *pass, *secout;
334 KEYRING *keys;
335 int err = 0, res, recreate_pubring = 0, dsa_ok = 0;
336 #ifdef USE_RSA
337 #ifdef USE_IDEA
338 int rsa_ok = 0;
339 #endif /* USE_IDEA */
340 #endif /* USE_RSA */
341 long expires;
342 LOCK *seclock;
343
344 key = buf_new();
345 out = buf_new();
346 keybak = buf_new();
347 secout = buf_new();
348
349 userid = buf_new();
350 buf_sets(userid, REMAILERNAME);
351 pass = buf_new();
352 buf_sets(pass, PASSPHRASE);
353 outtxt = buf_new();
354 outkey = buf_new();
355
356 #ifdef USE_RSA
357 /* We only want to build RSA keys if we also can do IDEA
358 * This is to not lose any mail should users try our RSA key
359 * with IDEA.
360 */
361 #ifdef USE_IDEA
362 /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring
363 * which probably works most of the time if the keys are in the correct order
364 * it doesn't return the latest expiration date (or 0) if the key in question
365 * is before another matching key in the keyring tho
366 */
367 res = pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, &expires, NULL, NULL,
368 NULL, NULL, NULL, pass);
369 if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) {
370 rsa_ok = -1;
371 pgp_keygen(PGP_ES_RSA, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
372 };
373
374 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL,
375 NULL, NULL, PGPKEY, NULL) < 0) && rsa_ok == 0)
376 rsa_ok = 1;
377 #endif /* USE_IDEA */
378 #endif /* USE_RSA */
379 /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring
380 * which probably works most of the time if the keys are in the correct order
381 * it doesn't return the latest expiration date (or 0) if the key in question
382 * is before another matching key in the keyring tho
383 */
384 res = pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, &expires, NULL, NULL,
385 NULL, NULL, NULL, pass);
386 if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) {
387 dsa_ok = -1;
388 pgp_keygen(PGP_E_ELG, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
389 }
390
391 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL,
392 NULL, NULL, PGPKEY, NULL) > 0) && dsa_ok == 0)
393 dsa_ok = 1;
394
395 /* No need to rewrite the files - we didn't change a thing */
396 if (
397 #ifdef USE_RSA
398 #ifdef USE_IDEA
399 rsa_ok == 1 &&
400 #endif /* USE_IDEA */
401 #endif /* USE_RSA */
402 dsa_ok == 1)
403 goto end;
404
405 /* write keys one key per armor to make hand editing easy and old PGP
406 * versions happy */
407 err = -1;
408 keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC);
409 if (keys == NULL)
410 recreate_pubring = 1;
411 else {
412 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
413 buf_clear(outtxt);
414 if (pgp_makekeyheader(PGP_PUBKEY, key, outtxt, NULL, PGP_ANY) == 0) {
415 err = 0;
416 buf_appends(out, "Type Bits/KeyID Date User ID\n");
417 buf_cat(out, outtxt);
418 buf_nl(out);
419 pgp_armor(key, PGP_ARMOR_KEY);
420 buf_cat(out, key);
421 buf_nl(out);
422 }
423 }
424 pgpdb_close(keys);
425 }
426 if (err != 0)
427 recreate_pubring = 1;
428 err = -1;
429
430 keys = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE);
431 if (keys == NULL)
432 goto end;
433 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
434 buf_clear(outtxt);
435 buf_clear(outkey);
436 buf_clear(keybak);
437 buf_cat(keybak, key);
438 if (pgp_makekeyheader(PGP_SECKEY, key, outtxt, pass, PGP_ANY) == 0) {
439 err = 0;
440 buf_appends(secout, "Type Bits/KeyID Date User ID\n");
441 buf_cat(secout, outtxt);
442 buf_nl(secout);
443 pgp_armor(key, PGP_ARMOR_SECKEY);
444 buf_cat(secout, key);
445 buf_nl(secout);
446 }
447 buf_clear(outtxt);
448 if (recreate_pubring &&
449 pgp_makepubkey(keybak, outtxt, outkey, pass, PGP_ANY) == 0) {
450 buf_appends(out, "Type Bits/KeyID Date User ID\n");
451 buf_cat(out, outtxt);
452 buf_nl(out);
453 pgp_armor(outkey, PGP_ARMOR_KEY);
454 buf_cat(out, outkey);
455 buf_nl(out);
456 }
457 }
458 pgpdb_close(keys);
459
460 seclock = lockfile(PGPREMSECRING);
461 if (err == 0 && (f = mix_openfile(PGPREMSECRING, "w")) != NULL) {
462 buf_write(secout, f);
463 fclose(f);
464 } else
465 err = -1;
466 unlockfile(seclock);
467 if (err == 0 && (f = mix_openfile(PGPKEY, "w")) != NULL) {
468 buf_write(out, f);
469 fclose(f);
470 } else
471 err = -1;
472 end:
473 buf_free(key);
474 buf_free(keybak);
475 buf_free(out);
476 buf_free(userid);
477 buf_free(pass);
478 buf_free(outtxt);
479 buf_free(outkey);
480 buf_free(secout);
481 return (err);
482 }
483
484 int pgp_latestkeys(BUFFER* outtxt, int algo)
485 /* returns our latest key from pgpkey.txt in the buffer outtxt
486 * with pgp key header, ascii armored
487 *
488 * Can probably be extended to do this for all keys if we pass
489 * the keyring file and the userid
490 *
491 * IN: algo: PGP_ANY, PGP_ES_RSA, PGP_E_ELG, PGP_S_DSA
492 * OUT: outtxt
493 */
494 {
495 int err = -1;
496 long expires_found = 0, expires;
497 BUFFER *key, *userid, *tmptxt;
498 KEYRING *keys;
499
500 key = buf_new();
501 userid = buf_new();
502 buf_sets(userid, REMAILERNAME);
503 tmptxt = buf_new();
504
505 keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC);
506 if (keys != NULL) {
507 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
508 buf_clear(tmptxt);
509 if (pgp_makekeyheader(PGP_PUBKEY, key, tmptxt, NULL, algo) == 0) {
510 buf_rewind(key);
511 pgp_getkey(PK_VERIFY, algo, NULL, NULL, &expires, key, NULL, NULL, NULL, NULL);
512 if (expires == 0 || (expires_found <= expires)) {
513 err = 0;
514 buf_clear(outtxt);
515 buf_appends(outtxt, "Type Bits/KeyID Date User ID\n");
516 buf_cat(outtxt, tmptxt);
517 buf_nl(outtxt);
518 pgp_armor(key, PGP_ARMOR_KEY);
519 buf_cat(outtxt, key);
520 buf_nl(outtxt);
521 expires_found = expires;
522 }
523 }
524 }
525 pgpdb_close(keys);
526 }
527
528 buf_free(key);
529 buf_free(userid);
530 buf_free(tmptxt);
531
532 return (err);
533 }
534
535 int pgp_rlist(REMAILER remailer[], int n)
536 /* verify that keys are available */
537 {
538 BUFFER *keyring, *p;
539 int i, type, pgpkey[MAXREM];
540
541 keyring = buf_new();
542 p = buf_new();
543 for (i = 1; i < n; i++)
544 pgpkey[i] = 0;
545 if (pgp_readkeyring(keyring, PGPREMPUBRING) == -1)
546 pgp_readkeyring(keyring, PGPREMPUBASC);
547 while ((type = pgp_getpacket(keyring, p)) != -1)
548 if (type == PGP_USERID)
549 for (i = 1; i < n; i++)
550 if (remailer[i].flags.pgp && bufifind(p, remailer[i].name))
551 pgpkey[i] = 1;
552 for (i = 1; i < n; i++)
553 remailer[i].flags.pgp = pgpkey[i];
554 buf_free(p);
555 buf_free(keyring);
556 return (0);
557 }
558
559 int pgp_rkeylist(REMAILER remailer[], int keyid[], int n)
560 /* Step through all remailers and get keyid */
561 {
562 BUFFER *userid;
563 BUFFER *id;
564 int i, err;
565
566 userid = buf_new();
567 id = buf_new();
568
569 for (i = 1; i < n; i++) {
570 buf_clear(userid);
571 buf_setf(userid, "<%s>", remailer[i].addr);
572
573 keyid[i]=0;
574 if (remailer[i].flags.pgp) {
575 buf_clear(id);
576 err = pgpdb_getkey(PK_VERIFY, PGP_ANY, NULL, NULL, NULL, NULL, userid, NULL, id, NULL, NULL);
577 if (id->length == 8) {
578 /* printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
579 id->data[0], id->data[1], id->data[2], id->data[3], id->data[4], id->data[5], id->data[6], id->data[7], id->data[8], remailer[i].addr); */
580 keyid[i] = (((((id->data[4] << 8) + id->data[5]) << 8) + id->data[6]) << 8) + id->data[7];
581 }
582 }
583 }
584
585 buf_free(userid);
586 return (0);
587 }
588
589 #endif /* USE_PGP */

  ViewVC Help
Powered by ViewVC 1.1.5