tpgpdb.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
tpgpdb.c (15387B)
---
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
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 934 2006-06-24 13:40:39Z rabbi $ */
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(PGPREMPUBASC, NULL, 0, PGP_TYPE_PUBLIC);
263 if (r != NULL && r->filetype == -1) {
264 pgpdb_close(r);
265 r = pgpdb_open(PGPREMPUBRING, 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_IDEA
337 int rsa_ok = 0;
338 #endif /* USE_IDEA */
339 long expires;
340 LOCK *seclock;
341
342 key = buf_new();
343 out = buf_new();
344 keybak = buf_new();
345 secout = buf_new();
346
347 userid = buf_new();
348 buf_sets(userid, REMAILERNAME);
349 pass = buf_new();
350 buf_sets(pass, PASSPHRASE);
351 outtxt = buf_new();
352 outkey = buf_new();
353
354 /* We only want to build RSA keys if we also can do IDEA
355 * This is to not lose any mail should users try our RSA key
356 * with IDEA.
357 */
358 #ifdef USE_IDEA
359 /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring
360 * which probably works most of the time if the keys are in the correct order
361 * it doesn't return the latest expiration date (or 0) if the key in question
362 * is before another matching key in the keyring tho
363 */
364 res = pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, &expires, NULL, NULL,
365 NULL, NULL, NULL, pass);
366 if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) {
367 rsa_ok = -1;
368 pgp_keygen(PGP_ES_RSA, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
369 };
370
371 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL, NULL,
372 NULL, NULL, PGPKEY, NULL) < 0) && rsa_ok == 0)
373 rsa_ok = 1;
374 #endif /* USE_IDEA */
375 /* FIXME: pgpdb_getky returns the expiration date from the last key in the keyring
376 * which probably works most of the time if the keys are in the correct order
377 * it doesn't return the latest expiration date (or 0) if the key in question
378 * is before another matching key in the keyring tho
379 */
380 res = pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, &expires, NULL, NULL,
381 NULL, NULL, NULL, pass);
382 if (force == 2 || res < 0 || (expires > 0 && expires - KEYOVERLAPPERIOD < time(NULL))) {
383 dsa_ok = -1;
384 pgp_keygen(PGP_E_ELG, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
385 }
386
387 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL, NULL,
388 NULL, NULL, PGPKEY, NULL) > 0) && dsa_ok == 0)
389 dsa_ok = 1;
390
391 /* No need to rewrite the files - we didn't change a thing */
392 if (
393 #ifdef USE_IDEA
394 rsa_ok == 1 &&
395 #endif /* USE_IDEA */
396 dsa_ok == 1)
397 goto end;
398
399 /* write keys one key per armor to make hand editing easy and old PGP
400 * versions happy */
401 err = -1;
402 keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC);
403 if (keys == NULL)
404 recreate_pubring = 1;
405 else {
406 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
407 buf_clear(outtxt);
408 if (pgp_makekeyheader(PGP_PUBKEY, key, outtxt, NULL, PGP_ANY) == 0) {
409 err = 0;
410 buf_appends(out, "Type Bits/KeyID Date User ID\n");
411 buf_cat(out, outtxt);
412 buf_nl(out);
413 pgp_armor(key, PGP_ARMOR_KEY);
414 buf_cat(out, key);
415 buf_nl(out);
416 }
417 }
418 pgpdb_close(keys);
419 }
420 if (err != 0)
421 recreate_pubring = 1;
422 err = -1;
423
424 keys = pgpdb_open(PGPREMSECRING, NULL, 0, PGP_TYPE_PRIVATE);
425 if (keys == NULL)
426 goto end;
427 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
428 buf_clear(outtxt);
429 buf_clear(outkey);
430 buf_clear(keybak);
431 buf_cat(keybak, key);
432 if (pgp_makekeyheader(PGP_SECKEY, key, outtxt, pass, PGP_ANY) == 0) {
433 err = 0;
434 buf_appends(secout, "Type Bits/KeyID Date User ID\n");
435 buf_cat(secout, outtxt);
436 buf_nl(secout);
437 pgp_armor(key, PGP_ARMOR_SECKEY);
438 buf_cat(secout, key);
439 buf_nl(secout);
440 }
441 buf_clear(outtxt);
442 if (recreate_pubring &&
443 pgp_makepubkey(keybak, outtxt, outkey, pass, PGP_ANY) == 0) {
444 buf_appends(out, "Type Bits/KeyID Date User ID\n");
445 buf_cat(out, outtxt);
446 buf_nl(out);
447 pgp_armor(outkey, PGP_ARMOR_KEY);
448 buf_cat(out, outkey);
449 buf_nl(out);
450 }
451 }
452 pgpdb_close(keys);
453
454 seclock = lockfile(PGPREMSECRING);
455 if (err == 0 && (f = mix_openfile(PGPREMSECRING, "w")) != NULL) {
456 buf_write(secout, f);
457 fclose(f);
458 } else
459 err = -1;
460 unlockfile(seclock);
461 if (err == 0 && (f = mix_openfile(PGPKEY, "w")) != NULL) {
462 buf_write(out, f);
463 fclose(f);
464 } else
465 err = -1;
466 end:
467 buf_free(key);
468 buf_free(keybak);
469 buf_free(out);
470 buf_free(userid);
471 buf_free(pass);
472 buf_free(outtxt);
473 buf_free(outkey);
474 buf_free(secout);
475 return (err);
476 }
477
478 int pgp_latestkeys(BUFFER* outtxt, int algo)
479 /* returns our latest key from pgpkey.txt in the buffer outtxt
480 * with pgp key header, ascii armored
481 *
482 * Can probably be extended to do this for all keys if we pass
483 * the keyring file and the userid
484 *
485 * IN: algo: PGP_ANY, PGP_ES_RSA, PGP_E_ELG, PGP_S_DSA
486 * OUT: outtxt
487 */
488 {
489 int err = -1;
490 long expires_found = 0, expires;
491 BUFFER *key, *userid, *tmptxt;
492 KEYRING *keys;
493
494 key = buf_new();
495 userid = buf_new();
496 buf_sets(userid, REMAILERNAME);
497 tmptxt = buf_new();
498
499 keys = pgpdb_open(PGPKEY, NULL, 0, PGP_TYPE_PUBLIC);
500 if (keys != NULL) {
501 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
502 buf_clear(tmptxt);
503 if (pgp_makekeyheader(PGP_PUBKEY, key, tmptxt, NULL, algo) == 0) {
504 buf_rewind(key);
505 pgp_getkey(PK_VERIFY, algo, NULL, NULL, &expires, key, NULL, NULL, NULL, NULL);
506 if (expires == 0 || (expires_found <= expires)) {
507 err = 0;
508 buf_clear(outtxt);
509 buf_appends(outtxt, "Type Bits/KeyID Date User ID\n");
510 buf_cat(outtxt, tmptxt);
511 buf_nl(outtxt);
512 pgp_armor(key, PGP_ARMOR_KEY);
513 buf_cat(outtxt, key);
514 buf_nl(outtxt);
515 expires_found = expires;
516 }
517 }
518 }
519 pgpdb_close(keys);
520 }
521
522 buf_free(key);
523 buf_free(userid);
524 buf_free(tmptxt);
525
526 return (err);
527 }
528
529 int pgp_rlist(REMAILER remailer[], int n)
530 /* verify that keys are available */
531 {
532 BUFFER *keyring, *p;
533 int i, type, pgpkey[MAXREM];
534
535 keyring = buf_new();
536 p = buf_new();
537 for (i = 1; i < n; i++)
538 pgpkey[i] = 0;
539 if (pgp_readkeyring(keyring, PGPREMPUBASC) == -1)
540 pgp_readkeyring(keyring, PGPREMPUBRING);
541 while ((type = pgp_getpacket(keyring, p)) != -1)
542 if (type == PGP_USERID)
543 for (i = 1; i < n; i++)
544 if (remailer[i].flags.pgp && bufifind(p, remailer[i].name))
545 pgpkey[i] = 1;
546 for (i = 1; i < n; i++)
547 remailer[i].flags.pgp = pgpkey[i];
548 buf_free(p);
549 buf_free(keyring);
550 return (0);
551 }
552
553 int pgp_rkeylist(REMAILER remailer[], int keyid[], int n)
554 /* Step through all remailers and get keyid */
555 {
556 BUFFER *userid;
557 BUFFER *id;
558 int i, err;
559
560 userid = buf_new();
561 id = buf_new();
562
563 for (i = 1; i < n; i++) {
564 buf_clear(userid);
565 buf_setf(userid, "<%s>", remailer[i].addr);
566
567 keyid[i]=0;
568 if (remailer[i].flags.pgp) {
569 buf_clear(id);
570 err = pgpdb_getkey(PK_VERIFY, PGP_ANY, NULL, NULL, NULL, NULL, userid, NULL, id, NULL, NULL);
571 if (id->length == 8) {
572 /* printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
573 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); */
574 keyid[i] = (((((id->data[4] << 8) + id->data[5]) << 8) + id->data[6]) << 8) + id->data[7];
575 }
576 }
577 }
578
579 buf_free(userid);
580 return (0);
581 }
582
583 #endif /* USE_PGP */