add tofu logic

This commit is contained in:
Christian Grothoff 2020-12-05 13:09:49 +01:00
parent ba4f585d69
commit c898ff53a2
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC

View File

@ -534,7 +534,7 @@ load_offline_key (void)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange",
"MASTER_PRIV_FILE");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
return GNUNET_SYSERR;
}
if (GNUNET_YES !=
@ -552,7 +552,7 @@ load_offline_key (void)
fn,
"could not create file");
GNUNET_free (fn);
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
return GNUNET_SYSERR;
}
GNUNET_free (fn);
@ -629,6 +629,8 @@ upload_denom_revocation (const char *exchange_url,
err_name,
err_line,
(unsigned int) idx);
global_ret = 7;
test_shutdown ();
return;
}
drr = GNUNET_new (struct DenomRevocationRequest);
@ -712,6 +714,8 @@ upload_signkey_revocation (const char *exchange_url,
err_name,
err_line,
(unsigned int) idx);
global_ret = 7;
test_shutdown ();
return;
}
srr = GNUNET_new (struct SignkeyRevocationRequest);
@ -801,6 +805,8 @@ upload_wire_add (const char *exchange_url,
err_name,
err_line,
(unsigned int) idx);
global_ret = 7;
test_shutdown ();
return;
}
war = GNUNET_new (struct WireAddRequest);
@ -889,6 +895,8 @@ upload_wire_del (const char *exchange_url,
err_name,
err_line,
(unsigned int) idx);
global_ret = 7;
test_shutdown ();
return;
}
wdr = GNUNET_new (struct WireDelRequest);
@ -985,6 +993,8 @@ upload_wire_fee (const char *exchange_url,
err_name,
err_line,
(unsigned int) idx);
global_ret = 7;
test_shutdown ();
return;
}
wfr = GNUNET_new (struct WireFeeRequest);
@ -1035,7 +1045,7 @@ trigger_upload (const char *exchange_url)
.key = "set-wire-fee",
.cb = &upload_wire_fee
},
// FIXME: many more handlers here!
// FIXME: Add POST /management/keys handlers here!
/* array termination */
{
.key = NULL
@ -1056,7 +1066,7 @@ trigger_upload (const char *exchange_url)
fprintf (stderr,
"Malformed JSON input\n");
global_ret = 3;
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
return;
}
/* block of code that uses key and value */
@ -1078,7 +1088,7 @@ trigger_upload (const char *exchange_url)
"Upload does not know how to handle `%s'\n",
key);
global_ret = 3;
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
return;
}
}
@ -1099,7 +1109,7 @@ do_upload (char *const *args)
{
fprintf (stderr,
"Downloaded data was not consumed, refusing upload\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1118,7 +1128,7 @@ do_upload (char *const *args)
err.line,
err.source,
err.position);
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 2;
return;
}
@ -1127,7 +1137,7 @@ do_upload (char *const *args)
{
fprintf (stderr,
"Error: expected JSON array for `upload` command\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 2;
return;
}
@ -1141,7 +1151,7 @@ do_upload (char *const *args)
"exchange",
"BASE_URL");
global_ret = 1;
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
return;
}
trigger_upload (exchange_url);
@ -1167,7 +1177,7 @@ do_revoke_denomination_key (char *const *args)
{
fprintf (stderr,
"Downloaded data was not consumed, refusing revocation\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1180,7 +1190,7 @@ do_revoke_denomination_key (char *const *args)
{
fprintf (stderr,
"You must specify a denomination key with this subcommand\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 5;
return;
}
@ -1216,7 +1226,7 @@ do_revoke_signkey (char *const *args)
{
fprintf (stderr,
"Downloaded data was not consumed, refusing revocation\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1229,7 +1239,7 @@ do_revoke_signkey (char *const *args)
{
fprintf (stderr,
"You must specify an exchange signing key with this subcommand\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 5;
return;
}
@ -1266,7 +1276,7 @@ do_add_wire (char *const *args)
{
fprintf (stderr,
"Downloaded data was not consumed, not adding wire account\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1274,7 +1284,7 @@ do_add_wire (char *const *args)
{
fprintf (stderr,
"You must specify a payto://-URI with this subcommand\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 5;
return;
}
@ -1321,7 +1331,7 @@ do_del_wire (char *const *args)
{
fprintf (stderr,
"Downloaded data was not consumed, not deleting wire account\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1329,7 +1339,7 @@ do_del_wire (char *const *args)
{
fprintf (stderr,
"You must specify a payto://-URI with this subcommand\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 5;
return;
}
@ -1377,7 +1387,7 @@ do_set_wire_fee (char *const *args)
{
fprintf (stderr,
"Downloaded data was not consumed, not setting wire fee\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1400,7 +1410,7 @@ do_set_wire_fee (char *const *args)
{
fprintf (stderr,
"You must use YEAR, METHOD, WIRE-FEE and CLOSING-FEE as arguments for this subcommand\n");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 5;
return;
}
@ -1466,7 +1476,7 @@ download_cb (void *cls,
hr->hint,
hr->http_status,
(unsigned int) hr->ec);
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 4;
return;
}
@ -1503,7 +1513,7 @@ do_download (char *const *args)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange",
"BASE_URL");
GNUNET_SCHEDULER_shutdown ();
test_shutdown ();
global_ret = 1;
return;
}
@ -1515,6 +1525,304 @@ do_download (char *const *args)
}
/**
* Check that the security module keys are the same as before. If we had no
* keys in store before, remember them (Trust On First Use).
*
* @param secm security module keys, must be an array of length 2
* @return #GNUNET_OK if keys match with what we have in store
* #GNUNET_NO if we had nothing in store but now do
* #GNUNET_SYSERR if keys changed from what we remember or other error
*/
static int
tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
{
char *fn;
struct TALER_SecurityModulePublicKeyP old[2];
ssize_t ret;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (kcfg,
"exchange-offline",
"SECM_TOFU_FILE",
&fn))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange-offline",
"SECM_TOFU_FILE");
return GNUNET_SYSERR;
}
ret = GNUNET_DISK_fn_read (fn,
&old,
sizeof (old));
if (GNUNET_SYSERR != ret)
{
if (ret != sizeof (old))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"File `%s' corrupt\n",
fn);
GNUNET_free (fn);
return GNUNET_SYSERR;
}
GNUNET_free (fn);
/* TOFU check */
if (0 != memcmp (old,
secm,
sizeof (old)))
return GNUNET_SYSERR;
return GNUNET_OK;
}
/* persist keys for future runs */
ret = GNUNET_DISK_fn_write (fn,
secm,
sizeof (old),
GNUNET_DISK_PERM_USER_READ);
if (ret != sizeof (old))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to store key material in file `%s'\n",
fn);
GNUNET_free (fn);
return GNUNET_SYSERR;
}
return GNUNET_NO;
}
/**
* Output @a signkeys for human consumption.
*
* @param signkeys keys to output
* @return #GNUNET_OK on success
*/
static int
show_signkeys (const json_t *signkeys)
{
size_t index;
json_t *value;
json_array_foreach (signkeys, index, value) {
const char *err_name;
unsigned int err_line;
struct GNUNET_JSON_Specification spec[] = {
// FIXME!
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (value,
spec,
&err_name,
&err_line))
{
fprintf (stderr,
"Invalid input for signing key to 'show': %s#%u at %u (skipping)\n",
err_name,
err_line,
(unsigned int) index);
global_ret = 7;
test_shutdown ();
return GNUNET_SYSERR;
}
// FIXME: print
}
return GNUNET_OK;
}
/**
* Output @a denomkeys for human consumption.
*
* @param denomkeys keys to output
* @return #GNUNET_OK on success
*/
static int
show_denomkeys (const json_t *denomkeys)
{
size_t index;
json_t *value;
json_array_foreach (denomkeys, index, value) {
const char *err_name;
unsigned int err_line;
struct GNUNET_JSON_Specification spec[] = {
// FIXME!
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (value,
spec,
&err_name,
&err_line))
{
fprintf (stderr,
"Invalid input for signing key to 'show': %s#%u at %u (skipping)\n",
err_name,
err_line,
(unsigned int) index);
global_ret = 7;
test_shutdown ();
return GNUNET_SYSERR;
}
// FIXME: print
}
return GNUNET_OK;
}
/**
* Show future keys.
*
* @param args the array of command-line arguments to process next
*/
static void
do_show (char *const *args)
{
if (NULL == in)
{
json_error_t err;
out = json_loadf (stdin,
JSON_REJECT_DUPLICATES,
&err);
if (NULL == in)
{
fprintf (stderr,
"Failed to read JSON input: %s at %d:%s (offset: %d)\n",
err.text,
err.line,
err.source,
err.position);
global_ret = 2;
test_shutdown ();
return;
}
}
{
const char *err_name;
unsigned int err_line;
json_t *denomkeys;
json_t *signkeys;
struct TALER_MasterPublicKeyP mpub;
struct TALER_SecurityModulePublicKeyP secm[2];
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("future_denoms",
&denomkeys),
GNUNET_JSON_spec_json ("future_signkeys",
&signkeys),
GNUNET_JSON_spec_fixed_auto ("master_pub",
&mpub),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
&secm[0]),
GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
&secm[1]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (in,
spec,
&err_name,
&err_line))
{
fprintf (stderr,
"Invalid input to 'show': %s#%u (skipping)\n",
err_name,
err_line);
global_ret = 7;
test_shutdown ();
return;
}
if (0 !=
GNUNET_memcmp (&master_pub,
&mpub))
{
fprintf (stderr,
"Fatal: exchange uses different master key!\n");
global_ret = 6;
test_shutdown ();
GNUNET_JSON_parse_free (spec);
return;
}
if (GNUNET_SYSERR ==
tofu_check (secm))
{
fprintf (stderr,
"Fatal: security module keys changed!\n");
global_ret = 8;
test_shutdown ();
GNUNET_JSON_parse_free (spec);
return;
}
if ( (GNUNET_OK !=
show_signkeys (signkeys)) ||
(GNUNET_OK !=
show_denomkeys (denomkeys)) )
{
global_ret = 8;
test_shutdown ();
GNUNET_JSON_parse_free (spec);
return;
}
GNUNET_JSON_parse_free (spec);
}
/* do NOT consume input if next argument is '-' */
if ( (NULL != args[0]) &&
(0 == strcmp ("-",
args[0])) )
{
next (args + 1);
return;
}
json_decref (in);
in = NULL;
next (args);
}
/**
* Sign future keys.
*
* @param args the array of command-line arguments to process next
*/
static void
do_sign (char *const *args)
{
if (NULL == in)
{
json_error_t err;
out = json_loadf (stdin,
JSON_REJECT_DUPLICATES,
&err);
if (NULL == in)
{
fprintf (stderr,
"Failed to read JSON input: %s at %d:%s (offset: %d)\n",
err.text,
err.line,
err.source,
err.position);
global_ret = 2;
test_shutdown ();
return;
}
}
// FIXME: do work here!
/* consume input */
json_decref (in);
in = NULL;
next (args);
}
static void
work (void *cls)
{
@ -1526,6 +1834,18 @@ work (void *cls)
"obtain future public keys from exchange (to be performed online!)",
.cb = &do_download
},
{
.name = "show",
.help =
"display future public keys from exchange for human review (pass '-' as argument to disable consuming input)",
.cb = &do_show
},
{
.name = "sign",
.help =
"sing all future public keys from the input",
.cb = &do_sign
},
{
.name = "revoke-denomination",
.help =
@ -1562,7 +1882,6 @@ work (void *cls)
"upload operation result to exchange (to be performed online!)",
.cb = &do_upload
},
// FIXME: many more handlers here!
/* list terminator */
{
.name = NULL,