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