From 7fbae8f69f35b2bb2ace2c9131cd3ce67e9bc943 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 19 Sep 2015 16:11:31 +0200 Subject: [PATCH] implementing retrieval of auditor information from /keys in mint API (with updated specification) - #3847 --- src/include/taler_mint_service.h | 32 +++++- src/include/taler_signatures.h | 72 +++++++++++-- src/mint-lib/mint_api_handle.c | 167 ++++++++++++++++++++++++++++++- 3 files changed, 258 insertions(+), 13 deletions(-) diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h index 3f89b0745..8d569d4bc 100644 --- a/src/include/taler_mint_service.h +++ b/src/include/taler_mint_service.h @@ -149,6 +149,11 @@ struct TALER_MINT_DenomPublicKey */ struct TALER_DenominationPublicKey key; + /** + * The hash of the public key. + */ + struct GNUNET_HashCode h_key; + /** * Timestamp indicating when the denomination key becomes valid */ @@ -165,6 +170,15 @@ struct TALER_MINT_DenomPublicKey */ 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 */ @@ -204,6 +218,8 @@ struct TALER_MINT_AuditorInformation * that website. We expect that in practice software is going to * often ship with an initial list of accepted auditors, just like * browsers ship with a CA root store. + * + * This field may be NULL. (#3987). */ const char *auditor_url; @@ -218,7 +234,7 @@ struct TALER_MINT_AuditorInformation * elements point to the same locations as the entries * 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. */ - struct TALER_AuditorPublicKeyP *auditors; + struct TALER_MINT_AuditorInformation *auditors; /** * Length of the @e sign_keys array. @@ -353,6 +369,18 @@ TALER_MINT_get_denomination_key (const struct TALER_MINT_Keys *keys, 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 *********************** */ diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index ffbc9fd45..3bdc4eee1 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -653,13 +653,73 @@ struct TALER_MintKeyValidityPS struct TALER_MasterPublicKeyP master; /** - * Array of hash(es) of the mint's denomination keys. - * 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). + * Start time of the validity period for this key. */ - /* 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; }; diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c index f5e26ff15..9eaa6171d 100644 --- a/src/mint-lib/mint_api_handle.c +++ b/src/mint-lib/mint_api_handle.c @@ -325,9 +325,11 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey *denom_key, &denom_key_issue.denom_hash, sizeof (struct GNUNET_HashCode)); denom_key->key.rsa_public_key = pk; + denom_key->h_key = denom_key_issue.denom_hash; denom_key->valid_from = valid_from; denom_key->withdraw_valid_until = withdraw_valid_until; denom_key->deposit_valid_until = deposit_valid_until; + denom_key->expire_legal = expire_legal; denom_key->value = value; denom_key->fee_withdraw = fee_withdraw; 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;jnum_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 * in the @a key_data. @@ -394,8 +506,8 @@ decode_keys_json (json_t *resp_obj, EXITIF (0 == (key_data->num_sign_keys = json_array_size (sign_keys_array))); key_data->sign_keys - = GNUNET_malloc (sizeof (struct TALER_MINT_SigningPublicKey) - * key_data->num_sign_keys); + = GNUNET_new_array (key_data->num_sign_keys, + struct TALER_MINT_SigningPublicKey); index = 0; json_array_foreach (sign_keys_array, index, sign_key_obj) { EXITIF (GNUNET_SYSERR == @@ -415,8 +527,8 @@ decode_keys_json (json_t *resp_obj, json_object_get (resp_obj, "denoms"))); EXITIF (JSON_ARRAY != json_typeof (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->num_denom_keys); + key_data->denom_keys = GNUNET_new_array (key_data->num_denom_keys, + struct TALER_MINT_DenomPublicKey); index = 0; json_array_foreach (denom_keys_array, index, denom_key_obj) { 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... */ ks.purpose.size = htonl (sizeof (ks)); @@ -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;inum_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. *