tpgpdb.c - mixmaster - mixmaster 3.0 patched for libressl
 (HTM) 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 */