diff options
Diffstat (limited to 'src/exchangedb')
-rw-r--r-- | src/exchangedb/exchangedb_denomkeys.c | 256 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb_denomkeys.c | 57 |
2 files changed, 171 insertions, 142 deletions
diff --git a/src/exchangedb/exchangedb_denomkeys.c b/src/exchangedb/exchangedb_denomkeys.c index 400912168..9dfb0e855 100644 --- a/src/exchangedb/exchangedb_denomkeys.c +++ b/src/exchangedb/exchangedb_denomkeys.c @@ -25,66 +25,70 @@ #include "taler_exchangedb_lib.h" +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Contents of a file with a revocation certificate. + */ +struct RevocationFileP +{ + + /** + * Hash of the denomination public key being revoked. + */ + struct GNUNET_HashCode denom_hash; + + /** + * Master signature over the revocation, must match purpose + * #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED. + */ + struct TALER_MasterSignatureP msig; +}; + +GNUNET_NETWORK_STRUCT_END + + /** * Mark the given denomination key as revoked and request the wallets * to initiate /payback. * - * @param exchange_base_dir base directory for the exchange, - * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS - * subdirectory - * @param alias coin alias - * @param dki the denomination key to revoke - * @param mpriv master private key to sign + * @param revocation_dir where to write the revocation certificate + * @param denom_hash hash of the denomination key to revoke + * @param mpriv master private key to sign with * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. */ int -TALER_EXCHANGEDB_denomination_key_revoke (const char *exchange_base_dir, - const char *alias, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, +TALER_EXCHANGEDB_denomination_key_revoke (const char *revocation_dir, + const struct GNUNET_HashCode *denom_hash, const struct TALER_MasterPrivateKeyP *mpriv) { - struct GNUNET_TIME_Absolute start; - struct TALER_MasterDenominationKeyRevocation rm; - struct TALER_MasterSignatureP msig; + struct TALER_MasterDenominationKeyRevocationPS rm; char *fn; - struct GNUNET_DISK_FileHandle *fh; - ssize_t wrote; int ret; + struct RevocationFileP rd; ret = GNUNET_SYSERR; - start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start); GNUNET_asprintf (&fn, - "%s" DIR_SEPARATOR_STR - TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR - "%s" DIR_SEPARATOR_STR - "%llu.rev", - exchange_base_dir, - alias, - (unsigned long long) start.abs_value_us); - + "%s" DIR_SEPARATOR_STR + "%s.rev", + revocation_dir, + GNUNET_h2s_full (denom_hash)); rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED); rm.purpose.size = htonl (sizeof (rm)); - rm.h_denom_pub = dki->issue.properties.denom_hash; + rm.h_denom_pub = *denom_hash; GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (&mpriv->eddsa_priv, &rm.purpose, - &msig.eddsa_signature)); - if (NULL == (fh = GNUNET_DISK_file_open - (fn, - GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, - GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) - goto cleanup; - if (GNUNET_SYSERR == - (wrote = GNUNET_DISK_file_write (fh, - &msig, - sizeof (msig)))) - goto cleanup; - if (wrote != sizeof (msig)) - goto cleanup; - ret = GNUNET_OK; -cleanup: - if (NULL != fh) - (void) GNUNET_DISK_file_close (fh); + &rd.msig.eddsa_signature)); + rd.denom_hash = *denom_hash; + if (sizeof (rd) != + GNUNET_DISK_fn_write (fn, + &rd, + sizeof (rd), + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)) + ret = GNUNET_SYSERR; + else + ret = GNUNET_OK; GNUNET_free (fn); return ret; } @@ -229,11 +233,6 @@ struct DenomkeysIterateContext const char *alias; /** - * Master public key to use to validate revocations. - */ - const struct TALER_MasterPublicKeyP *master_pub; - - /** * Function to call on each denomination key. */ TALER_EXCHANGEDB_DenominationKeyIterator it; @@ -263,16 +262,6 @@ denomkeys_iterate_keydir_iter (void *cls, struct DenomkeysIterateContext *dic = cls; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue; int ret; - char *rev; - struct TALER_MasterSignatureP msig; - struct TALER_MasterDenominationKeyRevocation rm; - const struct TALER_MasterSignatureP *revoked; - - /* FIXME: #5536: should move .rev files into DB! */ - if ( (strlen(filename) > strlen (".rev")) && - (0 == strcmp (&filename[strlen(filename) - strlen (".rev")], - ".rev")) ) - return GNUNET_OK; /* ignore revocation files _here_; we'll try for them just below */ memset (&issue, 0, sizeof (issue)); if (GNUNET_OK != @@ -284,52 +273,9 @@ denomkeys_iterate_keydir_iter (void *cls, filename); return GNUNET_OK; } - /* check for revocation file */ - GNUNET_asprintf (&rev, - "%s.rev", - filename); - revoked = NULL; - if (GNUNET_YES == GNUNET_DISK_file_test (rev)) - { - /* Check if revocation is valid... */ - if (sizeof (msig) != - GNUNET_DISK_fn_read (rev, - &msig, - sizeof (msig))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Invalid revocation file `%s' found and ignored (bad size)\n"), - rev); - } - else - { - rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED); - rm.purpose.size = htonl (sizeof (rm)); - rm.h_denom_pub = issue.issue.properties.denom_hash; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED, - &rm.purpose, - &msig.eddsa_signature, - &dic->master_pub->eddsa_pub)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Invalid revocation file `%s' found and ignored (bad signature)\n"), - rev); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Denomination key `%s' was revoked!\n", - filename); - revoked = &msig; - } - } - } - GNUNET_free (rev); ret = dic->it (dic->it_cls, dic->alias, - &issue, - revoked); + &issue); GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key); GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key); return ret; @@ -367,7 +313,6 @@ denomkeys_iterate_topdir_iter (void *cls, * @param exchange_base_dir base directory for the exchange, * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS * subdirectory - * @param master_pub master public key (used to check revocations) * @param it function to call on each denomination key found * @param it_cls closure for @a it * @return -1 on error, 0 if no files were found, otherwise @@ -377,7 +322,6 @@ denomkeys_iterate_topdir_iter (void *cls, */ int TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, - const struct TALER_MasterPublicKeyP *master_pub, TALER_EXCHANGEDB_DenominationKeyIterator it, void *it_cls) { @@ -388,7 +332,6 @@ TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, GNUNET_asprintf (&dir, "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS, exchange_base_dir); - dic.master_pub = master_pub; dic.it = it; dic.it_cls = it_cls; ret = GNUNET_DISK_directory_scan (dir, @@ -399,4 +342,111 @@ TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, } +/** + * Closure for #revocations_iterate_cb(). + */ +struct RevocationsIterateContext +{ + + /** + * Function to call on each revoked denomination key. + */ + TALER_EXCHANGEDB_RevocationIterator it; + + /** + * Closure for @e it. + */ + void *it_cls; + + /** + * Master public key to use to validate revocations. + */ + const struct TALER_MasterPublicKeyP *master_pub; + +}; + + +/** + * Decode the revocation certificate in the given file @a filename and call + * the callback in @a cls with the information. + * + * @param cls the `struct RevocationsIterateContext *` + * @param filename name of a file that should contain + * a denomination key + * @return #GNUNET_OK to continue to iterate + * #GNUNET_NO to abort iteration with success + * #GNUNET_SYSERR to abort iteration with failure + */ +static int +revocations_iterate_cb (void *cls, + const char *filename) +{ + struct RevocationsIterateContext *ric = cls; + struct RevocationFileP rf; + struct TALER_MasterDenominationKeyRevocationPS rm; + + /* Check if revocation is valid... */ + if (sizeof (rm) != + GNUNET_DISK_fn_read (filename, + &rf, + sizeof (rf))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Invalid revocation file `%s' found and ignored (bad size)\n"), + filename); + return GNUNET_OK; + } + rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED); + rm.purpose.size = htonl (sizeof (rm)); + rm.h_denom_pub = rf.denom_hash; + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED, + &rm.purpose, + &rf.msig.eddsa_signature, + &ric->master_pub->eddsa_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Invalid revocation file `%s' found and ignored (bad signature)\n"), + filename); + return GNUNET_OK; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Denomination key `%s' was revoked!\n", + GNUNET_h2s (&rm.h_denom_pub)); + return ric->it (ric->it_cls, + &rm.h_denom_pub, + &rf.msig); +} + + +/** + * Call @a it for each revoked denomination key found in the @a revocation_dir. + * + * @param revocation_dir base directory where revocations are stored + * @param master_pub master public key (used to check revocations) + * @param it function to call on each revoked denomination key found + * @param it_cls closure for @a it + * @return -1 on error, 0 if no files were found, otherwise + * a positive number (however, even with a positive + * number it is possible that @a it was never called + * as maybe none of the files were well-formed) + */ +int +TALER_EXCHANGEDB_revocations_iterate (const char *revocation_dir, + const struct TALER_MasterPublicKeyP *master_pub, + TALER_EXCHANGEDB_RevocationIterator it, + void *it_cls) +{ + struct RevocationsIterateContext ric = { + .it = it, + .it_cls = it_cls, + .master_pub = master_pub + }; + + return GNUNET_DISK_directory_scan (revocation_dir, + &revocations_iterate_cb, + &ric); +} + + /* end of exchangedb_denomkeys.c */ diff --git a/src/exchangedb/test_exchangedb_denomkeys.c b/src/exchangedb/test_exchangedb_denomkeys.c index 06465a4ea..b558b3b3b 100644 --- a/src/exchangedb/test_exchangedb_denomkeys.c +++ b/src/exchangedb/test_exchangedb_denomkeys.c @@ -38,7 +38,6 @@ * @param cls closure with expected DKI * @param dki the denomination key * @param alias coin alias - * @param revocation_master_sig non-NULL if @a dki was revoked * @return #GNUNET_OK to continue to iterate, * #GNUNET_NO to stop iteration with no error, * #GNUNET_SYSERR to abort iteration with error! @@ -46,16 +45,10 @@ static int dki_iter (void *cls, const char *alias, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, - const struct TALER_MasterSignatureP *revocation_master_sig) + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) { const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls; - if (NULL != revocation_master_sig) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } if (0 != memcmp (&exp->issue, &dki->issue, sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP))) @@ -85,8 +78,7 @@ dki_iter (void *cls, * @brief Iterator called on revoked denomination key. * * @param cls closure with expected DKI - * @param dki the denomination key - * @param alias coin alias + * @param denom_hash hash of the revoked denomination key * @param revocation_master_sig non-NULL if @a dki was revoked * @return #GNUNET_OK to continue to iterate, * #GNUNET_NO to stop iteration with no error, @@ -94,8 +86,7 @@ dki_iter (void *cls, */ static int dki_iter_revoked (void *cls, - const char *alias, - const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, + const struct GNUNET_HashCode *denom_hash, const struct TALER_MasterSignatureP *revocation_master_sig) { const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls; @@ -105,28 +96,13 @@ dki_iter_revoked (void *cls, GNUNET_break (0); return GNUNET_SYSERR; } - if (0 != memcmp (&exp->issue, - &dki->issue, - sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP))) + if (0 != memcmp (denom_hash, + &exp->issue.properties.denom_hash, + sizeof (struct GNUNET_HashCode))) { GNUNET_break (0); return GNUNET_SYSERR; } - if (0 != - GNUNET_CRYPTO_rsa_private_key_cmp (exp->denom_priv.rsa_private_key, - dki->denom_priv.rsa_private_key)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (0 != - GNUNET_CRYPTO_rsa_public_key_cmp (exp->denom_pub.rsa_public_key, - dki->denom_pub.rsa_public_key)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; } @@ -146,6 +122,7 @@ main (int argc, size_t enc_read_size; char *tmpfile; char *tmpdir; + char *revdir; int ret; struct GNUNET_TIME_Absolute start; @@ -180,6 +157,10 @@ main (int argc, TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS, "cur-unit-uuid", (unsigned long long) start.abs_value_us); + GNUNET_asprintf (&revdir, + "%s/revocations/", + tmpdir, + TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS); EXITIF (GNUNET_OK != TALER_EXCHANGEDB_denomination_key_write (tmpfile, &dki)); @@ -188,21 +169,19 @@ main (int argc, &dki_read)); EXITIF (1 != TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir, - &master_pub, &dki_iter, &dki)); EXITIF (GNUNET_OK != - TALER_EXCHANGEDB_denomination_key_revoke (tmpdir, - "cur-unit-uuid", - &dki, + TALER_EXCHANGEDB_denomination_key_revoke (revdir, + &dki.issue.properties.denom_hash, &master_priv)); EXITIF (1 != - TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir, - &master_pub, - &dki_iter_revoked, - &dki)); - + TALER_EXCHANGEDB_revocations_iterate (revdir, + &master_pub, + &dki_iter_revoked, + &dki)); + GNUNET_free (revdir); enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key, &enc_read); |