/* This file is part of TALER (C) 2014 Christian Grothoff (and other contributing authors) 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 key_io.c * @brief I/O operations for the Mint's private keys * @author Florian Dold * @author Benedikt Mueller * @author Sree Harsha Totakura * @author Christian Grothoff */ #include "platform.h" #include "mint.h" #include "key_io.h" struct SignkeysIterateContext { TALER_MINT_SignkeyIterator it; void *it_cls; }; struct DenomkeysIterateContext { const char *alias; TALER_MINT_DenomkeyIterator it; void *it_cls; }; static int signkeys_iterate_dir_iter (void *cls, const char *filename) { struct SignkeysIterateContext *skc = cls; ssize_t nread; struct TALER_MINT_SignKeyIssuePriv issue; nread = GNUNET_DISK_fn_read (filename, &issue, sizeof (struct TALER_MINT_SignKeyIssuePriv)); if (nread != sizeof (struct TALER_MINT_SignKeyIssuePriv)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid signkey file: '%s'\n", filename); return GNUNET_OK; } return skc->it (skc->it_cls, &issue); } int TALER_MINT_signkeys_iterate (const char *mint_base_dir, TALER_MINT_SignkeyIterator it, void *cls) { char *signkey_dir; size_t len; struct SignkeysIterateContext skc; len = GNUNET_asprintf (&signkey_dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS), mint_base_dir); GNUNET_assert (len > 0); skc.it = it; skc.it_cls = cls; return GNUNET_DISK_directory_scan (signkey_dir, &signkeys_iterate_dir_iter, &skc); } /** * Import a denomination key from the given file * * @param filename the file to import the key from * @param dki pointer to return the imported denomination key * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ int TALER_MINT_read_denom_key (const char *filename, struct TALER_MINT_DenomKeyIssuePriv *dki) { uint64_t size; size_t offset; void *data; struct GNUNET_CRYPTO_rsa_PrivateKey *priv; int ret; ret = GNUNET_SYSERR; data = NULL; offset = sizeof (struct TALER_MINT_DenomKeyIssuePriv) - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.signature); if (GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES, GNUNET_YES)) goto cleanup; if (size <= offset) { GNUNET_break (0); goto cleanup; } data = GNUNET_malloc (size); if (size != GNUNET_DISK_fn_read (filename, data, size)) goto cleanup; if (NULL == (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset, size - offset))) goto cleanup; dki->denom_priv = priv; memcpy (&dki->issue.signature, data, offset); ret = GNUNET_OK; cleanup: GNUNET_free_non_null (data); return ret; } /** * 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_MINT_write_denom_key (const char *filename, const struct TALER_MINT_DenomKeyIssuePriv *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, &priv_enc); ret = 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_MINT_DenomKeyIssuePriv) - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.signature); if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh, &dki->issue.signature, 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; } static int denomkeys_iterate_keydir_iter (void *cls, const char *filename) { struct DenomkeysIterateContext *dic = cls; struct TALER_MINT_DenomKeyIssuePriv issue; if (GNUNET_OK != TALER_MINT_read_denom_key (filename, &issue)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid denomkey file: '%s'\n", filename); return GNUNET_OK; } return dic->it (dic->it_cls, dic->alias, &issue); } static int denomkeys_iterate_topdir_iter (void *cls, const char *filename) { struct DenomkeysIterateContext *dic = cls; dic->alias = GNUNET_STRINGS_get_short_name (filename); // FIXME: differentiate between error case and normal iteration abortion if (0 > GNUNET_DISK_directory_scan (filename, &denomkeys_iterate_keydir_iter, dic)) return GNUNET_SYSERR; return GNUNET_OK; } int TALER_MINT_denomkeys_iterate (const char *mint_base_dir, TALER_MINT_DenomkeyIterator it, void *cls) { char *dir; size_t len; struct DenomkeysIterateContext dic; len = GNUNET_asprintf (&dir, "%s" DIR_SEPARATOR_STR DIR_DENOMKEYS, mint_base_dir); GNUNET_assert (len > 0); dic.it = it; dic.it_cls = cls; // scan over alias dirs return GNUNET_DISK_directory_scan (dir, &denomkeys_iterate_topdir_iter, &dic); } /* end of mint_common.c */