donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

donau_json.c (16220B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024 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/donau_json.c
     18  * @brief helper functions for JSON processing using libjansson
     19  * @author Lukas Matyja
     20  */
     21 #include "donau_config.h"
     22 #include <gnunet/gnunet_util_lib.h>
     23 #include <taler/taler_util.h>
     24 #include <taler/taler_json_lib.h>
     25 #include <unistr.h>
     26 #include "donau_json_lib.h"
     27 
     28 /**
     29  * Convert string value to numeric cipher value.
     30  *
     31  * @param cipher_s input string
     32  * @return numeric cipher value
     33  */
     34 static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
     35 string_to_cipher (const char *cipher_s)
     36 {
     37   if (0 == strcasecmp (cipher_s,
     38                        "RSA"))
     39     return GNUNET_CRYPTO_BSA_RSA;
     40   if (0 == strcasecmp (cipher_s,
     41                        "CS"))
     42     return GNUNET_CRYPTO_BSA_CS;
     43   return GNUNET_CRYPTO_BSA_INVALID;
     44 }
     45 
     46 
     47 /**
     48  * Parse given JSON object partially into a donation unit public key.
     49  *
     50  * Depending on the cipher in cls, it parses the corresponding public key type.
     51  *
     52  * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
     53  * @param root the json object representing data
     54  * @param[out] spec where to write the data
     55  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     56  */
     57 static enum GNUNET_GenericReturnValue
     58 parse_donation_unit_pub (void *cls,
     59                          json_t *root,
     60                          struct GNUNET_JSON_Specification *spec)
     61 {
     62   struct DONAU_DonationUnitPublicKey *donation_unit_pub = spec->ptr;
     63   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
     64   const char *cipher;
     65   struct GNUNET_JSON_Specification dspec[] = {
     66     GNUNET_JSON_spec_string ("cipher",
     67                              &cipher),
     68     GNUNET_JSON_spec_end ()
     69   };
     70   const char *emsg;
     71   unsigned int eline;
     72 
     73   (void) cls;
     74   if (GNUNET_OK !=
     75       GNUNET_JSON_parse (root,
     76                          dspec,
     77                          &emsg,
     78                          &eline))
     79   {
     80     GNUNET_break_op (0);
     81     return GNUNET_SYSERR;
     82   }
     83 
     84   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
     85   bsign_pub->rc = 1;
     86   bsign_pub->cipher = string_to_cipher (cipher);
     87   switch (bsign_pub->cipher)
     88   {
     89   case GNUNET_CRYPTO_BSA_INVALID:
     90     break;
     91   case GNUNET_CRYPTO_BSA_RSA:
     92     {
     93       struct GNUNET_JSON_Specification ispec[] = {
     94         GNUNET_JSON_spec_rsa_public_key (
     95           "rsa_public_key",
     96           &bsign_pub->details.rsa_public_key),
     97         GNUNET_JSON_spec_fixed_auto (
     98           "pub_key_hash",
     99           &bsign_pub->pub_key_hash),
    100         GNUNET_JSON_spec_end ()
    101       };
    102 
    103       if (GNUNET_OK !=
    104           GNUNET_JSON_parse (root,
    105                              ispec,
    106                              &emsg,
    107                              &eline))
    108       {
    109         GNUNET_break_op (0);
    110         GNUNET_free (bsign_pub);
    111         return GNUNET_SYSERR;
    112       }
    113       donation_unit_pub->bsign_pub_key = bsign_pub;
    114       return GNUNET_OK;
    115     }
    116   case GNUNET_CRYPTO_BSA_CS:
    117     {
    118       struct GNUNET_JSON_Specification ispec[] = {
    119         GNUNET_JSON_spec_fixed ("cs_public_key",
    120                                 &bsign_pub->details.cs_public_key,
    121                                 sizeof (bsign_pub->details.cs_public_key)),
    122         GNUNET_JSON_spec_fixed_auto (
    123           "pub_key_hash",
    124           &bsign_pub->pub_key_hash),
    125         GNUNET_JSON_spec_end ()
    126       };
    127 
    128       if (GNUNET_OK !=
    129           GNUNET_JSON_parse (root,
    130                              ispec,
    131                              &emsg,
    132                              &eline))
    133       {
    134         GNUNET_break_op (0);
    135         GNUNET_free (bsign_pub);
    136         return GNUNET_SYSERR;
    137       }
    138       donation_unit_pub->bsign_pub_key = bsign_pub;
    139       return GNUNET_OK;
    140     }
    141   }
    142   GNUNET_break_op (0);
    143   GNUNET_free (bsign_pub);
    144   return GNUNET_SYSERR;
    145 }
    146 
    147 
    148 /**
    149  * Cleanup data left from parsing donation unit public key.
    150  *
    151  * @param cls closure, NULL
    152  * @param[out] spec where to free the data
    153  */
    154 static void
    155 clean_donation_unit_pub (void *cls,
    156                          struct GNUNET_JSON_Specification *spec)
    157 {
    158   struct DONAU_DonationUnitPublicKey *donation_unit_pub = spec->ptr;
    159 
    160   (void) cls;
    161   DONAU_donation_unit_pub_free (donation_unit_pub);
    162 }
    163 
    164 
    165 struct GNUNET_JSON_Specification
    166 DONAU_JSON_spec_donation_unit_pub (const char *field,
    167                                    struct DONAU_DonationUnitPublicKey *pk)
    168 {
    169   struct GNUNET_JSON_Specification ret = {
    170     .parser = &parse_donation_unit_pub,
    171     .cleaner = &clean_donation_unit_pub,
    172     .field = field,
    173     .ptr = pk
    174   };
    175 
    176   return ret;
    177 }
    178 
    179 
    180 /**
    181  * Parse given JSON object to blinded unique donation identifier.
    182  *
    183  * @param cls closure, NULL
    184  * @param root the json object representing data
    185  * @param[out] spec where to write the data
    186  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    187  */
    188 static enum GNUNET_GenericReturnValue
    189 parse_blinded_donation_identifier (void *cls,
    190                                    json_t *root,
    191                                    struct GNUNET_JSON_Specification *spec)
    192 {
    193   struct DONAU_BlindedUniqueDonorIdentifier *blinded_udi = spec->ptr;
    194   struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
    195   const char *cipher;
    196   struct GNUNET_JSON_Specification dspec[] = {
    197     GNUNET_JSON_spec_string ("cipher",
    198                              &cipher),
    199     GNUNET_JSON_spec_end ()
    200   };
    201   const char *emsg;
    202   unsigned int eline;
    203 
    204   (void) cls;
    205   if (GNUNET_OK !=
    206       GNUNET_JSON_parse (root,
    207                          dspec,
    208                          &emsg,
    209                          &eline))
    210   {
    211     GNUNET_break_op (0);
    212     return GNUNET_SYSERR;
    213   }
    214   blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
    215   blinded_message->rc = 1;
    216   blinded_message->cipher = string_to_cipher (cipher);
    217   switch (blinded_message->cipher)
    218   {
    219   case GNUNET_CRYPTO_BSA_INVALID:
    220     break;
    221   case GNUNET_CRYPTO_BSA_RSA:
    222     {
    223       struct GNUNET_JSON_Specification ispec[] = {
    224         GNUNET_JSON_spec_varsize (
    225           "rsa_blinded_identifier",
    226           &blinded_message->details.rsa_blinded_message.blinded_msg,
    227           &blinded_message->details.rsa_blinded_message.blinded_msg_size),
    228         GNUNET_JSON_spec_end ()
    229       };
    230 
    231       if (GNUNET_OK !=
    232           GNUNET_JSON_parse (root,
    233                              ispec,
    234                              &emsg,
    235                              &eline))
    236       {
    237         GNUNET_break_op (0);
    238         GNUNET_free (blinded_message);
    239         return GNUNET_SYSERR;
    240       }
    241       blinded_udi->blinded_message = blinded_message;
    242       return GNUNET_OK;
    243     }
    244   case GNUNET_CRYPTO_BSA_CS:
    245     {
    246       struct GNUNET_JSON_Specification ispec[] = {
    247         GNUNET_JSON_spec_fixed_auto (
    248           "cs_nonce",
    249           &blinded_message->details.cs_blinded_message.nonce),
    250         GNUNET_JSON_spec_fixed_auto (
    251           "cs_blinded_c0",
    252           &blinded_message->details.cs_blinded_message.c[0]),
    253         GNUNET_JSON_spec_fixed_auto (
    254           "cs_blinded_c1",
    255           &blinded_message->details.cs_blinded_message.c[1]),
    256         GNUNET_JSON_spec_end ()
    257       };
    258 
    259       if (GNUNET_OK !=
    260           GNUNET_JSON_parse (root,
    261                              ispec,
    262                              &emsg,
    263                              &eline))
    264       {
    265         GNUNET_break_op (0);
    266         GNUNET_free (blinded_message);
    267         return GNUNET_SYSERR;
    268       }
    269       blinded_udi->blinded_message = blinded_message;
    270       return GNUNET_OK;
    271     }
    272   }
    273   GNUNET_break_op (0);
    274   GNUNET_free (blinded_message);
    275   return GNUNET_SYSERR;
    276 }
    277 
    278 
    279 /**
    280  * Cleanup data left from parsing blinded unique donation identifier.
    281  *
    282  * @param cls closure, NULL
    283  * @param[out] spec where to free the data
    284  */
    285 static void
    286 clean_blinded_donation_identifier (void *cls,
    287                                    struct GNUNET_JSON_Specification *spec)
    288 {
    289   struct TALER_BlindedPlanchet *blinded_udi = spec->ptr;
    290 
    291   (void) cls;
    292   TALER_blinded_planchet_free (blinded_udi);
    293 }
    294 
    295 
    296 struct GNUNET_JSON_Specification
    297 DONAU_JSON_spec_blinded_donation_identifier (const char *field,
    298                                              struct
    299                                              DONAU_BlindedUniqueDonorIdentifier
    300                                              *
    301                                              blinded_udi)
    302 {
    303   struct GNUNET_JSON_Specification ret = {
    304     .parser = &parse_blinded_donation_identifier,
    305     .cleaner = &clean_blinded_donation_identifier,
    306     .field = field,
    307     .ptr = blinded_udi
    308   };
    309 
    310   blinded_udi->blinded_message = NULL;
    311   return ret;
    312 }
    313 
    314 
    315 /**
    316  * Parse given JSON object to blinded donation unit signature.
    317  *
    318  * @param cls closure, NULL
    319  * @param root the json object representing data
    320  * @param[out] spec where to write the data
    321  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    322  */
    323 static enum GNUNET_GenericReturnValue
    324 parse_blinded_donation_unit_sig (void *cls,
    325                                  json_t *root,
    326                                  struct GNUNET_JSON_Specification *spec)
    327 {
    328   struct DONAU_BlindedDonationUnitSignature *du_sig = spec->ptr;
    329   struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
    330   const char *cipher;
    331   struct GNUNET_JSON_Specification dspec[] = {
    332     GNUNET_JSON_spec_string ("cipher",
    333                              &cipher),
    334     GNUNET_JSON_spec_end ()
    335   };
    336   const char *emsg;
    337   unsigned int eline;
    338 
    339   (void) cls;
    340   if (GNUNET_OK !=
    341       GNUNET_JSON_parse (root,
    342                          dspec,
    343                          &emsg,
    344                          &eline))
    345   {
    346     GNUNET_break_op (0);
    347     return GNUNET_SYSERR;
    348   }
    349   blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    350   blinded_sig->cipher = string_to_cipher (cipher);
    351   blinded_sig->rc = 1;
    352   switch (blinded_sig->cipher)
    353   {
    354   case GNUNET_CRYPTO_BSA_INVALID:
    355     break;
    356   case GNUNET_CRYPTO_BSA_RSA:
    357     {
    358       struct GNUNET_JSON_Specification ispec[] = {
    359         GNUNET_JSON_spec_rsa_signature (
    360           "blinded_rsa_signature",
    361           &blinded_sig->details.blinded_rsa_signature),
    362         GNUNET_JSON_spec_end ()
    363       };
    364 
    365       if (GNUNET_OK !=
    366           GNUNET_JSON_parse (root,
    367                              ispec,
    368                              &emsg,
    369                              &eline))
    370       {
    371         GNUNET_break_op (0);
    372         GNUNET_free (blinded_sig);
    373         return GNUNET_SYSERR;
    374       }
    375       du_sig->blinded_sig = blinded_sig;
    376       return GNUNET_OK;
    377     }
    378   case GNUNET_CRYPTO_BSA_CS:
    379     {
    380       struct GNUNET_JSON_Specification ispec[] = {
    381         GNUNET_JSON_spec_uint32 ("b",
    382                                  &blinded_sig->details.blinded_cs_answer.b),
    383         GNUNET_JSON_spec_fixed_auto ("s",
    384                                      &blinded_sig->details.blinded_cs_answer.
    385                                      s_scalar),
    386         GNUNET_JSON_spec_end ()
    387       };
    388 
    389       if (GNUNET_OK !=
    390           GNUNET_JSON_parse (root,
    391                              ispec,
    392                              &emsg,
    393                              &eline))
    394       {
    395         GNUNET_break_op (0);
    396         GNUNET_free (blinded_sig);
    397         return GNUNET_SYSERR;
    398       }
    399       du_sig->blinded_sig = blinded_sig;
    400       return GNUNET_OK;
    401     }
    402   }
    403   GNUNET_break_op (0);
    404   GNUNET_free (blinded_sig);
    405   return GNUNET_SYSERR;
    406 }
    407 
    408 
    409 /**
    410  * Cleanup data left from parsing donation unit public key.
    411  *
    412  * @param cls closure, NULL
    413  * @param[out] spec where to free the data
    414  */
    415 static void
    416 clean_blinded_donation_unit_sig (void *cls,
    417                                  struct GNUNET_JSON_Specification *spec)
    418 {
    419   struct DONAU_BlindedDonationUnitSignature *du_sig = spec->ptr;
    420 
    421   (void) cls;
    422   DONAU_blinded_donation_unit_sig_free (du_sig);
    423 }
    424 
    425 
    426 struct GNUNET_JSON_Specification
    427 DONAU_JSON_spec_blinded_donation_unit_sig (const char *field,
    428                                            struct
    429                                            DONAU_BlindedDonationUnitSignature *
    430                                            sig)
    431 {
    432   struct GNUNET_JSON_Specification ret = {
    433     .parser = &parse_blinded_donation_unit_sig,
    434     .cleaner = &clean_blinded_donation_unit_sig,
    435     .field = field,
    436     .ptr = sig
    437   };
    438 
    439   sig->blinded_sig = NULL;
    440   return ret;
    441 }
    442 
    443 
    444 struct GNUNET_JSON_PackSpec
    445 DONAU_JSON_pack_donation_unit_sig (
    446   const char *name,
    447   const struct DONAU_DonationUnitSignature *sig)
    448 {
    449   const struct GNUNET_CRYPTO_UnblindedSignature *bs;
    450   struct GNUNET_JSON_PackSpec ps = {
    451     .field_name = name,
    452   };
    453 
    454   if (NULL == sig)
    455     return ps;
    456   bs = sig->unblinded_sig;
    457   switch (bs->cipher)
    458   {
    459   case GNUNET_CRYPTO_BSA_INVALID:
    460     break;
    461   case GNUNET_CRYPTO_BSA_RSA:
    462     ps.object = GNUNET_JSON_PACK (
    463       GNUNET_JSON_pack_string ("cipher",
    464                                "RSA"),
    465       GNUNET_JSON_pack_rsa_signature ("rsa_signature",
    466                                       bs->details.rsa_signature));
    467     return ps;
    468   case GNUNET_CRYPTO_BSA_CS:
    469     ps.object = GNUNET_JSON_PACK (
    470       GNUNET_JSON_pack_string ("cipher",
    471                                "CS"),
    472       GNUNET_JSON_pack_data_auto ("cs_signature_r",
    473                                   &bs->details.cs_signature.r_point),
    474       GNUNET_JSON_pack_data_auto ("cs_signature_s",
    475                                   &bs->details.cs_signature.s_scalar));
    476     return ps;
    477   }
    478   GNUNET_assert (0);
    479   return ps;
    480 }
    481 
    482 
    483 struct GNUNET_JSON_PackSpec
    484 DONAU_JSON_pack_blinded_donation_unit_sig (
    485   const char *name,
    486   const struct DONAU_BlindedDonationUnitSignature *sig)
    487 {
    488   const struct GNUNET_CRYPTO_BlindedSignature *bs;
    489   struct GNUNET_JSON_PackSpec ps = {
    490     .field_name = name,
    491   };
    492 
    493   if (NULL == sig)
    494     return ps;
    495   bs = sig->blinded_sig;
    496   switch (bs->cipher)
    497   {
    498   case GNUNET_CRYPTO_BSA_INVALID:
    499     break;
    500   case GNUNET_CRYPTO_BSA_RSA:
    501     ps.object = GNUNET_JSON_PACK (
    502       GNUNET_JSON_pack_string ("cipher",
    503                                "RSA"),
    504       GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
    505                                       bs->details.blinded_rsa_signature));
    506     return ps;
    507   case GNUNET_CRYPTO_BSA_CS:
    508     ps.object = GNUNET_JSON_PACK (
    509       GNUNET_JSON_pack_string ("cipher",
    510                                "CS"),
    511       GNUNET_JSON_pack_uint64 ("b",
    512                                bs->details.blinded_cs_answer.b),
    513       GNUNET_JSON_pack_data_auto ("s",
    514                                   &bs->details.blinded_cs_answer.s_scalar));
    515     return ps;
    516   }
    517   GNUNET_assert (0);
    518   return ps;
    519 }
    520 
    521 
    522 struct GNUNET_JSON_PackSpec
    523 DONAU_JSON_pack_blinded_donation_identifier (
    524   const char *name,
    525   const struct DONAU_BlindedUniqueDonorIdentifier *blinded_udi)
    526 {
    527   const struct GNUNET_CRYPTO_BlindedMessage *bm;
    528   struct GNUNET_JSON_PackSpec ps = {
    529     .field_name = name,
    530   };
    531 
    532   if (NULL == blinded_udi)
    533     return ps;
    534   bm = blinded_udi->blinded_message;
    535   switch (bm->cipher)
    536   {
    537   case GNUNET_CRYPTO_BSA_INVALID:
    538     break;
    539   case GNUNET_CRYPTO_BSA_RSA:
    540     ps.object = GNUNET_JSON_PACK (
    541       GNUNET_JSON_pack_string ("cipher",
    542                                "RSA"),
    543       GNUNET_JSON_pack_data_varsize (
    544         "rsa_blinded_identifier",
    545         bm->details.rsa_blinded_message.blinded_msg,
    546         bm->details.rsa_blinded_message.blinded_msg_size));
    547     return ps;
    548   case GNUNET_CRYPTO_BSA_CS:
    549     ps.object = GNUNET_JSON_PACK (
    550       GNUNET_JSON_pack_string ("cipher",
    551                                "CS"),
    552       GNUNET_JSON_pack_data_auto (
    553         "cs_nonce",
    554         &bm->details.cs_blinded_message.nonce),
    555       GNUNET_JSON_pack_data_auto (
    556         "cs_blinded_c0",
    557         &bm->details.cs_blinded_message.c[0]),
    558       GNUNET_JSON_pack_data_auto (
    559         "cs_blinded_c1",
    560         &bm->details.cs_blinded_message.c[1]));
    561     return ps;
    562   }
    563   GNUNET_assert (0);
    564   return ps;
    565 }
    566 
    567 
    568 /* end of json/donau_json.c */