diff options
Diffstat (limited to 'src/mint/taler-mint-keyup.c')
-rw-r--r-- | src/mint/taler-mint-keyup.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/src/mint/taler-mint-keyup.c b/src/mint/taler-mint-keyup.c new file mode 100644 index 000000000..8a1a77882 --- /dev/null +++ b/src/mint/taler-mint-keyup.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* | ||
2 | This file is part of TALER | ||
3 | (C) 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | TALER is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | TALER is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file taler-mint-keyup.c | ||
19 | * @brief Update the mint's keys for coins and signatures, | ||
20 | * using the mint's offline master key. | ||
21 | * @author Florian Dold | ||
22 | * @author Benedikt Mueller | ||
23 | */ | ||
24 | |||
25 | #include <platform.h> | ||
26 | #include <gnunet/gnunet_util_lib.h> | ||
27 | #include "taler_util.h" | ||
28 | #include "taler_signatures.h" | ||
29 | #include "mint.h" | ||
30 | |||
31 | #define HASH_CUTOFF 20 | ||
32 | |||
33 | /** | ||
34 | * Macro to round microseconds to seconds in GNUNET_TIME_* structs. | ||
35 | */ | ||
36 | #define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000); | ||
37 | |||
38 | |||
39 | GNUNET_NETWORK_STRUCT_BEGIN | ||
40 | |||
41 | struct CoinTypeNBO | ||
42 | { | ||
43 | struct GNUNET_TIME_RelativeNBO duration_spend; | ||
44 | struct GNUNET_TIME_RelativeNBO duration_withdraw; | ||
45 | struct TALER_AmountNBO value; | ||
46 | struct TALER_AmountNBO fee_withdraw; | ||
47 | struct TALER_AmountNBO fee_deposit; | ||
48 | struct TALER_AmountNBO fee_refresh; | ||
49 | }; | ||
50 | |||
51 | GNUNET_NETWORK_STRUCT_END | ||
52 | |||
53 | struct CoinTypeParams | ||
54 | { | ||
55 | struct GNUNET_TIME_Relative duration_spend; | ||
56 | struct GNUNET_TIME_Relative duration_withdraw; | ||
57 | struct GNUNET_TIME_Relative duration_overlap; | ||
58 | struct TALER_Amount value; | ||
59 | struct TALER_Amount fee_withdraw; | ||
60 | struct TALER_Amount fee_deposit; | ||
61 | struct TALER_Amount fee_refresh; | ||
62 | struct GNUNET_TIME_Absolute anchor; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Filename of the master private key. | ||
68 | */ | ||
69 | static char *masterkeyfile; | ||
70 | |||
71 | /** | ||
72 | * Director of the mint, containing the keys. | ||
73 | */ | ||
74 | static char *mintdir; | ||
75 | |||
76 | /** | ||
77 | * Time to pretend when the key update is executed. | ||
78 | */ | ||
79 | static char *pretend_time_str; | ||
80 | |||
81 | /** | ||
82 | * Handle to the mint's configuration | ||
83 | */ | ||
84 | static struct GNUNET_CONFIGURATION_Handle *kcfg; | ||
85 | |||
86 | /** | ||
87 | * Time when the key update is executed. Either the actual current time, or a | ||
88 | * pretended time. | ||
89 | */ | ||
90 | static struct GNUNET_TIME_Absolute now; | ||
91 | |||
92 | /** | ||
93 | * Master private key of the mint. | ||
94 | */ | ||
95 | static struct GNUNET_CRYPTO_EddsaPrivateKey *master_priv; | ||
96 | |||
97 | /** | ||
98 | * Master public key of the mint. | ||
99 | */ | ||
100 | static struct GNUNET_CRYPTO_EddsaPublicKey *master_pub; | ||
101 | |||
102 | /** | ||
103 | * Until what time do we provide keys? | ||
104 | */ | ||
105 | static struct GNUNET_TIME_Absolute lookahead_sign_stamp; | ||
106 | |||
107 | |||
108 | int | ||
109 | config_get_denom (const char *section, const char *option, struct TALER_Amount *denom) | ||
110 | { | ||
111 | char *str; | ||
112 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, section, option, &str)) | ||
113 | return GNUNET_NO; | ||
114 | if (GNUNET_OK != TALER_string_to_amount (str, denom)) | ||
115 | return GNUNET_SYSERR; | ||
116 | return GNUNET_OK; | ||
117 | } | ||
118 | |||
119 | |||
120 | char * | ||
121 | get_signkey_dir () | ||
122 | { | ||
123 | char *dir; | ||
124 | size_t len; | ||
125 | len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS), mintdir); | ||
126 | GNUNET_assert (len > 0); | ||
127 | return dir; | ||
128 | } | ||
129 | |||
130 | |||
131 | char * | ||
132 | get_signkey_file (struct GNUNET_TIME_Absolute start) | ||
133 | { | ||
134 | char *dir; | ||
135 | size_t len; | ||
136 | len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS DIR_SEPARATOR_STR "%llu"), | ||
137 | mintdir, (long long) start.abs_value_us); | ||
138 | GNUNET_assert (len > 0); | ||
139 | return dir; | ||
140 | } | ||
141 | |||
142 | |||
143 | |||
144 | /** | ||
145 | * Hash the data defining the coin type. | ||
146 | * Exclude information that may not be the same for all | ||
147 | * instances of the coin type (i.e. the anchor, overlap). | ||
148 | */ | ||
149 | void | ||
150 | hash_coin_type (const struct CoinTypeParams *p, struct GNUNET_HashCode *hash) | ||
151 | { | ||
152 | struct CoinTypeNBO p_nbo; | ||
153 | |||
154 | memset (&p_nbo, 0, sizeof (struct CoinTypeNBO)); | ||
155 | |||
156 | p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend); | ||
157 | p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw); | ||
158 | p_nbo.value = TALER_amount_hton (p->value); | ||
159 | p_nbo.fee_withdraw = TALER_amount_hton (p->fee_withdraw); | ||
160 | p_nbo.fee_deposit = TALER_amount_hton (p->fee_deposit); | ||
161 | p_nbo.fee_refresh = TALER_amount_hton (p->fee_refresh); | ||
162 | |||
163 | GNUNET_CRYPTO_hash (&p_nbo, sizeof (struct CoinTypeNBO), hash); | ||
164 | } | ||
165 | |||
166 | |||
167 | static const char * | ||
168 | get_cointype_dir (const struct CoinTypeParams *p) | ||
169 | { | ||
170 | static char dir[4096]; | ||
171 | size_t len; | ||
172 | struct GNUNET_HashCode hash; | ||
173 | char *hash_str; | ||
174 | char *val_str; | ||
175 | unsigned int i; | ||
176 | |||
177 | hash_coin_type (p, &hash); | ||
178 | hash_str = TALER_data_to_string_alloc (&hash, sizeof (struct GNUNET_HashCode)); | ||
179 | GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1); | ||
180 | GNUNET_assert (NULL != hash_str); | ||
181 | hash_str[HASH_CUTOFF] = 0; | ||
182 | |||
183 | val_str = TALER_amount_to_string (p->value); | ||
184 | for (i = 0; i < strlen (val_str); i++) | ||
185 | if (':' == val_str[i] || '.' == val_str[i]) | ||
186 | val_str[i] = '_'; | ||
187 | |||
188 | len = GNUNET_snprintf (dir, sizeof (dir), | ||
189 | ("%s" DIR_SEPARATOR_STR DIR_DENOMKEYS DIR_SEPARATOR_STR "%s-%s"), | ||
190 | mintdir, val_str, hash_str); | ||
191 | GNUNET_assert (len > 0); | ||
192 | GNUNET_free (hash_str); | ||
193 | return dir; | ||
194 | } | ||
195 | |||
196 | |||
197 | static const char * | ||
198 | get_cointype_file (struct CoinTypeParams *p, | ||
199 | struct GNUNET_TIME_Absolute start) | ||
200 | { | ||
201 | const char *dir; | ||
202 | static char filename[4096]; | ||
203 | size_t len; | ||
204 | dir = get_cointype_dir (p); | ||
205 | len = GNUNET_snprintf (filename, sizeof (filename), ("%s" DIR_SEPARATOR_STR "%llu"), | ||
206 | dir, (unsigned long long) start.abs_value_us); | ||
207 | GNUNET_assert (len > 0); | ||
208 | return filename; | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Get the latest key file from the past. | ||
214 | * | ||
215 | * @param cls closure | ||
216 | * @param filename complete filename (absolute path) | ||
217 | * @return #GNUNET_OK to continue to iterate, | ||
218 | * #GNUNET_NO to stop iteration with no error, | ||
219 | * #GNUNET_SYSERR to abort iteration with error! | ||
220 | */ | ||
221 | static int | ||
222 | get_anchor_iter (void *cls, | ||
223 | const char *filename) | ||
224 | { | ||
225 | struct GNUNET_TIME_Absolute stamp; | ||
226 | struct GNUNET_TIME_Absolute *anchor = cls; | ||
227 | const char *base; | ||
228 | char *end = NULL; | ||
229 | |||
230 | base = GNUNET_STRINGS_get_short_name (filename); | ||
231 | stamp.abs_value_us = strtol (base, &end, 10); | ||
232 | |||
233 | if ((NULL == end) || (0 != *end)) | ||
234 | { | ||
235 | fprintf(stderr, "Ignoring unexpected file '%s'.\n", filename); | ||
236 | return GNUNET_OK; | ||
237 | } | ||
238 | |||
239 | // TODO: check if it's actually a valid key file | ||
240 | |||
241 | if ((stamp.abs_value_us <= now.abs_value_us) && (stamp.abs_value_us > anchor->abs_value_us)) | ||
242 | *anchor = stamp; | ||
243 | |||
244 | return GNUNET_OK; | ||
245 | } | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Get the timestamp where the first new key should be generated. | ||
250 | * Relies on correctly named key files. | ||
251 | * | ||
252 | * @param dir directory with the signed stuff | ||
253 | * @param duration how long is one key valid? | ||
254 | * @param overlap what's the overlap between the keys validity period? | ||
255 | * @param[out] anchor the timestamp where the first new key should be generated | ||
256 | */ | ||
257 | void | ||
258 | get_anchor (const char *dir, | ||
259 | struct GNUNET_TIME_Relative duration, | ||
260 | struct GNUNET_TIME_Relative overlap, | ||
261 | struct GNUNET_TIME_Absolute *anchor) | ||
262 | { | ||
263 | GNUNET_assert (0 == duration.rel_value_us % 1000000); | ||
264 | GNUNET_assert (0 == overlap.rel_value_us % 1000000); | ||
265 | if (GNUNET_YES != GNUNET_DISK_directory_test (dir, GNUNET_YES)) | ||
266 | { | ||
267 | *anchor = now; | ||
268 | printf ("Can't look for anchor (%s)\n", dir); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | *anchor = GNUNET_TIME_UNIT_ZERO_ABS; | ||
273 | if (-1 == GNUNET_DISK_directory_scan (dir, &get_anchor_iter, anchor)) | ||
274 | { | ||
275 | *anchor = now; | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | if ((GNUNET_TIME_absolute_add (*anchor, duration)).abs_value_us < now.abs_value_us) | ||
280 | { | ||
281 | // there's no good anchor, start from now | ||
282 | // (existing keys are too old) | ||
283 | *anchor = now; | ||
284 | } | ||
285 | else if (anchor->abs_value_us != now.abs_value_us) | ||
286 | { | ||
287 | // we have a good anchor | ||
288 | *anchor = GNUNET_TIME_absolute_add (*anchor, duration); | ||
289 | *anchor = GNUNET_TIME_absolute_subtract (*anchor, overlap); | ||
290 | } | ||
291 | // anchor is now the stamp where we need to create a new key | ||
292 | } | ||
293 | |||
294 | static void | ||
295 | create_signkey_issue (struct GNUNET_TIME_Absolute start, | ||
296 | struct GNUNET_TIME_Relative duration, | ||
297 | struct TALER_MINT_SignKeyIssue *issue) | ||
298 | { | ||
299 | struct GNUNET_CRYPTO_EddsaPrivateKey *priv; | ||
300 | |||
301 | priv = GNUNET_CRYPTO_eddsa_key_create (); | ||
302 | GNUNET_assert (NULL != priv); | ||
303 | issue->signkey_priv = *priv; | ||
304 | GNUNET_free (priv); | ||
305 | issue->master_pub = *master_pub; | ||
306 | issue->start = GNUNET_TIME_absolute_hton (start); | ||
307 | issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start, duration)); | ||
308 | |||
309 | GNUNET_CRYPTO_eddsa_key_get_public (&issue->signkey_priv, &issue->signkey_pub); | ||
310 | |||
311 | issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY); | ||
312 | issue->purpose.size = htonl (sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose)); | ||
313 | |||
314 | if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &issue->purpose, &issue->signature)) | ||
315 | { | ||
316 | GNUNET_abort (); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | |||
321 | static int | ||
322 | check_signkey_valid (const char *signkey_filename) | ||
323 | { | ||
324 | // FIXME: do real checks | ||
325 | return GNUNET_OK; | ||
326 | } | ||
327 | |||
328 | |||
329 | int | ||
330 | mint_keys_update_signkeys () | ||
331 | { | ||
332 | struct GNUNET_TIME_Relative signkey_duration; | ||
333 | struct GNUNET_TIME_Absolute anchor; | ||
334 | char *signkey_dir; | ||
335 | |||
336 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_keys", "signkey_duration", &signkey_duration)) | ||
337 | { | ||
338 | fprintf (stderr, "Can't read config value mint_keys.signkey_duration\n"); | ||
339 | return GNUNET_SYSERR; | ||
340 | } | ||
341 | ROUND_TO_SECS (signkey_duration, rel_value_us); | ||
342 | signkey_dir = get_signkey_dir (); | ||
343 | // make sure the directory exists | ||
344 | if (GNUNET_OK != GNUNET_DISK_directory_create (signkey_dir)) | ||
345 | { | ||
346 | fprintf (stderr, "Cant create signkey dir\n"); | ||
347 | return GNUNET_SYSERR; | ||
348 | } | ||
349 | |||
350 | get_anchor (signkey_dir, signkey_duration, GNUNET_TIME_UNIT_ZERO, &anchor); | ||
351 | |||
352 | while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) { | ||
353 | char *skf; | ||
354 | skf = get_signkey_file (anchor); | ||
355 | if (GNUNET_YES != GNUNET_DISK_file_test (skf)) | ||
356 | { | ||
357 | struct TALER_MINT_SignKeyIssue signkey_issue; | ||
358 | ssize_t nwrite; | ||
359 | printf ("Generating signing key for %s.\n", GNUNET_STRINGS_absolute_time_to_string (anchor)); | ||
360 | create_signkey_issue (anchor, signkey_duration, &signkey_issue); | ||
361 | nwrite = GNUNET_DISK_fn_write (skf, &signkey_issue, sizeof (struct TALER_MINT_SignKeyIssue), | ||
362 | (GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ)); | ||
363 | if (nwrite != sizeof (struct TALER_MINT_SignKeyIssue)) | ||
364 | { | ||
365 | fprintf (stderr, "Can't write to file '%s'\n", skf); | ||
366 | return GNUNET_SYSERR; | ||
367 | } | ||
368 | } | ||
369 | else if (GNUNET_OK != check_signkey_valid (skf)) | ||
370 | { | ||
371 | return GNUNET_SYSERR; | ||
372 | } | ||
373 | anchor = GNUNET_TIME_absolute_add (anchor, signkey_duration); | ||
374 | } | ||
375 | return GNUNET_OK; | ||
376 | } | ||
377 | |||
378 | |||
379 | int | ||
380 | get_cointype_params (const char *ct, struct CoinTypeParams *params) | ||
381 | { | ||
382 | const char *dir; | ||
383 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_withdraw", ct, ¶ms->duration_withdraw)) | ||
384 | { | ||
385 | fprintf (stderr, "Withdraw duration not given for coin type '%s'\n", ct); | ||
386 | return GNUNET_SYSERR; | ||
387 | } | ||
388 | ROUND_TO_SECS (params->duration_withdraw, rel_value_us); | ||
389 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_spend", ct, ¶ms->duration_spend)) | ||
390 | { | ||
391 | fprintf (stderr, "Spend duration not given for coin type '%s'\n", ct); | ||
392 | return GNUNET_SYSERR; | ||
393 | } | ||
394 | ROUND_TO_SECS (params->duration_spend, rel_value_us); | ||
395 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_overlap", ct, ¶ms->duration_overlap)) | ||
396 | { | ||
397 | fprintf (stderr, "Overlap duration not given for coin type '%s'\n", ct); | ||
398 | return GNUNET_SYSERR; | ||
399 | } | ||
400 | ROUND_TO_SECS (params->duration_overlap, rel_value_us); | ||
401 | |||
402 | if (GNUNET_OK != config_get_denom ("mint_denom_value", ct, ¶ms->value)) | ||
403 | { | ||
404 | fprintf (stderr, "Value not given for coin type '%s'\n", ct); | ||
405 | return GNUNET_SYSERR; | ||
406 | } | ||
407 | |||
408 | if (GNUNET_OK != config_get_denom ("mint_denom_fee_withdraw", ct, ¶ms->fee_withdraw)) | ||
409 | { | ||
410 | fprintf (stderr, "Withdraw fee not given for coin type '%s'\n", ct); | ||
411 | return GNUNET_SYSERR; | ||
412 | } | ||
413 | |||
414 | if (GNUNET_OK != config_get_denom ("mint_denom_fee_deposit", ct, ¶ms->fee_deposit)) | ||
415 | { | ||
416 | fprintf (stderr, "Deposit fee not given for coin type '%s'\n", ct); | ||
417 | return GNUNET_SYSERR; | ||
418 | } | ||
419 | |||
420 | if (GNUNET_OK != config_get_denom ("mint_denom_fee_refresh", ct, ¶ms->fee_refresh)) | ||
421 | { | ||
422 | fprintf (stderr, "Deposit fee not given for coin type '%s'\n", ct); | ||
423 | return GNUNET_SYSERR; | ||
424 | } | ||
425 | |||
426 | dir = get_cointype_dir (params); | ||
427 | get_anchor (dir, params->duration_spend, params->duration_overlap, ¶ms->anchor); | ||
428 | return GNUNET_OK; | ||
429 | } | ||
430 | |||
431 | |||
432 | static void | ||
433 | create_denomkey_issue (struct CoinTypeParams *params, struct TALER_MINT_DenomKeyIssue *dki) | ||
434 | { | ||
435 | GNUNET_assert (NULL != (dki->denom_priv = TALER_RSA_key_create ())); | ||
436 | TALER_RSA_key_get_public (dki->denom_priv, &dki->denom_pub); | ||
437 | dki->master = *master_pub; | ||
438 | dki->start = GNUNET_TIME_absolute_hton (params->anchor); | ||
439 | dki->expire_withdraw = | ||
440 | GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor, | ||
441 | params->duration_withdraw)); | ||
442 | dki->expire_spend = | ||
443 | GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor, | ||
444 | params->duration_spend)); | ||
445 | dki->value = TALER_amount_hton (params->value); | ||
446 | dki->fee_withdraw = TALER_amount_hton (params->fee_withdraw); | ||
447 | dki->fee_deposit = TALER_amount_hton (params->fee_deposit); | ||
448 | dki->fee_refresh = TALER_amount_hton (params->fee_refresh); | ||
449 | |||
450 | dki->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM); | ||
451 | dki->purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssue) - offsetof (struct TALER_MINT_DenomKeyIssue, purpose)); | ||
452 | |||
453 | if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &dki->purpose, &dki->signature)) | ||
454 | { | ||
455 | GNUNET_abort (); | ||
456 | } | ||
457 | } | ||
458 | |||
459 | |||
460 | static int | ||
461 | check_cointype_valid (const char *filename, struct CoinTypeParams *params) | ||
462 | { | ||
463 | // FIXME: add real checks | ||
464 | return GNUNET_OK; | ||
465 | } | ||
466 | |||
467 | |||
468 | int | ||
469 | mint_keys_update_cointype (const char *coin_alias) | ||
470 | { | ||
471 | struct CoinTypeParams p; | ||
472 | const char *cointype_dir; | ||
473 | |||
474 | if (GNUNET_OK != get_cointype_params (coin_alias, &p)) | ||
475 | return GNUNET_SYSERR; | ||
476 | |||
477 | cointype_dir = get_cointype_dir (&p); | ||
478 | if (GNUNET_OK != GNUNET_DISK_directory_create (cointype_dir)) | ||
479 | return GNUNET_SYSERR; | ||
480 | |||
481 | while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) { | ||
482 | const char *dkf; | ||
483 | dkf = get_cointype_file (&p, p.anchor); | ||
484 | |||
485 | if (GNUNET_YES != GNUNET_DISK_file_test (dkf)) | ||
486 | { | ||
487 | struct TALER_MINT_DenomKeyIssue denomkey_issue; | ||
488 | int ret; | ||
489 | printf ("Generating denomination key for type '%s', start %s.\n", | ||
490 | coin_alias, GNUNET_STRINGS_absolute_time_to_string (p.anchor)); | ||
491 | printf ("Target path: %s\n", dkf); | ||
492 | create_denomkey_issue (&p, &denomkey_issue); | ||
493 | ret = TALER_MINT_write_denom_key (dkf, &denomkey_issue); | ||
494 | TALER_RSA_key_free (denomkey_issue.denom_priv); | ||
495 | if (GNUNET_OK != ret) | ||
496 | { | ||
497 | fprintf (stderr, "Can't write to file '%s'\n", dkf); | ||
498 | return GNUNET_SYSERR; | ||
499 | } | ||
500 | } | ||
501 | else if (GNUNET_OK != check_cointype_valid (dkf, &p)) | ||
502 | { | ||
503 | return GNUNET_SYSERR; | ||
504 | } | ||
505 | p.anchor = GNUNET_TIME_absolute_add (p.anchor, p.duration_spend); | ||
506 | p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, p.duration_overlap); | ||
507 | } | ||
508 | return GNUNET_OK; | ||
509 | } | ||
510 | |||
511 | |||
512 | int | ||
513 | mint_keys_update_denomkeys () | ||
514 | { | ||
515 | char *coin_types; | ||
516 | char *ct; | ||
517 | char *tok_ctx; | ||
518 | |||
519 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, "mint_keys", "coin_types", &coin_types)) | ||
520 | { | ||
521 | fprintf (stderr, "mint_keys.coin_types not in configuration\n"); | ||
522 | return GNUNET_SYSERR; | ||
523 | } | ||
524 | |||
525 | for (ct = strtok_r (coin_types, " ", &tok_ctx); | ||
526 | ct != NULL; | ||
527 | ct = strtok_r (NULL, " ", &tok_ctx)) | ||
528 | { | ||
529 | if (GNUNET_OK != mint_keys_update_cointype (ct)) | ||
530 | { | ||
531 | GNUNET_free (coin_types); | ||
532 | return GNUNET_SYSERR; | ||
533 | } | ||
534 | } | ||
535 | GNUNET_free (coin_types); | ||
536 | return GNUNET_OK; | ||
537 | } | ||
538 | |||
539 | |||
540 | static int | ||
541 | mint_keys_update () | ||
542 | { | ||
543 | int ret; | ||
544 | struct GNUNET_TIME_Relative lookahead_sign; | ||
545 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_keys", "lookahead_sign", &lookahead_sign)) | ||
546 | { | ||
547 | fprintf (stderr, "mint_keys.lookahead_sign not found\n"); | ||
548 | return GNUNET_SYSERR; | ||
549 | } | ||
550 | if (lookahead_sign.rel_value_us == 0) | ||
551 | { | ||
552 | fprintf (stderr, "mint_keys.lookahead_sign must not be zero\n"); | ||
553 | return GNUNET_SYSERR; | ||
554 | } | ||
555 | ROUND_TO_SECS (lookahead_sign, rel_value_us); | ||
556 | lookahead_sign_stamp = GNUNET_TIME_absolute_add (now, lookahead_sign); | ||
557 | |||
558 | ret = mint_keys_update_signkeys (); | ||
559 | if (GNUNET_OK != ret) | ||
560 | return GNUNET_SYSERR; | ||
561 | |||
562 | return mint_keys_update_denomkeys (); | ||
563 | } | ||
564 | |||
565 | |||
566 | /** | ||
567 | * The main function of the keyup tool | ||
568 | * | ||
569 | * @param argc number of arguments from the command line | ||
570 | * @param argv command line arguments | ||
571 | * @return 0 ok, 1 on error | ||
572 | */ | ||
573 | int | ||
574 | main (int argc, char *const *argv) | ||
575 | { | ||
576 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
577 | GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"), | ||
578 | {'m', "master-key", "FILE", | ||
579 | "master key file (private key)", 1, | ||
580 | &GNUNET_GETOPT_set_filename, &masterkeyfile}, | ||
581 | {'d', "mint-dir", "DIR", | ||
582 | "mint directory with keys to update", 1, | ||
583 | &GNUNET_GETOPT_set_filename, &mintdir}, | ||
584 | {'t', "time", "TIMESTAMP", | ||
585 | "pretend it is a different time for the update", 0, | ||
586 | &GNUNET_GETOPT_set_string, &pretend_time_str}, | ||
587 | GNUNET_GETOPT_OPTION_END | ||
588 | }; | ||
589 | |||
590 | GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keyup", "WARNING", NULL)); | ||
591 | |||
592 | if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0) | ||
593 | return 1; | ||
594 | if (NULL == mintdir) | ||
595 | { | ||
596 | fprintf (stderr, "mint directory not given\n"); | ||
597 | return 1; | ||
598 | } | ||
599 | |||
600 | if (NULL != pretend_time_str) | ||
601 | { | ||
602 | if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str, &now)) | ||
603 | { | ||
604 | fprintf (stderr, "timestamp invalid\n"); | ||
605 | return 1; | ||
606 | } | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | now = GNUNET_TIME_absolute_get (); | ||
611 | } | ||
612 | ROUND_TO_SECS (now, abs_value_us); | ||
613 | |||
614 | kcfg = TALER_MINT_config_load (mintdir); | ||
615 | if (NULL == kcfg) | ||
616 | { | ||
617 | fprintf (stderr, "can't load mint configuration\n"); | ||
618 | return 1; | ||
619 | } | ||
620 | |||
621 | if (NULL == masterkeyfile) | ||
622 | { | ||
623 | fprintf (stderr, "master key file not given\n"); | ||
624 | return 1; | ||
625 | } | ||
626 | master_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile); | ||
627 | if (NULL == master_priv) | ||
628 | { | ||
629 | fprintf (stderr, "master key invalid\n"); | ||
630 | return 1; | ||
631 | } | ||
632 | |||
633 | master_pub = GNUNET_new (struct GNUNET_CRYPTO_EddsaPublicKey); | ||
634 | GNUNET_CRYPTO_eddsa_key_get_public (master_priv, master_pub); | ||
635 | |||
636 | // check if key from file matches the one from the configuration | ||
637 | { | ||
638 | struct GNUNET_CRYPTO_EddsaPublicKey master_pub_from_cfg; | ||
639 | if (GNUNET_OK != TALER_configuration_get_data (kcfg, "mint", "master_pub", | ||
640 | &master_pub_from_cfg, | ||
641 | sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) | ||
642 | { | ||
643 | fprintf (stderr, "master key missing in configuration (mint.master_pub)\n"); | ||
644 | return 1; | ||
645 | } | ||
646 | if (0 != memcmp (master_pub, &master_pub_from_cfg, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) | ||
647 | { | ||
648 | fprintf (stderr, "Mismatch between key from mint configuration and master private key file from command line.\n"); | ||
649 | return 1; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | if (GNUNET_OK != mint_keys_update ()) | ||
654 | return 1; | ||
655 | return 0; | ||
656 | } | ||
657 | |||