exchange

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

json.c (22900B)


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