diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2022-06-26 16:59:27 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2022-06-26 16:59:27 +0200 |
commit | 31f74059e0d710254397688aabc201b230ef27da (patch) | |
tree | 8a9717ae3d729c5916db15c7407d8d68b2828f85 /src/json | |
parent | b39febe36fd66c8a36469cbedbc6197cc6c60135 (diff) |
[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.
Diffstat (limited to 'src/json')
-rw-r--r-- | src/json/json_helper.c | 188 | ||||
-rw-r--r-- | src/json/json_pack.c | 23 |
2 files changed, 195 insertions, 16 deletions
diff --git a/src/json/json_helper.c b/src/json/json_helper.c index 11aeceefb..9752bb9f8 100644 --- a/src/json/json_helper.c +++ b/src/json/json_helper.c @@ -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_uint32 ("age_mask", - &denom_pub->age_mask.bits), + 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) { @@ -434,6 +523,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. * * @param cls closure, NULL diff --git a/src/json/json_pack.c b/src/json/json_pack.c index 090a8b96b..bb52eeb05 100644 --- a/src/json/json_pack.c +++ b/src/json/json_pack.c @@ -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; } |