mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

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