A patch is attached.

1. Old secret keys are to be deleted automatically after expiry.
   (I was surprised to see that was not already happening.  An adversary
    capturing your old keyfile seems able to decrypt old messages.)
   This patch overwrites the old file after replacing it with a new one
   that no longer contains the expired keys.

   I encourage operators to check whether they have unwanted secret keys
   still present on their systems.

2. A new command-line option enables you to set a key lifetime.
   mixmaster -G --lifetime=28
   If you do not specify the lifetime (in days) the default is used.

   If a remailer has a long-term key (such as 1 year) as well
   as generating a short-term key each day then someone who wanted to
   could choose a key that was close to expiry and less at risk of
   disclosure.
   (Automation of that would require changes in the client.)

   (Plus a greater volume of 1024-bit keys is more work for anyone
   factoring the remailer keys.)

3. A new file contains all public keys for your remailer.

Keep up the good work.
diff -r -C3 mixmaster-3.0/Src/crypto.c mixmaster-3.0-mymods2/Src/crypto.c
*** mixmaster-3.0/Src/crypto.c  2006-06-24 14:40:39.000000000 +0100
--- mixmaster-3.0-mymods2/Src/crypto.c  2013-10-11 18:41:55.128007032 +0100
***************
*** 285,291 ****
    return (ret);
  }
  
! int v2createkey(void)
  {
    RSA *k;
    BUFFER *b, *ek, *iv;
--- 285,291 ----
    return (ret);
  }
  
! int v2createkey(long int lifeindays)
  {
    RSA *k;
    BUFFER *b, *ek, *iv;
***************
*** 310,317 ****
        gt = gmtime(&now);
        strftime(line, LINELEN, "%Y-%m-%d", gt);
        fprintf(f, "%s\nCreated: %s\n", begin_key, line);
        if (KEYLIFETIME) {
!       now += KEYLIFETIME;
        gt = gmtime(&now);
        strftime(line, LINELEN, "%Y-%m-%d", gt);
        fprintf(f, "Expires: %s\n", line);
--- 310,322 ----
        gt = gmtime(&now);
        strftime(line, LINELEN, "%Y-%m-%d", gt);
        fprintf(f, "%s\nCreated: %s\n", begin_key, line);
+ /* lifeindays comes from the command line and may override
+    the default of KEYLIFETIME (in seconds). */
        if (KEYLIFETIME) {
!         if ((lifeindays>0) && (lifeindays*86400<KEYLIFETIME))
!           now += lifeindays*86400;
!         else
!           now += KEYLIFETIME;
        gt = gmtime(&now);
        strftime(line, LINELEN, "%Y-%m-%d", gt);
        fprintf(f, "Expires: %s\n", line);
diff -r -C3 mixmaster-3.0/Src/keymgt.c mixmaster-3.0-mymods2/Src/keymgt.c
*** mixmaster-3.0/Src/keymgt.c  2006-06-24 14:40:39.000000000 +0100
--- mixmaster-3.0-mymods2/Src/keymgt.c  2013-10-11 21:08:27.491976517 +0100
***************
*** 194,200 ****
    buf_appends(out, SHORTNAME);
    buf_appends(out, "\n\n");
  
!   keymgt(0);
  
    conf_premail(out);
    buf_nl(out);
--- 194,200 ----
    buf_appends(out, SHORTNAME);
    buf_appends(out, "\n\n");
  
!   keymgt(0,0);
  
    conf_premail(out);
    buf_nl(out);
***************
*** 259,265 ****
        return err;
  }
  
! int v2keymgt(int force)
  /*
   * Mixmaster v2 Key Management
   *
--- 259,265 ----
        return err;
  }
  
! int v2keymgt(int force,long int lifeindays)
  /*
   * Mixmaster v2 Key Management
   *
***************
*** 280,292 ****
   *   (force = 2 is used by mixmaster -G)
   */
  {
!   FILE *keyring, *f;
    char line[LINELEN];
    byte k1[16], k1_found[16];
!   BUFFER *b, *temp, *iv, *pass, *pk, *pk_found;
    int err = 0;
    int found, foundnonexpiring;
    time_t created, expires, created_found, expires_found;
    char *res;
  
    b = buf_new();
--- 280,293 ----
   *   (force = 2 is used by mixmaster -G)
   */
  {
!   FILE *keyring, *all_pub, *f;
    char line[LINELEN];
    byte k1[16], k1_found[16];
!   BUFFER *b, *temp, *iv, *pass, *pk, *pk_found, *pk_temp;
    int err = 0;
    int found, foundnonexpiring;
    time_t created, expires, created_found, expires_found;
+   int need2delete=0;
    char *res;
  
    b = buf_new();
***************
*** 302,307 ****
--- 303,309 ----
      created_found = 0;
      expires_found = 0;
  
+     all_pub = mix_openfile("all_my_pubkeys.txt", "w");
      keyring = mix_openfile(SECRING, "r");
      if (keyring != NULL) {
        for (;;) {
***************
*** 325,333 ****
          } while ( res != NULL && strchr(line, ':') != NULL );
          if (res == NULL)
            break;
!         if (((created != 0) && (created > time(NULL))) ||
!             ((expires != 0) && (expires < time(NULL)))) {
!           /* Key already is expired or has creation date in the future */
            continue;
          }
          id_decode(line, k1);
--- 327,339 ----
          } while ( res != NULL && strchr(line, ':') != NULL );
          if (res == NULL)
            break;
!         if ((created != 0) && (created > time(NULL))) {
!           /* Key has creation date in the future */
!           continue;
!           }
!         if  ((expires != 0) && (expires < time(NULL))) {
!           /* Key already is expired.*/
!             need2delete=1;
            continue;
          }
          id_decode(line, k1);
***************
*** 351,356 ****
--- 357,363 ----
          buf_crypt(b, pass, iv, DECRYPT);
          buf_clear(pk);
          if (seckeytopub(pk, b, k1) == 0) {
+             long pos; /* file position */
            found = 1;
            if (expires == 0 || (expires - KEYOVERLAPPERIOD >= time(NULL)))
              foundnonexpiring = 1;
***************
*** 361,374 ****
              expires_found = expires;
              created_found = created;
            }
          }
        }
        }
        fclose(keyring);
      }
  
      if (!foundnonexpiring || (force == 2)) {
!       v2createkey();
        foundnonexpiring = 1;
        force = 1;
      } else
--- 368,390 ----
              expires_found = expires;
              created_found = created;
            }
+             /* write all the pub keys */
+             pk_temp = buf_new();
+           buf_clear(pk_temp);
+           buf_cat(pk_temp, pk);
+             pos=ftell(keyring);
+             write_pubkey_file(keyring,all_pub,pk_temp,k1,created,expires);
+             fseek(keyring,pos,SEEK_SET);
+             buf_free(pk_temp);
          }
        }
        }
        fclose(keyring);
+       fclose(all_pub);
      }
  
      if (!foundnonexpiring || (force == 2)) {
!       v2createkey(lifeindays);
        foundnonexpiring = 1;
        force = 1;
      } else
***************
*** 377,405 ****
  
    if (found) {
      if ((f = mix_openfile(KEYFILE, "w")) != NULL) {
!       id_encode(k1_found, line);
!       fprintf(f, "%s %s %s %s:%s %s%s", SHORTNAME,
!             REMAILERADDR, line, mixmaster_protocol, VERSION,
!             MIDDLEMAN ? "M" : "",
!             NEWS[0] == '\0' ? "C" : (strchr(NEWS, '@') ? "CNm" : "CNp"));
!       if (created_found) {
!       struct tm *gt;
!       gt = gmtime(&created_found);
!       strftime(line, LINELEN, "%Y-%m-%d", gt);
!       fprintf(f, " %s", line);
!       if (expires_found) {
!         struct tm *gt;
!         gt = gmtime(&expires_found);
!         strftime(line, LINELEN, "%Y-%m-%d", gt);
!         fprintf(f, " %s", line);
!       }
!       }
!       fprintf(f, "\n\n%s\n", begin_key);
!       id_encode(k1_found, line);
!       fprintf(f, "%s\n258\n", line);
!       encode(pk_found, 40);
!       buf_write(pk_found, f);
!       fprintf(f, "%s\n\n", end_key);
        fclose(f);
      }
    } else
--- 393,399 ----
  
    if (found) {
      if ((f = mix_openfile(KEYFILE, "w")) != NULL) {
!       
write_pubkey_file(keyring,f,pk_found,k1_found,created_found,expires_found);
        fclose(f);
      }
    } else
***************
*** 412,421 ****
    buf_free(pk);
    buf_free(pk_found);
  
    return (err);
  }
  
! int keymgt(int force)
  {
    /* force = 0: write key file if there is none
       force = 1: update key file
--- 406,418 ----
    buf_free(pk);
    buf_free(pk_found);
  
+   if (need2delete)
+       fprintf(stderr, "key deletion returns %d\n", deleteoldkeys());
+ 
    return (err);
  }
  
! int keymgt(int force,long int lifeindays)
  {
    /* force = 0: write key file if there is none
       force = 1: update key file
***************
*** 423,429 ****
    int err = 0;
  
    if (REMAIL || force == 2) {
!     if (MIX && (err = v2keymgt(force)) == -1)
        err = -1;
  #ifdef USE_PGP
      if (PGP && (err = pgp_keymgt(force)) == -1)
--- 420,426 ----
    int err = 0;
  
    if (REMAIL || force == 2) {
!     if (MIX && (err = v2keymgt(force,lifeindays)) == -1)
        err = -1;
  #ifdef USE_PGP
      if (PGP && (err = pgp_keymgt(force)) == -1)
***************
*** 432,434 ****
--- 429,543 ----
    }
    return (err);
  }
+ 
+ int deleteoldkeys(void)
+ {
+   FILE *keyring, *newsecring;
+   int show=1;
+   int linecount=0;
+   int expires;
+   char line[LINELEN];
+   BUFFER *header;
+   char *res=line;
+ 
+     keyring = mix_openfile(SECRING, "r");
+     if (!keyring)
+         return -1;
+     newsecring = mix_openfile("secring.mix.new", "w");
+     if (!newsecring)
+         return -1;
+ 
+     while (res) {
+         linecount++;
+         if (fgets(line, sizeof(line), keyring) == NULL)
+             break;
+         if (strleft(line, begin_key)) {
+             expires = 0;
+             header = buf_new();
+             buf_clear(header);
+             show = 0; /* store text but do not show it yet */
+           buf_append(header, line, strlen(line));
+             do {
+                 linecount++;
+                 res = fgets(line, sizeof(line), keyring);
+                 switch (show) {
+                 case 0:
+                   buf_append(header, line, strlen(line));
+                     break;
+                 case 1:
+                     fprintf(newsecring, "%s", line);
+                     break;
+                 default:
+                     /* no action */
+                     break;
+                 }
+                 if (strileft(line, "expires:")) {
+                     expires = parse_yearmonthday(strchr(line, ':')+1);
+                     if (expires == -1)
+                         expires = 0;
+                   if  (expires < time(NULL)) {
+                         show=2; /* do not show this key */
+                     } else {
+                         show=1; /* show this key */
+                     }
+                     if (1==show) buf_write(header, newsecring);
+                     buf_free(header);
+                 }
+             /* Fetch lines until end key or eof */
+             if (res == NULL)
+                 break;  /* quit from two loops */
+             } while ( !strileft(line,end_key) );
+             fprintf(newsecring, "\n");
+         }
+     }
+ 
+     if (fclose(keyring)) return -11;
+     if (fclose(newsecring)) return -12;
+     /* replace the file and wipe the old one */
+     keyring = mix_openfile(SECRING, "r+");
+     {
+     /* rename the "secring.mix.new" in the MIXDIR not CWD */
+     char path1[PATHMAX], path2[PATHMAX];
+     mixfile(path1, "secring.mix.new");
+     mixfile(path2, SECRING);
+     if (rename(path1, path2)) return -14;
+     }
+     sync();
+     if (!keyring) return -15;
+     memset(line,'\n',LINELEN-1);
+     line[LINELEN-1]='\0';
+     for (;linecount>0;linecount--)
+         fprintf(keyring,"%s",line);
+     fclose(keyring);
+ return 0;
+ }
+ 
+ int write_pubkey_file(FILE *in, FILE *out, BUFFER *pk_found, byte *k1_found, 
time_t created_found, time_t expires_found)
+ {
+   char line[LINELEN];
+ 
+       id_encode(k1_found, line);
+       fprintf(out, "%s %s %s %s:%s %s%s", SHORTNAME,
+             REMAILERADDR, line, mixmaster_protocol, VERSION,
+             MIDDLEMAN ? "M" : "",
+             NEWS[0] == '\0' ? "C" : (strchr(NEWS, '@') ? "CNm" : "CNp"));
+       if (created_found) {
+       struct tm *gt;
+       gt = gmtime(&created_found);
+       strftime(line, LINELEN, "%Y-%m-%d", gt);
+       fprintf(out, " %s", line);
+       if (expires_found) {
+         struct tm *gt;
+         gt = gmtime(&expires_found);
+         strftime(line, LINELEN, "%Y-%m-%d", gt);
+         fprintf(out, " %s", line);
+       }
+       }
+       fprintf(out, "\n\n%s\n", begin_key);
+       id_encode(k1_found, line);
+       fprintf(out, "%s\n258\n", line);
+       encode(pk_found, 40);
+       buf_write(pk_found, out);
+       fprintf(out, "%s\n\n", end_key);
+ return 0;
+ }
diff -r -C3 mixmaster-3.0/Src/main.c mixmaster-3.0-mymods2/Src/main.c
*** mixmaster-3.0/Src/main.c    2006-06-24 16:52:20.000000000 +0100
--- mixmaster-3.0-mymods2/Src/main.c    2013-10-11 18:41:55.128007032 +0100
***************
*** 45,50 ****
--- 45,51 ----
    int daemon = 0, type_list = 0, nodetach = 0;
    int update_stats = 0, update_pingerlist = 0;
    int never_ask_for_passphrase = 0;
+   long int lifeindays=0;
  
  #ifdef USE_SOCK
    int pop3 = 0;
***************
*** 153,158 ****
--- 154,163 ----
            deflt = 0;
            fprintf(stderr, "%s: No current stats source --%s\n", argv[0], p);
          }
+       } else if (strleft(p, "lifetime") && p[strlen("lifetime")] == '=') {
+             lifeindays=strtol(p + strlen("lifetime") + 1,NULL,10);
+             if (lifeindays<0)
+                 lifeindays=0;
        } else if (strleft(p, "update-stats") && p[strlen("update-stats")] == 
'=') {
          buf_clear(statssrc);
          buf_appendf(statssrc, "%s", (p + strlen("update-stats") + 1));
***************
*** 682,688 ****
  
    if (keygen) {
      check_get_pass(0, never_ask_for_passphrase);
!     keymgt(keygen);
    }
    if (sendpool)
      mix_send();
--- 687,693 ----
  
    if (keygen) {
      check_get_pass(0, never_ask_for_passphrase);
!     keymgt(keygen,lifeindays);
    }
    if (sendpool)
      mix_send();
diff -r -C3 mixmaster-3.0/Src/mix3.h mixmaster-3.0-mymods2/Src/mix3.h
*** mixmaster-3.0/Src/mix3.h    2006-06-24 14:40:39.000000000 +0100
--- mixmaster-3.0-mymods2/Src/mix3.h    2013-10-11 18:41:55.131007041 +0100
***************
*** 210,216 ****
  int digest_rmd160(BUFFER *b, BUFFER *md);
  
  #define KEY_ID_LEN 32
! int keymgt(int force);
  int key(BUFFER *b);
  int adminkey(BUFFER *b);
  
--- 210,216 ----
  int digest_rmd160(BUFFER *b, BUFFER *md);
  
  #define KEY_ID_LEN 32
! int keymgt(int force,long int lifeindays);
  int key(BUFFER *b);
  int adminkey(BUFFER *b);
  
***************
*** 234,240 ****
  int pk_encrypt(BUFFER *plaintext, BUFFER *privkey);
  int check_seckey(BUFFER *buf, const byte id[]);
  int check_pubkey(BUFFER *buf, const byte id[]);
! int v2createkey(void);
  int getv2seckey(byte keyid[], BUFFER *key);
  int seckeytopub(BUFFER *pub, BUFFER *sec, byte keyid[]);
  
--- 234,240 ----
  int pk_encrypt(BUFFER *plaintext, BUFFER *privkey);
  int check_seckey(BUFFER *buf, const byte id[]);
  int check_pubkey(BUFFER *buf, const byte id[]);
! int v2createkey(long int lifeindays);
  int getv2seckey(byte keyid[], BUFFER *key);
  int seckeytopub(BUFFER *pub, BUFFER *sec, byte keyid[]);
  
***************
*** 370,375 ****
--- 370,376 ----
  int v2_merge(BUFFER *mid);
  int mix_armor(BUFFER *in);
  int mix_dearmor(BUFFER *armored, BUFFER *bin);
+ int deleteoldkeys(void);
  
  /* type 1 */
  #define HDRMARK "::"
diff -r -C3 mixmaster-3.0/Src/mix.c mixmaster-3.0-mymods2/Src/mix.c
*** mixmaster-3.0/Src/mix.c     2007-11-19 13:42:41.000000000 +0000
--- mixmaster-3.0-mymods2/Src/mix.c     2013-10-11 18:41:55.133007047 +0100
***************
*** 1022,1028 ****
    pgpmaxexp();
    pool_packetexp();
    stats(NULL);
!   keymgt(0);
    return (0);
  }
  
--- 1022,1028 ----
    pgpmaxexp();
    pool_packetexp();
    stats(NULL);
!   keymgt(0,0);
    return (0);
  }
  
------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60134071&iu=/4140/ostg.clktrk
_______________________________________________
Mixmaster-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixmaster-devel

Reply via email to