/[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 185 - (show annotations) (download)
Mon Aug 26 19:17:31 2002 UTC (10 years, 8 months ago) by weaselp
File MIME type: text/plain
File size: 11844 byte(s)
Fixed a bug with reading armored keyrings consisting of more than one armored
block or having comments in front of the one armored block.

The secret pgp keyring is now stored ASCII armored with one key per ascii
armor.

NB: Due to the bug with reading armored keyrings and secring being stored
armored now, it is not adviseable to downgrade mixmaster unless special action
is taked to preserve the secret pgp keyring.
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.9 2002/08/26 19:17:31 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)
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 pgp_armor(keydb->db, PGP_ARMOR_KEY);
126 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 int pgpdb_getkey(int mode, int algo, int *sym, int *mdc, BUFFER *key, BUFFER *userid,
229 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 thisalgo = pgp_getkey(mode, algo, sym, mdc, thiskey, thiskey, thisid, founduid,
268 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 BUFFER *key, *keybak, *userid, *out, *outkey, *outtxt, *pass, *secout;
321 KEYRING *keys;
322 int err = 0, type = 0;
323 LOCK *seclock;
324
325 key = buf_new();
326 out = buf_new();
327 keybak = buf_new();
328 secout = buf_new();
329
330 userid = buf_new();
331 buf_sets(userid, REMAILERNAME);
332 pass = buf_new();
333 buf_sets(pass, PASSPHRASE);
334 outtxt = buf_new();
335 outkey = buf_new();
336
337 #ifdef USE_RSA
338 /* We only want to build RSA keys if we also can do IDEA
339 * This is to not lose any mail should users try our RSA key
340 * with IDEA.
341 */
342 #ifdef USE_IDEA
343 if (force == 2 || (pgpdb_getkey(PK_DECRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL,
344 NULL, NULL, NULL, pass) < 0))
345 pgp_keygen(PGP_ES_RSA, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
346
347 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_ES_RSA, NULL, NULL, NULL, NULL,
348 NULL, NULL, PGPKEY, NULL) < 0))
349 goto end;
350 #endif
351 #endif
352 if (force == 2 || (pgpdb_getkey(PK_DECRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL,
353 NULL, NULL, NULL, pass) < 0))
354 pgp_keygen(PGP_E_ELG, 0, userid, pass, PGPKEY, PGPREMSECRING, 0);
355
356 if (force == 0 && (pgpdb_getkey(PK_ENCRYPT, PGP_E_ELG, NULL, NULL, NULL, NULL,
357 NULL, NULL, PGPKEY, NULL) > 0))
358 goto end;
359
360 /* write RSA and DSA/ElGamal keys separately to make old PGP
361 versions happy */
362 err = -1;
363 for (type = 0; type < 2; type++) {
364 keys = pgpdb_open(PGPREMSECRING, NULL, 0);
365 if (keys == NULL)
366 goto end;
367 while (pgpdb_getnext(keys, key, NULL, userid) != -1) {
368 buf_clear(outtxt);
369 buf_clear(outkey);
370 buf_clear(keybak);
371 buf_cat(keybak, key);
372 if (pgp_makeseckey(key, outtxt, pass,
373 type == 0 ? PGP_ES_RSA : PGP_S_DSA) == 0) {
374 err = 0;
375 buf_appends(secout, "Type Bits/KeyID Date User ID\n");
376 buf_cat(secout, outtxt);
377 buf_nl(secout);
378 pgp_armor(key, PGP_ARMOR_SECKEY);
379 buf_cat(secout, key);
380 buf_nl(secout);
381 }
382 buf_clear(outtxt);
383 if (pgp_makepubkey(keybak, outtxt, outkey, pass,
384 type == 0 ? PGP_ES_RSA : PGP_S_DSA) == 0) {
385 err = 0;
386 buf_appends(out, "Type Bits/KeyID Date User ID\n");
387 buf_cat(out, outtxt);
388 buf_nl(out);
389 pgp_armor(outkey, PGP_ARMOR_KEY);
390 buf_cat(out, outkey);
391 buf_nl(out);
392 }
393 }
394 pgpdb_close(keys);
395 }
396
397 seclock = lockfile(PGPREMSECRING);
398 if (err == 0 && (f = mix_openfile(PGPREMSECRING, "w")) != NULL) {
399 buf_write(secout, f);
400 fclose(f);
401 } else
402 err = -1;
403 unlockfile(seclock);
404 if (err == 0 && (f = mix_openfile(PGPKEY, "w")) != NULL) {
405 buf_write(out, f);
406 fclose(f);
407 } else
408 err = -1;
409 end:
410 buf_free(key);
411 buf_free(keybak);
412 buf_free(out);
413 buf_free(userid);
414 buf_free(pass);
415 buf_free(outtxt);
416 buf_free(outkey);
417 buf_free(secout);
418 return (err);
419 }
420
421 int pgp_rlist(REMAILER remailer[], int n)
422 /* verify that keys are available */
423 {
424 BUFFER *keyring, *p;
425 int i, type, pgpkey[MAXREM];
426
427 keyring = buf_new();
428 p = buf_new();
429 for (i = 1; i < n; i++)
430 pgpkey[i] = 0;
431 if (pgp_readkeyring(keyring, PGPREMPUBRING) == -1)
432 pgp_readkeyring(keyring, PGPREMPUBASC);
433 while ((type = pgp_getpacket(keyring, p)) != -1)
434 if (type == PGP_USERID)
435 for (i = 1; i < n; i++)
436 if (remailer[i].flags.pgp && bufifind(p, remailer[i].name))
437 pgpkey[i] = 1;
438 for (i = 1; i < n; i++)
439 remailer[i].flags.pgp = pgpkey[i];
440 buf_free(p);
441 buf_free(keyring);
442 return (0);
443 }
444
445 int pgp_rkeylist(REMAILER remailer[], int keyid[], int n)
446 /* Step through all remailers and get keyid */
447 {
448 BUFFER *userid;
449 BUFFER *id;
450 int i, err;
451 int mdc, sym;
452
453 userid = buf_new();
454 id = buf_new();
455
456 for (i = 1; i < n; i++) {
457 buf_clear(userid);
458 buf_setf(userid, "<%s>", remailer[i].addr);
459
460 keyid[i]=0;
461 if (remailer[i].flags.pgp) {
462 mdc = sym = 0;
463 buf_clear(id);
464 err = pgpdb_getkey(PK_VERIFY, PGP_ANY, &sym, &mdc, NULL, userid, NULL, id, NULL, NULL);
465 if (id->length == 8) {
466 /* printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
467 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); */
468 keyid[i] = (((((id->data[4] << 8) + id->data[5]) << 8) + id->data[6]) << 8) + id->data[7];
469 }
470 }
471 }
472
473 buf_free(userid);
474 return (0);
475 }
476
477 #endif /* USE_PGP */

  ViewVC Help
Powered by ViewVC 1.1.5