mention need to audit randomness of gamma

This commit is contained in:
Christian Grothoff 2015-09-27 20:32:30 +02:00
commit bf8b9d1435
2159 changed files with 115320 additions and 1535 deletions

1
.gitignore vendored
View File

@ -30,6 +30,7 @@ GTAGS
src/lib/test_mint_api src/lib/test_mint_api
doc/doxygen/doxygen_sqlite3.db doc/doxygen/doxygen_sqlite3.db
src/mint-lib/test_mint_api src/mint-lib/test_mint_api
src/mint-tools/taler-auditor-sign
src/mint-tools/taler-mint-dbinit src/mint-tools/taler-mint-dbinit
src/mint-tools/taler-mint-keycheck src/mint-tools/taler-mint-keycheck
src/mint-tools/taler-mint-keyup src/mint-tools/taler-mint-keyup

View File

@ -2,7 +2,8 @@
# Currency supported by the mint (can only be one) # Currency supported by the mint (can only be one)
CURRENCY = EUR CURRENCY = EUR
# Wire format supproted by the mint (currently only SEPA is implemented) # Wire format supported by the mint, case-insensitive.
# Examples for formats include 'test' for testing and 'sepa' (for EU IBAN).
WIREFORMAT = SEPA WIREFORMAT = SEPA
# HTTP port the mint listens to # HTTP port the mint listens to
@ -19,3 +20,9 @@ TESTRUN = YES
[mintdb-postgres] [mintdb-postgres]
DB_CONN_STR = "postgres:///talercheck" DB_CONN_STR = "postgres:///talercheck"
[mint-wire-sepa]
SEPA_RESPONSE_FILE = "sepa.json"
[mint-wire-test]
REDIRECT_URL = "http://test/"

View File

@ -3,6 +3,7 @@
SUBDIRS = . doxygen SUBDIRS = . doxygen
man_MANS = \ man_MANS = \
taler-auditor-sign.1 \
taler-mint-dbinit.1 \ taler-mint-dbinit.1 \
taler-mint-httpd.1 \ taler-mint-httpd.1 \
taler-mint-keyup.1 \ taler-mint-keyup.1 \

98714
doc/paper/rfc.bib Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,13 @@
year={2008} year={2008}
} }
@InProceedings{apod,
author = {Elli Androulaki and Steven Bellovin},
title = {APOD: Anonymous Physical Object Delivery},
booktitle = {Symposium on Privacy-Enhancing Technologies (PETS)},
year = {2009},
}
@Article{blum1981, @Article{blum1981,
author = {Manuel Blum}, author = {Manuel Blum},
title = {Coin Flipping by Telephone}, title = {Coin Flipping by Telephone},
@ -12,6 +19,64 @@
pages = {11-15}, pages = {11-15},
} }
@Misc{greece2015cash,
author = {Reuters},
title = {Greek council recommends 60 euro limit on ATM withdrawals from Tuesday},
howpublished = {\url{http://www.reuters.com/article/2015/06/28/eurozone-greece-limits-idUSA8N0Z302P20150628}},
month = {June},
year = {2015},
}
@Misc{france2015cash,
author = {Heinz-Peter Bader},
title = {France steps up monitoring of cash payments to fight low-cost terrorism},
howpublished = {\url{http://www.reuters.com/article/2015/03/18/us-france-security-financing-idUSKBN0ME14720150318}},
month = {Mar},
year = {2015},
}
@Misc{fatf1997,
title = {FATF-IX report on money laundering typologies},
howpublished = {\url{http://www.fatf-gafi.org/media/fatf/documents/reports/1996\%201997\%20ENG.pdf}},
month = {feb},
year = {1998},
}
@TechReport{,
author = {},
title = {},
institution = {},
year = {},
OPTkey = {},
OPTtype = {},
OPTnumber = {},
OPTaddress = {},
OPTmonth = {},
OPTnote = {},
OPTannote = {}
}
@InProceedings{sander1999escrow,
author = {Tomas Sander and Amnon Ta-Shma},
title = {On Anonymous Electronic Cash and Crime},
booktitle = {ISW'99},
year = {1999},
series = {LNCS 1729},
pages = {202--206},
}
@Article{solms1992perfect,
author = {Sebastiaan H. von Solms and David Naccache},
title = {On blind signatures and perfect crimes},
journal = {Computers \& Security},
year = {1992},
volume = {11},
number = {6},
pages = {581--583},
}
@inproceedings{chaum1990untraceable, @inproceedings{chaum1990untraceable,
title={Untraceable electronic cash}, title={Untraceable electronic cash},
author={Chaum, David and Fiat, Amos and Naor, Moni}, author={Chaum, David and Fiat, Amos and Naor, Moni},
@ -48,6 +113,23 @@
organization={IEEE} organization={IEEE}
} }
@InProceedings{fc2014murdoch,
author = {Stephen Murdoch and Ross Anderson},
title = {Security Protocols and Evidence: Where Many Payment Systems Fail},
booktitle = {Financial Cryptography and Data Security},
year = {2014},
}
@book{ engels1844,
author = "Friedrich Engels",
title = "{Umrisse zu einer Kritik der National\"okonomie}",
year = "1844",
publisher = "Ruge and Marx, Paris",
}
@inproceedings{selby2004analyzing, @inproceedings{selby2004analyzing,
title={Analyzing the Success and Failure of Recent e-Payment Schemes}, title={Analyzing the Success and Failure of Recent e-Payment Schemes},
author={Selby, Jack R}, author={Selby, Jack R},
@ -91,4 +173,3 @@
www_pdf_url = {https://www.torproject.org/svn/trunk/doc/design-paper/tor-design.pdf}, www_pdf_url = {https://www.torproject.org/svn/trunk/doc/design-paper/tor-design.pdf},
www_section = {Anonymous communication}, www_section = {Anonymous communication},
} }

File diff suppressed because it is too large Load Diff

35
doc/taler-auditor-sign.1 Normal file
View File

@ -0,0 +1,35 @@
.TH TALER\-AUDITOR\-SIGN 1 "Sep 15, 2015" "GNU Taler"
.SH NAME
taler\-auditor\-sign \- Sign mint denomination as auditor.
.SH SYNOPSIS
.B taler\-auditor\-sign
.RI [ options ]
.br
.SH DESCRIPTION
\fBtaler\-auditor\-sign\fP is a command line tool to be used by an auditor to sign that he is aware of certain keys being used by a mint. Using this signature, the auditor affirms that he will verify that the mint is properly accounting for those coins.
.SH OPTIONS
.B
.IP "\-a FILE, \-\-auditor-key=FILE"
Location of the private EdDSA auditor key. If it does not exist, it will be created.
.B
.IP "\-h, \-\-help"
Print short help on options.
.B
.IP "\-m KEY, \-\-mint-key=KEY"
Public key of the mint in Crockford base32 encoding, for example as generated by gnunet\-ecc \-p.
.B
.IP "\-r FILE, \-\-mint-request=FILE"
File with the mint's denomination key signing request as generated by taler\-mint\-keyup \-o.
.B
.IP "\-o FILE, \-\-output=FILE"
File where the auditor should write the EdDSA signature.
.SH BUGS
Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
.SH "SEE ALSO"
\fBtaler\-mint\-keyup\fP(1), \fBgnunet\-ecc\fP(1), \fBtaler.conf\fP(5)

View File

@ -13,6 +13,9 @@ taler\-mint\-httpd \- Run Taler mint (with RESTful API)
.SH OPTIONS .SH OPTIONS
.B .B
.IP "\-C, \-\-connection-close"
Force each HTTP connection to be closed after each request (useful in combination with \-f to avoid having to wait for nc to time out).
.B
.IP "\-d DIRNAME, \-\-mint-dir=DIRNAME" .IP "\-d DIRNAME, \-\-mint-dir=DIRNAME"
Use the configuration and other resources for the mint to operate from DIRNAME. Use the configuration and other resources for the mint to operate from DIRNAME.
.B .B

View File

@ -22,6 +22,9 @@ Print short help on options.
.IP "\-m FILE, \-\-master-key=FILE" .IP "\-m FILE, \-\-master-key=FILE"
Location of the private EdDSA offline master key of the mint. Location of the private EdDSA offline master key of the mint.
.B .B
.IP "\-o FILE, \-\-ouptut=FILE"
Where to write a denomination key signing request file to be given to the auditor.
.B
.IP "\-t TIMESTAMP, \-\-time=TIMESTAMP" .IP "\-t TIMESTAMP, \-\-time=TIMESTAMP"
Operate as if the current time was TIMESTAMP. Operate as if the current time was TIMESTAMP.
.B .B

View File

@ -189,6 +189,18 @@ struct TALER_AuditorPublicKeyP
}; };
/**
* @brief Type of the public key used by the auditor.
*/
struct TALER_AuditorSignatureP
{
/**
* Taler uses EdDSA signatures for auditors.
*/
struct GNUNET_CRYPTO_EddsaSignature eddsa_sig;
};
/** /**
* @brief Type of the offline master public keys used by the mint. * @brief Type of the offline master public keys used by the mint.
*/ */

View File

@ -167,12 +167,12 @@ TALER_hash_json (json_t *json,
/** /**
* Check if the given wire format JSON object is correctly formatted * Check if the given wire format JSON object is correctly formatted
* *
* @param type the type of the wire format * @param allowed NULL-terminated array of allowed wire format types
* @param wire the JSON wire format object * @param wire the JSON wire format object
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not * @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
*/ */
int int
TALER_json_validate_wireformat (const char *type, TALER_json_validate_wireformat (const char **allowed,
const json_t *wire); const json_t *wire);

View File

@ -149,6 +149,11 @@ struct TALER_MINT_DenomPublicKey
*/ */
struct TALER_DenominationPublicKey key; struct TALER_DenominationPublicKey key;
/**
* The hash of the public key.
*/
struct GNUNET_HashCode h_key;
/** /**
* Timestamp indicating when the denomination key becomes valid * Timestamp indicating when the denomination key becomes valid
*/ */
@ -165,6 +170,15 @@ struct TALER_MINT_DenomPublicKey
*/ */
struct GNUNET_TIME_Absolute deposit_valid_until; struct GNUNET_TIME_Absolute deposit_valid_until;
/**
* When do signatures with this denomination key become invalid?
* After this point, these signatures cannot be used in (legal)
* disputes anymore, as the Mint is then allowed to destroy its side
* of the evidence. @e expire_legal is expected to be significantly
* larger than @e expire_spend (by a year or more).
*/
struct GNUNET_TIME_Absolute expire_legal;
/** /**
* The value of this denomination * The value of this denomination
*/ */
@ -204,6 +218,8 @@ struct TALER_MINT_AuditorInformation
* that website. We expect that in practice software is going to * that website. We expect that in practice software is going to
* often ship with an initial list of accepted auditors, just like * often ship with an initial list of accepted auditors, just like
* browsers ship with a CA root store. * browsers ship with a CA root store.
*
* This field may be NULL. (#3987).
*/ */
const char *auditor_url; const char *auditor_url;
@ -218,7 +234,7 @@ struct TALER_MINT_AuditorInformation
* elements point to the same locations as the entries * elements point to the same locations as the entries
* in the key's main `denom_keys` array. * in the key's main `denom_keys` array.
*/ */
struct TALER_MINT_DenomPublicKey *const*denom_keys; const struct TALER_MINT_DenomPublicKey **denom_keys;
}; };
@ -246,7 +262,7 @@ struct TALER_MINT_Keys
/** /**
* Array of the keys of the auditors of the mint. * Array of the keys of the auditors of the mint.
*/ */
struct TALER_AuditorPublicKeyP *auditors; struct TALER_MINT_AuditorInformation *auditors;
/** /**
* Length of the @e sign_keys array. * Length of the @e sign_keys array.
@ -353,6 +369,100 @@ TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys,
const struct TALER_DenominationPublicKey *pk); const struct TALER_DenominationPublicKey *pk);
/**
* Obtain the denomination key details from the mint.
*
* @param keys the mint's key set
* @param hc hash of the public key of the denomination to lookup
* @return details about the given denomination key
*/
const struct TALER_MINT_DenomPublicKey *
TALER_MINT_get_denomination_key_by_hash (const struct TALER_MINT_Keys *keys,
const struct GNUNET_HashCode *hc);
/* ********************* /wire *********************** */
/**
* @brief A Wire format inquiry handle
*/
struct TALER_MINT_WireHandle;
/**
* Callbacks of this type are used to serve the result of submitting a
* wire format inquiry request to a mint.
*
* The callback is invoked multiple times, once for each supported @a
* method. Finally, it is invoked one more time with cls/0/NULL/NULL
* to indicate the end of the iteration. If any request fails to
* generate a valid response from the mint, @a http_status will also
* be zero and the iteration will also end. Thus, the iteration
* always ends with a final call with an @a http_status of 0. If the
* @a http_status is already 0 on the first call, then the response to
* the /wire request was invalid. Later, clients can tell the
* difference between @a http_status of 0 indicating a failed
* /wire/method request and a regular end of the iteration by @a
* method being non-NULL. If the mint simply correctly asserts that
* it does not support any methods, @a method will be NULL but the @a
* http_status will be #MHD_HTTP_OK for the first call (followed by a
* cls/0/NULL/NULL call to signal the end of the iteration).
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
* 0 if the mint's reply is bogus (fails to follow the protocol)
* @param method wire format method supported, i.e. "test" or "sepa", or NULL
* if already the /wire request failed.
* @param obj the received JSON reply, if successful this should be the wire
* format details as provided by /wire/METHOD/, or NULL if the
* reply was not in JSON format (in this case, the client might
* want to do an HTTP request to /wire/METHOD/ with a browser to
* provide more information to the user about the @a method).
*/
typedef void
(*TALER_MINT_WireResultCallback) (void *cls,
unsigned int http_status,
const char *method,
json_t *obj);
/**
* Obtain information about a mint's wire instructions.
* A mint may provide wire instructions for creating
* a reserve. The wire instructions also indicate
* which wire formats merchants may use with the mint.
* This API is typically used by a wallet for wiring
* funds, and possibly by a merchant to determine
* supported wire formats.
*
* Note that while we return the (main) response verbatim to the
* caller for further processing, we do already verify that the
* response is well-formed (i.e. that signatures included in the
* response are all valid). If the mint's reply is not well-formed,
* we return an HTTP status code of zero to @a cb.
*
* @param mint the mint handle; the mint must be ready to operate
* @param wire_cb the callback to call when a reply for this request is available
* @param wire_cb_cls closure for the above callback
* @return a handle for this request
*/
struct TALER_MINT_WireHandle *
TALER_MINT_wire (struct TALER_MINT_Handle *mint,
TALER_MINT_WireResultCallback wire_cb,
void *wire_cb_cls);
/**
* Cancel a wire information request. This function cannot be used
* on a request handle if a response is already served for it.
*
* @param wh the wire information request handle
*/
void
TALER_MINT_wire_cancel (struct TALER_MINT_WireHandle *wh);
/* ********************* /deposit *********************** */ /* ********************* /deposit *********************** */
@ -437,13 +547,13 @@ void
TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit); TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit);
/* ********************* /withdraw/status *********************** */ /* ********************* /reserve/status *********************** */
/** /**
* @brief A /withdraw/status Handle * @brief A /reserve/status Handle
*/ */
struct TALER_MINT_WithdrawStatusHandle; struct TALER_MINT_ReserveStatusHandle;
/** /**
@ -513,7 +623,7 @@ struct TALER_MINT_ReserveHistory
* @param history detailed transaction history, NULL on error * @param history detailed transaction history, NULL on error
*/ */
typedef void typedef void
(*TALER_MINT_WithdrawStatusResultCallback) (void *cls, (*TALER_MINT_ReserveStatusResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
json_t *json, json_t *json,
const struct TALER_Amount *balance, const struct TALER_Amount *balance,
@ -537,10 +647,10 @@ typedef void
* @return a handle for this request; NULL if the inputs are invalid (i.e. * @return a handle for this request; NULL if the inputs are invalid (i.e.
* signatures fail to verify). In this case, the callback is not called. * signatures fail to verify). In this case, the callback is not called.
*/ */
struct TALER_MINT_WithdrawStatusHandle * struct TALER_MINT_ReserveStatusHandle *
TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint, TALER_MINT_reserve_status (struct TALER_MINT_Handle *mint,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
TALER_MINT_WithdrawStatusResultCallback cb, TALER_MINT_ReserveStatusResultCallback cb,
void *cb_cls); void *cb_cls);
@ -551,16 +661,16 @@ TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint,
* @param wsh the withdraw status request handle * @param wsh the withdraw status request handle
*/ */
void void
TALER_MINT_withdraw_status_cancel (struct TALER_MINT_WithdrawStatusHandle *wsh); TALER_MINT_reserve_status_cancel (struct TALER_MINT_ReserveStatusHandle *wsh);
/* ********************* /withdraw/sign *********************** */ /* ********************* /reserve/withdraw *********************** */
/** /**
* @brief A /withdraw/sign Handle * @brief A /reserve/withdraw Handle
*/ */
struct TALER_MINT_WithdrawSignHandle; struct TALER_MINT_ReserveWithdrawHandle;
/** /**
@ -574,14 +684,14 @@ struct TALER_MINT_WithdrawSignHandle;
* @param full_response full response from the mint (for logging, in case of errors) * @param full_response full response from the mint (for logging, in case of errors)
*/ */
typedef void typedef void
(*TALER_MINT_WithdrawSignResultCallback) (void *cls, (*TALER_MINT_ReserveWithdrawResultCallback) (void *cls,
unsigned int http_status, unsigned int http_status,
const struct TALER_DenominationSignature *sig, const struct TALER_DenominationSignature *sig,
json_t *full_response); json_t *full_response);
/** /**
* Withdraw a coin from the mint using a /withdraw/sign request. This * Withdraw a coin from the mint using a /reserve/withdraw request. This
* API is typically used by a wallet. Note that to ensure that no * API is typically used by a wallet. Note that to ensure that no
* money is lost in case of hardware failures, the caller must have * money is lost in case of hardware failures, the caller must have
* committed (most of) the arguments to disk before calling, and be * committed (most of) the arguments to disk before calling, and be
@ -601,13 +711,13 @@ typedef void
* if the inputs are invalid (i.e. denomination key not with this mint). * if the inputs are invalid (i.e. denomination key not with this mint).
* In this case, the callback is not called. * In this case, the callback is not called.
*/ */
struct TALER_MINT_WithdrawSignHandle * struct TALER_MINT_ReserveWithdrawHandle *
TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint, TALER_MINT_reserve_withdraw (struct TALER_MINT_Handle *mint,
const struct TALER_MINT_DenomPublicKey *pk, const struct TALER_MINT_DenomPublicKey *pk,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_CoinSpendPrivateKeyP *coin_priv, const struct TALER_CoinSpendPrivateKeyP *coin_priv,
const struct TALER_DenominationBlindingKey *blinding_key, const struct TALER_DenominationBlindingKey *blinding_key,
TALER_MINT_WithdrawSignResultCallback res_cb, TALER_MINT_ReserveWithdrawResultCallback res_cb,
void *res_cb_cls); void *res_cb_cls);
@ -618,7 +728,7 @@ TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint,
* @param sign the withdraw sign request handle * @param sign the withdraw sign request handle
*/ */
void void
TALER_MINT_withdraw_sign_cancel (struct TALER_MINT_WithdrawSignHandle *sign); TALER_MINT_reserve_withdraw_cancel (struct TALER_MINT_ReserveWithdrawHandle *sign);
/* ********************* /refresh/melt+reveal ***************************** */ /* ********************* /refresh/melt+reveal ***************************** */

View File

@ -37,6 +37,12 @@
*/ */
#define TALER_MINTDB_DIR_DENOMINATION_KEYS "denomkeys" #define TALER_MINTDB_DIR_DENOMINATION_KEYS "denomkeys"
/**
* Subdirectory under the mint's base directory which contains
* the mint's auditing information.
*/
#define TALER_MINTDB_DIR_AUDITORS "auditors"
GNUNET_NETWORK_STRUCT_BEGIN GNUNET_NETWORK_STRUCT_BEGIN
@ -123,23 +129,6 @@ typedef int
const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski); const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski);
/**
* @brief Iterator over denomination keys.
*
* @param cls closure
* @param dki the denomination key
* @param alias coin alias
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
*/
typedef int
(*TALER_MINTDB_DenominationKeyIterator)(void *cls,
const char *alias,
const struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
/** /**
* Call @a it for each signing key found in the @a mint_base_dir. * Call @a it for each signing key found in the @a mint_base_dir.
* *
@ -158,6 +147,23 @@ TALER_MINTDB_signing_keys_iterate (const char *mint_base_dir,
void *it_cls); void *it_cls);
/**
* @brief Iterator over denomination keys.
*
* @param cls closure
* @param dki the denomination key
* @param alias coin alias
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
*/
typedef int
(*TALER_MINTDB_DenominationKeyIterator)(void *cls,
const char *alias,
const struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
/** /**
* Call @a it for each denomination key found in the @a mint_base_dir. * Call @a it for each denomination key found in the @a mint_base_dir.
* *
@ -201,6 +207,67 @@ TALER_MINTDB_denomination_key_read (const char *filename,
struct TALER_MINTDB_DenominationKeyIssueInformation *dki); struct TALER_MINTDB_DenominationKeyIssueInformation *dki);
/**
* @brief Iterator over auditor information.
*
* @param cls closure
* @param apub the auditor's public key
* @param mpub the mint's public key (as expected by the auditor)
* @param dki_len length of @a asig and @a dki arrays
* @param asigs array of the auditor's signatures over the @a dks, of length @a dki_len
* @param dki array of denomination coin data signed by the auditor, of length @a dki_len
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
*/
typedef int
(*TALER_MINTDB_AuditorIterator)(void *cls,
const struct TALER_AuditorPublicKeyP *apub,
const struct TALER_MasterPublicKeyP *mpub,
unsigned int dki_len,
const struct TALER_AuditorSignatureP *asigs,
const struct TALER_DenominationKeyValidityPS *dki);
/**
* Call @a it with information for each auditor found in the @a mint_base_dir.
*
* @param mint_base_dir base directory for the mint,
* the signing keys must be in the #TALER_MINTDB_DIR_DENOMINATION_KEYS
* subdirectory
* @param it function to call with auditor information
* @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_MINTDB_auditor_iterate (const char *mint_base_dir,
TALER_MINTDB_AuditorIterator it,
void *it_cls);
/**
* Write auditor information to the given file.
*
* @param filename the file where to write the auditor information to
* @param apub the auditor's public key
* @param asigs the auditor's signatures, array of length @a dki_len
* @param mpub the mint's public key (as expected by the auditor)
* @param dki_len length of @a dki and @a asigs arrays
* @param dki array of denomination coin data signed by the auditor
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
*/
int
TALER_MINTDB_auditor_write (const char *filename,
const struct TALER_AuditorPublicKeyP *apub,
const struct TALER_AuditorSignatureP *asigs,
const struct TALER_MasterPublicKeyP *mpub,
unsigned int dki_len,
const struct TALER_DenominationKeyValidityPS *dki);
/** /**
* Initialize the plugin. * Initialize the plugin.
* *

View File

@ -416,30 +416,6 @@ struct TALER_MINTDB_LinkDataList
}; };
/**
* @brief Specification for a /lock operation.
*/
struct TALER_MINTDB_LockOperation
{
/**
* Information about the coin that is being locked.
*/
struct TALER_CoinPublicInfo coin;
/**
* Signature over the locking operation.
*/
struct TALER_CoinSpendSignatureP coin_sig;
/**
* How much value is being locked?
*/
struct TALER_Amount amount;
// FIXME: more needed...
};
/** /**
* @brief Enumeration to classify the different types of transactions * @brief Enumeration to classify the different types of transactions
* that can be done with a coin. * that can be done with a coin.
@ -454,12 +430,8 @@ enum TALER_MINTDB_TransactionType
/** /**
* /refresh/melt operation. * /refresh/melt operation.
*/ */
TALER_MINTDB_TT_REFRESH_MELT = 1, TALER_MINTDB_TT_REFRESH_MELT = 1
/**
* /lock operation.
*/
TALER_MINTDB_TT_LOCK = 2
}; };
@ -495,11 +467,6 @@ struct TALER_MINTDB_TransactionList
*/ */
struct TALER_MINTDB_RefreshMelt *melt; struct TALER_MINTDB_RefreshMelt *melt;
/**
* Details if transaction was a /lock operation.
*/
struct TALER_MINTDB_LockOperation *lock;
} details; } details;
}; };
@ -549,6 +516,31 @@ struct TALER_MINTDB_MeltCommitment
struct TALER_MINTDB_Session; struct TALER_MINTDB_Session;
/**
* Function called with details about deposits that
* have been made, with the goal of executing the
* corresponding wire transaction.
*
* @param cls closure
* @param id transaction ID (used as future `min_id` to avoid
* iterating over transactions more than once)
* @param amount_with_fee amount that was deposited including fee
* @param deposit_fee amount the mint gets to keep as transaction fees
* @param transaction_id unique transaction ID chosen by the merchant
* @param h_contract hash of the contract between merchant and customer
* @param wire wire details for the merchant
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
typedef int
(*TALER_MINTDB_DepositIterator)(void *cls,
uint64_t id,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *deposit_fee,
uint64_t transaction_id,
const struct GNUNET_HashCode *h_contract,
const json_t *wire);
/** /**
* Function called with the session hashes and transfer secret * Function called with the session hashes and transfer secret
* information for a given coin. * information for a given coin.
@ -636,23 +628,24 @@ struct TALER_MINTDB_Plugin
* Commit a transaction. * Commit a transaction.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion connection to use * @param session connection to use
* @return #GNUNET_OK on success * @return #GNUNET_OK on success, #GNUNET_NO if the transaction
* can be retried, #GNUNET_SYSERR on hard failures
*/ */
int int
(*commit) (void *cls, (*commit) (void *cls,
struct TALER_MINTDB_Session *sesssion); struct TALER_MINTDB_Session *session);
/** /**
* Abort/rollback a transaction. * Abort/rollback a transaction.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion connection to use * @param session connection to use
*/ */
void void
(*rollback) (void *cls, (*rollback) (void *cls,
struct TALER_MINTDB_Session *sesssion); struct TALER_MINTDB_Session *session);
/** /**
@ -661,7 +654,7 @@ struct TALER_MINTDB_Plugin
* with this key have. * with this key have.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion connection to use * @param session connection to use
* @param denom_pub the public key used for signing coins of this denomination * @param denom_pub the public key used for signing coins of this denomination
* @param issue issuing information with value, fees and other info about the coin * @param issue issuing information with value, fees and other info about the coin
* @return #GNUNET_OK on success; #GNUNET_SYSERR on failure * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure
@ -677,7 +670,7 @@ struct TALER_MINTDB_Plugin
* Fetch information about a denomination key. * Fetch information about a denomination key.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion connection to use * @param session connection to use
* @param denom_pub the public key used for signing coins of this denomination * @param denom_pub the public key used for signing coins of this denomination
* @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL * @param[out] issue set to issue information with value, fees and other info about the coin, can be NULL
* @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure * @return #GNUNET_OK on success; #GNUNET_NO if no record was found, #GNUNET_SYSERR on failure
@ -736,7 +729,7 @@ struct TALER_MINTDB_Plugin
* key of the hash of the blinded message. * key of the hash of the blinded message.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param h_blind hash of the blinded coin to be signed (will match * @param h_blind hash of the blinded coin to be signed (will match
* `h_coin_envelope` in the @a collectable to be returned) * `h_coin_envelope` in the @a collectable to be returned)
* @param collectable corresponding collectable coin (blind signature) * @param collectable corresponding collectable coin (blind signature)
@ -747,7 +740,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_withdraw_info) (void *cls, (*get_withdraw_info) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *h_blind, const struct GNUNET_HashCode *h_blind,
struct TALER_MINTDB_CollectableBlindcoin *collectable); struct TALER_MINTDB_CollectableBlindcoin *collectable);
@ -757,7 +750,7 @@ struct TALER_MINTDB_Plugin
* hash of the blinded message. * hash of the blinded message.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param collectable corresponding collectable coin (blind signature) * @param collectable corresponding collectable coin (blind signature)
* if a coin is found * if a coin is found
* @return #GNUNET_SYSERR on internal error * @return #GNUNET_SYSERR on internal error
@ -766,7 +759,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_withdraw_info) (void *cls, (*insert_withdraw_info) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct TALER_MINTDB_CollectableBlindcoin *collectable); const struct TALER_MINTDB_CollectableBlindcoin *collectable);
@ -775,13 +768,13 @@ struct TALER_MINTDB_Plugin
* reserve. * reserve.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion connection to use * @param session connection to use
* @param reserve_pub public key of the reserve * @param reserve_pub public key of the reserve
* @return known transaction history (NULL if reserve is unknown) * @return known transaction history (NULL if reserve is unknown)
*/ */
struct TALER_MINTDB_ReserveHistory * struct TALER_MINTDB_ReserveHistory *
(*get_reserve_history) (void *cls, (*get_reserve_history) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct TALER_ReservePublicKeyP *reserve_pub); const struct TALER_ReservePublicKeyP *reserve_pub);
@ -800,7 +793,7 @@ struct TALER_MINTDB_Plugin
* Check if we have the specified deposit already in the database. * Check if we have the specified deposit already in the database.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param deposit deposit to search for * @param deposit deposit to search for
* @return #GNUNET_YES if we know this operation, * @return #GNUNET_YES if we know this operation,
* #GNUNET_NO if this exact deposit is unknown to us, * #GNUNET_NO if this exact deposit is unknown to us,
@ -808,30 +801,53 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*have_deposit) (void *cls, (*have_deposit) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct TALER_MINTDB_Deposit *deposit); const struct TALER_MINTDB_Deposit *deposit);
/** /**
* Insert information about deposited coin into the * Insert information about deposited coin into the database.
* database.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion connection to the database * @param session connection to the database
* @param deposit deposit information to store * @param deposit deposit information to store
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/ */
int int
(*insert_deposit) (void *cls, (*insert_deposit) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct TALER_MINTDB_Deposit *deposit); const struct TALER_MINTDB_Deposit *deposit);
/**
* Obtain information about deposits. Iterates over all deposits
* above a certain ID. Use a @a min_id of 0 to start at the beginning.
* This operation is executed in its own transaction in transaction
* mode "REPEATABLE READ", i.e. we should only see valid deposits.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to the database
* @param min_id deposit to start at
* @param limit maximum number of transactions to fetch
* @param deposit_cb function to call for each deposit
* @param deposit_cb_cls closure for @a deposit_cb
* @return number of rows processed, 0 if none exist,
* #GNUNET_SYSERR on error
*/
int
(*iterate_deposits) (void *cls,
struct TALER_MINTDB_Session *session,
uint64_t min_id,
uint32_t limit,
TALER_MINTDB_DepositIterator deposit_cb,
void *deposit_cb_cls);
/** /**
* Lookup refresh session data under the given @a session_hash. * Lookup refresh session data under the given @a session_hash.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database handle to use * @param session database handle to use
* @param session_hash hash over the melt to use for the lookup * @param session_hash hash over the melt to use for the lookup
* @param[out] refresh_session where to store the result * @param[out] refresh_session where to store the result
* @return #GNUNET_YES on success, * @return #GNUNET_YES on success,
@ -840,7 +856,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_refresh_session) (void *cls, (*get_refresh_session) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
struct TALER_MINTDB_RefreshSession *refresh_session); struct TALER_MINTDB_RefreshSession *refresh_session);
@ -849,7 +865,7 @@ struct TALER_MINTDB_Plugin
* Store new refresh session data under the given @a session_hash. * Store new refresh session data under the given @a session_hash.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database handle to use * @param session database handle to use
* @param session_hash hash over the melt to use to locate the session * @param session_hash hash over the melt to use to locate the session
* @param refresh_session session data to store * @param refresh_session session data to store
* @return #GNUNET_YES on success, * @return #GNUNET_YES on success,
@ -857,7 +873,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*create_refresh_session) (void *cls, (*create_refresh_session) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
const struct TALER_MINTDB_RefreshSession *refresh_session); const struct TALER_MINTDB_RefreshSession *refresh_session);
@ -866,7 +882,7 @@ struct TALER_MINTDB_Plugin
* Store the given /refresh/melt request in the database. * Store the given /refresh/melt request in the database.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param oldcoin_index index of the coin to store * @param oldcoin_index index of the coin to store
* @param melt coin melt operation details to store; includes * @param melt coin melt operation details to store; includes
* the session hash of the melt * the session hash of the melt
@ -875,7 +891,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_refresh_melt) (void *cls, (*insert_refresh_melt) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
uint16_t oldcoin_index, uint16_t oldcoin_index,
const struct TALER_MINTDB_RefreshMelt *melt); const struct TALER_MINTDB_RefreshMelt *melt);
@ -884,7 +900,7 @@ struct TALER_MINTDB_Plugin
* Get information about melted coin details from the database. * Get information about melted coin details from the database.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param oldcoin_index index of the coin to retrieve * @param oldcoin_index index of the coin to retrieve
* @param melt melt data to fill in, can be NULL * @param melt melt data to fill in, can be NULL
@ -893,7 +909,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_refresh_melt) (void *cls, (*get_refresh_melt) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t oldcoin_index, uint16_t oldcoin_index,
struct TALER_MINTDB_RefreshMelt *melt); struct TALER_MINTDB_RefreshMelt *melt);
@ -904,7 +920,7 @@ struct TALER_MINTDB_Plugin
* in a given refresh operation. * in a given refresh operation.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param num_newcoins number of coins to generate, size of the @a denom_pubs array * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
* @param denom_pubs array denominations of the coins to create * @param denom_pubs array denominations of the coins to create
@ -913,7 +929,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_refresh_order) (void *cls, (*insert_refresh_order) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t num_newcoins, uint16_t num_newcoins,
const struct TALER_DenominationPublicKey *denom_pubs); const struct TALER_DenominationPublicKey *denom_pubs);
@ -924,7 +940,7 @@ struct TALER_MINTDB_Plugin
* create in the given refresh operation. * create in the given refresh operation.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param num_newcoins size of the @a denom_pubs array * @param num_newcoins size of the @a denom_pubs array
* @param[out] denom_pubs where to write @a num_newcoins denomination keys * @param[out] denom_pubs where to write @a num_newcoins denomination keys
@ -933,7 +949,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_refresh_order) (void *cls, (*get_refresh_order) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t num_newcoins, uint16_t num_newcoins,
struct TALER_DenominationPublicKey *denom_pubs); struct TALER_DenominationPublicKey *denom_pubs);
@ -944,7 +960,7 @@ struct TALER_MINTDB_Plugin
* for the given refresh session in the database. * for the given refresh session in the database.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA
* @param num_newcoins coin index size of the @a commit_coins array * @param num_newcoins coin index size of the @a commit_coins array
@ -954,7 +970,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_refresh_commit_coins) (void *cls, (*insert_refresh_commit_coins) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t cnc_index, uint16_t cnc_index,
uint16_t num_newcoins, uint16_t num_newcoins,
@ -966,7 +982,7 @@ struct TALER_MINTDB_Plugin
* given coin of the given refresh session from the database. * given coin of the given refresh session from the database.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param cnc_index cut and choose set index (1st dimension) * @param cnc_index cut and choose set index (1st dimension)
* @param num_coins size of the @a commit_coins array * @param num_coins size of the @a commit_coins array
@ -977,7 +993,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_refresh_commit_coins) (void *cls, (*get_refresh_commit_coins) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t cnc_index, uint16_t cnc_index,
uint16_t num_coins, uint16_t num_coins,
@ -989,7 +1005,7 @@ struct TALER_MINTDB_Plugin
* for the given refresh session. * for the given refresh session.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA * @param cnc_index cut and choose index (1st dimension), relating to #TALER_CNC_KAPPA
* @param num_links size of the @a commit_link array * @param num_links size of the @a commit_link array
@ -998,7 +1014,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_refresh_commit_links) (void *cls, (*insert_refresh_commit_links) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t cnc_index, uint16_t cnc_index,
uint16_t num_links, uint16_t num_links,
@ -1009,7 +1025,7 @@ struct TALER_MINTDB_Plugin
* for the given refresh session. * for the given refresh session.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param cnc_index cut and choose index (1st dimension) * @param cnc_index cut and choose index (1st dimension)
* @param num_links size of the @a links array to return * @param num_links size of the @a links array to return
@ -1020,7 +1036,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_refresh_commit_links) (void *cls, (*get_refresh_commit_links) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t cnc_index, uint16_t cnc_index,
uint16_t num_links, uint16_t num_links,
@ -1031,14 +1047,14 @@ struct TALER_MINTDB_Plugin
* Get all of the information from the given melt commit operation. * Get all of the information from the given melt commit operation.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection to use * @param session database connection to use
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @return NULL if the @a session_hash does not correspond to any known melt * @return NULL if the @a session_hash does not correspond to any known melt
* operation * operation
*/ */
struct TALER_MINTDB_MeltCommitment * struct TALER_MINTDB_MeltCommitment *
(*get_melt_commitment) (void *cls, (*get_melt_commitment) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash); const struct GNUNET_HashCode *session_hash);
@ -1060,7 +1076,7 @@ struct TALER_MINTDB_Plugin
* be used to try to obtain the private keys during "/refresh/link". * be used to try to obtain the private keys during "/refresh/link".
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param session_hash hash to identify refresh session * @param session_hash hash to identify refresh session
* @param newcoin_index coin index * @param newcoin_index coin index
* @param ev_sig coin signature * @param ev_sig coin signature
@ -1068,7 +1084,7 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*insert_refresh_out) (void *cls, (*insert_refresh_out) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash, const struct GNUNET_HashCode *session_hash,
uint16_t newcoin_index, uint16_t newcoin_index,
const struct TALER_DenominationSignature *ev_sig); const struct TALER_DenominationSignature *ev_sig);
@ -1079,13 +1095,13 @@ struct TALER_MINTDB_Plugin
* information, the denomination keys and the signatures. * information, the denomination keys and the signatures.
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param session_hash session to get linkage data for * @param session_hash session to get linkage data for
* @return all known link data for the session * @return all known link data for the session
*/ */
struct TALER_MINTDB_LinkDataList * struct TALER_MINTDB_LinkDataList *
(*get_link_data_list) (void *cls, (*get_link_data_list) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct GNUNET_HashCode *session_hash); const struct GNUNET_HashCode *session_hash);
@ -1108,7 +1124,7 @@ struct TALER_MINTDB_Plugin
* *
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param coin_pub public key of the coin * @param coin_pub public key of the coin
* @param tdc function to call for each session the coin was melted into * @param tdc function to call for each session the coin was melted into
* @param tdc_cls closure for @a tdc * @param tdc_cls closure for @a tdc
@ -1118,56 +1134,24 @@ struct TALER_MINTDB_Plugin
*/ */
int int
(*get_transfer) (void *cls, (*get_transfer) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
TALER_MINTDB_TransferDataCallback tdc, TALER_MINTDB_TransferDataCallback tdc,
void *tdc_cls); void *tdc_cls);
/**
* Test if the given /lock request is known to us.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection
* @param lock lock operation
* @return #GNUNET_YES if known,
* #GNUNET_NO if not,
* #GNUNET_SYSERR on internal error
*/
int
(*have_lock) (void *cls,
struct TALER_MINTDB_Session *sesssion,
const struct TALER_MINTDB_LockOperation *lock);
/**
* Store the given /lock request in the database.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection
* @param lock lock operation
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
int
(*insert_lock) (void *cls,
struct TALER_MINTDB_Session *sesssion,
const struct TALER_MINTDB_LockOperation *lock);
/** /**
* Compile a list of all (historic) transactions performed * Compile a list of all (historic) transactions performed
* with the given coin (/refresh/melt and /deposit operations). * with the given coin (/refresh/melt and /deposit operations).
* *
* @param cls the @e cls of this struct with the plugin-specific state * @param cls the @e cls of this struct with the plugin-specific state
* @param sesssion database connection * @param session database connection
* @param coin_pub coin to investigate * @param coin_pub coin to investigate
* @return list of transactions, NULL if coin is fresh * @return list of transactions, NULL if coin is fresh
*/ */
struct TALER_MINTDB_TransactionList * struct TALER_MINTDB_TransactionList *
(*get_coin_transactions) (void *cls, (*get_coin_transactions) (void *cls,
struct TALER_MINTDB_Session *sesssion, struct TALER_MINTDB_Session *session,
const struct TALER_CoinSpendPublicKeyP *coin_pub); const struct TALER_CoinSpendPublicKeyP *coin_pub);

View File

@ -653,13 +653,73 @@ struct TALER_MintKeyValidityPS
struct TALER_MasterPublicKeyP master; struct TALER_MasterPublicKeyP master;
/** /**
* Array of hash(es) of the mint's denomination keys. * Start time of the validity period for this key.
* Specifically, this is the hash over the
* `struct TALER_DenominationKeyValidityPS`, not just
* the public key (as the auditor needs to check against
* the correct valuations and fee structure).
*/ */
/* struct GNUNET_HashCode h_dks; */ struct GNUNET_TIME_AbsoluteNBO start;
/**
* The mint 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 Mint to limit the financial damage in case of a key being
* compromised. Thus, mints with low volume are expected to have a
* longer withdraw period (@e expire_withdraw - @e start) than mints
* with high transaction volume. The period may also differ between
* types of coins. A mint 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_AbsoluteNBO expire_withdraw;
/**
* Coins signed with the denomination key must be spent or refreshed
* between @e start and this expiration time. After this time, the
* mint 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_spend must be
* significantly larger than @e expire_withdraw (by months or even
* years).
*/
struct GNUNET_TIME_AbsoluteNBO expire_spend;
/**
* When do signatures with this denomination key become invalid?
* After this point, these signatures cannot be used in (legal)
* disputes anymore, as the Mint is then allowed to destroy its side
* of the evidence. @e expire_legal is expected to be significantly
* larger than @e expire_spend (by a year or more).
*/
struct GNUNET_TIME_AbsoluteNBO expire_legal;
/**
* The value of the coins signed with this denomination key.
*/
struct TALER_AmountNBO value;
/**
* The fee the mint charges when a coin of this type is withdrawn.
* (can be zero).
*/
struct TALER_AmountNBO fee_withdraw;
/**
* The fee the mint charges when a coin of this type is deposited.
* (can be zero).
*/
struct TALER_AmountNBO fee_deposit;
/**
* The fee the mint charges when a coin of this type is refreshed.
* (can be zero).
*/
struct TALER_AmountNBO fee_refresh;
/**
* Hash code of the denomination public key. (Used to avoid having
* the variable-size RSA key in this struct.)
*/
struct GNUNET_HashCode denom_hash GNUNET_PACKED;
}; };

View File

@ -22,7 +22,8 @@ libtalermint_la_SOURCES = \
mint_api_deposit.c \ mint_api_deposit.c \
mint_api_refresh.c \ mint_api_refresh.c \
mint_api_refresh_link.c \ mint_api_refresh_link.c \
mint_api_withdraw.c mint_api_reserve.c \
mint_api_wire.c
libtalermint_la_LIBADD = \ libtalermint_la_LIBADD = \
-lgnunetutil \ -lgnunetutil \

View File

@ -0,0 +1,34 @@
#!/bin/sh
#
# This file is part of TALER
# Copyright (C) 2015 GNUnet e.V.
#
# TALER is free software; you can redistribute it and/or modify it under the
# terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License along with
# TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
#
#
# This will generate testcases in a directory 'afl-tests', which can then
# be moved into src/mint/afl-tests/ to be run during mint-testing.
#
# This script uses American Fuzzy Loop (AFL) to fuzz the mint to
# automatically create tests with good coverage. You must install
# AFL and set AFL_HOME to the directory where AFL is installed
# before running. Also, a directory "baseline/" should exist with
# templates for inputs for AFL to fuzz. These can be generated
# by running wireshark on loopback while running 'make check' in
# this directory. Save each HTTP request to a new file.
#
# Note that you want to switch 'TESTRUN = NO' and pre-init the
# database before running this, otherwise it will be awfully slow.
#
# Must be run from this directory.
#
$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-mint-httpd -f /tmp/afl-input -d test-mint-home/ -C

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,8 @@
POST /deposit HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 1658
Expect: 100-continue
{"ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26E9M8S0M6CSH6X334GSN8RW30D9G8MT46CA660W34GSG6MT4AD9K8GT3ECSH6MVK0E2374V38H1M8MR4CDJ66MWK4E1S6MR3GCT28CV32H1Q8N23GCHG70S36C1K8MS3GCSN8RV36D9S710KGD9K6GWKEGJ28GRM4CJ56X1K6DJ18D2KGHA46D13GDA66GVK4GHJ8N13AE9J8RVK6GT184S48E1K6X336G9Q8N142CJ4692M6EA16GRKJD9N6523ADA36X13GG9G70TK6DHN68R36CT18GR4CDSJ6CW3GCT364W46CSR8RV42GJ474SMADSH851K4H9Q8GS42CHS8RV3GCSJ64V46DSN8RSM6HHN6N246D9S6934AH9P6X23JGSH652K0DJ5612KJGA26N242CH35452081918G2J2G0","timestamp":"/Date(1442821652)/","f":{"currency":"EUR","value":5,"fraction":0},"wire":{"type":"TEST","bank":"dest bank","account":42},"coin_pub":"JXWK4NS0H2W4V4BETQ90CCEDADP6QQ3MV3YZ7RV2KXEM8PWXE8Q0","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","H_contract":"1CMEEFQ5S4QJGGAMVYFV07XQRHQA311CR2MTRNC5M9KZV6ETDV1SY00WJFEV2CG9BXQTEQPZAF8A54C2HX32TZCN20VBGPFPS2Z16B0","merchant_pub":"C36TEXQXFW00170C2EJ66ZR0000CX9VPZNZG00109NX020000000","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","transaction_id":1,"refund_deadline":"/Date(0)/","coin_sig":"X16E0DP8C2BJNVNX09G24FFC5GA4W7RN2YXZP9WJTAN9BY6B4GMA39QNYR51XNNEZ3H1J7TP0K9G55JZ8V7WS7CZMD7E64HWYBFWM00"}

View File

@ -0,0 +1,7 @@
GET /keys HTTP/1.1
User-Agent: Wget/1.16.3 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: 127.0.0.1:8081
Connection: Keep-Alive

View File

@ -0,0 +1,5 @@
GET /refresh/link?coin_pub=WQHES0X5XK43VBG1Y8FXR2YEJM04HQVMDTCS07MH691XWADG8QCG HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
POST /refresh/reveal HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 255
{"session_hash":"V97SB8T670M9V71D1Q0KVQ4GSJCVQ5AAKTTH9QKT0ZJZZBFNZAV4NA8NMWRRGVPFEBEGB6ANCN9BPQASJ40TM4Y1C49648TJJ07PGSG","transfer_privs":[["EQKJA401A9NJ2YJDFZJ1EV8AYXBHWZB6NT5T0TWSJHVKVDM6W8A0"],["TKDJ4DF3GZVG0DGAB9E3RGBGSTANYB6JVVWXJGPMB2AY4VQNTBA0"]]}

View File

@ -0,0 +1,4 @@
GET /reserve/status?reserve_pub=TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0 HTTP/1.1
Host: localhost:8081
Accept: */*

View File

@ -0,0 +1,7 @@
POST /reserve/withdraw HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 919
{"coin_ev":"Q5X8A8TCBFH7E5BMY7HSB17SHFTM1JPJGV61P2CA7Z9EXG8P2HYS69B31NZESKXHSZHNJ2DQN3CC2AWFNC6V90J577JD3TXBMAY8Y5M9V60KKT73Z1DW24JFSNAK91G1F2WT55ADP1EG7N5F9AY7A7ZJD03MPYSH0RDP7SVZS2KRPA5JRHFR4GDJ59CFNE7A43M95ZKQHQAS8","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","reserve_sig":"8427B3RTB217124EB1C37ZVJFC08KN17RHGHE9ENZQMQVJ0S11SAX6H8Z06SWCKT06DRQ9DQ8XD786XKQ94T27PYR9GC9EMT1Y02W10"}

View File

@ -0,0 +1,5 @@
GET /wire HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

View File

@ -0,0 +1,5 @@
GET /wire/sepa HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

View File

@ -0,0 +1,5 @@
GET /wire/test HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

View File

@ -435,6 +435,29 @@ MAC_download_get_result (struct MAC_DownloadBuffer *db,
{ {
json_t *json; json_t *json;
json_error_t error; json_error_t error;
char *ct;
if ( (CURLE_OK !=
curl_easy_getinfo (eh,
CURLINFO_CONTENT_TYPE,
&ct)) ||
(NULL == ct) ||
(0 != strcasecmp (ct,
"application/json")) )
{
/* No content type or explicitly not JSON, refuse to parse
(but keep response code) */
if (CURLE_OK !=
curl_easy_getinfo (eh,
CURLINFO_RESPONSE_CODE,
response_code))
{
/* unexpected error... */
GNUNET_break (0);
*response_code = 0;
}
return NULL;
}
json = NULL; json = NULL;
if (0 == db->eno) if (0 == db->eno)

View File

@ -325,9 +325,11 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey *denom_key,
&denom_key_issue.denom_hash, &denom_key_issue.denom_hash,
sizeof (struct GNUNET_HashCode)); sizeof (struct GNUNET_HashCode));
denom_key->key.rsa_public_key = pk; denom_key->key.rsa_public_key = pk;
denom_key->h_key = denom_key_issue.denom_hash;
denom_key->valid_from = valid_from; denom_key->valid_from = valid_from;
denom_key->withdraw_valid_until = withdraw_valid_until; denom_key->withdraw_valid_until = withdraw_valid_until;
denom_key->deposit_valid_until = deposit_valid_until; denom_key->deposit_valid_until = deposit_valid_until;
denom_key->expire_legal = expire_legal;
denom_key->value = value; denom_key->value = value;
denom_key->fee_withdraw = fee_withdraw; denom_key->fee_withdraw = fee_withdraw;
denom_key->fee_deposit = fee_deposit; denom_key->fee_deposit = fee_deposit;
@ -340,6 +342,116 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey *denom_key,
} }
/**
* Parse a mint's auditor information encoded in JSON.
*
* @param[out] auditor where to return the result
* @param[in] auditor_obj json to parse
* @param key_data information about denomination keys
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
static int
parse_json_auditor (struct TALER_MINT_AuditorInformation *auditor,
json_t *auditor_obj,
const struct TALER_MINT_Keys *key_data)
{
json_t *keys;
json_t *key;
unsigned int len;
unsigned int off;
unsigned int i;
struct TALER_MintKeyValidityPS kv;
struct MAJ_Specification spec[] = {
MAJ_spec_fixed_auto ("auditor_pub",
&auditor->auditor_pub),
MAJ_spec_json ("denomination_keys",
&keys),
MAJ_spec_end
};
auditor->auditor_url = NULL; /* #3987 */
if (GNUNET_OK !=
MAJ_parse_json (auditor_obj,
spec))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_MINT_KEYS);
kv.purpose.size = htonl (sizeof (struct TALER_MintKeyValidityPS));
kv.master = key_data->master_pub;
len = json_array_size (keys);
auditor->denom_keys = GNUNET_new_array (len,
const struct TALER_MINT_DenomPublicKey *);
i = 0;
off = 0;
json_array_foreach (keys, i, key) {
struct TALER_AuditorSignatureP auditor_sig;
struct GNUNET_HashCode denom_h;
const struct TALER_MINT_DenomPublicKey *dk;
unsigned int j;
struct MAJ_Specification spec[] = {
MAJ_spec_fixed_auto ("denom_pub_h",
&denom_h),
MAJ_spec_fixed_auto ("auditor_sig",
&auditor_sig),
MAJ_spec_end
};
if (GNUNET_OK !=
MAJ_parse_json (key,
spec))
{
GNUNET_break_op (0);
continue;
}
dk = NULL;
for (j=0;j<key_data->num_denom_keys;j++)
{
if (0 == memcmp (&denom_h,
&key_data->denom_keys[j].h_key,
sizeof (struct GNUNET_HashCode)))
{
dk = &key_data->denom_keys[j];
break;
}
}
if (NULL == dk)
{
GNUNET_break_op (0);
continue;
}
kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until);
kv.expire_spend = GNUNET_TIME_absolute_hton (dk->deposit_valid_until);
kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
TALER_amount_hton (&kv.value,
&dk->value);
TALER_amount_hton (&kv.fee_withdraw,
&dk->fee_withdraw);
TALER_amount_hton (&kv.fee_deposit,
&dk->fee_deposit);
TALER_amount_hton (&kv.fee_refresh,
&dk->fee_refresh);
kv.denom_hash = dk->h_key;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_MINT_KEYS,
&kv.purpose,
&auditor_sig.eddsa_sig,
&auditor->auditor_pub.eddsa_pub))
{
GNUNET_break_op (0);
continue;
}
auditor->denom_keys[off] = dk;
off++;
}
auditor->num_denom_keys = off;
return GNUNET_OK;
}
/** /**
* Decode the JSON in @a resp_obj from the /keys response and store the data * Decode the JSON in @a resp_obj from the /keys response and store the data
* in the @a key_data. * in the @a key_data.
@ -394,8 +506,8 @@ decode_keys_json (json_t *resp_obj,
EXITIF (0 == (key_data->num_sign_keys = EXITIF (0 == (key_data->num_sign_keys =
json_array_size (sign_keys_array))); json_array_size (sign_keys_array)));
key_data->sign_keys key_data->sign_keys
= GNUNET_malloc (sizeof (struct TALER_MINT_SigningPublicKey) = GNUNET_new_array (key_data->num_sign_keys,
* key_data->num_sign_keys); struct TALER_MINT_SigningPublicKey);
index = 0; index = 0;
json_array_foreach (sign_keys_array, index, sign_key_obj) { json_array_foreach (sign_keys_array, index, sign_key_obj) {
EXITIF (GNUNET_SYSERR == EXITIF (GNUNET_SYSERR ==
@ -415,8 +527,8 @@ decode_keys_json (json_t *resp_obj,
json_object_get (resp_obj, "denoms"))); json_object_get (resp_obj, "denoms")));
EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array))); EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array)));
key_data->denom_keys = GNUNET_malloc (sizeof (struct TALER_MINT_DenomPublicKey) key_data->denom_keys = GNUNET_new_array (key_data->num_denom_keys,
* key_data->num_denom_keys); struct TALER_MINT_DenomPublicKey);
index = 0; index = 0;
json_array_foreach (denom_keys_array, index, denom_key_obj) { json_array_foreach (denom_keys_array, index, denom_key_obj) {
EXITIF (GNUNET_SYSERR == EXITIF (GNUNET_SYSERR ==
@ -427,7 +539,30 @@ decode_keys_json (json_t *resp_obj,
} }
} }
/* FIXME: parse the auditor keys (#3847) */ /* parse the auditor information */
{
json_t *auditors_array;
json_t *auditor_info;
unsigned int len;
unsigned int index;
EXITIF (NULL == (auditors_array =
json_object_get (resp_obj, "auditors")));
EXITIF (JSON_ARRAY != json_typeof (auditors_array));
len = json_array_size (auditors_array);
if (0 != len)
{
key_data->auditors = GNUNET_new_array (len,
struct TALER_MINT_AuditorInformation);
index = 0;
json_array_foreach (auditors_array, index, auditor_info) {
EXITIF (GNUNET_SYSERR ==
parse_json_auditor (&key_data->auditors[index],
auditor_info,
key_data));
}
}
}
/* Validate signature... */ /* Validate signature... */
ks.purpose.size = htonl (sizeof (ks)); ks.purpose.size = htonl (sizeof (ks));
@ -551,7 +686,7 @@ MAH_handle_is_ready (struct TALER_MINT_Handle *h)
* Obtain the URL to use for an API request. * Obtain the URL to use for an API request.
* *
* @param h the mint handle to query * @param h the mint handle to query
* @param path Taler API path (i.e. "/withdraw/sign") * @param path Taler API path (i.e. "/reserve/withdraw")
* @return the full URI to use with cURL * @return the full URI to use with cURL
*/ */
char * char *
@ -708,6 +843,28 @@ TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys,
} }
/**
* Obtain the denomination key details from the mint.
*
* @param keys the mint's key set
* @param hc hash of the public key of the denomination to lookup
* @return details about the given denomination key
*/
const struct TALER_MINT_DenomPublicKey *
TALER_MINT_get_denomination_key_by_hash (const struct TALER_MINT_Keys *keys,
const struct GNUNET_HashCode *hc)
{
unsigned int i;
for (i=0;i<keys->num_denom_keys;i++)
if (0 == memcmp (hc,
&keys->denom_keys[i].h_key,
sizeof (struct GNUNET_HashCode)))
return &keys->denom_keys[i];
return NULL;
}
/** /**
* Obtain the keys from the mint. * Obtain the keys from the mint.
* *

View File

@ -48,7 +48,7 @@ MAH_handle_is_ready (struct TALER_MINT_Handle *h);
* Obtain the URL to use for an API request. * Obtain the URL to use for an API request.
* *
* @param h the mint handle to query * @param h the mint handle to query
* @param path Taler API path (i.e. "/withdraw/sign") * @param path Taler API path (i.e. "/reserve/withdraw")
* @return the full URI to use with cURL * @return the full URI to use with cURL
*/ */
char * char *

View File

@ -15,8 +15,8 @@
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file mint-lib/mint_api_withdraw.c * @file mint-lib/mint_api_reserve.c
* @brief Implementation of the /withdraw requests of the mint's HTTP API * @brief Implementation of the /reserve requests of the mint's HTTP API
* @author Christian Grothoff * @author Christian Grothoff
*/ */
#include "platform.h" #include "platform.h"
@ -31,12 +31,12 @@
#include "taler_signatures.h" #include "taler_signatures.h"
/* ********************** /withdraw/status ********************** */ /* ********************** /reserve/status ********************** */
/** /**
* @brief A Withdraw Status Handle * @brief A Withdraw Status Handle
*/ */
struct TALER_MINT_WithdrawStatusHandle struct TALER_MINT_ReserveStatusHandle
{ {
/** /**
@ -57,7 +57,7 @@ struct TALER_MINT_WithdrawStatusHandle
/** /**
* Function to call with the result. * Function to call with the result.
*/ */
TALER_MINT_WithdrawStatusResultCallback cb; TALER_MINT_ReserveStatusResultCallback cb;
/** /**
* Public key of the reserve we are querying. * Public key of the reserve we are querying.
@ -264,16 +264,16 @@ parse_reserve_history (json_t *history,
/** /**
* Function called when we're done processing the * Function called when we're done processing the
* HTTP /withdraw/status request. * HTTP /reserve/status request.
* *
* @param cls the `struct TALER_MINT_WithdrawStatusHandle` * @param cls the `struct TALER_MINT_ReserveStatusHandle`
* @param eh curl handle of the request that finished * @param eh curl handle of the request that finished
*/ */
static void static void
handle_withdraw_status_finished (void *cls, handle_reserve_status_finished (void *cls,
CURL *eh) CURL *eh)
{ {
struct TALER_MINT_WithdrawStatusHandle *wsh = cls; struct TALER_MINT_ReserveStatusHandle *wsh = cls;
long response_code; long response_code;
json_t *json; json_t *json;
@ -376,7 +376,7 @@ handle_withdraw_status_finished (void *cls,
NULL, NULL,
0, NULL); 0, NULL);
json_decref (json); json_decref (json);
TALER_MINT_withdraw_status_cancel (wsh); TALER_MINT_reserve_status_cancel (wsh);
} }
@ -396,13 +396,13 @@ handle_withdraw_status_finished (void *cls,
* @return a handle for this request; NULL if the inputs are invalid (i.e. * @return a handle for this request; NULL if the inputs are invalid (i.e.
* signatures fail to verify). In this case, the callback is not called. * signatures fail to verify). In this case, the callback is not called.
*/ */
struct TALER_MINT_WithdrawStatusHandle * struct TALER_MINT_ReserveStatusHandle *
TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint, TALER_MINT_reserve_status (struct TALER_MINT_Handle *mint,
const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReservePublicKeyP *reserve_pub,
TALER_MINT_WithdrawStatusResultCallback cb, TALER_MINT_ReserveStatusResultCallback cb,
void *cb_cls) void *cb_cls)
{ {
struct TALER_MINT_WithdrawStatusHandle *wsh; struct TALER_MINT_ReserveStatusHandle *wsh;
struct TALER_MINT_Context *ctx; struct TALER_MINT_Context *ctx;
CURL *eh; CURL *eh;
char *pub_str; char *pub_str;
@ -417,10 +417,10 @@ TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint,
pub_str = GNUNET_STRINGS_data_to_string_alloc (reserve_pub, pub_str = GNUNET_STRINGS_data_to_string_alloc (reserve_pub,
sizeof (struct TALER_ReservePublicKeyP)); sizeof (struct TALER_ReservePublicKeyP));
GNUNET_asprintf (&arg_str, GNUNET_asprintf (&arg_str,
"/withdraw/status?reserve_pub=%s", "/reserve/status?reserve_pub=%s",
pub_str); pub_str);
GNUNET_free (pub_str); GNUNET_free (pub_str);
wsh = GNUNET_new (struct TALER_MINT_WithdrawStatusHandle); wsh = GNUNET_new (struct TALER_MINT_ReserveStatusHandle);
wsh->mint = mint; wsh->mint = mint;
wsh->cb = cb; wsh->cb = cb;
wsh->cb_cls = cb_cls; wsh->cb_cls = cb_cls;
@ -446,7 +446,7 @@ TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint,
wsh->job = MAC_job_add (ctx, wsh->job = MAC_job_add (ctx,
eh, eh,
GNUNET_NO, GNUNET_NO,
&handle_withdraw_status_finished, &handle_reserve_status_finished,
wsh); wsh);
return wsh; return wsh;
} }
@ -459,7 +459,7 @@ TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint,
* @param wsh the withdraw status request handle * @param wsh the withdraw status request handle
*/ */
void void
TALER_MINT_withdraw_status_cancel (struct TALER_MINT_WithdrawStatusHandle *wsh) TALER_MINT_reserve_status_cancel (struct TALER_MINT_ReserveStatusHandle *wsh)
{ {
if (NULL != wsh->job) if (NULL != wsh->job)
{ {
@ -472,12 +472,12 @@ TALER_MINT_withdraw_status_cancel (struct TALER_MINT_WithdrawStatusHandle *wsh)
} }
/* ********************** /withdraw/sign ********************** */ /* ********************** /reserve/withdraw ********************** */
/** /**
* @brief A Withdraw Sign Handle * @brief A Withdraw Sign Handle
*/ */
struct TALER_MINT_WithdrawSignHandle struct TALER_MINT_ReserveWithdrawHandle
{ {
/** /**
@ -503,7 +503,7 @@ struct TALER_MINT_WithdrawSignHandle
/** /**
* Function to call with the result. * Function to call with the result.
*/ */
TALER_MINT_WithdrawSignResultCallback cb; TALER_MINT_ReserveWithdrawResultCallback cb;
/** /**
* Key used to blind the value. * Key used to blind the value.
@ -539,7 +539,7 @@ struct TALER_MINT_WithdrawSignHandle
/** /**
* We got a 200 OK response for the /withdraw/sign operation. * We got a 200 OK response for the /reserve/withdraw operation.
* Extract the coin's signature and return it to the caller. * Extract the coin's signature and return it to the caller.
* The signature we get from the mint is for the blinded value. * The signature we get from the mint is for the blinded value.
* Thus, we first must unblind it and then should verify its * Thus, we first must unblind it and then should verify its
@ -553,7 +553,7 @@ struct TALER_MINT_WithdrawSignHandle
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/ */
static int static int
withdraw_sign_ok (struct TALER_MINT_WithdrawSignHandle *wsh, reserve_withdraw_ok (struct TALER_MINT_ReserveWithdrawHandle *wsh,
json_t *json) json_t *json)
{ {
struct GNUNET_CRYPTO_rsa_Signature *blind_sig; struct GNUNET_CRYPTO_rsa_Signature *blind_sig;
@ -598,7 +598,7 @@ withdraw_sign_ok (struct TALER_MINT_WithdrawSignHandle *wsh,
/** /**
* We got a 402 PAYMENT REQUIRED response for the /withdraw/sign operation. * We got a 402 PAYMENT REQUIRED response for the /reserve/withdraw operation.
* Check the signatures on the withdraw transactions in the provided * Check the signatures on the withdraw transactions in the provided
* history and that the balances add up. We don't do anything directly * history and that the balances add up. We don't do anything directly
* with the information, as the JSON will be returned to the application. * with the information, as the JSON will be returned to the application.
@ -610,7 +610,7 @@ withdraw_sign_ok (struct TALER_MINT_WithdrawSignHandle *wsh,
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/ */
static int static int
withdraw_sign_payment_required (struct TALER_MINT_WithdrawSignHandle *wsh, reserve_withdraw_payment_required (struct TALER_MINT_ReserveWithdrawHandle *wsh,
json_t *json) json_t *json)
{ {
struct TALER_Amount balance; struct TALER_Amount balance;
@ -690,16 +690,16 @@ withdraw_sign_payment_required (struct TALER_MINT_WithdrawSignHandle *wsh,
/** /**
* Function called when we're done processing the * Function called when we're done processing the
* HTTP /withdraw/sign request. * HTTP /reserve/withdraw request.
* *
* @param cls the `struct TALER_MINT_WithdrawSignHandle` * @param cls the `struct TALER_MINT_ReserveWithdrawHandle`
* @param eh curl handle of the request that finished * @param eh curl handle of the request that finished
*/ */
static void static void
handle_withdraw_sign_finished (void *cls, handle_reserve_withdraw_finished (void *cls,
CURL *eh) CURL *eh)
{ {
struct TALER_MINT_WithdrawSignHandle *wsh = cls; struct TALER_MINT_ReserveWithdrawHandle *wsh = cls;
long response_code; long response_code;
json_t *json; json_t *json;
@ -713,7 +713,7 @@ handle_withdraw_sign_finished (void *cls,
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
if (GNUNET_OK != if (GNUNET_OK !=
withdraw_sign_ok (wsh, reserve_withdraw_ok (wsh,
json)) json))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -728,7 +728,7 @@ handle_withdraw_sign_finished (void *cls,
/* The mint says that the reserve has insufficient funds; /* The mint says that the reserve has insufficient funds;
check the signatures in the history... */ check the signatures in the history... */
if (GNUNET_OK != if (GNUNET_OK !=
withdraw_sign_payment_required (wsh, reserve_withdraw_payment_required (wsh,
json)) json))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
@ -766,12 +766,12 @@ handle_withdraw_sign_finished (void *cls,
NULL, NULL,
json); json);
json_decref (json); json_decref (json);
TALER_MINT_withdraw_sign_cancel (wsh); TALER_MINT_reserve_withdraw_cancel (wsh);
} }
/** /**
* Withdraw a coin from the mint using a /withdraw/sign request. Note * Withdraw a coin from the mint using a /reserve/withdraw request. Note
* that to ensure that no money is lost in case of hardware failures, * that to ensure that no money is lost in case of hardware failures,
* the caller must have committed (most of) the arguments to disk * the caller must have committed (most of) the arguments to disk
* before calling, and be ready to repeat the request with the same * before calling, and be ready to repeat the request with the same
@ -790,16 +790,16 @@ handle_withdraw_sign_finished (void *cls,
* if the inputs are invalid (i.e. denomination key not with this mint). * if the inputs are invalid (i.e. denomination key not with this mint).
* In this case, the callback is not called. * In this case, the callback is not called.
*/ */
struct TALER_MINT_WithdrawSignHandle * struct TALER_MINT_ReserveWithdrawHandle *
TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint, TALER_MINT_reserve_withdraw (struct TALER_MINT_Handle *mint,
const struct TALER_MINT_DenomPublicKey *pk, const struct TALER_MINT_DenomPublicKey *pk,
const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_ReservePrivateKeyP *reserve_priv,
const struct TALER_CoinSpendPrivateKeyP *coin_priv, const struct TALER_CoinSpendPrivateKeyP *coin_priv,
const struct TALER_DenominationBlindingKey *blinding_key, const struct TALER_DenominationBlindingKey *blinding_key,
TALER_MINT_WithdrawSignResultCallback res_cb, TALER_MINT_ReserveWithdrawResultCallback res_cb,
void *res_cb_cls) void *res_cb_cls)
{ {
struct TALER_MINT_WithdrawSignHandle *wsh; struct TALER_MINT_ReserveWithdrawHandle *wsh;
struct TALER_WithdrawRequestPS req; struct TALER_WithdrawRequestPS req;
struct TALER_ReserveSignatureP reserve_sig; struct TALER_ReserveSignatureP reserve_sig;
struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CoinSpendPublicKeyP coin_pub;
@ -810,7 +810,7 @@ TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint,
json_t *withdraw_obj; json_t *withdraw_obj;
CURL *eh; CURL *eh;
wsh = GNUNET_new (struct TALER_MINT_WithdrawSignHandle); wsh = GNUNET_new (struct TALER_MINT_ReserveWithdrawHandle);
wsh->mint = mint; wsh->mint = mint;
wsh->cb = res_cb; wsh->cb = res_cb;
wsh->cb_cls = res_cb_cls; wsh->cb_cls = res_cb_cls;
@ -866,7 +866,7 @@ TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint,
GNUNET_free (coin_ev); GNUNET_free (coin_ev);
wsh->blinding_key = blinding_key; wsh->blinding_key = blinding_key;
wsh->url = MAH_path_to_url (mint, "/withdraw/sign"); wsh->url = MAH_path_to_url (mint, "/reserve/withdraw");
eh = curl_easy_init (); eh = curl_easy_init ();
GNUNET_assert (NULL != (wsh->json_enc = GNUNET_assert (NULL != (wsh->json_enc =
@ -897,7 +897,7 @@ TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint,
wsh->job = MAC_job_add (ctx, wsh->job = MAC_job_add (ctx,
eh, eh,
GNUNET_YES, GNUNET_YES,
&handle_withdraw_sign_finished, &handle_reserve_withdraw_finished,
wsh); wsh);
return wsh; return wsh;
} }
@ -910,7 +910,7 @@ TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint,
* @param sign the withdraw sign request handle * @param sign the withdraw sign request handle
*/ */
void void
TALER_MINT_withdraw_sign_cancel (struct TALER_MINT_WithdrawSignHandle *sign) TALER_MINT_reserve_withdraw_cancel (struct TALER_MINT_ReserveWithdrawHandle *sign)
{ {
if (NULL != sign->job) if (NULL != sign->job)
{ {
@ -924,4 +924,4 @@ TALER_MINT_withdraw_sign_cancel (struct TALER_MINT_WithdrawSignHandle *sign)
} }
/* end of mint_api_withdraw.c */ /* end of mint_api_reserve.c */

View File

@ -0,0 +1,619 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015 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
<http://www.gnu.org/licenses/>
*/
/**
* @file mint-lib/mint_api_wire.c
* @brief Implementation of the /wire request of the mint's HTTP API
* @author Christian Grothoff
*/
#include "platform.h"
#include <curl/curl.h>
#include <jansson.h>
#include <microhttpd.h> /* just for HTTP status codes */
#include <gnunet/gnunet_util_lib.h>
#include "taler_mint_service.h"
#include "mint_api_common.h"
#include "mint_api_json.h"
#include "mint_api_context.h"
#include "mint_api_handle.h"
#include "taler_signatures.h"
/**
* @brief A Wire Handle
*/
struct TALER_MINT_WireHandle
{
/**
* The connection to mint this request handle will use
*/
struct TALER_MINT_Handle *mint;
/**
* The url for this request.
*/
char *url;
/**
* Handle for the request.
*/
struct MAC_Job *job;
/**
* Function to call with the result.
*/
TALER_MINT_WireResultCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
/**
* Download buffer
*/
struct MAC_DownloadBuffer db;
/**
* Set to the "methods" JSON array returned by the
* /wire request.
*/
json_t *methods;
/**
* Current iteration offset in the @e methods array.
*/
unsigned int methods_off;
};
/**
* Verify that the signature on the "200 OK" response
* for /wire/sepa from the mint is valid.
*
* @param wh wire handle
* @param json json reply with the signature
* @return #GNUNET_SYSERR if @a json is invalid,
* #GNUNET_NO if the method is unknown,
* #GNUNET_OK if the json is valid
*/
static int
verify_wire_sepa_signature_ok (const struct TALER_MINT_WireHandle *wh,
json_t *json)
{
struct TALER_MasterSignatureP mint_sig;
struct TALER_MasterWireSepaDetailsPS mp;
const char *receiver_name;
const char *iban;
const char *bic;
const struct TALER_MINT_Keys *key_state;
struct GNUNET_HashContext *hc;
struct MAJ_Specification spec[] = {
MAJ_spec_fixed_auto ("sig", &mint_sig),
MAJ_spec_string ("receiver_name", &receiver_name),
MAJ_spec_string ("iban", &iban),
MAJ_spec_string ("bic", &bic),
MAJ_spec_end
};
if (GNUNET_OK !=
MAJ_parse_json (json,
spec))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
key_state = TALER_MINT_get_keys (wh->mint);
mp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
mp.purpose.size = htonl (sizeof (struct TALER_MasterWireSepaDetailsPS));
hc = GNUNET_CRYPTO_hash_context_start ();
GNUNET_CRYPTO_hash_context_read (hc,
receiver_name,
strlen (receiver_name) + 1);
GNUNET_CRYPTO_hash_context_read (hc,
iban,
strlen (iban) + 1);
GNUNET_CRYPTO_hash_context_read (hc,
bic,
strlen (bic) + 1);
GNUNET_CRYPTO_hash_context_finish (hc,
&mp.h_sepa_details);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
&mp.purpose,
&mint_sig.eddsa_signature,
&key_state->master_pub.eddsa_pub))
{
GNUNET_break_op (0);
MAJ_parse_free (spec);
return GNUNET_SYSERR;
}
MAJ_parse_free (spec);
return GNUNET_OK;
}
/**
* Verify that the signature on the "200 OK" response
* for /wire/METHOD from the mint is valid.
*
* @param wh wire handle with key material
* @param method method to verify the reply for
* @param json json reply with the signature
* @return #GNUNET_SYSERR if @a json is invalid,
* #GNUNET_NO if the method is unknown,
* #GNUNET_OK if the json is valid
*/
static int
verify_wire_method_signature_ok (const struct TALER_MINT_WireHandle *wh,
const char *method,
json_t *json)
{
struct
{
/**
* Name fo the method.
*/
const char *method;
/**
* Handler to invoke to verify signature.
*
* @param wh wire handle with key material
* @param json json reply with signature to verify
*/
int (*handler)(const struct TALER_MINT_WireHandle *wh,
json_t *json);
} handlers[] = {
{ "sepa", &verify_wire_sepa_signature_ok },
{ NULL, NULL }
};
unsigned int i;
for (i=0;NULL != handlers[i].method; i++)
if (0 == strcasecmp (handlers[i].method,
method))
return handlers[i].handler (wh,
json);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Wire transfer method `%s' not supported\n",
method);
return GNUNET_NO;
}
/**
* Perform the next /wire/method request or signal
* the end of the iteration.
*
* @param wh the wire handle
* @return a handle for this request
*/
static void
request_wire_method (struct TALER_MINT_WireHandle *wh);
/**
* Function called when we're done processing the
* HTTP /wire/METHOD request.
*
* @param cls the `struct TALER_MINT_WireHandle`
* @param eh the curl request handle
*/
static void
handle_wire_method_finished (void *cls,
CURL *eh)
{
struct TALER_MINT_WireHandle *wh = cls;
long response_code;
json_t *json;
wh->job = NULL;
json = MAC_download_get_result (&wh->db,
eh,
&response_code);
switch (response_code)
{
case 0:
break;
case MHD_HTTP_OK:
{
const char *method;
method = json_string_value (json_array_get (wh->methods,
wh->methods_off - 1));
if (GNUNET_OK !=
verify_wire_method_signature_ok (wh,
method,
json))
{
GNUNET_break_op (0);
response_code = 0;
break;
}
break;
}
case MHD_HTTP_FOUND:
/* /wire/test returns a 302 redirect, we should just give
this information back to the callback below */
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the mint is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
break;
default:
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
GNUNET_break (0);
response_code = 0;
break;
}
if (0 == response_code)
{
/* signal end of iteration */
wh->cb (wh->cb_cls,
0,
NULL,
NULL);
json_decref (json);
TALER_MINT_wire_cancel (wh);
return;
}
/* pass on successful reply */
wh->cb (wh->cb_cls,
response_code,
json_string_value (json_array_get (wh->methods,
wh->methods_off-1)),
json);
/* trigger request for the next /wire/method */
request_wire_method (wh);
}
/**
* Perform the next /wire/method request or signal
* the end of the iteration.
*
* @param wh the wire handle
* @return a handle for this request
*/
static void
request_wire_method (struct TALER_MINT_WireHandle *wh)
{
struct TALER_MINT_Context *ctx;
CURL *eh;
char *path;
if (json_array_size (wh->methods) <= wh->methods_off)
{
/* we are done, signal end of iteration */
wh->cb (wh->cb_cls,
0,
NULL,
NULL);
TALER_MINT_wire_cancel (wh);
return;
}
GNUNET_free_non_null (wh->db.buf);
wh->db.buf = NULL;
wh->db.buf_size = 0;
wh->db.eno = 0;
GNUNET_free_non_null (wh->url);
GNUNET_asprintf (&path,
"/wire/%s",
json_string_value (json_array_get (wh->methods,
wh->methods_off++)));
wh->url = MAH_path_to_url (wh->mint,
path);
GNUNET_free (path);
eh = curl_easy_init ();
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
wh->url));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_WRITEFUNCTION,
&MAC_download_cb));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_WRITEDATA,
&wh->db));
/* The default is 'disabled', but let's be sure */
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_FOLLOWLOCATION,
(long) 0));
ctx = MAH_handle_to_context (wh->mint);
wh->job = MAC_job_add (ctx,
eh,
GNUNET_YES,
&handle_wire_method_finished,
wh);
}
/**
* Verify that the signature on the "200 OK" response
* for /wire from the mint is valid.
*
* @param wh wire handle
* @param json json reply with the signature
* @return NULL if @a json is invalid, otherwise the
* "methods" array (with an RC of 1)
*/
static json_t *
verify_wire_signature_ok (const struct TALER_MINT_WireHandle *wh,
json_t *json)
{
struct TALER_MintSignatureP mint_sig;
struct TALER_MintPublicKeyP mint_pub;
struct TALER_MintWireSupportMethodsPS mp;
json_t *methods;
const struct TALER_MINT_Keys *key_state;
struct GNUNET_HashContext *hc;
struct MAJ_Specification spec[] = {
MAJ_spec_fixed_auto ("sig", &mint_sig),
MAJ_spec_fixed_auto ("pub", &mint_pub),
MAJ_spec_json ("methods", &methods),
MAJ_spec_end
};
unsigned int i;
if (GNUNET_OK !=
MAJ_parse_json (json,
spec))
{
GNUNET_break_op (0);
return NULL;
}
if (! json_is_array (methods))
{
GNUNET_break_op (0);
MAJ_parse_free (spec);
return NULL;
}
key_state = TALER_MINT_get_keys (wh->mint);
if (GNUNET_OK !=
TALER_MINT_test_signing_key (key_state,
&mint_pub))
{
GNUNET_break_op (0);
return NULL;
}
hc = GNUNET_CRYPTO_hash_context_start ();
for (i=0;i<json_array_size (methods);i++)
{
const json_t *element = json_array_get (methods, i);
const char *method;
if (! json_is_string (element))
{
GNUNET_CRYPTO_hash_context_abort (hc);
GNUNET_break_op (0);
MAJ_parse_free (spec);
return NULL;
}
method = json_string_value (element);
GNUNET_CRYPTO_hash_context_read (hc,
method,
strlen (method) + 1);
}
mp.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES);
mp.purpose.size = htonl (sizeof (struct TALER_MintWireSupportMethodsPS));
GNUNET_CRYPTO_hash_context_finish (hc,
&mp.h_wire_types);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_WIRE_TYPES,
&mp.purpose,
&mint_sig.eddsa_signature,
&mint_pub.eddsa_pub))
{
GNUNET_break_op (0);
MAJ_parse_free (spec);
return NULL;
}
return methods;
}
/**
* Function called when we're done processing the
* HTTP /wire request.
*
* @param cls the `struct TALER_MINT_WireHandle`
* @param eh the curl request handle
*/
static void
handle_wire_finished (void *cls,
CURL *eh)
{
struct TALER_MINT_WireHandle *wh = cls;
long response_code;
json_t *json;
wh->job = NULL;
json = MAC_download_get_result (&wh->db,
eh,
&response_code);
switch (response_code)
{
case 0:
break;
case MHD_HTTP_OK:
{
json_t *methods;
if (NULL ==
(methods = verify_wire_signature_ok (wh,
json)))
{
GNUNET_break_op (0);
response_code = 0;
break;
}
wh->methods = methods;
request_wire_method (wh);
return;
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the mint is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
break;
default:
/* unexpected response code */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u\n",
response_code);
GNUNET_break (0);
response_code = 0;
break;
}
if (0 != response_code)
{
/* pass on successful reply */
wh->cb (wh->cb_cls,
response_code,
NULL,
json);
}
/* signal end of iteration */
wh->cb (wh->cb_cls,
0,
NULL,
NULL);
if (NULL != json)
json_decref (json);
TALER_MINT_wire_cancel (wh);
}
/**
* Obtain information about a mint's wire instructions.
* A mint may provide wire instructions for creating
* a reserve. The wire instructions also indicate
* which wire formats merchants may use with the mint.
* This API is typically used by a wallet for wiring
* funds, and possibly by a merchant to determine
* supported wire formats.
*
* Note that while we return the (main) response verbatim to the
* caller for further processing, we do already verify that the
* response is well-formed (i.e. that signatures included in the
* response are all valid). If the mint's reply is not well-formed,
* we return an HTTP status code of zero to @a cb.
*
* @param mint the mint handle; the mint must be ready to operate
* @param wire_cb the callback to call when a reply for this request is available
* @param wire_cb_cls closure for the above callback
* @return a handle for this request
*/
struct TALER_MINT_WireHandle *
TALER_MINT_wire (struct TALER_MINT_Handle *mint,
TALER_MINT_WireResultCallback wire_cb,
void *wire_cb_cls)
{
struct TALER_MINT_WireHandle *wh;
struct TALER_MINT_Context *ctx;
CURL *eh;
if (GNUNET_YES !=
MAH_handle_is_ready (mint))
{
GNUNET_break (0);
return NULL;
}
wh = GNUNET_new (struct TALER_MINT_WireHandle);
wh->mint = mint;
wh->cb = wire_cb;
wh->cb_cls = wire_cb_cls;
wh->url = MAH_path_to_url (mint, "/wire");
eh = curl_easy_init ();
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
wh->url));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_WRITEFUNCTION,
&MAC_download_cb));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_WRITEDATA,
&wh->db));
ctx = MAH_handle_to_context (mint);
wh->job = MAC_job_add (ctx,
eh,
GNUNET_YES,
&handle_wire_finished,
wh);
return wh;
}
/**
* Cancel a wire information request. This function cannot be used
* on a request handle if a response is already served for it.
*
* @param wire the wire information request handle
*/
void
TALER_MINT_wire_cancel (struct TALER_MINT_WireHandle *wire)
{
if (NULL != wire->job)
{
MAC_job_cancel (wire->job);
wire->job = NULL;
}
if (NULL != wire->methods)
{
json_decref (wire->methods);
wire->methods = NULL;
}
GNUNET_free_non_null (wire->db.buf);
GNUNET_free (wire->url);
GNUNET_free (wire);
}
/* end of mint_api_wire.c */

View File

@ -2,9 +2,10 @@
# Currency supported by the mint (can only be one) # Currency supported by the mint (can only be one)
CURRENCY = EUR CURRENCY = EUR
# Wire format supproted by the mint # Wire format supported by the mint
# TEST is used for testing... (what a shock) # We use 'test' for testing of the actual
WIREFORMAT = TEST # coin operations, and 'sepa' to test SEPA-specific routines.
WIREFORMAT = test sepa
# HTTP port the mint listens to # HTTP port the mint listens to
PORT = 8081 PORT = 8081
@ -15,9 +16,15 @@ MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database # How to access our database
DB = postgres DB = postgres
# This is a testcase, use transient DB actions # Is this is a testcase, use transient DB actions?
TESTRUN = YES TESTRUN = NO
[mintdb-postgres] [mintdb-postgres]
DB_CONN_STR = "postgres:///talercheck" DB_CONN_STR = "postgres:///talercheck"
[mint-wire-sepa]
SEPA_RESPONSE_FILE = "test-mint-home/sepa.json"
[mint-wire-test]
REDIRECT_URL = "http://www.taler.net/"

View File

@ -0,0 +1,6 @@
{
"receiver_name": "Max Mustermann",
"iban": "DE89370400440532013000",
"bic": "COBADEFF370",
"sig": "8M5YJXM68PRAXKH76HYEBCJW657B23JA0RFGNDMZK2379YZMT626H1BN89KC0M1KJBWGYEN5Z763Q0Y7MCTZQ6BPPT7D9KFCTW60C10"
}

View File

@ -26,6 +26,15 @@
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
#include <microhttpd.h> #include <microhttpd.h>
/**
* Is the configuration file is set to include wire format 'test'?
*/
#define WIRE_TEST 1
/**
* Is the configuration file is set to include wire format 'sepa'?
*/
#define WIRE_SEPA 1
/** /**
* Main execution context for the main loop. * Main execution context for the main loop.
@ -97,7 +106,12 @@ enum OpCode
* Verify mint's /refresh/link by linking original private key to * Verify mint's /refresh/link by linking original private key to
* results from #OC_REFRESH_REVEAL step. * results from #OC_REFRESH_REVEAL step.
*/ */
OC_REFRESH_LINK OC_REFRESH_LINK,
/**
* Verify the mint's /wire-method.
*/
OC_WIRE
}; };
@ -116,7 +130,7 @@ struct MeltDetails
const char *amount; const char *amount;
/** /**
* Reference to withdraw_sign operations for coin to * Reference to reserve_withdraw operations for coin to
* be used for the /refresh/melt operation. * be used for the /refresh/melt operation.
*/ */
const char *coin_ref; const char *coin_ref;
@ -228,14 +242,14 @@ struct Command
/** /**
* Set to the API's handle during the operation. * Set to the API's handle during the operation.
*/ */
struct TALER_MINT_WithdrawStatusHandle *wsh; struct TALER_MINT_ReserveStatusHandle *wsh;
/** /**
* Expected reserve balance. * Expected reserve balance.
*/ */
const char *expected_balance; const char *expected_balance;
} withdraw_status; } reserve_status;
/** /**
* Information for a #OC_WITHDRAW_SIGN command. * Information for a #OC_WITHDRAW_SIGN command.
@ -281,9 +295,9 @@ struct Command
/** /**
* Withdraw handle (while operation is running). * Withdraw handle (while operation is running).
*/ */
struct TALER_MINT_WithdrawSignHandle *wsh; struct TALER_MINT_ReserveWithdrawHandle *wsh;
} withdraw_sign; } reserve_withdraw;
/** /**
* Information for a #OC_DEPOSIT command. * Information for a #OC_DEPOSIT command.
@ -297,7 +311,7 @@ struct Command
const char *amount; const char *amount;
/** /**
* Reference to a withdraw_sign operation for a coin to * Reference to a reserve_withdraw operation for a coin to
* be used for the /deposit operation. * be used for the /deposit operation.
*/ */
const char *coin_ref; const char *coin_ref;
@ -439,6 +453,23 @@ struct Command
} refresh_link; } refresh_link;
/**
* Information for the /wire command.
*/
struct {
/**
* Handle to the wire request.
*/
struct TALER_MINT_WireHandle *wh;
/**
* Format we expect to see, others will be *ignored*.
*/
const char *format;
} wire;
} details; } details;
}; };
@ -622,7 +653,7 @@ compare_admin_add_incoming_history (const struct TALER_MINT_ReserveHistory *h,
* @return #GNUNET_OK if they match, #GNUNET_SYSERR if not * @return #GNUNET_OK if they match, #GNUNET_SYSERR if not
*/ */
static int static int
compare_withdraw_sign_history (const struct TALER_MINT_ReserveHistory *h, compare_reserve_withdraw_history (const struct TALER_MINT_ReserveHistory *h,
const struct Command *cmd) const struct Command *cmd)
{ {
struct TALER_Amount amount; struct TALER_Amount amount;
@ -634,12 +665,12 @@ compare_withdraw_sign_history (const struct TALER_MINT_ReserveHistory *h,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (cmd->details.withdraw_sign.amount, TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
&amount)); &amount));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_amount_add (&amount_with_fee, TALER_amount_add (&amount_with_fee,
&amount, &amount,
&cmd->details.withdraw_sign.pk->fee_withdraw)); &cmd->details.reserve_withdraw.pk->fee_withdraw));
if (0 != TALER_amount_cmp (&amount_with_fee, if (0 != TALER_amount_cmp (&amount_with_fee,
&h->amount)) &h->amount))
{ {
@ -651,7 +682,7 @@ compare_withdraw_sign_history (const struct TALER_MINT_ReserveHistory *h,
/** /**
* Function called with the result of a /withdraw/status request. * Function called with the result of a /reserve/status request.
* *
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
@ -662,7 +693,7 @@ compare_withdraw_sign_history (const struct TALER_MINT_ReserveHistory *h,
* @param history detailed transaction history, NULL on error * @param history detailed transaction history, NULL on error
*/ */
static void static void
withdraw_status_cb (void *cls, reserve_status_cb (void *cls,
unsigned int http_status, unsigned int http_status,
json_t *json, json_t *json,
const struct TALER_Amount *balance, const struct TALER_Amount *balance,
@ -676,7 +707,7 @@ withdraw_status_cb (void *cls,
unsigned int j; unsigned int j;
struct TALER_Amount amount; struct TALER_Amount amount;
cmd->details.withdraw_status.wsh = NULL; cmd->details.reserve_status.wsh = NULL;
if (cmd->expected_response_code != http_status) if (cmd->expected_response_code != http_status)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -700,10 +731,10 @@ withdraw_status_cb (void *cls,
{ {
case OC_ADMIN_ADD_INCOMING: case OC_ADMIN_ADD_INCOMING:
if ( ( (NULL != rel->label) && if ( ( (NULL != rel->label) &&
(0 == strcmp (cmd->details.withdraw_status.reserve_reference, (0 == strcmp (cmd->details.reserve_status.reserve_reference,
rel->label) ) ) || rel->label) ) ) ||
( (NULL != rel->details.admin_add_incoming.reserve_reference) && ( (NULL != rel->details.admin_add_incoming.reserve_reference) &&
(0 == strcmp (cmd->details.withdraw_status.reserve_reference, (0 == strcmp (cmd->details.reserve_status.reserve_reference,
rel->details.admin_add_incoming.reserve_reference) ) ) ) rel->details.admin_add_incoming.reserve_reference) ) ) )
{ {
if (GNUNET_OK != if (GNUNET_OK !=
@ -718,11 +749,11 @@ withdraw_status_cb (void *cls,
} }
break; break;
case OC_WITHDRAW_SIGN: case OC_WITHDRAW_SIGN:
if (0 == strcmp (cmd->details.withdraw_status.reserve_reference, if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
rel->details.withdraw_sign.reserve_reference)) rel->details.reserve_withdraw.reserve_reference))
{ {
if (GNUNET_OK != if (GNUNET_OK !=
compare_withdraw_sign_history (&history[j], compare_reserve_withdraw_history (&history[j],
rel)) rel))
{ {
GNUNET_break (0); GNUNET_break (0);
@ -743,10 +774,10 @@ withdraw_status_cb (void *cls,
fail (is); fail (is);
return; return;
} }
if (NULL != cmd->details.withdraw_status.expected_balance) if (NULL != cmd->details.reserve_status.expected_balance)
{ {
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (cmd->details.withdraw_status.expected_balance, TALER_string_to_amount (cmd->details.reserve_status.expected_balance,
&amount)); &amount));
if (0 != TALER_amount_cmp (&amount, if (0 != TALER_amount_cmp (&amount,
balance)) balance))
@ -769,7 +800,7 @@ withdraw_status_cb (void *cls,
/** /**
* Function called upon completion of our /withdraw/sign request. * Function called upon completion of our /reserve/withdraw request.
* *
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
@ -778,7 +809,7 @@ withdraw_status_cb (void *cls,
* @param full_response full response from the mint (for logging, in case of errors) * @param full_response full response from the mint (for logging, in case of errors)
*/ */
static void static void
withdraw_sign_cb (void *cls, reserve_withdraw_cb (void *cls,
unsigned int http_status, unsigned int http_status,
const struct TALER_DenominationSignature *sig, const struct TALER_DenominationSignature *sig,
json_t *full_response) json_t *full_response)
@ -786,7 +817,7 @@ withdraw_sign_cb (void *cls,
struct InterpreterState *is = cls; struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip]; struct Command *cmd = &is->commands[is->ip];
cmd->details.withdraw_sign.wsh = NULL; cmd->details.reserve_withdraw.wsh = NULL;
if (cmd->expected_response_code != http_status) if (cmd->expected_response_code != http_status)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -807,7 +838,7 @@ withdraw_sign_cb (void *cls,
fail (is); fail (is);
return; return;
} }
cmd->details.withdraw_sign.sig.rsa_signature cmd->details.reserve_withdraw.sig.rsa_signature
= GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
break; break;
case MHD_HTTP_PAYMENT_REQUIRED: case MHD_HTTP_PAYMENT_REQUIRED:
@ -1011,10 +1042,6 @@ link_cb (void *cls,
return; return;
} }
/* check that the coins match */ /* check that the coins match */
fprintf (stderr,
"Got %u coins\n",
num_coins);
for (i=0;i<num_coins;i++) for (i=0;i<num_coins;i++)
for (j=i+1;j<num_coins;j++) for (j=i+1;j<num_coins;j++)
if (0 == memcmp (&coin_privs[i], if (0 == memcmp (&coin_privs[i],
@ -1115,6 +1142,83 @@ find_pk (const struct TALER_MINT_Keys *keys,
} }
/**
* Callbacks called with the result(s) of a
* wire format inquiry request to the mint.
*
* The callback is invoked multiple times, once for each supported @a
* method. Finally, it is invoked one more time with cls/0/NULL/NULL
* to indicate the end of the iteration. If any request fails to
* generate a valid response from the mint, @a http_status will also
* be zero and the iteration will also end. Thus, the iteration
* always ends with a final call with an @a http_status of 0. If the
* @a http_status is already 0 on the first call, then the response to
* the /wire request was invalid. Later, clients can tell the
* difference between @a http_status of 0 indicating a failed
* /wire/method request and a regular end of the iteration by @a
* method being non-NULL. If the mint simply correctly asserts that
* it does not support any methods, @a method will be NULL but the @a
* http_status will be #MHD_HTTP_OK for the first call (followed by a
* cls/0/NULL/NULL call to signal the end of the iteration).
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
* 0 if the mint's reply is bogus (fails to follow the protocol)
* @param method wire format method supported, i.e. "test" or "sepa", or NULL
* if already the /wire request failed.
* @param obj the received JSON reply, if successful this should be the wire
* format details as provided by /wire/METHOD/, or NULL if the
* reply was not in JSON format (in this case, the client might
* want to do an HTTP request to /wire/METHOD/ with a browser to
* provide more information to the user about the @a method).
*/
static void
wire_cb (void *cls,
unsigned int http_status,
const char *method,
json_t *obj)
{
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
if (0 == http_status)
{
/* 0 always signals the end of the iteration */
cmd->details.wire.wh = NULL;
}
else if ( (NULL != method) &&
(0 != strcasecmp (method,
cmd->details.wire.format)) )
{
/* not the method we care about, skip */
return;
}
if (cmd->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s/%s\n",
http_status,
cmd->label,
method);
json_dumpf (obj, stderr, 0);
fail (is);
return;
}
if (0 == http_status)
{
/* end of iteration, move to next command */
is->ip++;
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
is);
return;
}
/* For now, we only support to be called only once
with a "positive" result; so we switch to an
expected value of 0 for the 2nd iteration */
cmd->expected_response_code = 0;
}
/** /**
* Run the main interpreter loop that performs mint operations. * Run the main interpreter loop that performs mint operations.
* *
@ -1212,44 +1316,44 @@ interpreter_run (void *cls,
return; return;
case OC_WITHDRAW_STATUS: case OC_WITHDRAW_STATUS:
GNUNET_assert (NULL != GNUNET_assert (NULL !=
cmd->details.withdraw_status.reserve_reference); cmd->details.reserve_status.reserve_reference);
ref = find_command (is, ref = find_command (is,
cmd->details.withdraw_status.reserve_reference); cmd->details.reserve_status.reserve_reference);
GNUNET_assert (NULL != ref); GNUNET_assert (NULL != ref);
GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.admin_add_incoming.reserve_priv.eddsa_priv,
&reserve_pub.eddsa_pub); &reserve_pub.eddsa_pub);
cmd->details.withdraw_status.wsh cmd->details.reserve_status.wsh
= TALER_MINT_withdraw_status (mint, = TALER_MINT_reserve_status (mint,
&reserve_pub, &reserve_pub,
&withdraw_status_cb, &reserve_status_cb,
is); is);
trigger_context_task (); trigger_context_task ();
return; return;
case OC_WITHDRAW_SIGN: case OC_WITHDRAW_SIGN:
GNUNET_assert (NULL != GNUNET_assert (NULL !=
cmd->details.withdraw_sign.reserve_reference); cmd->details.reserve_withdraw.reserve_reference);
ref = find_command (is, ref = find_command (is,
cmd->details.withdraw_sign.reserve_reference); cmd->details.reserve_withdraw.reserve_reference);
GNUNET_assert (NULL != ref); GNUNET_assert (NULL != ref);
GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
if (NULL != cmd->details.withdraw_sign.amount) if (NULL != cmd->details.reserve_withdraw.amount)
{ {
if (GNUNET_OK != if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.withdraw_sign.amount, TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
&amount)) &amount))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %u\n", "Failed to parse amount `%s' at %u\n",
cmd->details.withdraw_sign.amount, cmd->details.reserve_withdraw.amount,
is->ip); is->ip);
fail (is); fail (is);
return; return;
} }
cmd->details.withdraw_sign.pk = find_pk (is->keys, cmd->details.reserve_withdraw.pk = find_pk (is->keys,
&amount); &amount);
} }
if (NULL == cmd->details.withdraw_sign.pk) if (NULL == cmd->details.reserve_withdraw.pk)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to determine denomination key at %u\n", "Failed to determine denomination key at %u\n",
@ -1263,23 +1367,22 @@ interpreter_run (void *cls,
struct GNUNET_CRYPTO_EddsaPrivateKey *priv; struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
priv = GNUNET_CRYPTO_eddsa_key_create (); priv = GNUNET_CRYPTO_eddsa_key_create ();
cmd->details.withdraw_sign.coin_priv.eddsa_priv = *priv; cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv;
GNUNET_free (priv); GNUNET_free (priv);
} }
GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.withdraw_sign.coin_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.reserve_withdraw.coin_priv.eddsa_priv,
&coin_pub.eddsa_pub); &coin_pub.eddsa_pub);
cmd->details.withdraw_sign.blinding_key.rsa_blinding_key cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key
= GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.withdraw_sign.pk->key.rsa_public_key)); = GNUNET_CRYPTO_rsa_blinding_key_create (GNUNET_CRYPTO_rsa_public_key_len (cmd->details.reserve_withdraw.pk->key.rsa_public_key));
cmd->details.reserve_withdraw.wsh
cmd->details.withdraw_sign.wsh = TALER_MINT_reserve_withdraw (mint,
= TALER_MINT_withdraw_sign (mint, cmd->details.reserve_withdraw.pk,
cmd->details.withdraw_sign.pk,
&ref->details.admin_add_incoming.reserve_priv, &ref->details.admin_add_incoming.reserve_priv,
&cmd->details.withdraw_sign.coin_priv, &cmd->details.reserve_withdraw.coin_priv,
&cmd->details.withdraw_sign.blinding_key, &cmd->details.reserve_withdraw.blinding_key,
&withdraw_sign_cb, &reserve_withdraw_cb,
is); is);
if (NULL == cmd->details.withdraw_sign.wsh) if (NULL == cmd->details.reserve_withdraw.wsh)
{ {
GNUNET_break (0); GNUNET_break (0);
fail (is); fail (is);
@ -1308,9 +1411,9 @@ interpreter_run (void *cls,
switch (ref->oc) switch (ref->oc)
{ {
case OC_WITHDRAW_SIGN: case OC_WITHDRAW_SIGN:
coin_priv = &ref->details.withdraw_sign.coin_priv; coin_priv = &ref->details.reserve_withdraw.coin_priv;
coin_pk = ref->details.withdraw_sign.pk; coin_pk = ref->details.reserve_withdraw.pk;
coin_pk_sig = &ref->details.withdraw_sign.sig; coin_pk_sig = &ref->details.reserve_withdraw.sig;
break; break;
case OC_REFRESH_REVEAL: case OC_REFRESH_REVEAL:
{ {
@ -1355,7 +1458,6 @@ interpreter_run (void *cls,
fail (is); fail (is);
return; return;
} }
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
&coin_pub.eddsa_pub); &coin_pub.eddsa_pub);
@ -1377,6 +1479,7 @@ interpreter_run (void *cls,
{ {
struct TALER_DepositRequestPS dr; struct TALER_DepositRequestPS dr;
memset (&dr, 0, sizeof (dr));
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.h_contract = h_contract; dr.h_contract = h_contract;
@ -1395,7 +1498,6 @@ interpreter_run (void *cls,
GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
&dr.purpose, &dr.purpose,
&coin_sig.eddsa_signature)); &coin_sig.eddsa_signature));
} }
cmd->details.deposit.dh cmd->details.deposit.dh
= TALER_MINT_deposit (mint, = TALER_MINT_deposit (mint,
@ -1454,7 +1556,7 @@ interpreter_run (void *cls,
GNUNET_assert (NULL != ref); GNUNET_assert (NULL != ref);
GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc); GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
melt_privs[i] = ref->details.withdraw_sign.coin_priv; melt_privs[i] = ref->details.reserve_withdraw.coin_priv;
if (GNUNET_OK != if (GNUNET_OK !=
TALER_string_to_amount (md->amount, TALER_string_to_amount (md->amount,
&melt_amounts[i])) &melt_amounts[i]))
@ -1466,8 +1568,8 @@ interpreter_run (void *cls,
fail (is); fail (is);
return; return;
} }
melt_sigs[i] = ref->details.withdraw_sign.sig; melt_sigs[i] = ref->details.reserve_withdraw.sig;
melt_pks[i] = *ref->details.withdraw_sign.pk; melt_pks[i] = *ref->details.reserve_withdraw.pk;
} }
for (i=0;i<num_fresh_coins;i++) for (i=0;i<num_fresh_coins;i++)
{ {
@ -1477,7 +1579,7 @@ interpreter_run (void *cls,
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %u\n", "Failed to parse amount `%s' at %u\n",
cmd->details.withdraw_sign.amount, cmd->details.reserve_withdraw.amount,
is->ip); is->ip);
fail (is); fail (is);
return; return;
@ -1544,7 +1646,7 @@ interpreter_run (void *cls,
/* find melt command */ /* find melt command */
ref = find_command (is, ref = find_command (is,
ref->details.refresh_reveal.melt_ref); ref->details.refresh_reveal.melt_ref);
/* find withdraw_sign command */ /* find reserve_withdraw command */
{ {
unsigned int idx; unsigned int idx;
const struct MeltDetails *md; const struct MeltDetails *md;
@ -1563,7 +1665,7 @@ interpreter_run (void *cls,
/* finally, use private key from withdraw sign command */ /* finally, use private key from withdraw sign command */
cmd->details.refresh_link.rlh cmd->details.refresh_link.rlh
= TALER_MINT_refresh_link (mint, = TALER_MINT_refresh_link (mint,
&ref->details.withdraw_sign.coin_priv, &ref->details.reserve_withdraw.coin_priv,
&link_cb, &link_cb,
is); is);
if (NULL == cmd->details.refresh_link.rlh) if (NULL == cmd->details.refresh_link.rlh)
@ -1574,6 +1676,12 @@ interpreter_run (void *cls,
} }
trigger_context_task (); trigger_context_task ();
return; return;
case OC_WIRE:
cmd->details.wire.wh = TALER_MINT_wire (mint,
&wire_cb,
is);
trigger_context_task ();
return;
default: default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n", "Unknown instruction %d at %u (%s)\n",
@ -1623,35 +1731,35 @@ do_shutdown (void *cls,
} }
break; break;
case OC_WITHDRAW_STATUS: case OC_WITHDRAW_STATUS:
if (NULL != cmd->details.withdraw_status.wsh) if (NULL != cmd->details.reserve_status.wsh)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %u (%s) did not complete\n", "Command %u (%s) did not complete\n",
i, i,
cmd->label); cmd->label);
TALER_MINT_withdraw_status_cancel (cmd->details.withdraw_status.wsh); TALER_MINT_reserve_status_cancel (cmd->details.reserve_status.wsh);
cmd->details.withdraw_status.wsh = NULL; cmd->details.reserve_status.wsh = NULL;
} }
break; break;
case OC_WITHDRAW_SIGN: case OC_WITHDRAW_SIGN:
if (NULL != cmd->details.withdraw_sign.wsh) if (NULL != cmd->details.reserve_withdraw.wsh)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %u (%s) did not complete\n", "Command %u (%s) did not complete\n",
i, i,
cmd->label); cmd->label);
TALER_MINT_withdraw_sign_cancel (cmd->details.withdraw_sign.wsh); TALER_MINT_reserve_withdraw_cancel (cmd->details.reserve_withdraw.wsh);
cmd->details.withdraw_sign.wsh = NULL; cmd->details.reserve_withdraw.wsh = NULL;
} }
if (NULL != cmd->details.withdraw_sign.sig.rsa_signature) if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature)
{ {
GNUNET_CRYPTO_rsa_signature_free (cmd->details.withdraw_sign.sig.rsa_signature); GNUNET_CRYPTO_rsa_signature_free (cmd->details.reserve_withdraw.sig.rsa_signature);
cmd->details.withdraw_sign.sig.rsa_signature = NULL; cmd->details.reserve_withdraw.sig.rsa_signature = NULL;
} }
if (NULL != cmd->details.withdraw_sign.blinding_key.rsa_blinding_key) if (NULL != cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key)
{ {
GNUNET_CRYPTO_rsa_blinding_key_free (cmd->details.withdraw_sign.blinding_key.rsa_blinding_key); GNUNET_CRYPTO_rsa_blinding_key_free (cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key);
cmd->details.withdraw_sign.blinding_key.rsa_blinding_key = NULL; cmd->details.reserve_withdraw.blinding_key.rsa_blinding_key = NULL;
} }
break; break;
case OC_DEPOSIT: case OC_DEPOSIT:
@ -1714,6 +1822,13 @@ do_shutdown (void *cls,
cmd->details.refresh_link.rlh = NULL; cmd->details.refresh_link.rlh = NULL;
} }
break; break;
case OC_WIRE:
if (NULL != cmd->details.wire.wh)
{
TALER_MINT_wire_cancel (cmd->details.wire.wh);
cmd->details.wire.wh = NULL;
}
break;
default: default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n", "Unknown instruction %d at %u (%s)\n",
@ -1880,6 +1995,28 @@ run (void *cls,
}; };
static struct Command commands[] = static struct Command commands[] =
{ {
/* *************** start of /wire testing ************** */
#if WIRE_TEST
{ .oc = OC_WIRE,
.label = "wire-test",
/* /wire/test replies with a 302 redirect */
.expected_response_code = MHD_HTTP_FOUND,
.details.wire.format = "test" },
#endif
#if WIRE_SEPA
{ .oc = OC_WIRE,
.label = "wire-sepa",
/* /wire/sepa replies with a 200 redirect */
.expected_response_code = MHD_HTTP_OK,
.details.wire.format = "sepa" },
#endif
/* *************** end of /wire testing ************** */
#if WIRE_TEST
/* None of this works if 'test' is not allowed as we do
/admin/add/incoming with format 'test' */
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */ /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
{ .oc = OC_ADMIN_ADD_INCOMING, { .oc = OC_ADMIN_ADD_INCOMING,
.label = "create-reserve-1", .label = "create-reserve-1",
@ -1890,15 +2027,15 @@ run (void *cls,
{ .oc = OC_WITHDRAW_SIGN, { .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-1", .label = "withdraw-coin-1",
.expected_response_code = MHD_HTTP_OK, .expected_response_code = MHD_HTTP_OK,
.details.withdraw_sign.reserve_reference = "create-reserve-1", .details.reserve_withdraw.reserve_reference = "create-reserve-1",
.details.withdraw_sign.amount = "EUR:5" }, .details.reserve_withdraw.amount = "EUR:5" },
/* Check that deposit and withdraw operation are in history, and /* Check that deposit and withdraw operation are in history, and
that the balance is now at zero */ that the balance is now at zero */
{ .oc = OC_WITHDRAW_STATUS, { .oc = OC_WITHDRAW_STATUS,
.label = "withdraw-status-1", .label = "withdraw-status-1",
.expected_response_code = MHD_HTTP_OK, .expected_response_code = MHD_HTTP_OK,
.details.withdraw_status.reserve_reference = "create-reserve-1", .details.reserve_status.reserve_reference = "create-reserve-1",
.details.withdraw_status.expected_balance = "EUR:0" }, .details.reserve_status.expected_balance = "EUR:0" },
/* Try to deposit the 5 EUR coin (in full) */ /* Try to deposit the 5 EUR coin (in full) */
{ .oc = OC_DEPOSIT, { .oc = OC_DEPOSIT,
.label = "deposit-simple", .label = "deposit-simple",
@ -1913,8 +2050,8 @@ run (void *cls,
{ .oc = OC_WITHDRAW_SIGN, { .oc = OC_WITHDRAW_SIGN,
.label = "withdraw-coin-2", .label = "withdraw-coin-2",
.expected_response_code = MHD_HTTP_PAYMENT_REQUIRED, .expected_response_code = MHD_HTTP_PAYMENT_REQUIRED,
.details.withdraw_sign.reserve_reference = "create-reserve-1", .details.reserve_withdraw.reserve_reference = "create-reserve-1",
.details.withdraw_sign.amount = "EUR:5" }, .details.reserve_withdraw.amount = "EUR:5" },
/* Try to double-spend the 5 EUR coin with different wire details */ /* Try to double-spend the 5 EUR coin with different wire details */
{ .oc = OC_DEPOSIT, { .oc = OC_DEPOSIT,
@ -1958,8 +2095,8 @@ run (void *cls,
{ .oc = OC_WITHDRAW_SIGN, { .oc = OC_WITHDRAW_SIGN,
.label = "refresh-withdraw-coin-1", .label = "refresh-withdraw-coin-1",
.expected_response_code = MHD_HTTP_OK, .expected_response_code = MHD_HTTP_OK,
.details.withdraw_sign.reserve_reference = "refresh-create-reserve-1", .details.reserve_withdraw.reserve_reference = "refresh-create-reserve-1",
.details.withdraw_sign.amount = "EUR:5" }, .details.reserve_withdraw.amount = "EUR:5" },
/* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full) /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
(merchant would receive EUR:0.99 due to 1 ct deposit fee) */ (merchant would receive EUR:0.99 due to 1 ct deposit fee) */
{ .oc = OC_DEPOSIT, { .oc = OC_DEPOSIT,
@ -2026,8 +2163,8 @@ run (void *cls,
// FIXME: also test with coin that was already melted // FIXME: also test with coin that was already melted
// (signature differs from coin that was deposited...) // (signature differs from coin that was deposited...)
/* *************** end of /refresh testing ************** */ /* *************** end of /refresh testing ************** */
#endif
{ .oc = OC_END } { .oc = OC_END }
}; };

View File

@ -7,6 +7,7 @@ if USE_COVERAGE
endif endif
bin_PROGRAMS = \ bin_PROGRAMS = \
taler-auditor-sign \
taler-mint-keyup \ taler-mint-keyup \
taler-mint-keycheck \ taler-mint-keycheck \
taler-mint-reservemod \ taler-mint-reservemod \
@ -15,7 +16,6 @@ bin_PROGRAMS = \
taler_mint_keyup_SOURCES = \ taler_mint_keyup_SOURCES = \
taler-mint-keyup.c taler-mint-keyup.c
taler_mint_keyup_LDADD = \ taler_mint_keyup_LDADD = \
$(LIBGCRYPT_LIBS) \ $(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/util/libtalerutil.la \
@ -24,6 +24,14 @@ taler_mint_keyup_LDADD = \
-lgnunetutil $(XLIB) -lgnunetutil $(XLIB)
taler_mint_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS) taler_mint_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS)
taler_auditor_sign_SOURCES = \
taler-auditor-sign.c
taler_auditor_sign_LDADD = \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/mintdb/libtalermintdb.la \
-lgnunetutil $(XLIB)
taler_mint_sepa_SOURCES = \ taler_mint_sepa_SOURCES = \
taler-mint-sepa.c taler-mint-sepa.c

View File

@ -23,6 +23,11 @@
#include "taler_mintdb_lib.h" #include "taler_mintdb_lib.h"
/**
* Are we running in verbose mode?
*/
static int verbose;
/** /**
* Filename of the auditor's private key. * Filename of the auditor's private key.
*/ */
@ -44,17 +49,68 @@ static char *mint_request_file;
*/ */
static char *output_file; static char *output_file;
/**
* Handle to the auditor's configuration
*/
static struct GNUNET_CONFIGURATION_Handle *kcfg;
/** /**
* Master public key of the mint. * Master public key of the mint.
*/ */
static struct TALER_MasterPublicKeyP master_public_key; static struct TALER_MasterPublicKeyP master_public_key;
/**
* Print denomination key details for diagnostics.
*
* @param dk denomination key to print
*/
static void
print_dk (const struct TALER_DenominationKeyValidityPS *dk)
{
struct TALER_Amount a;
char *s;
fprintf (stdout,
"Denomination key hash: %s\n",
GNUNET_h2s_full (&dk->denom_hash));
TALER_amount_ntoh (&a,
&dk->value);
fprintf (stdout,
"Value: %s\n",
s = TALER_amount_to_string (&a));
GNUNET_free (s);
TALER_amount_ntoh (&a,
&dk->fee_withdraw);
fprintf (stdout,
"Withdraw fee: %s\n",
s = TALER_amount_to_string (&a));
GNUNET_free (s);
TALER_amount_ntoh (&a,
&dk->fee_deposit);
fprintf (stdout,
"Deposit fee: %s\n",
s = TALER_amount_to_string (&a));
GNUNET_free (s);
TALER_amount_ntoh (&a,
&dk->fee_refresh);
fprintf (stdout,
"Refresh fee: %s\n",
s = TALER_amount_to_string (&a));
GNUNET_free (s);
fprintf (stdout,
"Validity start time: %s\n",
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->start)));
fprintf (stdout,
"Withdraw end time: %s\n",
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_withdraw)));
fprintf (stdout,
"Deposit end time: %s\n",
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_spend)));
fprintf (stdout,
"Legal dispute end time: %s\n",
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (dk->expire_legal)));
fprintf (stdout,
"\n");
}
/** /**
* The main function of the taler-auditor-sign tool. This tool is used * The main function of the taler-auditor-sign tool. This tool is used
@ -79,18 +135,24 @@ main (int argc,
"public key of the mint (Crockford base32 encoded)", 1, "public key of the mint (Crockford base32 encoded)", 1,
&GNUNET_GETOPT_set_filename, &mint_public_key}, &GNUNET_GETOPT_set_filename, &mint_public_key},
{'r', "mint-request", "FILE", {'r', "mint-request", "FILE",
"set of keys the mint requested the auditor to sign", 0, "set of keys the mint requested the auditor to sign", 1,
&GNUNET_GETOPT_set_string, &mint_request_file}, &GNUNET_GETOPT_set_string, &mint_request_file},
{'o', "output", "FILE", {'o', "output", "FILE",
"where to write our signature", 0, "where to write our signature", 1,
&GNUNET_GETOPT_set_string, &output_file}, &GNUNET_GETOPT_set_string, &output_file},
GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION), GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
GNUNET_GETOPT_OPTION_END GNUNET_GETOPT_OPTION_END
}; };
struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv; struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
struct TALER_AuditorSignatureP *sigs;
struct TALER_AuditorPublicKeyP apub;
struct GNUNET_DISK_FileHandle *fh; struct GNUNET_DISK_FileHandle *fh;
struct GNUNET_DISK_FileHandle *fout; struct TALER_DenominationKeyValidityPS *dks;
unsigned int dks_len;
struct TALER_MintKeyValidityPS kv;
off_t in_size; off_t in_size;
unsigned int i;
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
GNUNET_log_setup ("taler-mint-keyup", GNUNET_log_setup ("taler-mint-keyup",
@ -114,10 +176,13 @@ main (int argc,
auditor_key_file); auditor_key_file);
return 1; return 1;
} }
GNUNET_CRYPTO_eddsa_key_get_public (eddsa_priv,
&apub.eddsa_pub);
if (NULL == mint_public_key) if (NULL == mint_public_key)
{ {
fprintf (stderr, fprintf (stderr,
"Mint public key not given\n"); "Mint public key not given\n");
GNUNET_free (eddsa_priv);
return 1; return 1;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -129,12 +194,14 @@ main (int argc,
fprintf (stderr, fprintf (stderr,
"Public key `%s' malformed\n", "Public key `%s' malformed\n",
mint_public_key); mint_public_key);
GNUNET_free (eddsa_priv);
return 1; return 1;
} }
if (NULL == mint_request_file) if (NULL == mint_request_file)
{ {
fprintf (stderr, fprintf (stderr,
"Mint signing request not given\n"); "Mint signing request not given\n");
GNUNET_free (eddsa_priv);
return 1; return 1;
} }
fh = GNUNET_DISK_file_open (mint_request_file, fh = GNUNET_DISK_file_open (mint_request_file,
@ -146,6 +213,7 @@ main (int argc,
"Failed to open file `%s': %s\n", "Failed to open file `%s': %s\n",
mint_request_file, mint_request_file,
STRERROR (errno)); STRERROR (errno));
GNUNET_free (eddsa_priv);
return 1; return 1;
} }
if (GNUNET_OK != if (GNUNET_OK !=
@ -157,34 +225,95 @@ main (int argc,
mint_request_file, mint_request_file,
STRERROR (errno)); STRERROR (errno));
GNUNET_DISK_file_close (fh); GNUNET_DISK_file_close (fh);
GNUNET_free (eddsa_priv);
return 1; return 1;
} }
if (0 != (in_size % sizeof (struct TALER_DenominationKeyValidityPS)))
{
fprintf (stderr,
"Input file size of file `%s' is invalid\n",
mint_request_file);
GNUNET_DISK_file_close (fh);
GNUNET_free (eddsa_priv);
return 1;
}
dks_len = in_size / sizeof (struct TALER_DenominationKeyValidityPS);
kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_MINT_KEYS);
kv.purpose.size = htonl (sizeof (struct TALER_MintKeyValidityPS));
kv.master = master_public_key;
dks = GNUNET_new_array (dks_len,
struct TALER_DenominationKeyValidityPS);
sigs = GNUNET_new_array (dks_len,
struct TALER_AuditorSignatureP);
if (in_size !=
GNUNET_DISK_file_read (fh,
dks,
in_size))
{
fprintf (stderr,
"Failed to read input file `%s': %s\n",
mint_request_file,
STRERROR (errno));
GNUNET_DISK_file_close (fh);
GNUNET_free (sigs);
GNUNET_free (dks);
GNUNET_free (eddsa_priv);
return 1;
}
GNUNET_DISK_file_close (fh);
for (i=0;i<dks_len;i++)
{
struct TALER_DenominationKeyValidityPS *dk = &dks[i];
if (verbose)
print_dk (dk);
kv.start = dk->start;
kv.expire_withdraw = dk->expire_withdraw;
kv.expire_spend = dk->expire_spend;
kv.expire_legal = dk->expire_legal;
kv.value = dk->value;
kv.fee_withdraw = dk->fee_withdraw;
kv.fee_deposit = dk->fee_deposit;
kv.fee_refresh = dk->fee_refresh;
kv.denom_hash = dk->denom_hash;
/* Finally sign ... */
GNUNET_CRYPTO_eddsa_sign (eddsa_priv,
&kv.purpose,
&sigs[i].eddsa_sig);
}
if (NULL == output_file) if (NULL == output_file)
{ {
fprintf (stderr, fprintf (stderr,
"Output file not given\n"); "Output file not given\n");
GNUNET_DISK_file_close (fh); GNUNET_free (dks);
GNUNET_free (sigs);
GNUNET_free (eddsa_priv);
return 1; return 1;
} }
fout = GNUNET_DISK_file_open (output_file,
GNUNET_DISK_OPEN_READ | /* write result to disk */
GNUNET_DISK_OPEN_TRUNCATE | if (GNUNET_OK !=
GNUNET_DISK_OPEN_CREATE, TALER_MINTDB_auditor_write (output_file,
GNUNET_DISK_PERM_USER_READ | &apub,
GNUNET_DISK_PERM_USER_WRITE | sigs,
GNUNET_DISK_PERM_GROUP_READ | &master_public_key,
GNUNET_DISK_PERM_OTHER_READ); dks_len,
if (NULL == fout) dks))
{ {
fprintf (stderr, fprintf (stderr,
"Failed to open file `%s': %s\n", "Failed to write to file `%s': %s\n",
output_file, output_file,
STRERROR (errno)); STRERROR (errno));
GNUNET_DISK_file_close (fh); GNUNET_free (sigs);
GNUNET_free (dks);
return 1; return 1;
} }
/* FIXME: finally do real work... */ GNUNET_free (sigs);
GNUNET_free (dks);
GNUNET_free (eddsa_priv); GNUNET_free (eddsa_priv);
return 0; return 0;
} }

View File

@ -157,6 +157,17 @@ struct CoinTypeParams
*/ */
static char *masterkeyfile; static char *masterkeyfile;
/**
* Filename where to write denomination key signing
* requests for the auditor (optional, can be NULL).
*/
static char *auditorrequestfile;
/**
* Handle for writing the output for the auditor.
*/
static FILE *auditor_output_file;
/** /**
* Director of the mint, containing the keys. * Director of the mint, containing the keys.
*/ */
@ -807,6 +818,20 @@ mint_keys_update_cointype (void *cls,
GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
return; return;
} }
if ( (NULL != auditor_output_file) &&
(sizeof (denomkey_issue.issue.properties) !=
fwrite (&denomkey_issue.issue.properties,
sizeof (struct TALER_DenominationKeyValidityPS),
1,
auditor_output_file)) )
{
fprintf (stderr,
"Failed to write denomination key information to %s: %s\n",
auditorrequestfile,
STRERROR (errno));
*ret = GNUNET_SYSERR;
return;
}
GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key); GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
p.anchor = GNUNET_TIME_absolute_add (p.anchor, p.anchor = GNUNET_TIME_absolute_add (p.anchor,
p.duration_spend); p.duration_spend);
@ -859,6 +884,9 @@ main (int argc,
{'m', "master-key", "FILE", {'m', "master-key", "FILE",
"master key file (private key)", 1, "master key file (private key)", 1,
&GNUNET_GETOPT_set_filename, &masterkeyfile}, &GNUNET_GETOPT_set_filename, &masterkeyfile},
{'o', "output", "FILE",
"auditor denomination key signing request file to create", 1,
&GNUNET_GETOPT_set_filename, &auditorrequestfile},
{'t', "time", "TIMESTAMP", {'t', "time", "TIMESTAMP",
"pretend it is a different time for the update", 0, "pretend it is a different time for the update", 0,
&GNUNET_GETOPT_set_string, &pretend_time_str}, &GNUNET_GETOPT_set_string, &pretend_time_str},
@ -927,6 +955,20 @@ main (int argc,
GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
&master_public_key.eddsa_pub); &master_public_key.eddsa_pub);
if (NULL != auditorrequestfile)
{
auditor_output_file = FOPEN (auditorrequestfile,
"w");
if (NULL == auditor_output_file)
{
fprintf (stderr,
"Failed to open `%s' for writing: %s\n",
auditorrequestfile,
STRERROR (errno));
return 1;
}
}
/* check if key from file matches the one from the configuration */ /* check if key from file matches the one from the configuration */
{ {
struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg; struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg;
@ -986,6 +1028,11 @@ main (int argc,
if (GNUNET_OK != mint_keys_update_denomkeys ()) if (GNUNET_OK != mint_keys_update_denomkeys ())
return 1; return 1;
if (NULL != auditor_output_file)
{
FCLOSE (auditor_output_file);
auditor_output_file = NULL;
}
return 0; return 0;
} }

View File

@ -18,7 +18,7 @@ taler_mint_httpd_SOURCES = \
taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \ taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
taler-mint-httpd_admin.c taler-mint-httpd_admin.h \ taler-mint-httpd_admin.c taler-mint-httpd_admin.h \
taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \ taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \
taler-mint-httpd_withdraw.c taler-mint-httpd_withdraw.h \ taler-mint-httpd_reserve.c taler-mint-httpd_reserve.h \
taler-mint-httpd_wire.c taler-mint-httpd_wire.h \ taler-mint-httpd_wire.c taler-mint-httpd_wire.h \
taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h
taler_mint_httpd_LDADD = \ taler_mint_httpd_LDADD = \
@ -34,3 +34,9 @@ if HAVE_DEVELOPER
taler_mint_httpd_SOURCES += \ taler_mint_httpd_SOURCES += \
taler-mint-httpd_test.c taler-mint-httpd_test.h taler-mint-httpd_test.c taler-mint-httpd_test.h
endif endif
check_SCRIPTS = \
test_taler_mint_httpd.sh \
test_taler_mint_httpd_afl.sh
TESTS = $(check_SCRIPTS)

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,8 @@
POST /deposit HTTP/1.1
Host: locst:8081
Accept: */*
Content-: applicn/json
Content-Length: 1658
Expect: 100-continue
{"ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26E9M8S0M6CSH6X334GSN8RW30D9G8MT46CA660W34GSG6MT4AD9K8GT3ECSH6MVK0E2374V38H1M8MR4CDJ66MWK4E1S6MR3GCT28CV32H1Q8N23GCHG70S36C1K8MS3GCSN8RV36D9S710KGD9K6GWKEGJ28GRM4CJ56X1K6DJ18D2KGHA46D13GDA66GVK4GHJ8N13AE9J8RVK6GT184S48E1K6X336G9Q8N142CJ4692M6EA16GRKJD9N6523ADA36X13GG9G70TK6DHN68R36CT18GR4CDSJ6CW3GCT364W46CSR8RV42GJ474SMADSH851K4H9Q8GS42CHS8RV3GCSJ64V46DSN8RSM6HHN6N246D9S6934AH9P6X23JGSH652K0DJ5612KJGA26N242CH35452081918G2J2G0","timestamp":"/Date(1442821652)/","f":{"currency":"EUR","value":5,"fraction":0},"wire":{"type":"TEST","bank":"dest bank","account":42},"coin_pub":"JXWK4NS0H2W4V4BETQ90CCEDADP6QQ3MV3YZ7RV2KXEM8PWXE8Q0","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","H_contract":"1CMEEFQ5S4QJGGAMVYFV07XQRHQA311CR2MTRNC5M9KZV6ETDV1SY00WJFEV2CG9BXQTEQPZAF8A54C2HX32TZCN20VBGPFPS2Z16B0","merchant_pub":"C36TEXQXFW00170C2EJ66ZR0000CX9VPZNZG00109NX020000000","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","transaction_id":1,"refund_deadline":"/Date(0)/","coin_sig":"X16E0DP8C2BJNVNX09G24FFC5GA4W7RN2YXZP9WJTAN9BY6B4GMA39QNYR51XNNEZ3H1J7TP0K9G55JZ8V7WS7CZMD7E64HWYBFWM00"}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
GET /keys HTTP/1.1
User-Agent: Wget/1.16.3 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: 127.0.0.1:8081
Connection: Keep-Alive

View File

@ -0,0 +1,5 @@
GET /refresh/link?coin_pub=WQHES0X5XK43VBG1Y8FXR2YEJM04HQVMDTCS07MH691XWADG8QCG HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
POST /refresh/reveal HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 255
{"session_hash":"V97SB8T670M9V71D1Q0KVQ4GSJCVQ5AAKTTH9QKT0ZJZZBFNZAV4NA8NMWRRGVPFEBEGB6ANCN9BPQASJ40TM4Y1C49648TJJ07PGSG","transfer_privs":[["EQKJA401A9NJ2YJDFZJ1EV8AYXBHWZB6NT5T0TWSJHVKVDM6W8A0"],["TKDJ4DF3GZVG0DGAB9E3RGBGSTANYB6JVVWXJGPMB2AY4VQNTBA0"]]}

View File

@ -0,0 +1,4 @@
GET /reserve/status?reserve_pub=TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0 HTTP/1.1
Host: localhost:8081
Accept: */*

View File

@ -0,0 +1,7 @@
POST /reserve/withdraw HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 919
{"coin_ev":"Q5X8A8TCBFH7E5BMY7HSB17SHFTM1JPJGV61P2CA7Z9EXG8P2HYS69B31NZESKXHSZHNJ2DQN3CC2AWFNC6V90J577JD3TXBMAY8Y5M9V60KKT73Z1DW24JFSNAK91G1F2WT55ADP1EG7N5F9AY7A7ZJD03MPYSH0RDP7SVZS2KRPA5JRHFR4GDJ59CFNE7A43M95ZKQHQAS8","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","reserve_sig":"8427B3RTB217124EB1C37ZVJFC08KN17RHGHE9ENZQMQVJ0S11SAX6H8Z06SWCKT06DRQ9DQ8XD786XKQ94T27PYR9GC9EMT1Y02W10"}

View File

@ -0,0 +1,5 @@
GET /wire HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

View File

@ -0,0 +1,5 @@
GET /wire/sepa HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

View File

@ -0,0 +1,5 @@
GET /wire/test HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json

View File

@ -0,0 +1,7 @@
PoST /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POsT /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POSt /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST ¯admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST ¯admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST ?admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /adMin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin?add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST 'admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/aDd/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /aDmin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/atd/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admIn/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin?add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incOming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/Add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incmming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/aDd/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incomIng HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/iNcoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incominG HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incomiNg HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming @TTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HtTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HDTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HVTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTÔP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTDP/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HT\P/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTT@/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTÐ/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/±.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTT@/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/q.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTT/1.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/9.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/0.1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1&1
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.±
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.3
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

View File

@ -0,0 +1,7 @@
POST /admin/add/incoming HTTP/1.!
Host: localhost:8081
Accept: */*
Content-Type: application/json
Content-Length: 220
{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}}

Some files were not shown because too many files have changed in this diff Show More