diff options
Diffstat (limited to 'src/json/json_helper.c')
-rw-r--r-- | src/json/json_helper.c | 1376 |
1 files changed, 1160 insertions, 216 deletions
diff --git a/src/json/json_helper.c b/src/json/json_helper.c index 7c01cde0c..0a533610b 100644 --- a/src/json/json_helper.c +++ b/src/json/json_helper.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,6 +26,29 @@ #include "taler_json_lib.h" +/** + * Convert string value to numeric cipher value. + * + * @param cipher_s input string + * @return numeric cipher value + */ +static enum GNUNET_CRYPTO_BlindSignatureAlgorithm +string_to_cipher (const char *cipher_s) +{ + if ((0 == strcasecmp (cipher_s, + "RSA")) || + (0 == strcasecmp (cipher_s, + "RSA+age_restricted"))) + return GNUNET_CRYPTO_BSA_RSA; + if ((0 == strcasecmp (cipher_s, + "CS")) || + (0 == strcasecmp (cipher_s, + "CS+age_restricted"))) + return GNUNET_CRYPTO_BSA_CS; + return GNUNET_CRYPTO_BSA_INVALID; +} + + json_t * TALER_JSON_from_amount (const struct TALER_Amount *amount) { @@ -41,17 +64,6 @@ TALER_JSON_from_amount (const struct TALER_Amount *amount) } -json_t * -TALER_JSON_from_amount_nbo (const struct TALER_AmountNBO *amount) -{ - struct TALER_Amount a; - - TALER_amount_ntoh (&a, - amount); - return TALER_JSON_from_amount (&a); -} - - /** * Parse given JSON object to Amount * @@ -87,6 +99,11 @@ parse_amount (void *cls, r_amount->currency)) ) { GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Expected currency `%s', but amount used currency `%s' in field `%s'\n", + currency, + r_amount->currency, + spec->field); return GNUNET_SYSERR; } return GNUNET_OK; @@ -132,7 +149,7 @@ TALER_JSON_spec_amount_any (const char *name, /** - * Parse given JSON object to Amount in NBO. + * Parse given JSON object to currency spec. * * @param cls closure, NULL * @param root the json object representing data @@ -140,157 +157,200 @@ TALER_JSON_spec_amount_any (const char *name, * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ static enum GNUNET_GenericReturnValue -parse_amount_nbo (void *cls, - json_t *root, - struct GNUNET_JSON_Specification *spec) +parse_cspec (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) { - const char *currency = cls; - struct TALER_AmountNBO *r_amount = spec->ptr; - const char *sv; + struct TALER_CurrencySpecification *r_cspec = spec->ptr; + const char *currency = spec->cls; + const char *name; + uint32_t fid; + uint32_t fnd; + uint32_t ftzd; + const json_t *map; + struct GNUNET_JSON_Specification gspec[] = { + GNUNET_JSON_spec_string ("name", + &name), + GNUNET_JSON_spec_uint32 ("num_fractional_input_digits", + &fid), + GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits", + &fnd), + GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits", + &ftzd), + GNUNET_JSON_spec_object_const ("alt_unit_names", + &map), + GNUNET_JSON_spec_end () + }; + const char *emsg; + unsigned int eline; - (void) cls; - if (! json_is_string (root)) + memset (r_cspec->currency, + 0, + sizeof (r_cspec->currency)); + if (GNUNET_OK != + GNUNET_JSON_parse (root, + gspec, + &emsg, + &eline)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse %s at %u: %s\n", + spec[eline].field, + eline, + emsg); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (strlen (currency) >= TALER_CURRENCY_LEN) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if ( (fid > TALER_AMOUNT_FRAC_LEN) || + (fnd > TALER_AMOUNT_FRAC_LEN) || + (ftzd > TALER_AMOUNT_FRAC_LEN) ) { - GNUNET_break (0); + GNUNET_break_op (0); return GNUNET_SYSERR; } - sv = json_string_value (root); if (GNUNET_OK != - TALER_string_to_amount_nbo (sv, - r_amount)) + TALER_check_currency (currency)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "`%s' is not a valid amount\n", - sv); GNUNET_break_op (0); return GNUNET_SYSERR; } - if ( (NULL != currency) && - (0 != - strcasecmp (currency, - r_amount->currency)) ) + strcpy (r_cspec->currency, + currency); + if (GNUNET_OK != + TALER_check_currency_scale_map (map)) { GNUNET_break_op (0); return GNUNET_SYSERR; } + r_cspec->name = GNUNET_strdup (name); + r_cspec->map_alt_unit_names = json_incref ((json_t *) map); return GNUNET_OK; } -struct GNUNET_JSON_Specification -TALER_JSON_spec_amount_nbo (const char *name, - const char *currency, - struct TALER_AmountNBO *r_amount) +/** + * Cleanup data left from parsing encrypted contract. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_cspec (void *cls, + struct GNUNET_JSON_Specification *spec) { - struct GNUNET_JSON_Specification ret = { - .parser = &parse_amount_nbo, - .cleaner = NULL, - .cls = (void *) currency, - .field = name, - .ptr = r_amount, - .ptr_size = 0, - .size_ptr = NULL - }; + struct TALER_CurrencySpecification *cspec = spec->ptr; - GNUNET_assert (NULL != currency); - return ret; + (void) cls; + GNUNET_free (cspec->name); + json_decref (cspec->map_alt_unit_names); } struct GNUNET_JSON_Specification -TALER_JSON_spec_amount_any_nbo (const char *name, - struct TALER_AmountNBO *r_amount) +TALER_JSON_spec_currency_specification ( + const char *name, + const char *currency, + struct TALER_CurrencySpecification *r_cspec) { struct GNUNET_JSON_Specification ret = { - .parser = &parse_amount_nbo, - .cleaner = NULL, - .cls = NULL, + .parser = &parse_cspec, + .cleaner = &clean_cspec, + .cls = (void *) currency, .field = name, - .ptr = r_amount, - .ptr_size = 0, + .ptr = r_cspec, + .ptr_size = sizeof (*r_cspec), .size_ptr = NULL }; + memset (r_cspec, + 0, + sizeof (*r_cspec)); return ret; } -/** - * Parse given JSON object to *rounded* absolute time. - * - * @param cls closure, NULL - * @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_abs_time (void *cls, - json_t *root, - struct GNUNET_JSON_Specification *spec) +parse_denomination_group (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) { - struct GNUNET_TIME_Absolute *abs = spec->ptr; - json_t *json_t_ms; - unsigned long long int tval; + struct TALER_DenominationGroup *group = spec->ptr; + const char *cipher; + const char *currency = cls; + 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", + currency, + &group->value), + TALER_JSON_SPEC_DENOM_FEES ("fee", + 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; - (void) cls; - if (! json_is_object (root)) + if (GNUNET_OK != + GNUNET_JSON_parse (root, + gspec, + &emsg, + &eline)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse %s at %u: %s\n", + spec[eline].field, + eline, + emsg); GNUNET_break_op (0); return GNUNET_SYSERR; } - json_t_ms = json_object_get (root, - "t_ms"); - if (json_is_integer (json_t_ms)) + + group->cipher = string_to_cipher (cipher); + if (GNUNET_CRYPTO_BSA_INVALID == group->cipher) { - tval = json_integer_value (json_t_ms); - /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */ - abs->abs_value_us = tval * 1000LL; - if ((abs->abs_value_us) / 1000LL != tval) - { - /* Integer overflow */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_TIME_round_abs (abs)) - { - /* time not rounded */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; + GNUNET_break_op (0); + return GNUNET_SYSERR; } - if (json_is_string (json_t_ms)) - { - const char *val; - val = json_string_value (json_t_ms); - if ((0 == strcasecmp (val, "never"))) - { - *abs = GNUNET_TIME_UNIT_FOREVER_ABS; - return GNUNET_OK; - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "`%s' is not a valid absolute time\n", - json_string_value (json_t_ms)); + /* 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; } - return GNUNET_SYSERR; + + if (age_mask_missing) + group->age_mask.bits = 0; + + return GNUNET_OK; } struct GNUNET_JSON_Specification -TALER_JSON_spec_absolute_time (const char *name, - struct GNUNET_TIME_Absolute *r_time) +TALER_JSON_spec_denomination_group (const char *name, + const char *currency, + struct TALER_DenominationGroup *group) { struct GNUNET_JSON_Specification ret = { - .parser = &parse_abs_time, - .cleaner = NULL, - .cls = NULL, + .cls = (void *) currency, + .parser = &parse_denomination_group, .field = name, - .ptr = r_time, - .ptr_size = sizeof(struct GNUNET_TIME_Absolute), - .size_ptr = NULL + .ptr = group, + .ptr_size = sizeof(*group) }; return ret; @@ -298,7 +358,7 @@ TALER_JSON_spec_absolute_time (const char *name, /** - * Parse given JSON object to absolute time. + * Parse given JSON object to an encrypted contract. * * @param cls closure, NULL * @param root the json object representing data @@ -306,43 +366,64 @@ TALER_JSON_spec_absolute_time (const char *name, * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ static enum GNUNET_GenericReturnValue -parse_abs_time_nbo (void *cls, - json_t *root, - struct GNUNET_JSON_Specification *spec) +parse_econtract (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) { - struct GNUNET_TIME_AbsoluteNBO *abs = spec->ptr; - struct GNUNET_TIME_Absolute a; - struct GNUNET_JSON_Specification ispec; + struct TALER_EncryptedContract *econtract = spec->ptr; + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_varsize ("econtract", + &econtract->econtract, + &econtract->econtract_size), + GNUNET_JSON_spec_fixed_auto ("econtract_sig", + &econtract->econtract_sig), + GNUNET_JSON_spec_fixed_auto ("contract_pub", + &econtract->contract_pub), + GNUNET_JSON_spec_end () + }; + const char *emsg; + unsigned int eline; (void) cls; - ispec = *spec; - ispec.parser = &parse_abs_time; - ispec.ptr = &a; if (GNUNET_OK != - parse_abs_time (NULL, - root, - &ispec)) + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) { GNUNET_break_op (0); return GNUNET_SYSERR; } - *abs = GNUNET_TIME_absolute_hton (a); return GNUNET_OK; } +/** + * Cleanup data left from parsing encrypted contract. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_econtract (void *cls, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_EncryptedContract *econtract = spec->ptr; + + (void) cls; + GNUNET_free (econtract->econtract); +} + + struct GNUNET_JSON_Specification -TALER_JSON_spec_absolute_time_nbo (const char *name, - struct GNUNET_TIME_AbsoluteNBO *r_time) +TALER_JSON_spec_econtract (const char *name, + struct TALER_EncryptedContract *econtract) { struct GNUNET_JSON_Specification ret = { - .parser = &parse_abs_time_nbo, - .cleaner = NULL, - .cls = NULL, + .parser = &parse_econtract, + .cleaner = &clean_econtract, .field = name, - .ptr = r_time, - .ptr_size = sizeof(struct GNUNET_TIME_AbsoluteNBO), - .size_ptr = NULL + .ptr = econtract }; return ret; @@ -350,7 +431,7 @@ TALER_JSON_spec_absolute_time_nbo (const char *name, /** - * Parse given JSON object to relative time. + * Parse given JSON object to an age commitmnet * * @param cls closure, NULL * @param root the json object representing data @@ -358,70 +439,93 @@ TALER_JSON_spec_absolute_time_nbo (const char *name, * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ static enum GNUNET_GenericReturnValue -parse_rel_time (void *cls, - json_t *root, - struct GNUNET_JSON_Specification *spec) +parse_age_commitment (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) { - struct GNUNET_TIME_Relative *rel = spec->ptr; - json_t *json_d_ms; - unsigned long long int tval; + struct TALER_AgeCommitment *age_commitment = spec->ptr; + json_t *pk; + unsigned int idx; + size_t num; (void) cls; - if (! json_is_object (root)) + if ( (NULL == root) || + (! json_is_array (root))) { GNUNET_break_op (0); return GNUNET_SYSERR; } - json_d_ms = json_object_get (root, "d_ms"); - if (json_is_integer (json_d_ms)) + + num = json_array_size (root); + if (32 <= num || 0 == num) { - tval = json_integer_value (json_d_ms); - /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */ - rel->rel_value_us = tval * 1000LL; - if ((rel->rel_value_us) / 1000LL != tval) - { - /* Integer overflow */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + age_commitment->num = num; + age_commitment->keys = + GNUNET_new_array (num, + struct TALER_AgeCommitmentPublicKeyP); + + json_array_foreach (root, idx, pk) { + const char *emsg; + unsigned int eline; + struct GNUNET_JSON_Specification pkspec[] = { + GNUNET_JSON_spec_fixed_auto ( + NULL, + &age_commitment->keys[idx].pub), + GNUNET_JSON_spec_end () + }; + if (GNUNET_OK != - GNUNET_TIME_round_rel (rel)) + GNUNET_JSON_parse (pk, + pkspec, + &emsg, + &eline)) { - /* time not rounded */ GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); return GNUNET_SYSERR; } - return GNUNET_OK; - } - if (json_is_string (json_d_ms)) - { - const char *val; - val = json_string_value (json_d_ms); - if ((0 == strcasecmp (val, "forever"))) - { - *rel = GNUNET_TIME_UNIT_FOREVER_REL; - return GNUNET_OK; - } - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_break_op (0); - return GNUNET_SYSERR; + }; + + return GNUNET_OK; +} + + +/** + * Cleanup data left from parsing age commitment + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_age_commitment (void *cls, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_AgeCommitment *age_commitment = spec->ptr; + + (void) cls; + + if (NULL == age_commitment || + NULL == age_commitment->keys) + return; + + age_commitment->num = 0; + GNUNET_free (age_commitment->keys); } struct GNUNET_JSON_Specification -TALER_JSON_spec_relative_time (const char *name, - struct GNUNET_TIME_Relative *r_time) +TALER_JSON_spec_age_commitment (const char *name, + struct TALER_AgeCommitment *age_commitment) { struct GNUNET_JSON_Specification ret = { - .parser = &parse_rel_time, - .cleaner = NULL, - .cls = NULL, + .parser = &parse_age_commitment, + .cleaner = &clean_age_commitment, .field = name, - .ptr = r_time, - .ptr_size = sizeof(struct GNUNET_TIME_Relative), - .size_ptr = NULL + .ptr = age_commitment }; return ret; @@ -442,12 +546,16 @@ parse_denom_pub (void *cls, struct GNUNET_JSON_Specification *spec) { struct TALER_DenominationPublicKey *denom_pub = spec->ptr; - uint32_t cipher; + struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; + const char *cipher; + bool age_mask_missing = false; struct GNUNET_JSON_Specification dspec[] = { - GNUNET_JSON_spec_uint32 ("cipher", + GNUNET_JSON_spec_string ("cipher", &cipher), - GNUNET_JSON_spec_uint32 ("age_mask", - &denom_pub->age_mask.mask), + 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; @@ -463,15 +571,22 @@ parse_denom_pub (void *cls, GNUNET_break_op (0); return GNUNET_SYSERR; } - denom_pub->cipher = (enum TALER_DenominationCipher) cipher; - switch (denom_pub->cipher) + + if (age_mask_missing) + denom_pub->age_mask.bits = 0; + bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bsign_pub->rc = 1; + bsign_pub->cipher = string_to_cipher (cipher); + switch (bsign_pub->cipher) { - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: { struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_rsa_public_key ( "rsa_public_key", - &denom_pub->details.rsa_public_key), + &bsign_pub->details.rsa_public_key), GNUNET_JSON_spec_end () }; @@ -482,14 +597,38 @@ parse_denom_pub (void *cls, &eline)) { GNUNET_break_op (0); + GNUNET_free (bsign_pub); return GNUNET_SYSERR; } + denom_pub->bsign_pub_key = bsign_pub; + return GNUNET_OK; + } + case GNUNET_CRYPTO_BSA_CS: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_fixed ("cs_public_key", + &bsign_pub->details.cs_public_key, + sizeof (bsign_pub->details.cs_public_key)), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (bsign_pub); + return GNUNET_SYSERR; + } + denom_pub->bsign_pub_key = bsign_pub; return GNUNET_OK; } - default: - GNUNET_break_op (0); - return GNUNET_SYSERR; } + GNUNET_break_op (0); + GNUNET_free (bsign_pub); + return GNUNET_SYSERR; } @@ -521,6 +660,105 @@ TALER_JSON_spec_denom_pub (const char *field, .ptr = pk }; + pk->bsign_pub_key = NULL; + return ret; +} + + +/** + * 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 GNUNET_CRYPTO_BlindSignatureAlgorithm + * @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 GNUNET_CRYPTO_BlindSignatureAlgorithm cipher = + (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls; + struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; + const char *emsg; + unsigned int eline; + + bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bsign_pub->cipher = cipher; + bsign_pub->rc = 1; + switch (cipher) + { + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_rsa_public_key ( + "rsa_pub", + &bsign_pub->details.rsa_public_key), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (bsign_pub); + return GNUNET_SYSERR; + } + denom_pub->bsign_pub_key = bsign_pub; + return GNUNET_OK; + } + case GNUNET_CRYPTO_BSA_CS: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_fixed ("cs_pub", + &bsign_pub->details.cs_public_key, + sizeof (bsign_pub->details.cs_public_key)), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (bsign_pub); + return GNUNET_SYSERR; + } + denom_pub->bsign_pub_key = bsign_pub; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + GNUNET_free (bsign_pub); + return GNUNET_SYSERR; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_denom_pub_cipher (const char *field, + enum GNUNET_CRYPTO_BlindSignatureAlgorithm + 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; } @@ -539,9 +777,10 @@ parse_denom_sig (void *cls, struct GNUNET_JSON_Specification *spec) { struct TALER_DenominationSignature *denom_sig = spec->ptr; - uint32_t cipher; + struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig; + const char *cipher; struct GNUNET_JSON_Specification dspec[] = { - GNUNET_JSON_spec_uint32 ("cipher", + GNUNET_JSON_spec_string ("cipher", &cipher), GNUNET_JSON_spec_end () }; @@ -558,15 +797,19 @@ parse_denom_sig (void *cls, GNUNET_break_op (0); return GNUNET_SYSERR; } - denom_sig->cipher = (enum TALER_DenominationCipher) cipher; - switch (denom_sig->cipher) + unblinded_sig = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature); + unblinded_sig->cipher = string_to_cipher (cipher); + unblinded_sig->rc = 1; + switch (unblinded_sig->cipher) { - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: { struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_rsa_signature ( "rsa_signature", - &denom_sig->details.rsa_signature), + &unblinded_sig->details.rsa_signature), GNUNET_JSON_spec_end () }; @@ -577,14 +820,41 @@ parse_denom_sig (void *cls, &eline)) { GNUNET_break_op (0); + GNUNET_free (unblinded_sig); return GNUNET_SYSERR; } + denom_sig->unblinded_sig = unblinded_sig; + return GNUNET_OK; + } + case GNUNET_CRYPTO_BSA_CS: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_fixed_auto ("cs_signature_r", + &unblinded_sig->details.cs_signature. + r_point), + GNUNET_JSON_spec_fixed_auto ("cs_signature_s", + &unblinded_sig->details.cs_signature. + s_scalar), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (unblinded_sig); + return GNUNET_SYSERR; + } + denom_sig->unblinded_sig = unblinded_sig; return GNUNET_OK; } - default: - GNUNET_break_op (0); - return GNUNET_SYSERR; } + GNUNET_break_op (0); + GNUNET_free (unblinded_sig); + return GNUNET_SYSERR; } @@ -616,6 +886,7 @@ TALER_JSON_spec_denom_sig (const char *field, .ptr = sig }; + sig->unblinded_sig = NULL; return ret; } @@ -634,9 +905,10 @@ parse_blinded_denom_sig (void *cls, struct GNUNET_JSON_Specification *spec) { struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr; - uint32_t cipher; + struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; + const char *cipher; struct GNUNET_JSON_Specification dspec[] = { - GNUNET_JSON_spec_uint32 ("cipher", + GNUNET_JSON_spec_string ("cipher", &cipher), GNUNET_JSON_spec_end () }; @@ -653,15 +925,19 @@ parse_blinded_denom_sig (void *cls, GNUNET_break_op (0); return GNUNET_SYSERR; } - denom_sig->cipher = (enum TALER_DenominationCipher) cipher; - switch (denom_sig->cipher) + blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blinded_sig->cipher = string_to_cipher (cipher); + blinded_sig->rc = 1; + switch (blinded_sig->cipher) { - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: { struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_rsa_signature ( "blinded_rsa_signature", - &denom_sig->details.blinded_rsa_signature), + &blinded_sig->details.blinded_rsa_signature), GNUNET_JSON_spec_end () }; @@ -672,14 +948,40 @@ parse_blinded_denom_sig (void *cls, &eline)) { GNUNET_break_op (0); + GNUNET_free (blinded_sig); return GNUNET_SYSERR; } + denom_sig->blinded_sig = blinded_sig; + return GNUNET_OK; + } + case GNUNET_CRYPTO_BSA_CS: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_uint32 ("b", + &blinded_sig->details.blinded_cs_answer.b), + GNUNET_JSON_spec_fixed_auto ("s", + &blinded_sig->details.blinded_cs_answer. + s_scalar), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (blinded_sig); + return GNUNET_SYSERR; + } + denom_sig->blinded_sig = blinded_sig; return GNUNET_OK; } - default: - GNUNET_break_op (0); - return GNUNET_SYSERR; } + GNUNET_break_op (0); + GNUNET_free (blinded_sig); + return GNUNET_SYSERR; } @@ -712,6 +1014,253 @@ TALER_JSON_spec_blinded_denom_sig ( .ptr = sig }; + sig->blinded_sig = NULL; + return ret; +} + + +/** + * Parse given JSON object to blinded planchet. + * + * @param cls closure, NULL + * @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_blinded_planchet (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr; + struct GNUNET_CRYPTO_BlindedMessage *blinded_message; + const char *cipher; + struct GNUNET_JSON_Specification dspec[] = { + GNUNET_JSON_spec_string ("cipher", + &cipher), + GNUNET_JSON_spec_end () + }; + const char *emsg; + unsigned int eline; + + (void) cls; + if (GNUNET_OK != + GNUNET_JSON_parse (root, + dspec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); + blinded_message->rc = 1; + blinded_message->cipher = string_to_cipher (cipher); + switch (blinded_message->cipher) + { + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_varsize ( + "rsa_blinded_planchet", + &blinded_message->details.rsa_blinded_message.blinded_msg, + &blinded_message->details.rsa_blinded_message.blinded_msg_size), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (blinded_message); + return GNUNET_SYSERR; + } + blinded_planchet->blinded_message = blinded_message; + return GNUNET_OK; + } + case GNUNET_CRYPTO_BSA_CS: + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_fixed_auto ( + "cs_nonce", + &blinded_message->details.cs_blinded_message.nonce), + GNUNET_JSON_spec_fixed_auto ( + "cs_blinded_c0", + &blinded_message->details.cs_blinded_message.c[0]), + GNUNET_JSON_spec_fixed_auto ( + "cs_blinded_c1", + &blinded_message->details.cs_blinded_message.c[1]), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (blinded_message); + return GNUNET_SYSERR; + } + blinded_planchet->blinded_message = blinded_message; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + GNUNET_free (blinded_message); + return GNUNET_SYSERR; +} + + +/** + * Cleanup data left from parsing blinded planchet. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_blinded_planchet (void *cls, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr; + + (void) cls; + TALER_blinded_planchet_free (blinded_planchet); +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_blinded_planchet (const char *field, + struct TALER_BlindedPlanchet *blinded_planchet) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_blinded_planchet, + .cleaner = &clean_blinded_planchet, + .field = field, + .ptr = blinded_planchet + }; + + blinded_planchet->blinded_message = NULL; + return ret; +} + + +/** + * Parse given JSON object to exchange withdraw values (/csr). + * + * @param cls closure, NULL + * @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_exchange_withdraw_values (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_ExchangeWithdrawValues *ewv = spec->ptr; + struct GNUNET_CRYPTO_BlindingInputValues *bi; + const char *cipher; + struct GNUNET_JSON_Specification dspec[] = { + GNUNET_JSON_spec_string ("cipher", + &cipher), + GNUNET_JSON_spec_end () + }; + const char *emsg; + unsigned int eline; + enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci; + + (void) cls; + if (GNUNET_OK != + GNUNET_JSON_parse (root, + dspec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + ci = string_to_cipher (cipher); + switch (ci) + { + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs; + return GNUNET_OK; + case GNUNET_CRYPTO_BSA_CS: + bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues); + bi->cipher = GNUNET_CRYPTO_BSA_CS; + bi->rc = 1; + { + struct GNUNET_JSON_Specification ispec[] = { + GNUNET_JSON_spec_fixed ( + "r_pub_0", + &bi->details.cs_values.r_pub[0], + sizeof (struct GNUNET_CRYPTO_CsRPublic)), + GNUNET_JSON_spec_fixed ( + "r_pub_1", + &bi->details.cs_values.r_pub[1], + sizeof (struct GNUNET_CRYPTO_CsRPublic)), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (root, + ispec, + &emsg, + &eline)) + { + GNUNET_break_op (0); + GNUNET_free (bi); + return GNUNET_SYSERR; + } + ewv->blinding_inputs = bi; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + return GNUNET_SYSERR; +} + + +/** + * Cleanup data left from parsing withdraw values + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_exchange_withdraw_values ( + void *cls, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_ExchangeWithdrawValues *ewv = spec->ptr; + + (void) cls; + TALER_denom_ewv_free (ewv); +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_exchange_withdraw_values ( + const char *field, + struct TALER_ExchangeWithdrawValues *ewv) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_exchange_withdraw_values, + .cleaner = &clean_exchange_withdraw_values, + .field = field, + .ptr = ewv + }; + + ewv->blinding_inputs = NULL; return ret; } @@ -788,11 +1337,6 @@ parse_i18n_string (void *cls, const char *str; str = json_string_value (val); - if (NULL == str) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } *(const char **) spec->ptr = str; } return GNUNET_OK; @@ -812,8 +1356,11 @@ i18n_cleaner (void *cls, struct I18nContext *ctx = cls; (void) spec; - GNUNET_free (ctx->lp); - GNUNET_free (ctx); + if (NULL != ctx) + { + GNUNET_free (ctx->lp); + GNUNET_free (ctx); + } } @@ -833,8 +1380,9 @@ TALER_JSON_spec_i18n_string (const char *name, .size_ptr = NULL }; - ctx->lp = (NULL != language_pattern) ? GNUNET_strdup (language_pattern) : - NULL; + ctx->lp = (NULL != language_pattern) + ? GNUNET_strdup (language_pattern) + : NULL; ctx->field = name; *strptr = NULL; return ret; @@ -872,4 +1420,400 @@ TALER_JSON_spec_i18n_str (const char *name, } +/** + * Parse given JSON object with Taler error code. + * + * @param cls closure, NULL + * @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_ec (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + enum TALER_ErrorCode *ec = spec->ptr; + json_int_t num; + + (void) cls; + if (! json_is_integer (root)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + num = json_integer_value (root); + if (num < 0) + { + GNUNET_break_op (0); + *ec = TALER_EC_INVALID; + return GNUNET_SYSERR; + } + *ec = (enum TALER_ErrorCode) num; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_ec (const char *field, + enum TALER_ErrorCode *ec) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_ec, + .field = field, + .ptr = ec + }; + + *ec = TALER_EC_NONE; + return ret; +} + + +/** + * Parse given JSON object with AML decision. + * + * @param cls closure, NULL + * @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_aml_decision (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + enum TALER_AmlDecisionState *aml = spec->ptr; + json_int_t num; + + (void) cls; + if (! json_is_integer (root)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + num = json_integer_value (root); + if ( (num > TALER_AML_MAX) || + (num < 0) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + *aml = (enum TALER_AmlDecisionState) num; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_aml_decision (const char *field, + enum TALER_AmlDecisionState *aml_state) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_aml_decision, + .field = field, + .ptr = aml_state + }; + + return ret; +} + + +/** + * Parse given JSON object to web URL. + * + * @param cls closure, NULL + * @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_web_url (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + const char *str; + + (void) cls; + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! TALER_is_web_url (str)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + *(const char **) spec->ptr = str; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_web_url (const char *field, + const char **url) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_web_url, + .field = field, + .ptr = url + }; + + *url = NULL; + return ret; +} + + +/** + * Parse given JSON object to payto:// URI. + * + * @param cls closure, NULL + * @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_payto_uri (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + const char *str; + char *err; + + (void) cls; + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + err = TALER_payto_validate (str); + if (NULL != err) + { + GNUNET_break_op (0); + GNUNET_free (err); + return GNUNET_SYSERR; + } + *(const char **) spec->ptr = str; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_payto_uri (const char *field, + const char **payto_uri) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_payto_uri, + .field = field, + .ptr = payto_uri + }; + + *payto_uri = NULL; + return ret; +} + + +/** + * Parse given JSON object with protocol version. + * + * @param cls closure, NULL + * @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_protocol_version (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + struct TALER_JSON_ProtocolVersion *pv = spec->ptr; + const char *ver; + char dummy; + + (void) cls; + if (! json_is_string (root)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + ver = json_string_value (root); + if (3 != sscanf (ver, + "%u:%u:%u%c", + &pv->current, + &pv->revision, + &pv->age, + &dummy)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_version (const char *field, + struct TALER_JSON_ProtocolVersion *ver) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_protocol_version, + .field = field, + .ptr = ver + }; + + return ret; +} + + +/** + * Parse given JSON object to an OTP key. + * + * @param cls closure, NULL + * @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_otp_key (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + const char *pos_key; + + (void) cls; + pos_key = json_string_value (root); + if (NULL == pos_key) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + size_t pos_key_length = strlen (pos_key); + void *key; /* pos_key in binary */ + size_t key_len; /* length of the key */ + int dret; + + key_len = pos_key_length * 5 / 8; + key = GNUNET_malloc (key_len); + dret = TALER_rfc3548_base32decode (pos_key, + pos_key_length, + key, + key_len); + if (-1 == dret) + { + GNUNET_free (key); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_free (key); + } + *(const char **) spec->ptr = pos_key; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_otp_key (const char *name, + const char **otp_key) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_otp_key, + .field = name, + .ptr = otp_key + }; + + *otp_key = NULL; + return ret; +} + + +/** + * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm` + * + * @param cls closure, NULL + * @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_otp_type (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + static const struct Entry + { + const char *name; + enum TALER_MerchantConfirmationAlgorithm val; + } lt [] = { + { .name = "NONE", + .val = TALER_MCA_NONE }, + { .name = "TOTP_WITHOUT_PRICE", + .val = TALER_MCA_WITHOUT_PRICE }, + { .name = "TOTP_WITH_PRICE", + .val = TALER_MCA_WITH_PRICE }, + { .name = NULL, + .val = TALER_MCA_NONE }, + }; + enum TALER_MerchantConfirmationAlgorithm *res + = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr; + + (void) cls; + if (json_is_string (root)) + { + const char *str; + + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + for (unsigned int i = 0; NULL != lt[i].name; i++) + { + if (0 == strcasecmp (str, + lt[i].name)) + { + *res = lt[i].val; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + } + if (json_is_integer (root)) + { + json_int_t val; + + val = json_integer_value (root); + for (unsigned int i = 0; NULL != lt[i].name; i++) + { + if (val == lt[i].val) + { + *res = lt[i].val; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_break_op (0); + return GNUNET_SYSERR; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_otp_type (const char *name, + enum TALER_MerchantConfirmationAlgorithm *mca) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_otp_type, + .field = name, + .ptr = mca + }; + + *mca = TALER_MCA_NONE; + return ret; +} + + /* end of json/json_helper.c */ |