exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

json.c (23029B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014, 2015, 2016, 2020, 2021 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file json/json.c
     18  * @brief helper functions for JSON processing using libjansson
     19  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include "taler/taler_util.h"
     25 #include "taler/taler_json_lib.h"
     26 #include <unistr.h>
     27 
     28 
     29 /**
     30  * Check if @a json contains a 'real' value anywhere.
     31  *
     32  * @param json json to check
     33  * @return true if a real is in it somewhere
     34  */
     35 static bool
     36 contains_real (const json_t *json)
     37 {
     38   if (json_is_real (json))
     39     return true;
     40   if (json_is_object (json))
     41   {
     42     json_t *member;
     43     const char *name;
     44 
     45     json_object_foreach ((json_t *) json, name, member)
     46     if (contains_real (member))
     47       return true;
     48     return false;
     49   }
     50   if (json_is_array (json))
     51   {
     52     json_t *member;
     53     size_t index;
     54 
     55     json_array_foreach ((json_t *) json, index, member)
     56     if (contains_real (member))
     57       return true;
     58     return false;
     59   }
     60   return false;
     61 }
     62 
     63 
     64 /**
     65  * Dump the @a json to a string and hash it.
     66  *
     67  * @param json value to hash
     68  * @param salt salt value to include when using HKDF,
     69  *        NULL to not use any salt and to use SHA512
     70  * @param[out] hc where to store the hash
     71  * @return #GNUNET_OK on success,
     72  *         #GNUNET_NO if @a json was not hash-able
     73  *         #GNUNET_SYSERR on failure
     74  */
     75 static enum GNUNET_GenericReturnValue
     76 dump_and_hash (const json_t *json,
     77                const char *salt,
     78                struct GNUNET_HashCode *hc)
     79 {
     80   char *wire_enc;
     81   size_t len;
     82 
     83   if (NULL == json)
     84   {
     85     GNUNET_break_op (0);
     86     return GNUNET_NO;
     87   }
     88   if (contains_real (json))
     89   {
     90     GNUNET_break_op (0);
     91     return GNUNET_NO;
     92   }
     93   if (NULL == (wire_enc = json_dumps (json,
     94                                       JSON_ENCODE_ANY
     95                                       | JSON_COMPACT
     96                                       | JSON_SORT_KEYS)))
     97   {
     98     GNUNET_break (0);
     99     return GNUNET_SYSERR;
    100   }
    101   len = TALER_rfc8785encode (&wire_enc);
    102   if (NULL == salt)
    103   {
    104     GNUNET_CRYPTO_hash (wire_enc,
    105                         len,
    106                         hc);
    107   }
    108   else
    109   {
    110     if (GNUNET_YES !=
    111         GNUNET_CRYPTO_kdf (hc,
    112                            sizeof (*hc),
    113                            salt,
    114                            strlen (salt) + 1,
    115                            wire_enc,
    116                            len,
    117                            NULL,
    118                            0))
    119     {
    120       GNUNET_break (0);
    121       free (wire_enc);
    122       return GNUNET_SYSERR;
    123     }
    124   }
    125   free (wire_enc);
    126   return GNUNET_OK;
    127 }
    128 
    129 
    130 /**
    131  * Replace "forgettable" parts of a JSON object with their salted hash.
    132  *
    133  * @param[in] in some JSON value
    134  * @param[out] out resulting JSON value
    135  * @return #GNUNET_OK on success,
    136  *         #GNUNET_NO if @a json was not hash-able
    137  *         #GNUNET_SYSERR on failure
    138  */
    139 static enum GNUNET_GenericReturnValue
    140 forget (const json_t *in,
    141         json_t **out)
    142 {
    143   if (json_is_real (in))
    144   {
    145     /* floating point is not allowed! */
    146     GNUNET_break_op (0);
    147     return GNUNET_NO;
    148   }
    149   if (json_is_array (in))
    150   {
    151     /* array is a JSON array */
    152     size_t index;
    153     json_t *value;
    154     json_t *ret;
    155 
    156     ret = json_array ();
    157     if (NULL == ret)
    158     {
    159       GNUNET_break (0);
    160       return GNUNET_SYSERR;
    161     }
    162     json_array_foreach (in, index, value) {
    163       enum GNUNET_GenericReturnValue iret;
    164       json_t *t;
    165 
    166       iret = forget (value,
    167                      &t);
    168       if (GNUNET_OK != iret)
    169       {
    170         json_decref (ret);
    171         return iret;
    172       }
    173       if (0 != json_array_append_new (ret,
    174                                       t))
    175       {
    176         GNUNET_break (0);
    177         json_decref (ret);
    178         return GNUNET_SYSERR;
    179       }
    180     }
    181     *out = ret;
    182     return GNUNET_OK;
    183   }
    184   if (json_is_object (in))
    185   {
    186     json_t *ret;
    187     const char *key;
    188     json_t *value;
    189     json_t *fg;
    190     json_t *rx;
    191 
    192     fg = json_object_get (in,
    193                           "$forgettable");
    194     rx = json_object_get (in,
    195                           "$forgotten");
    196     if (NULL != rx)
    197     {
    198       rx = json_deep_copy (rx); /* should be shallow
    199                                    by structure, but
    200                                    deep copy is safer */
    201       if (NULL == rx)
    202       {
    203         GNUNET_break (0);
    204         return GNUNET_SYSERR;
    205       }
    206     }
    207     ret = json_object ();
    208     if (NULL == ret)
    209     {
    210       GNUNET_break (0);
    211       return GNUNET_SYSERR;
    212     }
    213     json_object_foreach ((json_t*) in, key, value) {
    214       json_t *t;
    215       json_t *salt;
    216       enum GNUNET_GenericReturnValue iret;
    217 
    218       if (fg == value)
    219         continue; /* skip! */
    220       if (rx == value)
    221         continue; /* skip! */
    222       if ( (NULL != rx) &&
    223            (NULL !=
    224             json_object_get (rx,
    225                              key)) )
    226       {
    227         (void) json_object_del (ret,
    228                                 key);
    229         continue; /* already forgotten earlier */
    230       }
    231       iret = forget (value,
    232                      &t);
    233       if (GNUNET_OK != iret)
    234       {
    235         json_decref (ret);
    236         json_decref (rx);
    237         return iret;
    238       }
    239       if ( (NULL != fg) &&
    240            (NULL != (salt = json_object_get (fg,
    241                                              key))) )
    242       {
    243         /* 't' is to be forgotten! */
    244         struct GNUNET_HashCode hc;
    245 
    246         if (! json_is_string (salt))
    247         {
    248           GNUNET_break_op (0);
    249           json_decref (ret);
    250           json_decref (rx);
    251           json_decref (t);
    252           return GNUNET_NO;
    253         }
    254         iret = dump_and_hash (t,
    255                               json_string_value (salt),
    256                               &hc);
    257         if (GNUNET_OK != iret)
    258         {
    259           json_decref (ret);
    260           json_decref (rx);
    261           json_decref (t);
    262           return iret;
    263         }
    264         json_decref (t);
    265         /* scrub salt */
    266         if (0 !=
    267             json_object_del (fg,
    268                              key))
    269         {
    270           GNUNET_break_op (0);
    271           json_decref (ret);
    272           json_decref (rx);
    273           return GNUNET_NO;
    274         }
    275         if (NULL == rx)
    276           rx = json_object ();
    277         if (NULL == rx)
    278         {
    279           GNUNET_break (0);
    280           json_decref (ret);
    281           return GNUNET_SYSERR;
    282         }
    283         if (0 !=
    284             json_object_set_new (rx,
    285                                  key,
    286                                  GNUNET_JSON_from_data_auto (&hc)))
    287         {
    288           GNUNET_break (0);
    289           json_decref (ret);
    290           json_decref (rx);
    291           return GNUNET_SYSERR;
    292         }
    293       }
    294       else
    295       {
    296         /* 't' to be used without 'forgetting' */
    297         if (0 !=
    298             json_object_set_new (ret,
    299                                  key,
    300                                  t))
    301         {
    302           GNUNET_break (0);
    303           json_decref (ret);
    304           json_decref (rx);
    305           return GNUNET_SYSERR;
    306         }
    307       }
    308     } /* json_object_foreach */
    309     if ( (NULL != rx) &&
    310          (0 !=
    311           json_object_set_new (ret,
    312                                "$forgotten",
    313                                rx)) )
    314     {
    315       GNUNET_break (0);
    316       json_decref (ret);
    317       return GNUNET_SYSERR;
    318     }
    319     *out = ret;
    320     return GNUNET_OK;
    321   }
    322   *out = json_incref ((json_t *) in);
    323   return GNUNET_OK;
    324 }
    325 
    326 
    327 enum GNUNET_GenericReturnValue
    328 TALER_JSON_contract_hash (const json_t *json,
    329                           struct TALER_PrivateContractHashP *hc)
    330 {
    331   enum GNUNET_GenericReturnValue ret;
    332   json_t *cjson;
    333   json_t *dc;
    334 
    335   dc = json_deep_copy (json);
    336   ret = forget (dc,
    337                 &cjson);
    338   json_decref (dc);
    339   if (GNUNET_OK != ret)
    340     return ret;
    341   ret = dump_and_hash (cjson,
    342                        NULL,
    343                        &hc->hash);
    344   json_decref (cjson);
    345   return ret;
    346 }
    347 
    348 
    349 enum GNUNET_GenericReturnValue
    350 TALER_JSON_contract_mark_forgettable (json_t *json,
    351                                       const char *field)
    352 {
    353   json_t *fg;
    354   struct GNUNET_ShortHashCode salt;
    355 
    356   if (! json_is_object (json))
    357   {
    358     GNUNET_break (0);
    359     return GNUNET_SYSERR;
    360   }
    361   /* check field name is legal for forgettable field */
    362   for (const char *f = field; '\0' != *f; f++)
    363   {
    364     char c = *f;
    365 
    366     if ( (c >= 'a') && (c <= 'z') )
    367       continue;
    368     if ( (c >= 'A') && (c <= 'Z') )
    369       continue;
    370     if ( (c >= '0') && (c <= '9') )
    371       continue;
    372     if ('_' == c)
    373       continue;
    374     GNUNET_break (0);
    375     return GNUNET_SYSERR;
    376   }
    377   if (NULL == json_object_get (json,
    378                                field))
    379   {
    380     /* field must exist */
    381     GNUNET_break (0);
    382     return GNUNET_SYSERR;
    383   }
    384   fg = json_object_get (json,
    385                         "$forgettable");
    386   if (NULL == fg)
    387   {
    388     fg = json_object ();
    389     if (0 !=
    390         json_object_set_new (json,
    391                              "$forgettable",
    392                              fg))
    393     {
    394       GNUNET_break (0);
    395       return GNUNET_SYSERR;
    396     }
    397   }
    398 
    399   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
    400                               &salt,
    401                               sizeof (salt));
    402   if (0 !=
    403       json_object_set_new (fg,
    404                            field,
    405                            GNUNET_JSON_from_data_auto (&salt)))
    406   {
    407     GNUNET_break (0);
    408     return GNUNET_SYSERR;
    409   }
    410   return GNUNET_OK;
    411 }
    412 
    413 
    414 enum GNUNET_GenericReturnValue
    415 TALER_JSON_contract_part_forget (json_t *json,
    416                                  const char *field)
    417 {
    418   json_t *fg;
    419   const json_t *part;
    420   json_t *fp;
    421   json_t *rx;
    422   struct GNUNET_HashCode hc;
    423   const char *salt;
    424   enum GNUNET_GenericReturnValue ret;
    425 
    426   if (! json_is_object (json))
    427   {
    428     GNUNET_break (0);
    429     return GNUNET_SYSERR;
    430   }
    431   if (NULL == (part = json_object_get (json,
    432                                        field)))
    433   {
    434     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    435                 "Did not find field `%s' we were asked to forget\n",
    436                 field);
    437     return GNUNET_SYSERR;
    438   }
    439   fg = json_object_get (json,
    440                         "$forgettable");
    441   if (NULL == fg)
    442   {
    443     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    444                 "Did not find '$forgettable' attribute trying to forget field `%s'\n",
    445                 field);
    446     return GNUNET_SYSERR;
    447   }
    448   rx = json_object_get (json,
    449                         "$forgotten");
    450   if (NULL == rx)
    451   {
    452     rx = json_object ();
    453     if (0 !=
    454         json_object_set_new (json,
    455                              "$forgotten",
    456                              rx))
    457     {
    458       GNUNET_break (0);
    459       return GNUNET_SYSERR;
    460     }
    461   }
    462   if (NULL !=
    463       json_object_get (rx,
    464                        field))
    465   {
    466     if (! json_is_null (json_object_get (json,
    467                                          field)))
    468     {
    469       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    470                   "Field `%s' market as forgotten, but still exists!\n",
    471                   field);
    472       return GNUNET_SYSERR;
    473     }
    474     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    475                 "Already forgot field `%s'\n",
    476                 field);
    477     return GNUNET_NO;
    478   }
    479   salt = json_string_value (json_object_get (fg,
    480                                              field));
    481   if (NULL == salt)
    482   {
    483     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    484                 "Did not find required salt to forget field `%s'\n",
    485                 field);
    486     return GNUNET_SYSERR;
    487   }
    488 
    489   /* need to recursively forget to compute 'hc' */
    490   ret = forget (part,
    491                 &fp);
    492   if (GNUNET_OK != ret)
    493     return ret;
    494   if (GNUNET_OK !=
    495       dump_and_hash (fp,
    496                      salt,
    497                      &hc))
    498   {
    499     json_decref (fp);
    500     GNUNET_break (0);
    501     return GNUNET_SYSERR;
    502   }
    503   json_decref (fp);
    504   /* drop salt */
    505   if (0 !=
    506       json_object_del (fg,
    507                        field))
    508   {
    509     json_decref (fp);
    510     GNUNET_break (0);
    511     return GNUNET_SYSERR;
    512   }
    513 
    514   /* remember field as 'forgotten' */
    515   if (0 !=
    516       json_object_set_new (rx,
    517                            field,
    518                            GNUNET_JSON_from_data_auto (&hc)))
    519   {
    520     GNUNET_break (0);
    521     return GNUNET_SYSERR;
    522   }
    523   /* finally, set 'forgotten' field to null */
    524   if (0 !=
    525       json_object_del (json,
    526                        field))
    527   {
    528     GNUNET_break (0);
    529     return GNUNET_SYSERR;
    530   }
    531   return GNUNET_OK;
    532 }
    533 
    534 
    535 /**
    536  * Loop over all of the values of a '$forgettable' object.  Replace 'True'
    537  * values with proper random salts.  Fails if any forgettable values are
    538  * neither 'True' nor valid salts (strings).
    539  *
    540  * @param[in,out] f JSON to transform
    541  * @return #GNUNET_OK on success
    542  */
    543 static enum GNUNET_GenericReturnValue
    544 seed_forgettable (json_t *f)
    545 {
    546   const char *key;
    547   json_t *val;
    548 
    549   json_object_foreach (f,
    550                        key,
    551                        val)
    552   {
    553     if (json_is_string (val))
    554       continue;
    555     if (json_is_true (val))
    556     {
    557       struct GNUNET_ShortHashCode sh;
    558 
    559       GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
    560                                   &sh,
    561                                   sizeof (sh));
    562       if (0 !=
    563           json_object_set_new (f,
    564                                key,
    565                                GNUNET_JSON_from_data_auto (&sh)))
    566       {
    567         GNUNET_break (0);
    568         return GNUNET_SYSERR;
    569       }
    570       continue;
    571     }
    572     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    573                 "Forgettable field `%s' has invalid value\n",
    574                 key);
    575     return GNUNET_SYSERR;
    576   }
    577   return GNUNET_OK;
    578 }
    579 
    580 
    581 enum GNUNET_GenericReturnValue
    582 TALER_JSON_contract_seed_forgettable (const json_t *spec,
    583                                       json_t *contract)
    584 {
    585   if (json_is_object (spec))
    586   {
    587     const char *key;
    588     json_t *val;
    589 
    590     json_object_foreach ((json_t *) spec,
    591                          key,
    592                          val)
    593     {
    594       json_t *cval = json_object_get (contract,
    595                                       key);
    596 
    597       if (0 == strcmp ("$forgettable",
    598                        key))
    599       {
    600         json_t *xval = json_deep_copy (val);
    601 
    602         if (GNUNET_OK !=
    603             seed_forgettable (xval))
    604         {
    605           json_decref (xval);
    606           return GNUNET_SYSERR;
    607         }
    608         GNUNET_assert (0 ==
    609                        json_object_set_new (contract,
    610                                             "$forgettable",
    611                                             xval));
    612         continue;
    613       }
    614       if (NULL == cval)
    615         continue;
    616       if (GNUNET_OK !=
    617           TALER_JSON_contract_seed_forgettable (val,
    618                                                 cval))
    619         return GNUNET_SYSERR;
    620     }
    621   }
    622   if (json_is_array (spec))
    623   {
    624     size_t index;
    625     json_t *val;
    626 
    627     json_array_foreach ((json_t *) spec,
    628                         index,
    629                         val)
    630     {
    631       json_t *ival = json_array_get (contract,
    632                                      index);
    633 
    634       if (NULL == ival)
    635         continue;
    636       if (GNUNET_OK !=
    637           TALER_JSON_contract_seed_forgettable (val,
    638                                                 ival))
    639         return GNUNET_SYSERR;
    640     }
    641   }
    642   return GNUNET_OK;
    643 }
    644 
    645 
    646 /**
    647  * Parse a json path.
    648  *
    649  * @param obj the object that the path is relative to.
    650  * @param prev the parent of @e obj.
    651  * @param path the path to parse.
    652  * @param cb the callback to call, if we get to the end of @e path.
    653  * @param cb_cls the closure for the callback.
    654  * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
    655  */
    656 static enum GNUNET_GenericReturnValue
    657 parse_path (json_t *obj,
    658             json_t *prev,
    659             const char *path,
    660             TALER_JSON_ExpandPathCallback cb,
    661             void *cb_cls)
    662 {
    663   char *id = GNUNET_strdup (path);
    664   char *next_id = strchr (id,
    665                           '.');
    666   char *next_path;
    667   char *bracket;
    668   json_t *next_obj = NULL;
    669   char *next_dot;
    670 
    671   GNUNET_assert (NULL != id); /* make stupid compiler happy */
    672   if (NULL == next_id)
    673   {
    674     cb (cb_cls,
    675         id,
    676         prev);
    677     GNUNET_free (id);
    678     return GNUNET_OK;
    679   }
    680   bracket = strchr (next_id,
    681                     '[');
    682   *next_id = '\0';
    683   next_id++;
    684   next_path = GNUNET_strdup (next_id);
    685   next_dot = strchr (next_id,
    686                      '.');
    687   if (NULL != next_dot)
    688     *next_dot = '\0';
    689   /* If this is the first time this is called, make sure id is "$" */
    690   if ( (NULL == prev) &&
    691        (0 != strcmp (id,
    692                      "$")))
    693   {
    694     GNUNET_free (id);
    695     GNUNET_free (next_path);
    696     return GNUNET_SYSERR;
    697   }
    698 
    699   /* Check for bracketed indices */
    700   if (NULL != bracket)
    701   {
    702     char *end_bracket = strchr (bracket,
    703                                 ']');
    704     json_t *array;
    705 
    706     if (NULL == end_bracket)
    707     {
    708       GNUNET_free (id);
    709       GNUNET_free (next_path);
    710       return GNUNET_SYSERR;
    711     }
    712     *end_bracket = '\0';
    713     *bracket = '\0';
    714     bracket++;
    715     array = json_object_get (obj,
    716                              next_id);
    717     if (0 == strcmp (bracket,
    718                      "*"))
    719     {
    720       size_t index;
    721       json_t *value;
    722       int ret = GNUNET_OK;
    723 
    724       json_array_foreach (array, index, value) {
    725         ret = parse_path (value,
    726                           obj,
    727                           next_path,
    728                           cb,
    729                           cb_cls);
    730         if (GNUNET_OK != ret)
    731         {
    732           GNUNET_free (id);
    733           GNUNET_free (next_path);
    734           return ret;
    735         }
    736       }
    737     }
    738     else
    739     {
    740       unsigned int index;
    741       char dummy;
    742 
    743       if (1 != sscanf (bracket,
    744                        "%u%c",
    745                        &index,
    746                        &dummy))
    747       {
    748         GNUNET_free (id);
    749         GNUNET_free (next_path);
    750         return GNUNET_SYSERR;
    751       }
    752       next_obj = json_array_get (array,
    753                                  index);
    754     }
    755   }
    756   else
    757   {
    758     /* No brackets, so just fetch the object by name */
    759     next_obj = json_object_get (obj,
    760                                 next_id);
    761   }
    762 
    763   if (NULL != next_obj)
    764   {
    765     int ret = parse_path (next_obj,
    766                           obj,
    767                           next_path,
    768                           cb,
    769                           cb_cls);
    770     GNUNET_free (id);
    771     GNUNET_free (next_path);
    772     return ret;
    773   }
    774   GNUNET_free (id);
    775   GNUNET_free (next_path);
    776   return GNUNET_OK;
    777 }
    778 
    779 
    780 enum GNUNET_GenericReturnValue
    781 TALER_JSON_expand_path (json_t *json,
    782                         const char *path,
    783                         TALER_JSON_ExpandPathCallback cb,
    784                         void *cb_cls)
    785 {
    786   return parse_path (json,
    787                      NULL,
    788                      path,
    789                      cb,
    790                      cb_cls);
    791 }
    792 
    793 
    794 enum TALER_ErrorCode
    795 TALER_JSON_get_error_code (const json_t *json)
    796 {
    797   const json_t *jc;
    798 
    799   if (NULL == json)
    800     return TALER_EC_GENERIC_INVALID_RESPONSE;
    801   jc = json_object_get (json, "code");
    802   /* The caller already knows that the JSON represents an error,
    803      so we are dealing with a missing error code here.  */
    804   if (NULL == jc)
    805   {
    806     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    807                 "Expected Taler error code `code' in JSON, but field does not exist!\n");
    808     return TALER_EC_INVALID;
    809   }
    810   if (json_is_integer (jc))
    811     return (enum TALER_ErrorCode) (int) json_integer_value (jc);
    812   GNUNET_break_op (0);
    813   return TALER_EC_INVALID;
    814 }
    815 
    816 
    817 const char *
    818 TALER_JSON_get_error_hint (const json_t *json)
    819 {
    820   const json_t *jc;
    821 
    822   if (NULL == json)
    823     return NULL;
    824   jc = json_object_get (json,
    825                         "hint");
    826   if (NULL == jc)
    827     return NULL; /* no hint, is allowed */
    828   if (! json_is_string (jc))
    829   {
    830     /* Hints must be strings */
    831     GNUNET_break_op (0);
    832     return NULL;
    833   }
    834   return json_string_value (jc);
    835 }
    836 
    837 
    838 enum TALER_ErrorCode
    839 TALER_JSON_get_error_code2 (const void *data,
    840                             size_t data_size)
    841 {
    842   json_t *json;
    843   enum TALER_ErrorCode ec;
    844   json_error_t err;
    845 
    846   json = json_loadb (data,
    847                      data_size,
    848                      JSON_REJECT_DUPLICATES,
    849                      &err);
    850   if (NULL == json)
    851     return TALER_EC_INVALID;
    852   ec = TALER_JSON_get_error_code (json);
    853   json_decref (json);
    854   if (ec == TALER_EC_NONE)
    855     return TALER_EC_INVALID;
    856   return ec;
    857 }
    858 
    859 
    860 void
    861 TALER_deposit_policy_hash (const json_t *policy,
    862                            struct TALER_ExtensionPolicyHashP *ech)
    863 {
    864   GNUNET_assert (GNUNET_OK ==
    865                  dump_and_hash (policy,
    866                                 "taler-extensions-policy",
    867                                 &ech->hash));
    868 }
    869 
    870 
    871 char *
    872 TALER_JSON_canonicalize (const json_t *input)
    873 {
    874   char *wire_enc;
    875 
    876   if (NULL == (wire_enc = json_dumps (input,
    877                                       JSON_ENCODE_ANY
    878                                       | JSON_COMPACT
    879                                       | JSON_SORT_KEYS)))
    880   {
    881     GNUNET_break (0);
    882     return NULL;
    883   }
    884   TALER_rfc8785encode (&wire_enc);
    885   return wire_enc;
    886 }
    887 
    888 
    889 enum GNUNET_GenericReturnValue
    890 TALER_JSON_extensions_manifests_hash (const json_t *manifests,
    891                                       struct TALER_ExtensionManifestsHashP *ech)
    892 {
    893   return dump_and_hash (manifests,
    894                         "taler-extensions-manifests",
    895                         &ech->hash);
    896 }
    897 
    898 
    899 json_t *
    900 TALER_JSON_currency_specs_to_json (
    901   const struct TALER_CurrencySpecification *cspec)
    902 {
    903   json_t *ca;
    904 
    905   ca = json_array ();
    906   GNUNET_assert (NULL != ca);
    907   for (unsigned int i = 0; i<cspec->num_common_amounts; i++)
    908     GNUNET_assert (
    909       0 ==
    910       json_array_append_new (
    911         ca,
    912         TALER_JSON_from_amount (&cspec->common_amounts[i])));
    913   return GNUNET_JSON_PACK (
    914     GNUNET_JSON_pack_string ("name",
    915                              cspec->name),
    916     /* 'currency' is deprecated as of exchange v18 and merchant v6;
    917        remove this line once current-age > 6*/
    918     GNUNET_JSON_pack_string ("currency",
    919                              cspec->currency),
    920     GNUNET_JSON_pack_array_steal ("common_amounts",
    921                                   ca),
    922     GNUNET_JSON_pack_uint64 ("num_fractional_input_digits",
    923                              cspec->num_fractional_input_digits),
    924     GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits",
    925                              cspec->num_fractional_normal_digits),
    926     GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits",
    927                              cspec->num_fractional_trailing_zero_digits),
    928     GNUNET_JSON_pack_object_incref ("alt_unit_names",
    929                                     cspec->map_alt_unit_names));
    930 }
    931 
    932 
    933 /* End of json/json.c */