pgpdb.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 */