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 }