/* This file is part of TALER Copyright (C) 2014, 2015 GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, If not, see */ /** * @file mint-lib/mint_api_json.c * @brief functions to parse incoming requests (JSON snippets) * @author Florian Dold * @author Benedikt Mueller * @author Christian Grothoff */ #include "platform.h" #include "mint_api_json.h" /** * Navigate and parse data in a JSON tree. * * @param root the JSON node to start the navigation at. * @param spec parse specification array * @return offset in @a spec where parsing failed, -1 on success (!) */ static int parse_json (json_t *root, struct MAJ_Specification *spec) { int i; json_t *pos; /* what's our current position? */ pos = root; for (i=0;MAJ_CMD_END != spec[i].cmd;i++) { pos = json_object_get (root, spec[i].field); if (NULL == pos) { GNUNET_break_op (0); return i; } switch (spec[i].cmd) { case MAJ_CMD_END: GNUNET_assert (0); return i; case MAJ_CMD_AMOUNT: if (GNUNET_OK != TALER_json_to_amount (pos, spec[i].details.amount)) { GNUNET_break_op (0); return i; } break; case MAJ_CMD_TIME_ABSOLUTE: if (GNUNET_OK != TALER_json_to_abs (pos, spec[i].details.abs_time)) { GNUNET_break_op (0); return i; } break; case MAJ_CMD_STRING: { const char *str; str = json_string_value (pos); if (NULL == str) { GNUNET_break_op (0); return i; } *spec[i].details.strptr = str; } break; case MAJ_CMD_BINARY_FIXED: { const char *str; int res; str = json_string_value (pos); if (NULL == str) { GNUNET_break_op (0); return i; } res = GNUNET_STRINGS_string_to_data (str, strlen (str), spec[i].details.fixed_data.dest, spec[i].details.fixed_data.dest_size); if (GNUNET_OK != res) { GNUNET_break_op (0); return i; } } break; case MAJ_CMD_BINARY_VARIABLE: { const char *str; size_t size; void *data; int res; str = json_string_value (pos); if (NULL == str) { GNUNET_break_op (0); return i; } size = (strlen (str) * 5) / 8; if (size >= 1024) { GNUNET_break_op (0); return i; } data = GNUNET_malloc (size); res = GNUNET_STRINGS_string_to_data (str, strlen (str), data, size); if (GNUNET_OK != res) { GNUNET_break_op (0); GNUNET_free (data); return i; } *spec[i].details.variable_data.dest_p = data; *spec[i].details.variable_data.dest_size_p = size; } break; case MAJ_CMD_RSA_PUBLIC_KEY: { size_t size; const char *str; int res; void *buf; str = json_string_value (pos); if (NULL == str) { GNUNET_break_op (0); return i; } size = (strlen (str) * 5) / 8; buf = GNUNET_malloc (size); res = GNUNET_STRINGS_string_to_data (str, strlen (str), buf, size); if (GNUNET_OK != res) { GNUNET_free (buf); GNUNET_break_op (0); return i; } *spec[i].details.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf, size); GNUNET_free (buf); if (NULL == spec[i].details.rsa_public_key) { GNUNET_break_op (0); return i; } } break; case MAJ_CMD_RSA_SIGNATURE: { size_t size; const char *str; int res; void *buf; str = json_string_value (pos); if (NULL == str) { GNUNET_break_op (0); return i; } size = (strlen (str) * 5) / 8; buf = GNUNET_malloc (size); res = GNUNET_STRINGS_string_to_data (str, strlen (str), buf, size); if (GNUNET_OK != res) { GNUNET_free (buf); GNUNET_break_op (0); return i; } *spec[i].details.rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf, size); GNUNET_free (buf); if (NULL == spec[i].details.rsa_signature) return i; } break; case MAJ_CMD_EDDSA_SIGNATURE: { struct TALER_CoinSpendSignatureP sig; struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; size_t size; struct MAJ_Specification sig_spec[] = { MAJ_spec_fixed_auto ("eddsa_sig", &sig), MAJ_spec_varsize ("eddsa_val", (void**) &purpose, &size), MAJ_spec_end }; if (GNUNET_OK != MAJ_parse_json (pos, sig_spec)) { GNUNET_break_op (0); MAJ_parse_free (sig_spec); return i; } if (size != ntohl (purpose->size)) { GNUNET_break_op (0); MAJ_parse_free (sig_spec); return i; } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (ntohl (purpose->purpose), purpose, &sig.eddsa_signature, spec[i].details.eddsa_signature.pub_key)) { GNUNET_break_op (0); MAJ_parse_free (sig_spec); return i; } *spec[i].details.eddsa_signature.purpose_p = purpose; } break; case MAJ_CMD_UINT16: { json_int_t val; if (! json_is_integer (pos)) { GNUNET_break_op (0); return i; } val = json_integer_value (pos); if ( (0 > val) || (val > UINT16_MAX) ) { GNUNET_break_op (0); return i; } *spec[i].details.u16 = (uint16_t) val; } break; case MAJ_CMD_JSON_OBJECT: { if (! (json_is_object (pos) || json_is_array (pos)) ) { GNUNET_break_op (0); return i; } json_incref (pos); *spec[i].details.obj = pos; } break; default: GNUNET_break (0); return i; } } return -1; /* all OK! */ } /** * Free all elements allocated during a * #MAJ_parse_json() operation. * * @param spec specification of the parse operation * @param end number of elements in @a spec to process */ static void parse_free (struct MAJ_Specification *spec, int end) { int i; for (i=0;i