/* This file is part of TALER Copyright (C) 2020-2024 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 offline_signatures.c * @brief Utility functions for Taler exchange offline signatures * @author Christian Grothoff */ #include "platform.h" #include "taler_util.h" #include "taler_signatures.h" GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Signature made by the exchange offline key over the information of * an AML officer status change. */ struct TALER_MasterAmlOfficerStatusPS { /** * Purpose is #TALER_SIGNATURE_MASTER_AML_KEY. Signed * by a `struct TALER_MasterPublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Time of the change. */ struct GNUNET_TIME_TimestampNBO change_date; /** * Public key of the AML officer. */ struct TALER_AmlOfficerPublicKeyP officer_pub; /** * Hash over the AML officer's name. */ struct GNUNET_HashCode h_officer_name GNUNET_PACKED; /** * Bitmask: 1 if enabled; 2 for read-only access. in NBO. */ uint32_t is_active GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_aml_officer_status_sign ( const struct TALER_AmlOfficerPublicKeyP *officer_pub, const char *officer_name, struct GNUNET_TIME_Timestamp change_date, bool is_active, bool read_only, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterAmlOfficerStatusPS as = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_AML_KEY), .purpose.size = htonl (sizeof (as)), .change_date = GNUNET_TIME_timestamp_hton (change_date), .officer_pub = *officer_pub, .is_active = htonl ((is_active ? 1 : 0) + (read_only ? 2 : 0)) }; GNUNET_CRYPTO_hash (officer_name, strlen (officer_name) + 1, &as.h_officer_name); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &as, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_aml_officer_status_verify ( const struct TALER_AmlOfficerPublicKeyP *officer_pub, const char *officer_name, struct GNUNET_TIME_Timestamp change_date, bool is_active, bool read_only, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterAmlOfficerStatusPS as = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_AML_KEY), .purpose.size = htonl (sizeof (as)), .change_date = GNUNET_TIME_timestamp_hton (change_date), .officer_pub = *officer_pub, .is_active = htonl ((is_active ? 1 : 0) + (read_only ? 2 : 0)) }; GNUNET_CRYPTO_hash (officer_name, strlen (officer_name) + 1, &as.h_officer_name); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_AML_KEY, &as, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Signature made by the exchange offline key over the information of * an auditor to be added to the exchange's set of auditors. */ struct TALER_MasterAddAuditorPS { /** * Purpose is #TALER_SIGNATURE_MASTER_ADD_AUDITOR. Signed * by a `struct TALER_MasterPublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Time of the change. */ struct GNUNET_TIME_TimestampNBO start_date; /** * Public key of the auditor. */ struct TALER_AuditorPublicKeyP auditor_pub; /** * Hash over the auditor's URL. */ struct GNUNET_HashCode h_auditor_url GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_auditor_add_sign ( const struct TALER_AuditorPublicKeyP *auditor_pub, const char *auditor_url, struct GNUNET_TIME_Timestamp start_date, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterAddAuditorPS kv = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_ADD_AUDITOR), .purpose.size = htonl (sizeof (kv)), .start_date = GNUNET_TIME_timestamp_hton (start_date), .auditor_pub = *auditor_pub, }; GNUNET_CRYPTO_hash (auditor_url, strlen (auditor_url) + 1, &kv.h_auditor_url); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_auditor_add_verify ( const struct TALER_AuditorPublicKeyP *auditor_pub, const char *auditor_url, struct GNUNET_TIME_Timestamp start_date, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterAddAuditorPS aa = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_ADD_AUDITOR), .purpose.size = htonl (sizeof (aa)), .start_date = GNUNET_TIME_timestamp_hton (start_date), .auditor_pub = *auditor_pub }; GNUNET_CRYPTO_hash (auditor_url, strlen (auditor_url) + 1, &aa.h_auditor_url); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_ADD_AUDITOR, &aa, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Signature made by the exchange offline key over the information of * an auditor to be removed from the exchange's set of auditors. */ struct TALER_MasterDelAuditorPS { /** * Purpose is #TALER_SIGNATURE_MASTER_DEL_AUDITOR. Signed * by a `struct TALER_MasterPublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Time of the change. */ struct GNUNET_TIME_TimestampNBO end_date; /** * Public key of the auditor. */ struct TALER_AuditorPublicKeyP auditor_pub; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_auditor_del_sign ( const struct TALER_AuditorPublicKeyP *auditor_pub, struct GNUNET_TIME_Timestamp end_date, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterDelAuditorPS kv = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DEL_AUDITOR), .purpose.size = htonl (sizeof (kv)), .end_date = GNUNET_TIME_timestamp_hton (end_date), .auditor_pub = *auditor_pub, }; GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_auditor_del_verify ( const struct TALER_AuditorPublicKeyP *auditor_pub, struct GNUNET_TIME_Timestamp end_date, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterDelAuditorPS da = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_DEL_AUDITOR), .purpose.size = htonl (sizeof (da)), .end_date = GNUNET_TIME_timestamp_hton (end_date), .auditor_pub = *auditor_pub }; return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DEL_AUDITOR, &da, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Message confirming that a denomination key was revoked. */ struct TALER_MasterDenominationKeyRevocationPS { /** * Purpose is #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Hash of the denomination key. */ struct TALER_DenominationHashP h_denom_pub; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_denomination_revoke_sign ( const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterDenominationKeyRevocationPS rm = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED), .purpose.size = htonl (sizeof (rm)), .h_denom_pub = *h_denom_pub }; GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &rm, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_denomination_revoke_verify ( const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterDenominationKeyRevocationPS kr = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED), .purpose.size = htonl (sizeof (kr)), .h_denom_pub = *h_denom_pub }; return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED, &kr, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Message confirming that an exchange online signing key was revoked. */ struct TALER_MasterSigningKeyRevocationPS { /** * Purpose is #TALER_SIGNATURE_MASTER_SIGNING_KEY_REVOKED. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * The exchange's public key. */ struct TALER_ExchangePublicKeyP exchange_pub; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_signkey_revoke_sign ( const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterSigningKeyRevocationPS kv = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_SIGNING_KEY_REVOKED), .purpose.size = htonl (sizeof (kv)), .exchange_pub = *exchange_pub }; GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_signkey_revoke_verify ( const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterSigningKeyRevocationPS rm = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_SIGNING_KEY_REVOKED), .purpose.size = htonl (sizeof (rm)), .exchange_pub = *exchange_pub }; return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_SIGNING_KEY_REVOKED, &rm, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Information about a signing key of the exchange. Signing keys are used * to sign exchange messages other than coins, i.e. to confirm that a * deposit was successful or that a refresh was accepted. */ struct TALER_ExchangeSigningKeyValidityPS { /** * Purpose is #TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * When does this signing key begin to be valid? */ struct GNUNET_TIME_TimestampNBO start; /** * When does this signing key expire? Note: This is currently when * the Exchange will definitively stop using it. Signatures made with * the key remain valid until @e end. When checking validity periods, * clients should allow for some overlap between keys and tolerate * the use of either key during the overlap time (due to the * possibility of clock skew). */ struct GNUNET_TIME_TimestampNBO expire; /** * When do signatures with this signing key become invalid? After * this point, these signatures cannot be used in (legal) disputes * anymore, as the Exchange is then allowed to destroy its side of the * evidence. @e end is expected to be significantly larger than @e * expire (by a year or more). */ struct GNUNET_TIME_TimestampNBO end; /** * The public online signing key that the exchange will use * between @e start and @e expire. */ struct TALER_ExchangePublicKeyP signkey_pub; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_signkey_validity_sign ( const struct TALER_ExchangePublicKeyP *exchange_pub, struct GNUNET_TIME_Timestamp start_sign, struct GNUNET_TIME_Timestamp end_sign, struct GNUNET_TIME_Timestamp end_legal, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_ExchangeSigningKeyValidityPS skv = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY), .purpose.size = htonl (sizeof (skv)), .start = GNUNET_TIME_timestamp_hton (start_sign), .expire = GNUNET_TIME_timestamp_hton (end_sign), .end = GNUNET_TIME_timestamp_hton (end_legal), .signkey_pub = *exchange_pub }; GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &skv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_signkey_validity_verify ( const struct TALER_ExchangePublicKeyP *exchange_pub, struct GNUNET_TIME_Timestamp start_sign, struct GNUNET_TIME_Timestamp end_sign, struct GNUNET_TIME_Timestamp end_legal, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_ExchangeSigningKeyValidityPS skv = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY), .purpose.size = htonl (sizeof (skv)), .start = GNUNET_TIME_timestamp_hton (start_sign), .expire = GNUNET_TIME_timestamp_hton (end_sign), .end = GNUNET_TIME_timestamp_hton (end_legal), .signkey_pub = *exchange_pub }; return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, &skv, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Information about a denomination key. Denomination keys * are used to sign coins of a certain value into existence. */ struct TALER_DenominationKeyValidityPS { /** * Purpose is #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * The long-term offline master key of the exchange that was * used to create @e signature. * * Note: This member is not strictly required, but here for * backwards-compatibility. If we ever again badly break * compatibility, we might want to remove it. */ struct TALER_MasterPublicKeyP master; /** * Start time of the validity period for this key. */ struct GNUNET_TIME_TimestampNBO start; /** * The exchange will sign fresh coins between @e start and this time. * @e expire_withdraw will be somewhat larger than @e start to * ensure a sufficiently large anonymity set, while also allowing * the Exchange to limit the financial damage in case of a key being * compromised. Thus, exchanges with low volume are expected to have a * longer withdraw period (@e expire_withdraw - @e start) than exchanges * with high transaction volume. The period may also differ between * types of coins. A exchange may also have a few denomination keys * with the same value with overlapping validity periods, to address * issues such as clock skew. */ struct GNUNET_TIME_TimestampNBO expire_withdraw; /** * Coins signed with the denomination key must be spent or refreshed * between @e start and this expiration time. After this time, the * exchange will refuse transactions involving this key as it will * "drop" the table with double-spending information (shortly after) * this time. Note that wallets should refresh coins significantly * before this time to be on the safe side. @e expire_deposit must be * significantly larger than @e expire_withdraw (by months or even * years). */ struct GNUNET_TIME_TimestampNBO expire_deposit; /** * When do signatures with this denomination key become invalid? * After this point, these signatures cannot be used in (legal) * disputes anymore, as the Exchange is then allowed to destroy its side * of the evidence. @e expire_legal is expected to be significantly * larger than @e expire_deposit (by a year or more). */ struct GNUNET_TIME_TimestampNBO expire_legal; /** * The value of the coins signed with this denomination key. */ struct TALER_AmountNBO value; /** * Fees for the coin. */ struct TALER_DenomFeeSetNBOP fees; /** * Hash code of the denomination public key. (Used to avoid having * the variable-size RSA key in this struct.) */ struct TALER_DenominationHashP denom_hash GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_denom_validity_sign ( const struct TALER_DenominationHashP *h_denom_pub, struct GNUNET_TIME_Timestamp stamp_start, struct GNUNET_TIME_Timestamp stamp_expire_withdraw, struct GNUNET_TIME_Timestamp stamp_expire_deposit, struct GNUNET_TIME_Timestamp stamp_expire_legal, const struct TALER_Amount *coin_value, const struct TALER_DenomFeeSet *fees, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_DenominationKeyValidityPS issue = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY), .purpose.size = htonl (sizeof (issue)), .start = GNUNET_TIME_timestamp_hton (stamp_start), .expire_withdraw = GNUNET_TIME_timestamp_hton (stamp_expire_withdraw), .expire_deposit = GNUNET_TIME_timestamp_hton (stamp_expire_deposit), .expire_legal = GNUNET_TIME_timestamp_hton (stamp_expire_legal), .denom_hash = *h_denom_pub }; GNUNET_CRYPTO_eddsa_key_get_public (&master_priv->eddsa_priv, &issue.master.eddsa_pub); TALER_amount_hton (&issue.value, coin_value); TALER_denom_fee_set_hton (&issue.fees, fees); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &issue, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_denom_validity_verify ( const struct TALER_DenominationHashP *h_denom_pub, struct GNUNET_TIME_Timestamp stamp_start, struct GNUNET_TIME_Timestamp stamp_expire_withdraw, struct GNUNET_TIME_Timestamp stamp_expire_deposit, struct GNUNET_TIME_Timestamp stamp_expire_legal, const struct TALER_Amount *coin_value, const struct TALER_DenomFeeSet *fees, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_DenominationKeyValidityPS dkv = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY), .purpose.size = htonl (sizeof (dkv)), .master = *master_pub, .start = GNUNET_TIME_timestamp_hton (stamp_start), .expire_withdraw = GNUNET_TIME_timestamp_hton (stamp_expire_withdraw), .expire_deposit = GNUNET_TIME_timestamp_hton (stamp_expire_deposit), .expire_legal = GNUNET_TIME_timestamp_hton (stamp_expire_legal), .denom_hash = *h_denom_pub }; TALER_amount_hton (&dkv.value, coin_value); TALER_denom_fee_set_hton (&dkv.fees, fees); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, &dkv, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Signature made by the exchange offline key over the information of * a payto:// URI to be added to the exchange's set of active wire accounts. */ struct TALER_MasterAddWirePS { /** * Purpose is #TALER_SIGNATURE_MASTER_ADD_WIRE. Signed * by a `struct TALER_MasterPublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Time of the change. */ struct GNUNET_TIME_TimestampNBO start_date; /** * Hash over the exchange's payto URI. */ struct TALER_FullPaytoHashP h_payto GNUNET_PACKED; /** * Hash over the conversion URL, all zeros if there * is no conversion URL. */ struct GNUNET_HashCode h_conversion_url; /** * Hash over the debit restrictions. */ struct GNUNET_HashCode h_debit_restrictions; /** * Hash over the credit restrictions. */ struct GNUNET_HashCode h_credit_restrictions; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_wire_add_sign ( const struct TALER_FullPayto payto_uri, const char *conversion_url, const json_t *debit_restrictions, const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp now, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterAddWirePS kv = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_ADD_WIRE), .purpose.size = htonl (sizeof (kv)), .start_date = GNUNET_TIME_timestamp_hton (now), }; TALER_full_payto_hash (payto_uri, &kv.h_payto); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, strlen (conversion_url) + 1, &kv.h_conversion_url); TALER_json_hash (debit_restrictions, &kv.h_debit_restrictions); TALER_json_hash (credit_restrictions, &kv.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_add_verify ( const struct TALER_FullPayto payto_uri, const char *conversion_url, const json_t *debit_restrictions, const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp sign_time, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterAddWirePS aw = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_ADD_WIRE), .purpose.size = htonl (sizeof (aw)), .start_date = GNUNET_TIME_timestamp_hton (sign_time), }; TALER_full_payto_hash (payto_uri, &aw.h_payto); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, strlen (conversion_url) + 1, &aw.h_conversion_url); TALER_json_hash (debit_restrictions, &aw.h_debit_restrictions); TALER_json_hash (credit_restrictions, &aw.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_ADD_WIRE, &aw, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Signature made by the exchange offline key over the information of * a wire method to be removed to the exchange's set of active accounts. */ struct TALER_MasterDelWirePS { /** * Purpose is #TALER_SIGNATURE_MASTER_DEL_WIRE. Signed * by a `struct TALER_MasterPublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Time of the change. */ struct GNUNET_TIME_TimestampNBO end_date; /** * Hash over the exchange's payto URI. */ struct TALER_FullPaytoHashP h_payto GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_wire_del_sign ( const struct TALER_FullPayto payto_uri, struct GNUNET_TIME_Timestamp now, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterDelWirePS kv = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DEL_WIRE), .purpose.size = htonl (sizeof (kv)), .end_date = GNUNET_TIME_timestamp_hton (now), }; TALER_full_payto_hash (payto_uri, &kv.h_payto); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_del_verify ( const struct TALER_FullPayto payto_uri, struct GNUNET_TIME_Timestamp sign_time, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterDelWirePS aw = { .purpose.purpose = htonl ( TALER_SIGNATURE_MASTER_DEL_WIRE), .purpose.size = htonl (sizeof (aw)), .end_date = GNUNET_TIME_timestamp_hton (sign_time), }; TALER_full_payto_hash (payto_uri, &aw.h_payto); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_DEL_WIRE, &aw, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Information signed by the exchange's master * key stating the wire fee to be paid per wire transfer. */ struct TALER_MasterWireFeePS { /** * Purpose is #TALER_SIGNATURE_MASTER_WIRE_FEES. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Hash over the wire method (yes, H("x-taler-bank") or H("iban")), in lower * case, including 0-terminator. Used to uniquely identify which * wire method these fees apply to. */ struct GNUNET_HashCode h_wire_method; /** * Start date when the fee goes into effect. */ struct GNUNET_TIME_TimestampNBO start_date; /** * End date when the fee stops being in effect (exclusive) */ struct GNUNET_TIME_TimestampNBO end_date; /** * Fees charged for wire transfers using the * given wire method. */ struct TALER_WireFeeSetNBOP fees; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_wire_fee_sign ( const char *payment_method, struct GNUNET_TIME_Timestamp start_time, struct GNUNET_TIME_Timestamp end_time, const struct TALER_WireFeeSet *fees, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterWireFeePS kv = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES), .purpose.size = htonl (sizeof (kv)), .start_date = GNUNET_TIME_timestamp_hton (start_time), .end_date = GNUNET_TIME_timestamp_hton (end_time), }; GNUNET_CRYPTO_hash (payment_method, strlen (payment_method) + 1, &kv.h_wire_method); TALER_wire_fee_set_hton (&kv.fees, fees); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_fee_verify ( const char *payment_method, struct GNUNET_TIME_Timestamp start_time, struct GNUNET_TIME_Timestamp end_time, const struct TALER_WireFeeSet *fees, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterWireFeePS wf = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES), .purpose.size = htonl (sizeof (wf)), .start_date = GNUNET_TIME_timestamp_hton (start_time), .end_date = GNUNET_TIME_timestamp_hton (end_time) }; GNUNET_CRYPTO_hash (payment_method, strlen (payment_method) + 1, &wf.h_wire_method); TALER_wire_fee_set_hton (&wf.fees, fees); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_FEES, &wf, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * Global fees charged by the exchange independent of * denomination or wire method. */ struct TALER_MasterGlobalFeePS { /** * Purpose is #TALER_SIGNATURE_MASTER_GLOBAL_FEES. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Start date when the fee goes into effect. */ struct GNUNET_TIME_TimestampNBO start_date; /** * End date when the fee stops being in effect (exclusive) */ struct GNUNET_TIME_TimestampNBO end_date; /** * How long does an exchange keep a purse around after a purse * has expired (or been successfully merged)? A 'GET' request * for a purse will succeed until the purse expiration time * plus this value. */ struct GNUNET_TIME_RelativeNBO purse_timeout; /** * How long will the exchange preserve the account history? After an * account was deleted/closed, the exchange will retain the account history * for legal reasons until this time. */ struct GNUNET_TIME_RelativeNBO history_expiration; /** * Fee charged to the merchant per wire transfer. */ struct TALER_GlobalFeeSetNBOP fees; /** * Number of concurrent purses that any * account holder is allowed to create without having * to pay the @e purse_fee. Here given in NBO. */ uint32_t purse_account_limit; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_global_fee_sign ( struct GNUNET_TIME_Timestamp start_time, struct GNUNET_TIME_Timestamp end_time, const struct TALER_GlobalFeeSet *fees, struct GNUNET_TIME_Relative purse_timeout, struct GNUNET_TIME_Relative history_expiration, uint32_t purse_account_limit, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterGlobalFeePS wf = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_GLOBAL_FEES), .purpose.size = htonl (sizeof (wf)), .start_date = GNUNET_TIME_timestamp_hton (start_time), .end_date = GNUNET_TIME_timestamp_hton (end_time), .purse_timeout = GNUNET_TIME_relative_hton (purse_timeout), .history_expiration = GNUNET_TIME_relative_hton (history_expiration), .purse_account_limit = htonl (purse_account_limit) }; TALER_global_fee_set_hton (&wf.fees, fees); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wf, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_global_fee_verify ( struct GNUNET_TIME_Timestamp start_time, struct GNUNET_TIME_Timestamp end_time, const struct TALER_GlobalFeeSet *fees, struct GNUNET_TIME_Relative purse_timeout, struct GNUNET_TIME_Relative history_expiration, uint32_t purse_account_limit, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterGlobalFeePS wf = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_GLOBAL_FEES), .purpose.size = htonl (sizeof (wf)), .start_date = GNUNET_TIME_timestamp_hton (start_time), .end_date = GNUNET_TIME_timestamp_hton (end_time), .purse_timeout = GNUNET_TIME_relative_hton (purse_timeout), .history_expiration = GNUNET_TIME_relative_hton (history_expiration), .purse_account_limit = htonl (purse_account_limit) }; TALER_global_fee_set_hton (&wf.fees, fees); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_GLOBAL_FEES, &wf, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Signature made by the exchange offline key over the manifest of * an extension. */ struct TALER_MasterExtensionManifestPS { /** * Purpose is #TALER_SIGNATURE_MASTER_EXTENSION. Signed * by a `struct TALER_MasterPublicKeyP` using EdDSA. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Hash of the JSON object that represents the manifests of extensions. */ struct TALER_ExtensionManifestsHashP h_manifest GNUNET_PACKED; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_extension_manifests_hash_sign ( const struct TALER_ExtensionManifestsHashP *h_manifest, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterExtensionManifestPS ec = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION), .purpose.size = htonl (sizeof(ec)), .h_manifest = *h_manifest }; GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &ec, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_extension_manifests_hash_verify ( const struct TALER_ExtensionManifestsHashP *h_manifest, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig ) { struct TALER_MasterExtensionManifestPS ec = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION), .purpose.size = htonl (sizeof(ec)), .h_manifest = *h_manifest }; return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_EXTENSION, &ec, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * @brief Information signed by the exchange's master * key affirming the IBAN details for the exchange. */ struct TALER_MasterWireDetailsPS { /** * Purpose is #TALER_SIGNATURE_MASTER_WIRE_DETAILS. */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * Hash over the account holder's payto:// URL. */ struct TALER_FullPaytoHashP h_wire_details GNUNET_PACKED; /** * Hash over the conversion URL, all zeros if there * is no conversion URL. */ struct GNUNET_HashCode h_conversion_url; /** * Hash over the debit restrictions. */ struct GNUNET_HashCode h_debit_restrictions; /** * Hash over the credit restrictions. */ struct GNUNET_HashCode h_credit_restrictions; }; GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_exchange_wire_signature_check ( const struct TALER_FullPayto payto_uri, const char *conversion_url, const json_t *debit_restrictions, const json_t *credit_restrictions, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterWireDetailsPS wd = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_DETAILS), .purpose.size = htonl (sizeof (wd)) }; TALER_full_payto_hash (payto_uri, &wd.h_wire_details); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, strlen (conversion_url) + 1, &wd.h_conversion_url); TALER_json_hash (debit_restrictions, &wd.h_debit_restrictions); TALER_json_hash (credit_restrictions, &wd.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS, &wd, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } void TALER_exchange_wire_signature_make ( const struct TALER_FullPayto payto_uri, const char *conversion_url, const json_t *debit_restrictions, const json_t *credit_restrictions, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_MasterWireDetailsPS wd = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_DETAILS), .purpose.size = htonl (sizeof (wd)) }; TALER_full_payto_hash (payto_uri, &wd.h_wire_details); if (NULL != conversion_url) GNUNET_CRYPTO_hash (conversion_url, strlen (conversion_url) + 1, &wd.h_conversion_url); TALER_json_hash (debit_restrictions, &wd.h_debit_restrictions); TALER_json_hash (credit_restrictions, &wd.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wd, &master_sig->eddsa_signature); } GNUNET_NETWORK_STRUCT_BEGIN /** * Message signed by account to merge a purse into a reserve. */ struct TALER_PartnerConfigurationPS { /** * Purpose is #TALER_SIGNATURE_MASTER_PARNTER_DETAILS */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; struct TALER_MasterPublicKeyP partner_pub; struct GNUNET_TIME_TimestampNBO start_date; struct GNUNET_TIME_TimestampNBO end_date; struct GNUNET_TIME_RelativeNBO wad_frequency; struct TALER_AmountNBO wad_fee; struct GNUNET_HashCode h_url; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_partner_details_sign ( const struct TALER_MasterPublicKeyP *partner_pub, struct GNUNET_TIME_Timestamp start_date, struct GNUNET_TIME_Timestamp end_date, struct GNUNET_TIME_Relative wad_frequency, const struct TALER_Amount *wad_fee, const char *partner_base_url, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_PartnerConfigurationPS wd = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_PARTNER_DETAILS), .purpose.size = htonl (sizeof (wd)), .partner_pub = *partner_pub, .start_date = GNUNET_TIME_timestamp_hton (start_date), .end_date = GNUNET_TIME_timestamp_hton (end_date), .wad_frequency = GNUNET_TIME_relative_hton (wad_frequency), }; GNUNET_CRYPTO_hash (partner_base_url, strlen (partner_base_url) + 1, &wd.h_url); TALER_amount_hton (&wd.wad_fee, wad_fee); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wd, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_partner_details_verify ( const struct TALER_MasterPublicKeyP *partner_pub, struct GNUNET_TIME_Timestamp start_date, struct GNUNET_TIME_Timestamp end_date, struct GNUNET_TIME_Relative wad_frequency, const struct TALER_Amount *wad_fee, const char *partner_base_url, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_PartnerConfigurationPS wd = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_PARTNER_DETAILS), .purpose.size = htonl (sizeof (wd)), .partner_pub = *partner_pub, .start_date = GNUNET_TIME_timestamp_hton (start_date), .end_date = GNUNET_TIME_timestamp_hton (end_date), .wad_frequency = GNUNET_TIME_relative_hton (wad_frequency), }; GNUNET_CRYPTO_hash (partner_base_url, strlen (partner_base_url) + 1, &wd.h_url); TALER_amount_hton (&wd.wad_fee, wad_fee); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_PARTNER_DETAILS, &wd, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } GNUNET_NETWORK_STRUCT_BEGIN /** * Message signed by account to drain profits * from the escrow account of the exchange. */ struct TALER_DrainProfitPS { /** * Purpose is #TALER_SIGNATURE_MASTER_DRAIN_PROFITS */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; struct TALER_WireTransferIdentifierRawP wtid; struct GNUNET_TIME_TimestampNBO date; struct TALER_AmountNBO amount; struct GNUNET_HashCode h_section; struct TALER_FullPaytoHashP h_payto; }; GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_profit_drain_sign ( const struct TALER_WireTransferIdentifierRawP *wtid, struct GNUNET_TIME_Timestamp date, const struct TALER_Amount *amount, const char *account_section, const struct TALER_FullPayto payto_uri, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { struct TALER_DrainProfitPS wd = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DRAIN_PROFIT), .purpose.size = htonl (sizeof (wd)), .wtid = *wtid, .date = GNUNET_TIME_timestamp_hton (date), }; GNUNET_CRYPTO_hash (account_section, strlen (account_section) + 1, &wd.h_section); TALER_full_payto_hash (payto_uri, &wd.h_payto); TALER_amount_hton (&wd.amount, amount); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wd, &master_sig->eddsa_signature); } enum GNUNET_GenericReturnValue TALER_exchange_offline_profit_drain_verify ( const struct TALER_WireTransferIdentifierRawP *wtid, struct GNUNET_TIME_Timestamp date, const struct TALER_Amount *amount, const char *account_section, const struct TALER_FullPayto payto_uri, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { struct TALER_DrainProfitPS wd = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DRAIN_PROFIT), .purpose.size = htonl (sizeof (wd)), .wtid = *wtid, .date = GNUNET_TIME_timestamp_hton (date), }; GNUNET_CRYPTO_hash (account_section, strlen (account_section) + 1, &wd.h_section); TALER_full_payto_hash (payto_uri, &wd.h_payto); TALER_amount_hton (&wd.amount, amount); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DRAIN_PROFIT, &wd, &master_sig->eddsa_signature, &master_pub->eddsa_pub); } /* end of offline_signatures.c */