tkeymgt.c - mixmaster - mixmaster 3.0 patched for libressl
 (HTM) git clone git://parazyd.org/mixmaster.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
       tkeymgt.c (10624B)
       ---
            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    Key management
            9    $Id: keymgt.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 
           12 #include "mix3.h"
           13 #include <string.h>
           14 #include <time.h>
           15 #include <assert.h>
           16 
           17 int getv2seckey(byte keyid[], BUFFER *key);
           18 static int getv2pubkey(byte keyid[], BUFFER *key);
           19 
           20 int db_getseckey(byte keyid[], BUFFER *key)
           21 {
           22   if (getv2seckey(keyid, key) == -1)
           23     return (-1);
           24   else
           25     return (0);
           26 }
           27 
           28 int db_getpubkey(byte keyid[], BUFFER *key)
           29 {
           30   if (getv2pubkey(keyid, key) == -1)
           31     return (-1);
           32   else
           33     return (0);
           34 }
           35 
           36 /* now accepts NULL keyid too, with NULL keyid any key
           37  * will be matched, with valid passphrase of course */
           38 int getv2seckey(byte keyid[], BUFFER *key)
           39 {
           40   FILE *keyring;
           41   BUFFER *iv, *pass, *temp;
           42   char idstr[KEY_ID_LEN+2];
           43   char line[LINELEN];
           44   int err = -1;
           45   char *res;
           46   time_t created, expires;
           47 
           48   pass = buf_new();
           49   iv = buf_new();
           50   temp = buf_new();
           51   if (keyid)
           52     id_encode(keyid, idstr);
           53   else
           54     idstr[0] = 0;
           55   strcat(idstr, "\n");
           56   if ((keyring = mix_openfile(SECRING, "r")) == NULL) {
           57     errlog(ERRORMSG, "No secret key file!\n");
           58   } else {
           59     while (err == -1) {
           60       buf_clear(key);
           61       if (fgets(line, sizeof(line), keyring) == NULL)
           62         break;
           63       if (strleft(line, begin_key)) {
           64         expires = 0;
           65         created = 0;
           66         do {
           67           res = fgets(line, sizeof(line), keyring);
           68           if (strileft(line, "created:")) {
           69             created = parse_yearmonthday(strchr(line, ':')+1);
           70             if (created == -1)
           71               created = 0;
           72           } else if (strileft(line, "expires:")) {
           73             expires = parse_yearmonthday(strchr(line, ':')+1);
           74             if (expires == -1)
           75               expires = 0;
           76           }
           77           /* Fetch lines until we fail or get a non-header line */
           78         } while ( res != NULL && strchr(line, ':') != NULL );
           79         if (res == NULL)
           80           break;
           81         if (keyid && (strncmp(line, idstr, KEY_ID_LEN) != 0))
           82           continue;
           83         if (created != 0 && (created > time(NULL))) {
           84           errlog(ERRORMSG, "Key is not valid yet (creation date in the future): %s", idstr);
           85           break;
           86         }
           87         if (expires != 0 && (expires + KEYGRACEPERIOD < time(NULL))) {
           88           errlog(ERRORMSG, "Key is expired: %s", idstr);
           89           break;
           90         }
           91         fgets(line, sizeof(line), keyring);
           92         fgets(line, sizeof(line), keyring);
           93         buf_sets(iv, line);
           94         decode(iv, iv);
           95         for (;;) {
           96           if (fgets(line, sizeof(line), keyring) == NULL)
           97             break;
           98           if (strleft(line, end_key)) {
           99             if (decode(key, key) == -1) {
          100               errlog(ERRORMSG, "Corrupt secret key.\n");
          101               break;
          102             }
          103             buf_sets(pass, PASSPHRASE);
          104             digest_md5(pass, pass);
          105             buf_crypt(key, pass, iv, DECRYPT);
          106             err = check_seckey(key, keyid);
          107             if (err == -1)
          108               errlog(ERRORMSG, "Corrupt secret key. Bad passphrase?\n");
          109             break;
          110           }
          111           buf_append(key, line, strlen(line) - 1);
          112         }
          113         break;
          114       }
          115     }
          116     fclose(keyring);
          117   }
          118 
          119   buf_free(pass);
          120   buf_free(iv);
          121   buf_free(temp);
          122   return (err);
          123 }
          124 
          125 static int getv2pubkey(byte keyid[], BUFFER *key)
          126 {
          127   FILE *keyring;
          128   BUFFER *b, *temp, *iv;
          129   char idstr[KEY_ID_LEN+2];
          130   char line[LINELEN];
          131   int err = 0;
          132 
          133   b = buf_new();
          134   iv = buf_new();
          135   temp = buf_new();
          136   id_encode(keyid, idstr);
          137   if ((keyring = mix_openfile(PUBRING, "r")) == NULL) {
          138     errlog(ERRORMSG, "Can't open %s!\n", PUBRING);
          139     err = -1;
          140     goto end;
          141   }
          142   for (;;) {
          143     if (fgets(line, sizeof(line), keyring) == NULL)
          144       break;
          145     if (strleft(line, begin_key)) {
          146       if (fgets(line, sizeof(line), keyring) == NULL)
          147         break;
          148       if ((strlen(line) > 0) && (line[strlen(line)-1] == '\n'))
          149         line[strlen(line)-1] = '\0';
          150       if ((strlen(line) > 0) && (line[strlen(line)-1] == '\r'))
          151         line[strlen(line)-1] = '\0';
          152       if (strncmp(line, idstr, KEY_ID_LEN) != 0)
          153         continue;
          154       fgets(line, sizeof(line), keyring);        /* ignore length */
          155       for (;;) {
          156         if (fgets(line, sizeof(line), keyring) == NULL)
          157           goto done;
          158         if (strleft(line, end_key))
          159           goto done;
          160         buf_append(key, line, strlen(line));
          161       }
          162       break;
          163     }
          164   }
          165 done:
          166   fclose(keyring);
          167 
          168   if (key->length == 0) {
          169     errlog(ERRORMSG, "No such public key: %s\n", idstr);
          170     err = -1;
          171     goto end;
          172   }
          173   err = decode(key, key);
          174   if (err != -1)
          175     err = check_pubkey(key, keyid);
          176   if (err == -1)
          177     errlog(ERRORMSG, "Corrupt public key %s\n", idstr);
          178 end:
          179   buf_free(b);
          180   buf_free(iv);
          181   buf_free(temp);
          182   return (err);
          183 }
          184 
          185 int key(BUFFER *out)
          186 {
          187   int err = -1;
          188   FILE *f;
          189   BUFFER *tmpkey;
          190 
          191   tmpkey = buf_new();
          192 
          193   buf_sets(out, "Subject: Remailer key for ");
          194   buf_appends(out, SHORTNAME);
          195   buf_appends(out, "\n\n");
          196 
          197   keymgt(0);
          198 
          199   conf_premail(out);
          200   buf_nl(out);
          201 
          202 #ifdef USE_PGP
          203   if (PGP) {
          204     if (pgp_latestkeys(tmpkey, PGP_ES_RSA) == 0) {
          205       buf_appends(out, "Here is the RSA PGP key:\n\n");
          206       buf_cat(out, tmpkey);
          207       buf_nl(out);
          208       err = 0;
          209     }
          210     if (pgp_latestkeys(tmpkey, PGP_S_DSA) == 0) {
          211       buf_appends(out, "Here is the DSA PGP key:\n\n");
          212       buf_cat(out, tmpkey);
          213       buf_nl(out);
          214       err = 0;
          215     }
          216   }
          217 #endif /* USE_PGP */
          218   if (MIX) {
          219     if ((f = mix_openfile(KEYFILE, "r")) != NULL) {
          220       buf_appends(out, "Here is the Mixmaster key:\n\n");
          221       buf_appends(out, "=-=-=-=-=-=-=-=-=-=-=-=\n");
          222       buf_read(out, f);
          223       buf_nl(out);
          224       fclose(f);
          225       err = 0;
          226     }
          227   }
          228   if (err == -1 && UNENCRYPTED) {
          229     buf_appends(out, "The remailer accepts unencrypted messages.\n");
          230     err = 0;
          231   }
          232   if (err == -1)
          233     errlog(ERRORMSG, "Cannot create remailer keys!");
          234 
          235   buf_free(tmpkey);
          236 
          237   return (err);
          238 }
          239 
          240 int adminkey(BUFFER *out)
          241 {
          242         int err = -1;
          243         FILE *f;
          244 
          245         buf_sets( out, "Subject: Admin key for the " );
          246         buf_appends( out, SHORTNAME );
          247         buf_appends( out, " remailer\n\n" );
          248 
          249         if ( (f = mix_openfile( ADMKEYFILE, "r" )) != NULL ) {
          250                 buf_read( out, f );
          251                 buf_nl( out );
          252                 fclose( f );
          253                 err = 0;
          254         }
          255 
          256         if ( err == -1 )
          257                 errlog( ERRORMSG, "Can not read admin key file!\n" );
          258 
          259         return err;
          260 }
          261 
          262 int v2keymgt(int force)
          263 /*
          264  * Mixmaster v2 Key Management
          265  *
          266  * This function triggers creation of mix keys (see parameter force) which are
          267  * stored in secring.mix. One public mix key is also written to key.txt. This
          268  * is the key with the latest expiration date (keys with no expiration date
          269  * are always considered newer if they appear later in the secret mix file 
          270  * - key creation appends keys).
          271  *
          272  * force:
          273  *   0, 1: create key when necessary:
          274  *          - no key exists as of yet
          275  *          - old keys are due to expire/already expired
          276  *   2: always create a new mix key.
          277  *
          278  *   (force = 0 is used in mix_daily, and before remailer-key replies)
          279  *   (force = 1 is used by mixmaster -K)
          280  *   (force = 2 is used by mixmaster -G)
          281  */
          282 {
          283   FILE *keyring, *f;
          284   char line[LINELEN];
          285   byte k1[16], k1_found[16];
          286   BUFFER *b, *temp, *iv, *pass, *pk, *pk_found;
          287   int err = 0;
          288   int found, foundnonexpiring;
          289   time_t created, expires, created_found, expires_found;
          290   char *res;
          291 
          292   b = buf_new();
          293   temp = buf_new();
          294   iv = buf_new();
          295   pass = buf_new();
          296   pk = buf_new();
          297   pk_found = buf_new();
          298 
          299   foundnonexpiring = 0;
          300   for (;;) {
          301     found = 0;
          302     created_found = 0;
          303     expires_found = 0;
          304 
          305     keyring = mix_openfile(SECRING, "r");
          306     if (keyring != NULL) {
          307       for (;;) {
          308         if (fgets(line, sizeof(line), keyring) == NULL)
          309           break;
          310         if (strleft(line, begin_key)) {
          311           expires = 0;
          312           created = 0;
          313           do {
          314             res = fgets(line, sizeof(line), keyring);
          315             if (strileft(line, "created:")) {
          316               created = parse_yearmonthday(strchr(line, ':')+1);
          317               if (created == -1)
          318                 created = 0;
          319             } else if (strileft(line, "expires:")) {
          320               expires = parse_yearmonthday(strchr(line, ':')+1);
          321               if (expires == -1)
          322                 expires = 0;
          323             }
          324             /* Fetch lines until we fail or get a non-header line */
          325           } while ( res != NULL && strchr(line, ':') != NULL );
          326           if (res == NULL)
          327             break;
          328           if (((created != 0) && (created > time(NULL))) ||
          329               ((expires != 0) && (expires < time(NULL)))) {
          330             /* Key already is expired or has creation date in the future */
          331             continue;
          332           }
          333           id_decode(line, k1);
          334           fgets(line, sizeof(line), keyring);
          335           if (fgets(line, sizeof(line), keyring) == NULL)
          336             break;
          337           buf_sets(iv, line);
          338           decode(iv, iv);
          339           buf_reset(b);
          340           for (;;) {
          341             if (fgets(line, sizeof(line), keyring) == NULL)
          342               break;
          343             if (strleft(line, end_key))
          344               break;
          345             buf_append(b, line, strlen(line) - 1);
          346           }
          347           if (decode(b, b) == -1)
          348             break;
          349           buf_sets(temp, PASSPHRASE);
          350           digest_md5(temp, pass);
          351           buf_crypt(b, pass, iv, DECRYPT);
          352           buf_clear(pk);
          353           if (seckeytopub(pk, b, k1) == 0) {
          354             found = 1;
          355             if (expires == 0 || (expires - KEYOVERLAPPERIOD >= time(NULL)))
          356               foundnonexpiring = 1;
          357             if (expires == 0 || (expires_found <= expires)) {
          358               buf_clear(pk_found);
          359               buf_cat(pk_found, pk);
          360               memcpy(&k1_found, &k1, sizeof(k1));
          361               expires_found = expires;
          362               created_found = created;
          363             }
          364           }
          365         }
          366       }
          367       fclose(keyring);
          368     }
          369 
          370     if (!foundnonexpiring || (force == 2)) {
          371       v2createkey();
          372       foundnonexpiring = 1;
          373       force = 1;
          374     } else
          375       break;
          376   };
          377 
          378   if (found) {
          379     if ((f = mix_openfile(KEYFILE, "w")) != NULL) {
          380       id_encode(k1_found, line);
          381       fprintf(f, "%s %s %s %s:%s %s%s", SHORTNAME,
          382               REMAILERADDR, line, mixmaster_protocol, VERSION,
          383               MIDDLEMAN ? "M" : "",
          384               NEWS[0] == '\0' ? "C" : (strchr(NEWS, '@') ? "CNm" : "CNp"));
          385       if (created_found) {
          386         struct tm *gt;
          387         gt = gmtime(&created_found);
          388         strftime(line, LINELEN, "%Y-%m-%d", gt);
          389         fprintf(f, " %s", line);
          390         if (expires_found) {
          391           struct tm *gt;
          392           gt = gmtime(&expires_found);
          393           strftime(line, LINELEN, "%Y-%m-%d", gt);
          394           fprintf(f, " %s", line);
          395         }
          396       }
          397       fprintf(f, "\n\n%s\n", begin_key);
          398       id_encode(k1_found, line);
          399       fprintf(f, "%s\n258\n", line);
          400       encode(pk_found, 40);
          401       buf_write(pk_found, f);
          402       fprintf(f, "%s\n\n", end_key);
          403       fclose(f);
          404     }
          405   } else
          406     err = -1;
          407 
          408   buf_free(b);
          409   buf_free(temp);
          410   buf_free(iv);
          411   buf_free(pass);
          412   buf_free(pk);
          413   buf_free(pk_found);
          414 
          415   return (err);
          416 }
          417 
          418 int keymgt(int force)
          419 {
          420   /* force = 0: write key file if there is none
          421      force = 1: update key file
          422      force = 2: generate new key */
          423   int err = 0;
          424 
          425   if (REMAIL || force == 2) {
          426     if (MIX && (err = v2keymgt(force)) == -1)
          427       err = -1;
          428 #ifdef USE_PGP
          429     if (PGP && (err = pgp_keymgt(force)) == -1)
          430       err = -1;
          431 #endif /* USE_PGP */
          432   }
          433   return (err);
          434 }