diff options
Diffstat (limited to 'src/exchangedb/exchangedb_denomkeys.c')
-rw-r--r-- | src/exchangedb/exchangedb_denomkeys.c | 256 |
1 files changed, 153 insertions, 103 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 */ |