mixmaster

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

keymgt.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 }