[new /keys response] create and parse denomination implemented
- /keys response now contains signed denomintations - hashes of denominations now XOR'ed per group into a single hash-code - final hash-code is now XOR of all group hash codes - final hash-code is signed - lib/exchange_api_handle support for new "denominations" implemented - parses array of denomation groups - creates running xor of hashes - verifies signature at the end - previous diff/merge logic for keys remains intact.
This commit is contained in:
parent
b39febe36f
commit
31f74059e0
@ -1726,12 +1726,13 @@ setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
|
||||
* @a recoup and @a denoms.
|
||||
*
|
||||
* @param[in,out] ksh key state handle we build @a krd for
|
||||
* @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms
|
||||
* @param[in] denom_keys_hash hash over all the denomination keys in @a denoms
|
||||
* @param last_cpd timestamp to use
|
||||
* @param signkeys list of sign keys to return
|
||||
* @param recoup list of revoked keys to return
|
||||
* @param denoms list of denominations to return
|
||||
* @param grouped_denominations list of grouped denominations to return
|
||||
* @param[in] h_grouped XOR of all hashes in @a grouped_demoninations
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
@ -1741,11 +1742,14 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
json_t *signkeys,
|
||||
json_t *recoup,
|
||||
json_t *denoms,
|
||||
json_t *grouped_denominations)
|
||||
json_t *grouped_denominations,
|
||||
const struct GNUNET_HashCode *h_grouped)
|
||||
{
|
||||
struct KeysResponseData krd;
|
||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
struct TALER_ExchangePublicKeyP grouped_exchange_pub;
|
||||
struct TALER_ExchangeSignatureP grouped_exchange_sig;
|
||||
json_t *keys;
|
||||
|
||||
GNUNET_assert (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time));
|
||||
@ -1753,11 +1757,13 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
GNUNET_assert (NULL != recoup);
|
||||
GNUNET_assert (NULL != denoms);
|
||||
GNUNET_assert (NULL != grouped_denominations);
|
||||
GNUNET_assert (NULL != h_grouped);
|
||||
GNUNET_assert (NULL != ksh->auditors);
|
||||
GNUNET_assert (NULL != TEH_currency);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Creating /keys at cherry pick date %s\n",
|
||||
GNUNET_TIME_timestamp2s (last_cpd));
|
||||
|
||||
/* Sign hash over denomination keys */
|
||||
{
|
||||
enum TALER_ErrorCode ec;
|
||||
@ -1779,6 +1785,33 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
}
|
||||
}
|
||||
|
||||
/* Sign grouped hash */
|
||||
{
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
if (TALER_EC_NONE !=
|
||||
(ec =
|
||||
TALER_exchange_online_key_set_sign (
|
||||
&TEH_keys_exchange_sign2_,
|
||||
ksh,
|
||||
last_cpd,
|
||||
h_grouped,
|
||||
&grouped_exchange_pub,
|
||||
&grouped_exchange_sig)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Could not create key response data: cannot sign grouped hash (%s)\n",
|
||||
TALER_ErrorCode_get_hint (ec));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* both public keys really must be the same */
|
||||
GNUNET_assert (0 ==
|
||||
memcmp (&grouped_exchange_pub,
|
||||
&exchange_pub,
|
||||
sizeof(exchange_pub)));
|
||||
|
||||
{
|
||||
const struct SigningKey *sk;
|
||||
|
||||
@ -1815,7 +1848,9 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
GNUNET_JSON_pack_data_auto ("eddsa_pub",
|
||||
&exchange_pub),
|
||||
GNUNET_JSON_pack_data_auto ("eddsa_sig",
|
||||
&exchange_sig));
|
||||
&exchange_sig),
|
||||
GNUNET_JSON_pack_data_auto ("denominations_sig",
|
||||
&grouped_exchange_sig));
|
||||
GNUNET_assert (NULL != keys);
|
||||
|
||||
/* Set wallet limit if KYC is configured */
|
||||
@ -1998,6 +2033,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
struct GNUNET_TIME_Timestamp last_cpd;
|
||||
struct GNUNET_CONTAINER_Heap *heap;
|
||||
struct GNUNET_HashContext *hash_context = NULL;
|
||||
struct GNUNET_HashCode grouped_hash_xor = {0};
|
||||
|
||||
sctx.signkeys = json_array ();
|
||||
GNUNET_assert (NULL != sctx.signkeys);
|
||||
@ -2043,8 +2079,11 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
/* groupData is the value we store for each group meta-data */
|
||||
struct groupData
|
||||
{
|
||||
json_t *json; /* The json blob with the group meta-data and list of denominations */
|
||||
struct GNUNET_HashContext *hash_context; /* hash over all denominations in that group */
|
||||
/* The json blob with the group meta-data and list of denominations */
|
||||
json_t *json;
|
||||
|
||||
/* xor of all hashes of denominations in that group */
|
||||
struct GNUNET_HashCode hash_xor;
|
||||
};
|
||||
|
||||
/* heap = min heap, sorted by start time */
|
||||
@ -2065,6 +2104,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
GNUNET_CRYPTO_hash_context_finish (
|
||||
GNUNET_CRYPTO_hash_context_copy (hash_context),
|
||||
&hc);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
create_krd (ksh,
|
||||
&hc,
|
||||
@ -2072,7 +2112,9 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
sctx.signkeys,
|
||||
recoup,
|
||||
denoms,
|
||||
grouped_denominations))
|
||||
grouped_denominations,
|
||||
|
||||
&grouped_hash_xor))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Failed to generate key response data for %s\n",
|
||||
@ -2139,21 +2181,14 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
json_t *list;
|
||||
json_t *entry;
|
||||
struct GNUNET_HashCode key;
|
||||
|
||||
/* Find the group/JSON-blob for the key */
|
||||
struct
|
||||
{
|
||||
enum TALER_DenominationCipher cipher;
|
||||
struct TALER_Amount value;
|
||||
struct TALER_DenomFeeSet fees;
|
||||
struct TALER_AgeMask age_mask;
|
||||
} meta = {
|
||||
struct TALER_DenominationGroup meta = {
|
||||
.cipher = dk->denom_pub.cipher,
|
||||
.value = dk->meta.value,
|
||||
.fees = dk->meta.fees,
|
||||
.age_mask = dk->meta.age_mask,
|
||||
};
|
||||
|
||||
/* Search the group/JSON-blob for the key */
|
||||
GNUNET_CRYPTO_hash (&meta, sizeof(meta), &key);
|
||||
|
||||
group =
|
||||
@ -2168,15 +2203,15 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
char *cipher;
|
||||
|
||||
group = GNUNET_new (struct groupData);
|
||||
group->hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
memset (group, 0, sizeof(*group));
|
||||
|
||||
switch (meta.cipher)
|
||||
{
|
||||
case TALER_DENOMINATION_RSA:
|
||||
cipher = age_restricted ? "RSA+age_restriction": "RSA";
|
||||
cipher = age_restricted ? "RSA+age_restricted": "RSA";
|
||||
break;
|
||||
case TALER_DENOMINATION_CS:
|
||||
cipher = age_restricted ? "CS+age_restriction": "CS";
|
||||
cipher = age_restricted ? "CS+age_restricted": "CS";
|
||||
break;
|
||||
default:
|
||||
GNUNET_assert (false);
|
||||
@ -2190,10 +2225,9 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
|
||||
if (age_restricted)
|
||||
{
|
||||
char *mask = TALER_age_mask_to_string (&meta.age_mask);
|
||||
int r = json_object_set (group->json,
|
||||
"age_mask",
|
||||
json_string (mask));
|
||||
json_integer (meta.age_mask.bits));
|
||||
GNUNET_assert (0 == r);
|
||||
}
|
||||
|
||||
@ -2252,12 +2286,11 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
GNUNET_assert (NULL != entry);
|
||||
}
|
||||
|
||||
// Build up the running hash of all denominations in this group
|
||||
//
|
||||
// TODO: FIXME-oec: this is cipher and age_restriction dependend?!
|
||||
GNUNET_CRYPTO_hash_context_read (group->hash_context,
|
||||
&dk->h_denom_pub,
|
||||
sizeof (struct GNUNET_HashCode));
|
||||
// Build up the running xor of all hashes of the denominations in this
|
||||
// group
|
||||
GNUNET_CRYPTO_hash_xor (&dk->h_denom_pub.hash,
|
||||
&group->hash_xor,
|
||||
&group->hash_xor);
|
||||
|
||||
// Finally, add the denomination to the list of denominations in this
|
||||
// group
|
||||
@ -2267,37 +2300,29 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
GNUNET_assert (0 ==
|
||||
json_array_append_new (list, entry));
|
||||
}
|
||||
}
|
||||
} /* loop over heap ends */
|
||||
|
||||
// Create the JSON-array of grouped denominations
|
||||
if (0 <
|
||||
GNUNET_CONTAINER_multihashmap_size (denominations_by_group))
|
||||
{
|
||||
struct GNUNET_CONTAINER_MultiHashMapIterator *iter;
|
||||
struct GNUNET_HashCode all_hashcode;
|
||||
struct GNUNET_HashContext *all_hash_ctx;
|
||||
struct groupData *group = NULL;
|
||||
|
||||
all_hash_ctx =
|
||||
GNUNET_CRYPTO_hash_context_start ();
|
||||
|
||||
iter =
|
||||
GNUNET_CONTAINER_multihashmap_iterator_create (denominations_by_group);
|
||||
|
||||
while (GNUNET_OK ==
|
||||
GNUNET_CONTAINER_multihashmap_iterator_next (iter, NULL, (const
|
||||
void **)
|
||||
&group))
|
||||
GNUNET_CONTAINER_multihashmap_iterator_next (iter,
|
||||
NULL,
|
||||
(const
|
||||
void **) &group))
|
||||
{
|
||||
struct GNUNET_HashCode hc;
|
||||
|
||||
GNUNET_CRYPTO_hash_context_finish (
|
||||
group->hash_context,
|
||||
&hc);
|
||||
|
||||
GNUNET_CRYPTO_hash_context_read (all_hash_ctx,
|
||||
&hc,
|
||||
sizeof (struct GNUNET_HashCode));
|
||||
GNUNET_CRYPTO_hash_xor (&group->hash_xor,
|
||||
&grouped_hash_xor,
|
||||
&grouped_hash_xor);
|
||||
|
||||
GNUNET_assert (0 ==
|
||||
json_object_set (
|
||||
@ -2317,12 +2342,6 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
GNUNET_CONTAINER_multihashmap_iterator_destroy (iter);
|
||||
GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group);
|
||||
|
||||
GNUNET_CRYPTO_hash_context_finish (
|
||||
all_hash_ctx,
|
||||
&all_hashcode);
|
||||
|
||||
// FIXME-oec: TODO:
|
||||
// sign all_hashcode and add the signature to the /keys response
|
||||
}
|
||||
}
|
||||
|
||||
@ -2333,7 +2352,6 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||
&hc);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
create_krd (ksh,
|
||||
&hc,
|
||||
@ -2341,7 +2359,8 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
|
||||
sctx.signkeys,
|
||||
recoup,
|
||||
denoms,
|
||||
grouped_denominations))
|
||||
grouped_denominations,
|
||||
&grouped_hash_xor))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Failed to generate key response data for %s\n",
|
||||
|
@ -359,6 +359,36 @@ TALER_JSON_spec_amount_any_nbo (const char *name,
|
||||
TALER_JSON_pack_amount ("account_fee", &(gfs)->account), \
|
||||
TALER_JSON_pack_amount ("purse_fee", &(gfs)->purse)
|
||||
|
||||
/**
|
||||
* Group of Denominations. These are the common fields of an array of
|
||||
* denominations.
|
||||
*
|
||||
* The corresponding JSON-blob will also contain an array of particular
|
||||
* denominations with only the timestamps, cipher-specific public key and the
|
||||
* master signature.
|
||||
*
|
||||
**/
|
||||
struct TALER_DenominationGroup
|
||||
{
|
||||
/* currency must be set prior to calling TALER_JSON_spec_denomination_group */
|
||||
const char *currency;
|
||||
enum TALER_DenominationCipher cipher;
|
||||
struct TALER_Amount value;
|
||||
struct TALER_DenomFeeSet fees;
|
||||
struct TALER_AgeMask age_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a parser for a group of denominations.
|
||||
* NOTE: group.currency MUST have been set prior to calling this function.
|
||||
*
|
||||
* @param field name of the field, maybe NULL
|
||||
* @param[out] group denomination group information
|
||||
* @return corresponding field spec
|
||||
*/
|
||||
struct GNUNET_JSON_Specification
|
||||
TALER_JSON_spec_denomination_group (const char *field,
|
||||
struct TALER_DenominationGroup *group);
|
||||
|
||||
/**
|
||||
* Generate line in parser specification for denomination public key.
|
||||
@ -371,6 +401,20 @@ struct GNUNET_JSON_Specification
|
||||
TALER_JSON_spec_denom_pub (const char *field,
|
||||
struct TALER_DenominationPublicKey *pk);
|
||||
|
||||
/**
|
||||
* Generate a parser specification for a denomination public key of a given
|
||||
* cipher.
|
||||
*
|
||||
* @param field name of the field
|
||||
* @parm cipher which cipher type to parse for
|
||||
* @param[out] pk key to fill
|
||||
* @return corresponding field spec
|
||||
*/
|
||||
struct GNUNET_JSON_Specification
|
||||
TALER_JSON_spec_denom_pub_cipher (const char *field,
|
||||
const enum TALER_DenominationCipher cipher,
|
||||
struct TALER_DenominationPublicKey *pk);
|
||||
|
||||
|
||||
/**
|
||||
* Generate line in parser specification for denomination signature.
|
||||
|
@ -35,11 +35,15 @@
|
||||
static enum TALER_DenominationCipher
|
||||
string_to_cipher (const char *cipher_s)
|
||||
{
|
||||
if (0 == strcasecmp (cipher_s,
|
||||
"RSA"))
|
||||
if ((0 == strcasecmp (cipher_s,
|
||||
"RSA")) ||
|
||||
(0 == strcasecmp (cipher_s,
|
||||
"RSA+age_restricted")))
|
||||
return TALER_DENOMINATION_RSA;
|
||||
if (0 == strcasecmp (cipher_s,
|
||||
"CS"))
|
||||
if ((0 == strcasecmp (cipher_s,
|
||||
"CS")) ||
|
||||
(0 == strcasecmp (cipher_s,
|
||||
"CS+age_restricted")))
|
||||
return TALER_DENOMINATION_CS;
|
||||
return TALER_DENOMINATION_INVALID;
|
||||
}
|
||||
@ -239,6 +243,84 @@ TALER_JSON_spec_amount_any_nbo (const char *name,
|
||||
}
|
||||
|
||||
|
||||
static enum GNUNET_GenericReturnValue
|
||||
parse_denomination_group (void *cls,
|
||||
json_t *root,
|
||||
struct GNUNET_JSON_Specification *spec)
|
||||
{
|
||||
struct TALER_DenominationGroup *group = spec->ptr;
|
||||
const char *cipher;
|
||||
bool age_mask_missing = false;
|
||||
bool has_age_restricted_suffix = false;
|
||||
struct GNUNET_JSON_Specification gspec[] = {
|
||||
GNUNET_JSON_spec_string ("cipher",
|
||||
&cipher),
|
||||
TALER_JSON_spec_amount ("value",
|
||||
group->currency,
|
||||
&group->value),
|
||||
TALER_JSON_SPEC_DENOM_FEES ("fee",
|
||||
group->currency,
|
||||
&group->fees),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_uint32 ("age_mask",
|
||||
&group->age_mask.bits),
|
||||
&age_mask_missing),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
const char *emsg;
|
||||
unsigned int eline;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (root,
|
||||
gspec,
|
||||
&emsg,
|
||||
&eline))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
group->cipher = string_to_cipher (cipher);
|
||||
if (TALER_DENOMINATION_INVALID == group->cipher)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* age_mask and suffix must be consistent */
|
||||
has_age_restricted_suffix =
|
||||
(NULL != strstr (cipher, "+age_restricted"));
|
||||
if (has_age_restricted_suffix && age_mask_missing)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (age_mask_missing)
|
||||
group->age_mask.bits = 0;
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
struct GNUNET_JSON_Specification
|
||||
TALER_JSON_spec_denomination_group (const char *name,
|
||||
struct TALER_DenominationGroup *group)
|
||||
{
|
||||
struct GNUNET_JSON_Specification ret = {
|
||||
.parser = &parse_denomination_group,
|
||||
.cleaner = NULL,
|
||||
.field = name,
|
||||
.ptr = group,
|
||||
.ptr_size = sizeof(*group),
|
||||
.size_ptr = NULL,
|
||||
};
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to an encrypted contract.
|
||||
*
|
||||
@ -330,11 +412,14 @@ parse_denom_pub (void *cls,
|
||||
{
|
||||
struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
|
||||
const char *cipher;
|
||||
bool age_mask_missing = false;
|
||||
struct GNUNET_JSON_Specification dspec[] = {
|
||||
GNUNET_JSON_spec_string ("cipher",
|
||||
&cipher),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_uint32 ("age_mask",
|
||||
&denom_pub->age_mask.bits),
|
||||
&age_mask_missing),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
const char *emsg;
|
||||
@ -350,6 +435,10 @@ parse_denom_pub (void *cls,
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (age_mask_missing)
|
||||
denom_pub->age_mask.bits = 0;
|
||||
|
||||
denom_pub->cipher = string_to_cipher (cipher);
|
||||
switch (denom_pub->cipher)
|
||||
{
|
||||
@ -433,6 +522,93 @@ TALER_JSON_spec_denom_pub (const char *field,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object partially into a denomination public key.
|
||||
*
|
||||
* Depending on the cipher in cls, it parses the corresponding public key type.
|
||||
*
|
||||
* @param cls closure, enum TALER_DenominationCipher
|
||||
* @param cipher cipher to parse for
|
||||
* @param root the json object representing data
|
||||
* @param[out] spec where to write the data
|
||||
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
parse_denom_pub_cipher (void *cls,
|
||||
json_t *root,
|
||||
struct GNUNET_JSON_Specification *spec)
|
||||
{
|
||||
struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
|
||||
enum TALER_DenominationCipher cipher = (enum TALER_DenominationCipher) cls;
|
||||
const char *emsg;
|
||||
unsigned int eline;
|
||||
|
||||
switch (cipher)
|
||||
{
|
||||
case TALER_DENOMINATION_RSA:
|
||||
{
|
||||
struct GNUNET_JSON_Specification ispec[] = {
|
||||
GNUNET_JSON_spec_rsa_public_key (
|
||||
"rsa_pub",
|
||||
&denom_pub->details.rsa_public_key),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (root,
|
||||
ispec,
|
||||
&emsg,
|
||||
&eline))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
case TALER_DENOMINATION_CS:
|
||||
{
|
||||
struct GNUNET_JSON_Specification ispec[] = {
|
||||
GNUNET_JSON_spec_fixed ("cs_pub",
|
||||
&denom_pub->details.cs_public_key,
|
||||
sizeof (denom_pub->details.cs_public_key)),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (root,
|
||||
ispec,
|
||||
&emsg,
|
||||
&eline))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
default:
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct GNUNET_JSON_Specification
|
||||
TALER_JSON_spec_denom_pub_cipher (const char *field,
|
||||
enum TALER_DenominationCipher cipher,
|
||||
struct TALER_DenominationPublicKey *pk)
|
||||
{
|
||||
struct GNUNET_JSON_Specification ret = {
|
||||
.parser = &parse_denom_pub_cipher,
|
||||
.cleaner = &clean_denom_pub,
|
||||
.field = field,
|
||||
.cls = (void *) cipher,
|
||||
.ptr = pk
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to denomination signature.
|
||||
*
|
||||
|
@ -79,35 +79,38 @@ TALER_JSON_pack_denom_pub (
|
||||
struct GNUNET_JSON_PackSpec ps = {
|
||||
.field_name = name,
|
||||
};
|
||||
struct GNUNET_JSON_PackSpec mask_or_end;
|
||||
|
||||
if (NULL == pk)
|
||||
return ps;
|
||||
|
||||
mask_or_end = (0 != pk->age_mask.bits) ?
|
||||
GNUNET_JSON_pack_uint64 ("age_mask", pk->age_mask.bits) :
|
||||
GNUNET_JSON_pack_end_ ();
|
||||
|
||||
switch (pk->cipher)
|
||||
{
|
||||
case TALER_DENOMINATION_RSA:
|
||||
ps.object
|
||||
= GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_string ("cipher",
|
||||
"RSA"),
|
||||
GNUNET_JSON_pack_uint64 ("age_mask",
|
||||
pk->age_mask.bits),
|
||||
GNUNET_JSON_pack_string ("cipher", "RSA"),
|
||||
GNUNET_JSON_pack_rsa_public_key ("rsa_public_key",
|
||||
pk->details.rsa_public_key));
|
||||
pk->details.rsa_public_key),
|
||||
mask_or_end);
|
||||
break;
|
||||
case TALER_DENOMINATION_CS:
|
||||
ps.object
|
||||
= GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_string ("cipher",
|
||||
"CS"),
|
||||
GNUNET_JSON_pack_uint64 ("age_mask",
|
||||
pk->age_mask.bits),
|
||||
GNUNET_JSON_pack_string ("cipher", "CS"),
|
||||
GNUNET_JSON_pack_data_varsize ("cs_public_key",
|
||||
&pk->details.cs_public_key,
|
||||
sizeof (pk->details.cs_public_key)));
|
||||
sizeof (pk->details.cs_public_key)),
|
||||
mask_or_end);
|
||||
break;
|
||||
default:
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
|
||||
return ps;
|
||||
}
|
||||
|
||||
|
@ -303,24 +303,31 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
|
||||
|
||||
|
||||
/**
|
||||
* Parse a exchange's denomination key encoded in JSON.
|
||||
* Parse a exchange's denomination key encoded in JSON partially.
|
||||
*
|
||||
* Only the values for master_sig, timestamps and the cipher-specific public
|
||||
* key are parsed. All other fields (fees, age_mask, value) MUST have been set
|
||||
* prior to calling this function, otherwise the signature verification
|
||||
* performed within this function will fail.
|
||||
*
|
||||
* @param currency expected currency of all fees
|
||||
* @param[out] denom_key where to return the result
|
||||
* @param cipher cipher type to parse
|
||||
* @param check_sigs should we check signatures?
|
||||
* @param[in] denom_key_obj json to parse
|
||||
* @param master_key master key to use to verify signature
|
||||
* @param hash_context where to accumulate data for signature verification
|
||||
* @param hash_xor where to accumulate data for signature verification via XOR
|
||||
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
|
||||
* invalid or the json malformed.
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
parse_json_denomkey (const char *currency,
|
||||
parse_json_denomkey_partially (const char *currency,
|
||||
struct TALER_EXCHANGE_DenomPublicKey *denom_key,
|
||||
enum TALER_DenominationCipher cipher,
|
||||
bool check_sigs,
|
||||
json_t *denom_key_obj,
|
||||
struct TALER_MasterPublicKeyP *master_key,
|
||||
struct GNUNET_HashContext *hash_context)
|
||||
struct GNUNET_HashCode *hash_xor)
|
||||
{
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("master_sig",
|
||||
@ -333,13 +340,8 @@ parse_json_denomkey (const char *currency,
|
||||
&denom_key->valid_from),
|
||||
GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
|
||||
&denom_key->expire_legal),
|
||||
TALER_JSON_spec_amount ("value",
|
||||
currency,
|
||||
&denom_key->value),
|
||||
TALER_JSON_SPEC_DENOM_FEES ("fee",
|
||||
currency,
|
||||
&denom_key->fees),
|
||||
TALER_JSON_spec_denom_pub ("denom_pub",
|
||||
TALER_JSON_spec_denom_pub_cipher (NULL,
|
||||
cipher,
|
||||
&denom_key->key),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
@ -354,10 +356,11 @@ parse_json_denomkey (const char *currency,
|
||||
}
|
||||
TALER_denom_pub_hash (&denom_key->key,
|
||||
&denom_key->h_key);
|
||||
if (NULL != hash_context)
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
&denom_key->h_key,
|
||||
sizeof (struct GNUNET_HashCode));
|
||||
if (NULL != hash_xor)
|
||||
GNUNET_CRYPTO_hash_xor (&denom_key->h_key.hash,
|
||||
hash_xor,
|
||||
hash_xor);
|
||||
|
||||
if (! check_sigs)
|
||||
return GNUNET_OK;
|
||||
EXITIF (GNUNET_SYSERR ==
|
||||
@ -729,15 +732,13 @@ decode_keys_json (const json_t *resp_obj,
|
||||
struct TALER_EXCHANGE_Keys *key_data,
|
||||
enum TALER_EXCHANGE_VersionCompatibility *vc)
|
||||
{
|
||||
struct TALER_ExchangeSignatureP sig;
|
||||
struct GNUNET_HashContext *hash_context = NULL;
|
||||
struct GNUNET_HashContext *hash_context_restricted = NULL;
|
||||
bool have_age_restricted_denom = false;
|
||||
struct TALER_ExchangeSignatureP denominations_sig;
|
||||
struct GNUNET_HashCode hash_xor = {0};
|
||||
struct TALER_ExchangePublicKeyP pub;
|
||||
const char *currency;
|
||||
struct GNUNET_JSON_Specification mspec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("eddsa_sig",
|
||||
&sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("denominations_sig",
|
||||
&denominations_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
|
||||
&pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("master_public_key",
|
||||
@ -760,7 +761,7 @@ decode_keys_json (const json_t *resp_obj,
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
#if DEBUG
|
||||
#if 1 /* DEBUG */
|
||||
json_dumpf (resp_obj,
|
||||
stderr,
|
||||
JSON_INDENT (2));
|
||||
@ -829,13 +830,6 @@ decode_keys_json (const json_t *resp_obj,
|
||||
}
|
||||
}
|
||||
|
||||
/* parse the master public key and issue date of the response */
|
||||
if (check_sig)
|
||||
{
|
||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
hash_context_restricted = GNUNET_CRYPTO_hash_context_start ();
|
||||
}
|
||||
|
||||
/* parse the global fees */
|
||||
{
|
||||
json_t *global_fees;
|
||||
@ -933,60 +927,65 @@ decode_keys_json (const json_t *resp_obj,
|
||||
/* parse the denomination keys, merging with the
|
||||
possibly EXISTING array as required (/keys cherry picking) */
|
||||
{
|
||||
/* The denominations can be in "denoms" and (optionally) in
|
||||
* "age_restricted_denoms"
|
||||
*/
|
||||
struct
|
||||
{
|
||||
char *name;
|
||||
struct GNUNET_HashContext *hc;
|
||||
bool is_optional_age_restriction;
|
||||
}
|
||||
hive[2] = {
|
||||
{
|
||||
"denoms",
|
||||
hash_context,
|
||||
false
|
||||
},
|
||||
{
|
||||
"age_restricted_denoms",
|
||||
hash_context_restricted,
|
||||
true
|
||||
}
|
||||
json_t *denominations_by_group;
|
||||
json_t *group_obj;
|
||||
unsigned int group_idx;
|
||||
|
||||
denominations_by_group =
|
||||
json_object_get (
|
||||
resp_obj,
|
||||
"denominations");
|
||||
|
||||
EXITIF (JSON_ARRAY !=
|
||||
json_typeof (denominations_by_group));
|
||||
|
||||
json_array_foreach (denominations_by_group, group_idx, group_obj) {
|
||||
/* First, parse { cipher, fees, value, age_mask } of the current group */
|
||||
|
||||
struct TALER_DenominationGroup group = {
|
||||
.currency = currency
|
||||
};
|
||||
struct GNUNET_JSON_Specification group_spec[] = {
|
||||
TALER_JSON_spec_denomination_group (NULL, &group),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
for (size_t s = 0; s < sizeof(hive) / sizeof(hive[0]); s++)
|
||||
EXITIF (GNUNET_SYSERR ==
|
||||
GNUNET_JSON_parse (group_obj,
|
||||
group_spec,
|
||||
NULL,
|
||||
NULL));
|
||||
|
||||
/* Now, parse the individual denominations */
|
||||
{
|
||||
json_t *denom_keys_array;
|
||||
json_t *denom_key_obj;
|
||||
unsigned int index;
|
||||
|
||||
denom_keys_array = json_object_get (resp_obj,
|
||||
hive[s].name);
|
||||
|
||||
if (NULL == denom_keys_array)
|
||||
continue;
|
||||
|
||||
denom_keys_array = json_object_get (group_obj, "denoms");
|
||||
EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
|
||||
|
||||
json_array_foreach (denom_keys_array, index, denom_key_obj) {
|
||||
struct TALER_EXCHANGE_DenomPublicKey dk;
|
||||
struct TALER_EXCHANGE_DenomPublicKey dk = {0};
|
||||
bool found = false;
|
||||
|
||||
/* mark that we have at least one age restricted denomination, needed
|
||||
* for the hash calculation and signature verification below. */
|
||||
have_age_restricted_denom |= hive[s].is_optional_age_restriction;
|
||||
memset (&dk, 0, sizeof (dk));
|
||||
|
||||
/* Set the common fields from the group for this particular
|
||||
* denomination. Required to make the validity check inside
|
||||
* parse_json_denomkey_partially pass */
|
||||
dk.key.cipher = group.cipher;
|
||||
dk.value = group.value;
|
||||
dk.fees = group.fees;
|
||||
dk.key.age_mask = group.age_mask;
|
||||
|
||||
memset (&dk,
|
||||
0,
|
||||
sizeof (dk));
|
||||
EXITIF (GNUNET_SYSERR ==
|
||||
parse_json_denomkey (key_data->currency,
|
||||
parse_json_denomkey_partially (key_data->currency,
|
||||
&dk,
|
||||
group.cipher,
|
||||
check_sig,
|
||||
denom_key_obj,
|
||||
&key_data->master_pub,
|
||||
hive[s].hc));
|
||||
check_sig ? &hash_xor: NULL));
|
||||
|
||||
for (unsigned int j = 0;
|
||||
j<key_data->num_denom_keys;
|
||||
@ -999,6 +998,7 @@ decode_keys_json (const json_t *resp_obj,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
/* 0:0:0 did not support /keys cherry picking */
|
||||
@ -1006,6 +1006,7 @@ decode_keys_json (const json_t *resp_obj,
|
||||
TALER_denom_pub_free (&dk.key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key_data->denom_keys_size == key_data->num_denom_keys)
|
||||
GNUNET_array_grow (key_data->denom_keys,
|
||||
key_data->denom_keys_size,
|
||||
@ -1018,8 +1019,9 @@ decode_keys_json (const json_t *resp_obj,
|
||||
key_data->last_denom_issue_date
|
||||
= GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
|
||||
dk.valid_from);
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/* parse the auditor information */
|
||||
@ -1139,30 +1141,6 @@ decode_keys_json (const json_t *resp_obj,
|
||||
|
||||
if (check_sig)
|
||||
{
|
||||
struct GNUNET_HashCode hc;
|
||||
|
||||
/* If we had any age restricted denominations, add their hash to the end of
|
||||
* the normal denominations. */
|
||||
if (have_age_restricted_denom)
|
||||
{
|
||||
struct GNUNET_HashCode hcr;
|
||||
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context_restricted,
|
||||
&hcr);
|
||||
hash_context_restricted = NULL;
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
&hcr,
|
||||
sizeof(struct GNUNET_HashCode));
|
||||
}
|
||||
else
|
||||
{
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context_restricted);
|
||||
hash_context_restricted = NULL;
|
||||
}
|
||||
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||
&hc);
|
||||
hash_context = NULL;
|
||||
EXITIF (GNUNET_OK !=
|
||||
TALER_EXCHANGE_test_signing_key (key_data,
|
||||
&pub));
|
||||
@ -1170,18 +1148,15 @@ decode_keys_json (const json_t *resp_obj,
|
||||
EXITIF (GNUNET_OK !=
|
||||
TALER_exchange_online_key_set_verify (
|
||||
key_data->list_issue_date,
|
||||
&hc,
|
||||
&hash_xor,
|
||||
&pub,
|
||||
&sig));
|
||||
&denominations_sig));
|
||||
}
|
||||
return GNUNET_OK;
|
||||
EXITIF_exit:
|
||||
|
||||
return GNUNET_OK;
|
||||
|
||||
EXITIF_exit:
|
||||
*vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
|
||||
if (NULL != hash_context)
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
if (NULL != hash_context_restricted)
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context_restricted);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user