/* This file is part of TALER Copyright (C) 2014-2021 Taler Systems SA 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, see */ /** * @file exchange-tools/taler-crypto-worker.c * @brief Standalone process to perform various cryptographic operations. * @author Florian Dold */ #include "platform.h" #include "taler_util.h" #include #include #include "taler_error_codes.h" #include "taler_json_lib.h" #include "taler_signatures.h" /** * Return value from main(). */ static int global_ret; /** * Main function that will be run under the GNUnet scheduler. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param cfg configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { (void) cls; (void) args; (void) cfgfile; json_t *req; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "started crypto worker\n"); for (;;) { const char *op; const json_t *args; req = json_loadf (stdin, JSON_DISABLE_EOF_CHECK, NULL); if (NULL == req) { if (feof (stdin)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "end of input\n"); global_ret = 0; return; } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid JSON\n"); global_ret = 1; return; } op = json_string_value (json_object_get (req, "op")); if (! op) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no op specified\n"); global_ret = 1; return; } args = json_object_get (req, "args"); if (! args) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no args specified\n"); global_ret = 1; return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got request\n"); if (0 == strcmp ("eddsa_get_public", op)) { struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub; struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv; json_t *resp; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("eddsa_priv", &eddsa_priv), GNUNET_JSON_spec_end () }; if (GNUNET_OK != GNUNET_JSON_parse (args, spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } GNUNET_CRYPTO_eddsa_key_get_public (&eddsa_priv, &eddsa_pub); resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("eddsa_pub", &eddsa_pub) ); json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (spec); continue; } if (0 == strcmp ("ecdhe_get_public", op)) { struct GNUNET_CRYPTO_EcdhePublicKey ecdhe_pub; struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_priv; json_t *resp; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("ecdhe_priv", &ecdhe_priv), GNUNET_JSON_spec_end () }; if (GNUNET_OK != GNUNET_JSON_parse (args, spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } GNUNET_CRYPTO_ecdhe_key_get_public (&ecdhe_priv, &ecdhe_pub); resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("ecdhe_pub", &ecdhe_pub) ); json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (spec); continue; } if (0 == strcmp ("eddsa_verify", op)) { struct GNUNET_CRYPTO_EddsaPublicKey pub; struct GNUNET_CRYPTO_EddsaSignature sig; struct GNUNET_CRYPTO_EccSignaturePurpose *msg; size_t msg_size; enum GNUNET_GenericReturnValue verify_ret; json_t *resp; struct GNUNET_JSON_Specification eddsa_verify_spec[] = { GNUNET_JSON_spec_fixed_auto ("pub", &pub), GNUNET_JSON_spec_fixed_auto ("sig", &sig), GNUNET_JSON_spec_varsize ("msg", (void **) &msg, &msg_size), GNUNET_JSON_spec_end () }; if (GNUNET_OK != GNUNET_JSON_parse (args, eddsa_verify_spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } verify_ret = GNUNET_CRYPTO_eddsa_verify_ ( ntohl (msg->purpose), msg, &sig, &pub); resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_bool ("valid", GNUNET_OK == verify_ret)); json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (eddsa_verify_spec); continue; } if (0 == strcmp ("kx_ecdhe_eddsa", op)) { struct GNUNET_CRYPTO_EcdhePrivateKey priv; struct GNUNET_CRYPTO_EddsaPublicKey pub; struct GNUNET_HashCode key_material; json_t *resp; struct GNUNET_JSON_Specification kx_spec[] = { GNUNET_JSON_spec_fixed_auto ("eddsa_pub", &pub), GNUNET_JSON_spec_fixed_auto ("ecdhe_priv", &priv), GNUNET_JSON_spec_end () }; if (GNUNET_OK != GNUNET_JSON_parse (args, kx_spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } if (GNUNET_OK != GNUNET_CRYPTO_ecdh_eddsa (&priv, &pub, &key_material)) { // FIXME: Return as result? GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "kx failed\n"); global_ret = 1; return; } resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("h", &key_material) ); json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (kx_spec); continue; } if (0 == strcmp ("eddsa_sign", op)) { struct GNUNET_CRYPTO_EddsaSignature sig; struct GNUNET_CRYPTO_EccSignaturePurpose *msg; struct GNUNET_CRYPTO_EddsaPrivateKey priv; size_t msg_size; json_t *resp; struct GNUNET_JSON_Specification eddsa_sign_spec[] = { GNUNET_JSON_spec_fixed_auto ("priv", &priv), GNUNET_JSON_spec_varsize ("msg", (void **) &msg, &msg_size), GNUNET_JSON_spec_end () }; if (GNUNET_OK != GNUNET_JSON_parse (args, eddsa_sign_spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } GNUNET_CRYPTO_eddsa_sign_ ( &priv, msg, &sig ); resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("sig", &sig) ); json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (eddsa_sign_spec); continue; } if (0 == strcmp ("setup_refresh_planchet", op)) { struct TALER_TransferSecretP transfer_secret; uint32_t coin_index; json_t *resp; struct GNUNET_JSON_Specification setup_refresh_planchet_spec[] = { GNUNET_JSON_spec_uint32 ("coin_index", &coin_index), GNUNET_JSON_spec_fixed_auto ("transfer_secret", &transfer_secret), GNUNET_JSON_spec_end () }; struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CoinSpendPrivateKeyP coin_priv; struct TALER_PlanchetMasterSecretP ps; struct TALER_ExchangeWithdrawValues alg_values = { // FIXME: also allow CS .cipher = TALER_DENOMINATION_RSA, }; union TALER_DenominationBlindingKeyP dbk; if (GNUNET_OK != GNUNET_JSON_parse (args, setup_refresh_planchet_spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } TALER_transfer_secret_to_planchet_secret (&transfer_secret, coin_index, &ps); TALER_planchet_setup_coin_priv (&ps, &alg_values, &coin_priv); GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv, &coin_pub.eddsa_pub); TALER_planchet_blinding_secret_create (&ps, &alg_values, &dbk); resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("coin_priv", &coin_priv), GNUNET_JSON_pack_data_auto ("coin_pub", &coin_pub), GNUNET_JSON_pack_data_auto ("blinding_key", &dbk.rsa_bks) ); json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (setup_refresh_planchet_spec); continue; } if (0 == strcmp ("rsa_blind", op)) { struct GNUNET_HashCode hm; struct GNUNET_CRYPTO_RsaBlindingKeySecret bks; void *pub_enc; size_t pub_enc_size; int success; struct GNUNET_CRYPTO_RsaPublicKey *pub; void *blinded_buf; size_t blinded_size; json_t *resp; struct GNUNET_JSON_Specification rsa_blind_spec[] = { GNUNET_JSON_spec_fixed_auto ("hm", &hm), GNUNET_JSON_spec_fixed_auto ("bks", &bks), GNUNET_JSON_spec_varsize ("pub", &pub_enc, &pub_enc_size), GNUNET_JSON_spec_end () }; if (GNUNET_OK != GNUNET_JSON_parse (args, rsa_blind_spec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "malformed op args\n"); global_ret = 1; return; } pub = GNUNET_CRYPTO_rsa_public_key_decode (pub_enc, pub_enc_size); success = GNUNET_CRYPTO_rsa_blind (&hm, &bks, pub, &blinded_buf, &blinded_size); if (GNUNET_YES == success) { resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_varsize ("blinded", blinded_buf, blinded_size), GNUNET_JSON_pack_bool ("success", true) ); } else { resp = GNUNET_JSON_PACK ( GNUNET_JSON_pack_bool ("success", false) ); } json_dumpf (resp, stdout, JSON_COMPACT); printf ("\n"); fflush (stdout); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent response\n"); GNUNET_JSON_parse_free (rsa_blind_spec); GNUNET_free (blinded_buf); continue; } GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported operation '%s'\n", op); global_ret = 1; return; } } /** * The entry point. * * @param argc number of arguments in @a argv * @param argv command-line arguments * @return 0 on normal termination */ int main (int argc, char **argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; int ret; /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ TALER_OS_init (); ret = GNUNET_PROGRAM_run (argc, argv, "taler-crypto-worker", "Execute cryptographic operations read from stdin", options, &run, NULL); if (GNUNET_NO == ret) return 0; if (GNUNET_SYSERR == ret) return 1; return global_ret; }