donau

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

donau_json.c (16621B)


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