tkeymgt.c - mixmaster - mixmaster 3.0 patched for libressl
HTML 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 }