diff options
| author | Florian Dold <florian@dold.me> | 2022-01-27 20:25:40 +0100 | 
|---|---|---|
| committer | Florian Dold <florian@dold.me> | 2022-01-27 20:25:40 +0100 | 
| commit | e6e0cabf084ca4a333718b953bc0b48ac12e7356 (patch) | |
| tree | c39e33b10046ecae33bec6e47537eb43f452e464 /src | |
| parent | 32f1276b8c9cdc65f6873b8dc8d86240f25c8907 (diff) | |
test and hopefully fix JSON canonicalization
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/taler_json_lib.h | 6 | ||||
| -rw-r--r-- | src/json/json.c | 27 | ||||
| -rw-r--r-- | src/json/test_json.c | 59 | 
3 files changed, 89 insertions, 3 deletions
| diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index 2a101d26..51ebe6d9 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -563,6 +563,12 @@ enum GNUNET_GenericReturnValue  TALER_JSON_parse_agemask (const json_t *root,                            struct TALER_AgeMask *mask); +/** + * Canonicalize a JSON input to a string according to RFC 8785. + */ +char * +TALER_JSON_canonicalize (const json_t *input); +  #endif /* TALER_JSON_LIB_H_ */  /* End of taler_json_lib.h */ diff --git a/src/json/json.c b/src/json/json.c index bf3b2a0e..da447252 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -144,6 +144,9 @@ rfc8785encode (char **inp)      if ( (1 == mbl) &&           (val <= 0x1F) )      { +      /* Should not happen, as input is produced by +       * JSON stringification */ +      GNUNET_break (0);        lowdump (&buf,                 val);      } @@ -193,6 +196,12 @@ rfc8785encode (char **inp)            }          }          break; +      default: +        mbl = 2; +        GNUNET_buffer_write (&buf, +                             pos, +                             mbl); +        break;        }      }      else @@ -1009,6 +1018,24 @@ TALER_deposit_extension_hash (const json_t *extensions,  } +char * +TALER_JSON_canonicalize (const json_t *input) +{ +  char *wire_enc; + +  if (NULL == (wire_enc = json_dumps (input, +                                      JSON_ENCODE_ANY +                                      | JSON_COMPACT +                                      | JSON_SORT_KEYS))) +  { +    GNUNET_break (0); +    return NULL; +  } +  rfc8785encode (&wire_enc); +  return wire_enc; +} + +  enum GNUNET_GenericReturnValue  TALER_JSON_extensions_config_hash (const json_t *config,                                     struct TALER_ExtensionConfigHash *ech) diff --git a/src/json/test_json.c b/src/json/test_json.c index a8c1c6d8..5fe51d46 100644 --- a/src/json/test_json.c +++ b/src/json/test_json.c @@ -160,7 +160,7 @@ test_contract (void)    GNUNET_assert (GNUNET_OK ==                   TALER_JSON_contract_part_forget (c1,                                                    "k2")); -  json_dumpf (c1, stderr, JSON_INDENT (2)); +  // json_dumpf (c1, stderr, JSON_INDENT (2));    GNUNET_assert (GNUNET_OK ==                   TALER_JSON_contract_hash (c1,                                             &h2)); @@ -182,7 +182,7 @@ test_contract (void)    GNUNET_assert (GNUNET_OK ==                   TALER_JSON_contract_hash (c1,                                             &h1)); -  json_dumpf (c1, stderr, JSON_INDENT (2)); +  // json_dumpf (c1, stderr, JSON_INDENT (2));    json_decref (c1);    {      char *s; @@ -331,6 +331,57 @@ test_contract (void)  static int +test_json_canon (void) +{ +  { +    json_t *c1; +    char *canon; +    c1 = json_pack ("{s:s}", +                    "k1", "Hello\nWorld"); + +    canon = TALER_JSON_canonicalize (c1); +    GNUNET_assert (NULL != canon); + +    printf ("canon: '%s'\n", canon); + +    GNUNET_assert (0 == strcmp (canon, +                                "{\"k1\":\"Hello\\nWorld\"}")); +  } +  { +    json_t *c1; +    char *canon; +    c1 = json_pack ("{s:s}", +                    "k1", "Testing “unicode” characters"); + +    canon = TALER_JSON_canonicalize (c1); +    GNUNET_assert (NULL != canon); + +    printf ("canon: '%s'\n", canon); + +    GNUNET_assert (0 == strcmp (canon, +                                "{\"k1\":\"Testing “unicode” characters\"}")); +  } +  { +    json_t *c1; +    char *canon; +    c1 = json_pack ("{s:s}", +                    "k1", "low range \x05 chars"); + +    canon = TALER_JSON_canonicalize (c1); +    GNUNET_assert (NULL != canon); + +    printf ("canon: '%s'\n", canon); + +    GNUNET_assert (0 == strcmp (canon, +                                "{\"k1\":\"low range \\u0005 chars\"}")); +  } + + +  return 0; +} + + +static int  test_rfc8785 (void)  {    struct TALER_PrivateContractHash h1; @@ -348,7 +399,7 @@ test_rfc8785 (void)                                               sizeof (h1));      if (0 !=          strcmp (s, -                "J678K3PW9Y3DG63Z3T7ZYR2P7CEXMVZ2SFPQMABACK9TJRYREPP82542PCJ0P7Y7FAQAMWECDX50XH1RBTWHX6SSJHH6FXRV0JCS6R8")) +                "531S33T8ZRGW6548G7T67PMDNGS4Z1D8A2GMB87G3PNKYTW6KGF7Q99XVCGXBKVA2HX6PR5ENJ1PQ5ZTYMMXQB6RM7S82VP7ZG2X5G8"))      {        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                    "Invalid reference hash: %s\n", @@ -377,6 +428,8 @@ main (int argc,      return 1;    if (0 != test_contract ())      return 2; +  if (0 != test_json_canon ()) +    return 2;    if (0 != test_rfc8785 ())      return 2;    return 0; | 
