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 11aeceef..9752bb9f 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 090a8b96..bb52eeb0 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;  } | 
