/[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 288 - (hide annotations) (download)
Fri Sep 27 09:15:54 2002 UTC (10 years, 7 months ago) by weaselp
File MIME type: text/plain
File size: 14067 byte(s)
Do not recreate the public keys from the private keyring if there still is a
public keyring in pgpkey.txt. This means we don't recreate the self signature
on binding keys amoung other things. It probably also means that one can
replace the keys in pgpkey.txt with keys signed by the adminkey and not have
them overriden the next time one does ./mix -[GK] (although I did not test
this).

We still need to fix keymgt to only return the latest keys - this should be
simple once I find out how to get expiration date for a specific key.

There's a small problem with the current keymanagement for PGP keys I guess. If
the latest key is not the last in the keyring we might screw up. Can you verify
this Disastry?
1 rabbi 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 weaselp 288 $Id: pgpdb.c,v 1.17 2002/09/27 09:15:54 weaselp Exp $ */
10 rabbi 1
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 weaselp 115 BUFFER *armored, *line, *tmp;
24 rabbi 1 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 weaselp 115 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 weaselp 185 buf_cat(tmp, line);
47 weaselp 115 buf_appends(tmp, "\n");
48 weaselp 185 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 weaselp 115
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 weaselp 185
65 rabbi 1 }
66     buf_free(armored);
67     return (err);
68     }
69    
70 weaselp 285 KEYRING *pgpdb_open(char *keyring, BUFFER *encryptkey, int writer, int type)
71 rabbi 1 {
72     KEYRING *keydb;
73    
74 weaselp 287 assert(! ((writer) && (type == PGP_TYPE_UNDEFINED)));
75 weaselp 285 keydb = pgpdb_new(keyring, -1, encryptkey, type);
76     #ifndef NDEBUG
77     keydb->writer = writer;
78     #endif
79 rabbi 1 if (writer)
80     keydb->lock = lockfile(keyring);
81     keydb->filetype = pgp_readkeyring(keydb->db, keyring);
82     #if 0
83     if (keydb->filetype == -1) {
84 weaselp 284 pgpdb_close(keydb);
85 rabbi 1 return (NULL);
86     }
87 rabbi 262 #endif /* if 0 */
88 rabbi 1 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 weaselp 285 KEYRING *pgpdb_new(char *keyring, int filetype, BUFFER *encryptkey, int type)
97 rabbi 1 {
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 weaselp 285 keydb->type = type;
108 rabbi 1 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 weaselp 284 int pgpdb_close(KEYRING *keydb)
120 rabbi 1 {
121     int err = 0;
122    
123     if (keydb->modified) {
124     FILE *f;
125 weaselp 285 #ifndef ndebug
126     assert(keydb->writer);
127     #endif
128 rabbi 1 if (keydb->encryptkey && keydb->encryptkey->length)
129     pgp_encrypt(PGP_NCONVENTIONAL | PGP_NOARMOR, keydb->db,
130     keydb->encryptkey, NULL, NULL, NULL, NULL);
131 weaselp 285 assert(keydb->type == PGP_TYPE_PRIVATE || keydb->type == PGP_TYPE_PUBLIC);
132 rabbi 1 if (keydb->filetype == ARMORED)
133 weaselp 285 pgp_armor(keydb->db, keydb->type == PGP_TYPE_PUBLIC ? PGP_ARMOR_KEY : PGP_ARMOR_SECKEY);
134 rabbi 1 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 rabbi 262 #endif /* DEBUG */
208 rabbi 1 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 weaselp 285 #ifndef ndebug
230     assert(keydb->writer);
231     #endif
232 rabbi 1 buf_cat(keydb->db, p);
233     keydb->modified = 1;
234     return (0);
235     }
236    
237     #define pgp_preferredalgo PGP_ES_RSA
238    
239 disastry 254 int pgpdb_getkey(int mode, int algo, int *sym, int *mdc, long *expires, BUFFER *key, BUFFER *userid,
240 rabbi 1 BUFFER *founduid, BUFFER *keyid, char *keyring, BUFFER *pass)
241     {
242     KEYRING *r;
243     BUFFER *id, *thisid, *thiskey;
244     int thisalgo, algofound = -1, needpass = 0;
245     int found = 0;
246    
247     id = buf_new();
248     thisid = buf_new();
249     thiskey = buf_new();
250     if (keyring)
251 weaselp 285 r = pgpdb_open(keyring, pass, 0, PGP_TYPE_UNDEFINED);
252 rabbi 1 else
253     switch (mode) {
254     case PK_DECRYPT:
255     case PK_SIGN:
256 weaselp 285 r = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE);
257 rabbi 1 break;
258     case PK_ENCRYPT:
259     case PK_VERIFY:
260 weaselp 285 r = pgpdb_open(PGPREMPUBRING, NULL, 0, PGP_TYPE_PUBLIC);
261 rabbi 1 if (r != NULL && r->filetype == -1) {
262 weaselp 284 pgpdb_close(r);
263 weaselp 285 r = pgpdb_open(PGPREMPUBASC, NULL, 0, PGP_TYPE_PUBLIC);
264 rabbi 1 }
265     break;
266     default:
267     r = NULL;
268     }
269     if (r == NULL)
270     goto end;
271    
272     for (;;) {
273     /* repeat until success or end of key ring */
274     if (pgpdb_getnext(r, thiskey, keyid, userid) == -1)
275     break;
276     if (keyid) /* pgp_getkey has to chose subkey with given keyid */
277     buf_set(thisid, keyid);
278 disastry 254 thisalgo = pgp_getkey(mode, algo, sym, mdc, expires, thiskey, thiskey, thisid, founduid,
279 rabbi 1 pass);
280     if (thisalgo == PGP_PASS)
281     needpass = 1;
282     if (thisalgo > 0) {
283     found++;
284     if ((thisalgo == pgp_preferredalgo && algofound != pgp_preferredalgo
285     && algofound > 0)
286     || (thisalgo != pgp_preferredalgo && algofound == pgp_preferredalgo))
287     found--; /* ignore the non-preferred algorithm */
288     if (found <= 1 || (thisalgo == pgp_preferredalgo &&
289     algofound != pgp_preferredalgo && algofound > 0)) {
290     algofound = thisalgo;
291     if (key)
292     buf_move(key, thiskey);
293     buf_set(id, thisid);
294     }
295     }
296     }
297 weaselp 284 pgpdb_close(r);
298 rabbi 1 end:
299     if (found < 1) {
300     if (needpass)
301     errlog(DEBUGINFO, "Need passphrase!\n");
302     else if (!sym || *sym != PGP_K_IDEA) { /* kludge: try again with 3DES */
303     if (userid)
304     errlog(NOTICE, "Key %b not found!\n", userid);
305     else if (keyid && keyid->length > 7)
306     errlog(NOTICE, "Key %02X%02X%02X%02X not found!\n", keyid->data[4],
307     keyid->data[5], keyid->data[6], keyid->data[7]);
308     }
309     }
310     if (found > 1) {
311     if (userid)
312     errlog(WARNING, "Key %b not unique!\n", userid);
313     else if (keyid && keyid->length > 7)
314     errlog(ERRORMSG, "Key %02X%02X%02X%02X not unique!\n", keyid->data[4],
315     keyid->data[5], keyid->data[6], keyid->data[7]);
316     else
317     errlog(WARNING, "Key not unique!\n");
318     }
319     if (found && keyid) /* return ID of found key */
320     buf_set(keyid, id);
321    
322     buf_free(thiskey);
323     buf_free(thisid);
324     buf_free(id);
325     return (algofound);
326     }
327    
328     int pgp_keymgt(int force)
329     {
330     FILE *f = NULL;
331 weaselp 185 BUFFER *key, *keybak, *userid, *out, *outkey, *outtxt, *pass, *secout;
332 rabbi 1 KEYRING *keys;
333 weaselp 288 int err = 0, res, recreate_pubring = 0, dsa_ok = 0;
334     #ifdef USE_RSA
335     #ifdef USE_IDEA
336     int rsa_ok = 0;
337     #endif /* USE_IDEA */
338     #endif /* USE_RSA */
339 disastry 254 long expires;
340 weaselp 185 LOCK *seclock;
341 rabbi 1
342     key = buf_new();
343     out = buf_new();
344 weaselp 185 keybak = buf_new();
345     secout = buf_new();
346 rabbi 1
347     userid = buf_new();
348     buf_sets(userid, REMAILERNAME);
349     pass = buf_new();
350 rabbi 102 buf_sets(pass, PASSPHRASE);
351 rabbi 1 outtxt = buf_new();
352     outkey = buf_new();
353    
354     #ifdef USE_RSA
355 weaselp 104 /* We only want to build RSA keys if we also can do IDEA
356     * This is to not lose any mail should users try our RSA key
357     * with IDEA.
358     */
359     #ifdef USE_IDEA
360 weaselp 288 /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring
361     * which probably works most of the time if the keys are in the correct order
362     * it doesn't return the latest expiration date (or 0) if the key in question
363     * is before another matching key in the keyring tho
364     */
365 disastry 254 res = pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, &expires, NULL, NULL,
366     NULL, NULL, NULL, pass);
367 weaselp 288 if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) {
368     rsa_ok = -1;
369 rabbi 1 pgp_keygen(PGP_ES_RSA, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
370 weaselp 288 };
371 rabbi 1
372 disastry 254 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL,
373 weaselp 288 NULL, NULL, PGPKEY, NULL) < 0) && rsa_ok == 0)
374     rsa_ok = 1;
375 rabbi 262 #endif /* USE_IDEA */
376     #endif /* USE_RSA */
377 weaselp 288 /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring
378     * which probably works most of the time if the keys are in the correct order
379     * it doesn't return the latest expiration date (or 0) if the key in question
380     * is before another matching key in the keyring tho
381     */
382 disastry 254 res = pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, &expires, NULL, NULL,
383     NULL, NULL, NULL, pass);
384 weaselp 288 if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) {
385     dsa_ok = -1;
386 rabbi 1 pgp_keygen(PGP_E_ELG, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
387 weaselp 288 }
388 rabbi 1
389 disastry 254 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL,
390 weaselp 288 NULL, NULL, PGPKEY, NULL) > 0) && dsa_ok == 0)
391     dsa_ok = 1;
392    
393     /* No need to rewrite the files - we didn't change a thing */
394     if (
395     #ifdef USE_RSA
396     #ifdef USE_IDEA
397     rsa_ok == 1 &&
398     #endif /* USE_IDEA */
399     #endif /* USE_RSA */
400     dsa_ok == 1)
401 rabbi 1 goto end;
402    
403 weaselp 288 /* write keys one key per armor to make hand editing easy and old PGP
404     * versions happy */
405 rabbi 1 err = -1;
406 weaselp 288 keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC);
407     if (keys == NULL)
408     recreate_pubring = 1;
409     else {
410 rabbi 1 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
411 weaselp 185 buf_clear(outtxt);
412 rabbi 1 buf_clear(outkey);
413 weaselp 288 buf_appends(outtxt, "FIXME");
414     err = 0;
415 weaselp 260 buf_appends(out, "Type Bits/KeyID Date User ID\n");
416 rabbi 1 buf_cat(out, outtxt);
417 weaselp 185 buf_nl(out);
418 weaselp 288 pgp_armor(key, PGP_ARMOR_KEY);
419     buf_cat(out, key);
420 rabbi 1 buf_nl(out);
421     }
422 weaselp 284 pgpdb_close(keys);
423 rabbi 1 }
424 weaselp 288 if (err != 0)
425     recreate_pubring = 1;
426     err = -1;
427 rabbi 1
428 weaselp 288 keys = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE);
429     if (keys == NULL)
430     goto end;
431     while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
432     buf_clear(outtxt);
433     buf_clear(outkey);
434     buf_clear(keybak);
435     buf_cat(keybak, key);
436     if (pgp_makeseckey(key, outtxt, pass, PGP_ANY) == 0) {
437     err = 0;
438     buf_appends(secout, "Type Bits/KeyID Date User ID\n");
439     buf_cat(secout, outtxt);
440     buf_nl(secout);
441     pgp_armor(key, PGP_ARMOR_SECKEY);
442     buf_cat(secout, key);
443     buf_nl(secout);
444     }
445     buf_clear(outtxt);
446     if (recreate_pubring &&
447     pgp_makepubkey(keybak, outtxt, outkey, pass, PGP_ANY) == 0) {
448     buf_appends(out, "Type Bits/KeyID Date User ID\n");
449     buf_cat(out, outtxt);
450     buf_nl(out);
451     pgp_armor(outkey, PGP_ARMOR_KEY);
452     buf_cat(out, outkey);
453     buf_nl(out);
454     }
455     }
456     pgpdb_close(keys);
457    
458 weaselp 185 seclock = lockfile(PGPREMSECRING);
459     if (err == 0 && (f = mix_openfile(PGPREMSECRING, "w")) != NULL) {
460     buf_write(secout, f);
461     fclose(f);
462     } else
463     err = -1;
464     unlockfile(seclock);
465 rabbi 1 if (err == 0 && (f = mix_openfile(PGPKEY, "w")) != NULL) {
466 weaselp 185 buf_write(out, f);
467     fclose(f);
468     } else
469     err = -1;
470 rabbi 1 end:
471     buf_free(key);
472 weaselp 185 buf_free(keybak);
473 rabbi 1 buf_free(out);
474     buf_free(userid);
475     buf_free(pass);
476     buf_free(outtxt);
477     buf_free(outkey);
478 weaselp 185 buf_free(secout);
479 rabbi 1 return (err);
480     }
481    
482     int pgp_rlist(REMAILER remailer[], int n)
483     /* verify that keys are available */
484     {
485     BUFFER *keyring, *p;
486     int i, type, pgpkey[MAXREM];
487    
488     keyring = buf_new();
489     p = buf_new();
490     for (i = 1; i < n; i++)
491     pgpkey[i] = 0;
492     if (pgp_readkeyring(keyring, PGPREMPUBRING) == -1)
493     pgp_readkeyring(keyring, PGPREMPUBASC);
494     while ((type = pgp_getpacket(keyring, p)) != -1)
495     if (type == PGP_USERID)
496     for (i = 1; i < n; i++)
497     if (remailer[i].flags.pgp && bufifind(p, remailer[i].name))
498     pgpkey[i] = 1;
499     for (i = 1; i < n; i++)
500     remailer[i].flags.pgp = pgpkey[i];
501     buf_free(p);
502     buf_free(keyring);
503     return (0);
504     }
505    
506 weaselp 171 int pgp_rkeylist(REMAILER remailer[], int keyid[], int n)
507     /* Step through all remailers and get keyid */
508     {
509     BUFFER *userid;
510     BUFFER *id;
511     int i, err;
512    
513     userid = buf_new();
514     id = buf_new();
515    
516     for (i = 1; i < n; i++) {
517     buf_clear(userid);
518     buf_setf(userid, "<%s>", remailer[i].addr);
519    
520     keyid[i]=0;
521     if (remailer[i].flags.pgp) {
522     buf_clear(id);
523 disastry 254 err = pgpdb_getkey(PK_VERIFY, PGP_ANY, NULL, NULL, NULL, NULL, userid, NULL, id, NULL, NULL);
524 weaselp 171 if (id->length == 8) {
525     /* printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
526     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); */
527     keyid[i] = (((((id->data[4] << 8) + id->data[5]) << 8) + id->data[6]) << 8) + id->data[7];
528     }
529     }
530     }
531    
532     buf_free(userid);
533     return (0);
534     }
535    
536 rabbi 1 #endif /* USE_PGP */

  ViewVC Help
Powered by ViewVC 1.1.5