/[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 254 - (hide annotations) (download)
Thu Sep 12 17:26:00 2002 UTC (10 years, 8 months ago) by disastry
File MIME type: text/plain
File size: 12034 byte(s)
check expiration and revocation of pgp keys, userids, subkeys

do not encrypt with expired or revoked keys, subkeys
do not sign with expired or revoked keys
do not decrypt with expired keys, subkeys after graceperiod

when encrypting use preferences from latest and/or primary userid

create new pgp keys if current are to expire in overlapperiod
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 disastry 254 $Id: pgpdb.c,v 1.10 2002/09/12 17:26:00 disastry 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     KEYRING *pgpdb_open(char *keyring, BUFFER *encryptkey, int writer)
71     {
72     KEYRING *keydb;
73    
74     keydb = pgpdb_new(keyring, -1, encryptkey);
75     if (writer)
76     keydb->lock = lockfile(keyring);
77     keydb->filetype = pgp_readkeyring(keydb->db, keyring);
78     #if 0
79     if (keydb->filetype == -1) {
80     pgpdb_close(keydb);
81     return (NULL);
82     }
83     #endif
84     if (encryptkey && encryptkey->length && pgp_isconventional(keydb->db) &&
85     pgp_decrypt(keydb->db, encryptkey, NULL, NULL, NULL) < 0) {
86     user_delpass();
87     return (NULL);
88     }
89     return (keydb);
90     }
91    
92     KEYRING *pgpdb_new(char *keyring, int filetype, BUFFER *encryptkey)
93     {
94     KEYRING *keydb;
95    
96     keydb = malloc(sizeof(KEYRING));
97    
98     if (keydb == NULL)
99     return NULL;
100     keydb->db = buf_new();
101     keydb->modified = 0;
102     keydb->lock = NULL;
103     strncpy(keydb->filename, keyring, sizeof(keydb->filename));
104     keydb->filetype = filetype;
105     if (encryptkey == NULL)
106     keydb->encryptkey = NULL;
107     else {
108     keydb->encryptkey = buf_new();
109     buf_set(keydb->encryptkey, encryptkey);
110     }
111     return (keydb);
112     }
113    
114     int pgpdb_close(KEYRING *keydb)
115     {
116     int err = 0;
117    
118     if (keydb->modified) {
119     FILE *f;
120    
121     if (keydb->encryptkey && keydb->encryptkey->length)
122     pgp_encrypt(PGP_NCONVENTIONAL | PGP_NOARMOR, keydb->db,
123     keydb->encryptkey, NULL, NULL, NULL, NULL);
124     if (keydb->filetype == ARMORED)
125 weaselp 182 pgp_armor(keydb->db, PGP_ARMOR_KEY);
126 rabbi 1 if (keydb->filetype == -1 || (f = mix_openfile(keydb->filename,
127     keydb->filetype ==
128     ARMORED ? "w" : "wb"))
129     == NULL)
130     err = -1;
131     else {
132     err = buf_write(keydb->db, f);
133     fclose(f);
134     }
135     }
136     if (keydb->lock)
137     unlockfile(keydb->lock);
138     if (keydb->encryptkey)
139     buf_free(keydb->encryptkey);
140     buf_free(keydb->db);
141     free(keydb);
142     return (err);
143     }
144    
145     int pgpdb_getnext(KEYRING *keydb, BUFFER *key, BUFFER *keyid, BUFFER *userid)
146     /* store next key from keydb with specified keyid/userid in key. */
147     {
148     int found = 0;
149     int type;
150     long ptr;
151     int tempbuf = 0;
152     BUFFER *p, *i, *thisid;
153    
154     p = buf_new();
155     i = buf_new();
156     thisid = buf_new();
157    
158     if (key == NULL) {
159     tempbuf = 1;
160     key = buf_new();
161     }
162     assert(key != keyid);
163     while (!found) {
164     buf_clear(key);
165     type = pgp_getpacket(keydb->db, key);
166     if (type == -1)
167     break;
168     if (type != PGP_PUBKEY && type != PGP_SECKEY)
169     continue;
170     if ((keyid == NULL || keyid->length == 0) &&
171     (userid == NULL || userid->length == 0))
172     found = 1;
173    
174     if (keyid && keyid->length > 0) {
175     pgp_keyid(key, thisid);
176     if (buf_eq(keyid, thisid))
177     found = 1;
178     }
179    
180     pgp_packet(key, type);
181    
182     while ((ptr = keydb->db->ptr, type = pgp_getpacket(keydb->db, p)) > 0) {
183     switch (type) {
184     case PGP_SECKEY:
185     case PGP_PUBKEY:
186     keydb->db->ptr = ptr;
187     goto nextkey;
188     case PGP_PUBSUBKEY:
189     case PGP_SECSUBKEY:
190     if (keyid && keyid->length > 0) {
191     pgp_keyid(p, thisid);
192     if (buf_eq(keyid, thisid))
193     found = 1;
194     }
195     break;
196     case PGP_USERID:
197     #ifdef DEBUG
198     printf("%s\n", p->data);
199     #endif
200     if (userid && userid->length > 0 && bufifind(p, userid->data))
201     found = 1;
202     break;
203     }
204     pgp_packet(p, type);
205     buf_cat(key, p);
206     }
207     nextkey:
208     ;
209     }
210     if (tempbuf)
211     buf_free(key);
212     buf_free(p);
213     buf_free(i);
214     buf_free(thisid);
215     return (found ? 0 : -1);
216     }
217    
218     int pgpdb_append(KEYRING *keydb, BUFFER *p)
219     {
220     assert(keydb->lock);
221     buf_cat(keydb->db, p);
222     keydb->modified = 1;
223     return (0);
224     }
225    
226     #define pgp_preferredalgo PGP_ES_RSA
227    
228 disastry 254 int pgpdb_getkey(int mode, int algo, int *sym, int *mdc, long *expires, BUFFER *key, BUFFER *userid,
229 rabbi 1 BUFFER *founduid, BUFFER *keyid, char *keyring, BUFFER *pass)
230     {
231     KEYRING *r;
232     BUFFER *id, *thisid, *thiskey;
233     int thisalgo, algofound = -1, needpass = 0;
234     int found = 0;
235    
236     id = buf_new();
237     thisid = buf_new();
238     thiskey = buf_new();
239     if (keyring)
240     r = pgpdb_open(keyring, pass, 0);
241     else
242     switch (mode) {
243     case PK_DECRYPT:
244     case PK_SIGN:
245     r = pgpdb_open(PGPREMSECRING, NULL, 0);
246     break;
247     case PK_ENCRYPT:
248     case PK_VERIFY:
249     r = pgpdb_open(PGPREMPUBRING, NULL, 0);
250     if (r != NULL && r->filetype == -1) {
251     pgpdb_close(r);
252     r = pgpdb_open(PGPREMPUBASC, NULL, 0);
253     }
254     break;
255     default:
256     r = NULL;
257     }
258     if (r == NULL)
259     goto end;
260    
261     for (;;) {
262     /* repeat until success or end of key ring */
263     if (pgpdb_getnext(r, thiskey, keyid, userid) == -1)
264     break;
265     if (keyid) /* pgp_getkey has to chose subkey with given keyid */
266     buf_set(thisid, keyid);
267 disastry 254 thisalgo = pgp_getkey(mode, algo, sym, mdc, expires, thiskey, thiskey, thisid, founduid,
268 rabbi 1 pass);
269     if (thisalgo == PGP_PASS)
270     needpass = 1;
271     if (thisalgo > 0) {
272     found++;
273     if ((thisalgo == pgp_preferredalgo && algofound != pgp_preferredalgo
274     && algofound > 0)
275     || (thisalgo != pgp_preferredalgo && algofound == pgp_preferredalgo))
276     found--; /* ignore the non-preferred algorithm */
277     if (found <= 1 || (thisalgo == pgp_preferredalgo &&
278     algofound != pgp_preferredalgo && algofound > 0)) {
279     algofound = thisalgo;
280     if (key)
281     buf_move(key, thiskey);
282     buf_set(id, thisid);
283     }
284     }
285     }
286     pgpdb_close(r);
287     end:
288     if (found < 1) {
289     if (needpass)
290     errlog(DEBUGINFO, "Need passphrase!\n");
291     else if (!sym || *sym != PGP_K_IDEA) { /* kludge: try again with 3DES */
292     if (userid)
293     errlog(NOTICE, "Key %b not found!\n", userid);
294     else if (keyid && keyid->length > 7)
295     errlog(NOTICE, "Key %02X%02X%02X%02X not found!\n", keyid->data[4],
296     keyid->data[5], keyid->data[6], keyid->data[7]);
297     }
298     }
299     if (found > 1) {
300     if (userid)
301     errlog(WARNING, "Key %b not unique!\n", userid);
302     else if (keyid && keyid->length > 7)
303     errlog(ERRORMSG, "Key %02X%02X%02X%02X not unique!\n", keyid->data[4],
304     keyid->data[5], keyid->data[6], keyid->data[7]);
305     else
306     errlog(WARNING, "Key not unique!\n");
307     }
308     if (found && keyid) /* return ID of found key */
309     buf_set(keyid, id);
310    
311     buf_free(thiskey);
312     buf_free(thisid);
313     buf_free(id);
314     return (algofound);
315     }
316    
317     int pgp_keymgt(int force)
318     {
319     FILE *f = NULL;
320 weaselp 185 BUFFER *key, *keybak, *userid, *out, *outkey, *outtxt, *pass, *secout;
321 rabbi 1 KEYRING *keys;
322 disastry 254 int err = 0, type = 0, res;
323     long expires;
324 weaselp 185 LOCK *seclock;
325 rabbi 1
326     key = buf_new();
327     out = buf_new();
328 weaselp 185 keybak = buf_new();
329     secout = buf_new();
330 rabbi 1
331     userid = buf_new();
332     buf_sets(userid, REMAILERNAME);
333     pass = buf_new();
334 rabbi 102 buf_sets(pass, PASSPHRASE);
335 rabbi 1 outtxt = buf_new();
336     outkey = buf_new();
337    
338     #ifdef USE_RSA
339 weaselp 104 /* We only want to build RSA keys if we also can do IDEA
340     * This is to not lose any mail should users try our RSA key
341     * with IDEA.
342     */
343     #ifdef USE_IDEA
344 disastry 254 res = pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, &expires, NULL, NULL,
345     NULL, NULL, NULL, pass);
346     if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL)))
347 rabbi 1 pgp_keygen(PGP_ES_RSA, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
348    
349 disastry 254 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL,
350 rabbi 1 NULL, NULL, PGPKEY, NULL) < 0))
351     goto end;
352     #endif
353 weaselp 104 #endif
354 disastry 254 res = pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, &expires, NULL, NULL,
355     NULL, NULL, NULL, pass);
356     if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL)))
357 rabbi 1 pgp_keygen(PGP_E_ELG, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
358    
359 disastry 254 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL,
360 rabbi 1 NULL, NULL, PGPKEY, NULL) > 0))
361     goto end;
362    
363     /* write RSA and DSA/ElGamal keys separately to make old PGP
364     versions happy */
365     err = -1;
366     for (type = 0; type < 2; type++) {
367     keys = pgpdb_open(PGPREMSECRING, NULL, 0);
368     if (keys == NULL)
369     goto end;
370     while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
371 weaselp 185 buf_clear(outtxt);
372 rabbi 1 buf_clear(outkey);
373 weaselp 185 buf_clear(keybak);
374     buf_cat(keybak, key);
375     if (pgp_makeseckey(key, outtxt, pass,
376     type == 0 ? PGP_ES_RSA : PGP_S_DSA) == 0) {
377     err = 0;
378     buf_appends(secout, "Type Bits/KeyID Date User ID\n");
379     buf_cat(secout, outtxt);
380     buf_nl(secout);
381     pgp_armor(key, PGP_ARMOR_SECKEY);
382     buf_cat(secout, key);
383     buf_nl(secout);
384     }
385 rabbi 1 buf_clear(outtxt);
386 weaselp 185 if (pgp_makepubkey(keybak, outtxt, outkey, pass,
387 rabbi 1 type == 0 ? PGP_ES_RSA : PGP_S_DSA) == 0) {
388     err = 0;
389     buf_appends(out, "Type Bits/KeyID Date User ID\n");
390     buf_cat(out, outtxt);
391 weaselp 185 buf_nl(out);
392 weaselp 182 pgp_armor(outkey, PGP_ARMOR_KEY);
393 rabbi 1 buf_cat(out, outkey);
394     buf_nl(out);
395     }
396     }
397     pgpdb_close(keys);
398     }
399    
400 weaselp 185 seclock = lockfile(PGPREMSECRING);
401     if (err == 0 && (f = mix_openfile(PGPREMSECRING, "w")) != NULL) {
402     buf_write(secout, f);
403     fclose(f);
404     } else
405     err = -1;
406     unlockfile(seclock);
407 rabbi 1 if (err == 0 && (f = mix_openfile(PGPKEY, "w")) != NULL) {
408 weaselp 185 buf_write(out, f);
409     fclose(f);
410     } else
411     err = -1;
412 rabbi 1 end:
413     buf_free(key);
414 weaselp 185 buf_free(keybak);
415 rabbi 1 buf_free(out);
416     buf_free(userid);
417     buf_free(pass);
418     buf_free(outtxt);
419     buf_free(outkey);
420 weaselp 185 buf_free(secout);
421 rabbi 1 return (err);
422     }
423    
424     int pgp_rlist(REMAILER remailer[], int n)
425     /* verify that keys are available */
426     {
427     BUFFER *keyring, *p;
428     int i, type, pgpkey[MAXREM];
429    
430     keyring = buf_new();
431     p = buf_new();
432     for (i = 1; i < n; i++)
433     pgpkey[i] = 0;
434     if (pgp_readkeyring(keyring, PGPREMPUBRING) == -1)
435     pgp_readkeyring(keyring, PGPREMPUBASC);
436     while ((type = pgp_getpacket(keyring, p)) != -1)
437     if (type == PGP_USERID)
438     for (i = 1; i < n; i++)
439     if (remailer[i].flags.pgp && bufifind(p, remailer[i].name))
440     pgpkey[i] = 1;
441     for (i = 1; i < n; i++)
442     remailer[i].flags.pgp = pgpkey[i];
443     buf_free(p);
444     buf_free(keyring);
445     return (0);
446     }
447    
448 weaselp 171 int pgp_rkeylist(REMAILER remailer[], int keyid[], int n)
449     /* Step through all remailers and get keyid */
450     {
451     BUFFER *userid;
452     BUFFER *id;
453     int i, err;
454    
455     userid = buf_new();
456     id = buf_new();
457    
458     for (i = 1; i < n; i++) {
459     buf_clear(userid);
460     buf_setf(userid, "<%s>", remailer[i].addr);
461    
462     keyid[i]=0;
463     if (remailer[i].flags.pgp) {
464     buf_clear(id);
465 disastry 254 err = pgpdb_getkey(PK_VERIFY, PGP_ANY, NULL, NULL, NULL, NULL, userid, NULL, id, NULL, NULL);
466 weaselp 171 if (id->length == 8) {
467     /* printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
468     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); */
469     keyid[i] = (((((id->data[4] << 8) + id->data[5]) << 8) + id->data[6]) << 8) + id->data[7];
470     }
471     }
472     }
473    
474     buf_free(userid);
475     return (0);
476     }
477    
478 rabbi 1 #endif /* USE_PGP */

  ViewVC Help
Powered by ViewVC 1.1.5