From 187fa67f3c8791bec65f075d285081460e5f2170 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 6 May 2016 19:22:39 +0200 Subject: refactoring exchangedb tests to improve coverage --- src/exchangedb/exchangedb_denomkeys.c | 269 ++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 src/exchangedb/exchangedb_denomkeys.c (limited to 'src/exchangedb/exchangedb_denomkeys.c') diff --git a/src/exchangedb/exchangedb_denomkeys.c b/src/exchangedb/exchangedb_denomkeys.c new file mode 100644 index 000000000..dea312dd2 --- /dev/null +++ b/src/exchangedb/exchangedb_denomkeys.c @@ -0,0 +1,269 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 Inria & GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see +*/ +/** + * @file exchangedb/exchangedb_denomkeys.c + * @brief I/O operations for the Exchange's denomination private keys + * @author Florian Dold + * @author Benedikt Mueller + * @author Sree Harsha Totakura + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" + + +/** + * Import a denomination key from the given file. + * + * @param filename the file to import the key from + * @param[out] dki set to the imported denomination key + * @return #GNUNET_OK upon success; + * #GNUNET_SYSERR upon failure + */ +int +TALER_EXCHANGEDB_denomination_key_read (const char *filename, + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + uint64_t size; + size_t offset; + void *data; + struct GNUNET_CRYPTO_RsaPrivateKey *priv; + + if (GNUNET_OK != GNUNET_DISK_file_size (filename, + &size, + GNUNET_YES, + GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping inaccessable denomination key file `%s'\n", + filename); + return GNUNET_SYSERR; + } + offset = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP); + if (size <= offset) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + data = GNUNET_malloc (size); + if (size != + GNUNET_DISK_fn_read (filename, + data, + size)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "read", + filename); + GNUNET_free (data); + return GNUNET_SYSERR; + } + if (NULL == + (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset, + size - offset))) + { + GNUNET_free (data); + return GNUNET_SYSERR; + } + GNUNET_assert (NULL == dki->denom_priv.rsa_private_key); + dki->denom_priv.rsa_private_key = priv; + dki->denom_pub.rsa_public_key + = GNUNET_CRYPTO_rsa_private_key_get_public (priv); + memcpy (&dki->issue, + data, + offset); + GNUNET_free (data); + return GNUNET_OK; +} + + +/** + * Exports a denomination key to the given file. + * + * @param filename the file where to write the denomination key + * @param dki the denomination key + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure. + */ +int +TALER_EXCHANGEDB_denomination_key_write (const char *filename, + const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki) +{ + char *priv_enc; + size_t priv_enc_size; + struct GNUNET_DISK_FileHandle *fh; + ssize_t wrote; + size_t wsize; + int ret; + + fh = NULL; + priv_enc_size + = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key, + &priv_enc); + ret = GNUNET_SYSERR; + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (filename)) + return GNUNET_SYSERR; + if (NULL == (fh = GNUNET_DISK_file_open + (filename, + GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) + goto cleanup; + wsize = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP); + if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, + &dki->issue, + wsize))) + goto cleanup; + if (wrote != wsize) + goto cleanup; + if (GNUNET_SYSERR == + (wrote = GNUNET_DISK_file_write (fh, + priv_enc, + priv_enc_size))) + goto cleanup; + if (wrote != priv_enc_size) + goto cleanup; + ret = GNUNET_OK; + cleanup: + GNUNET_free_non_null (priv_enc); + if (NULL != fh) + (void) GNUNET_DISK_file_close (fh); + return ret; +} + + +/** + * Closure for #denomkeys_iterate_keydir_iter() and + * #denomkeys_iterate_topdir_iter(). + */ +struct DenomkeysIterateContext +{ + + /** + * Set to the name of the directory below the top-level directory + * during the call to #denomkeys_iterate_keydir_iter(). + */ + const char *alias; + + /** + * Function to call on each denomination key. + */ + TALER_EXCHANGEDB_DenominationKeyIterator it; + + /** + * Closure for @e it. + */ + void *it_cls; +}; + + +/** + * Decode the denomination key in the given file @a filename and call + * the callback in @a cls with the information. + * + * @param cls the `struct DenomkeysIterateContext *` + * @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 +denomkeys_iterate_keydir_iter (void *cls, + const char *filename) +{ + struct DenomkeysIterateContext *dic = cls; + struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue; + int ret; + + memset (&issue, 0, sizeof (issue)); + if (GNUNET_OK != + TALER_EXCHANGEDB_denomination_key_read (filename, + &issue)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid denomkey file: '%s'\n", + filename); + return GNUNET_OK; + } + ret = dic->it (dic->it_cls, + dic->alias, + &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; +} + + +/** + * Function called on each subdirectory in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS. Will + * call the #denomkeys_iterate_keydir_iter() on each file in the + * subdirectory. + * + * @param cls the `struct DenomkeysIterateContext *` + * @param filename name of the subdirectory to scan + * @return #GNUNET_OK on success, + * #GNUNET_SYSERR if we need to abort + */ +static int +denomkeys_iterate_topdir_iter (void *cls, + const char *filename) +{ + struct DenomkeysIterateContext *dic = cls; + + dic->alias = GNUNET_STRINGS_get_short_name (filename); + if (0 > GNUNET_DISK_directory_scan (filename, + &denomkeys_iterate_keydir_iter, + dic)) + return GNUNET_SYSERR; + return GNUNET_OK; +} + + +/** + * Call @a it for each denomination key found in the @a exchange_base_dir. + * + * @param exchange_base_dir base directory for the exchange, + * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS + * subdirectory + * @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 + * 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_denomination_keys_iterate (const char *exchange_base_dir, + TALER_EXCHANGEDB_DenominationKeyIterator it, + void *it_cls) +{ + char *dir; + struct DenomkeysIterateContext dic; + int ret; + + GNUNET_asprintf (&dir, + "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS, + exchange_base_dir); + dic.it = it; + dic.it_cls = it_cls; + ret = GNUNET_DISK_directory_scan (dir, + &denomkeys_iterate_topdir_iter, + &dic); + GNUNET_free (dir); + return ret; +} + + +/* end of exchangedb_denomkeys.c */ -- cgit v1.2.3