json.c (22443B)
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 json_decref (fp); 507 GNUNET_break (0); 508 return GNUNET_SYSERR; 509 } 510 511 /* remember field as 'forgotten' */ 512 if (0 != 513 json_object_set_new (rx, 514 field, 515 GNUNET_JSON_from_data_auto (&hc))) 516 { 517 GNUNET_break (0); 518 return GNUNET_SYSERR; 519 } 520 /* finally, set 'forgotten' field to null */ 521 if (0 != 522 json_object_del (json, 523 field)) 524 { 525 GNUNET_break (0); 526 return GNUNET_SYSERR; 527 } 528 return GNUNET_OK; 529 } 530 531 532 /** 533 * Loop over all of the values of a '$forgettable' object. Replace 'True' 534 * values with proper random salts. Fails if any forgettable values are 535 * neither 'True' nor valid salts (strings). 536 * 537 * @param[in,out] f JSON to transform 538 * @return #GNUNET_OK on success 539 */ 540 static enum GNUNET_GenericReturnValue 541 seed_forgettable (json_t *f) 542 { 543 const char *key; 544 json_t *val; 545 546 json_object_foreach (f, 547 key, 548 val) 549 { 550 if (json_is_string (val)) 551 continue; 552 if (json_is_true (val)) 553 { 554 struct GNUNET_ShortHashCode sh; 555 556 GNUNET_CRYPTO_random_block (&sh, 557 sizeof (sh)); 558 if (0 != 559 json_object_set_new (f, 560 key, 561 GNUNET_JSON_from_data_auto (&sh))) 562 { 563 GNUNET_break (0); 564 return GNUNET_SYSERR; 565 } 566 continue; 567 } 568 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 569 "Forgettable field `%s' has invalid value\n", 570 key); 571 return GNUNET_SYSERR; 572 } 573 return GNUNET_OK; 574 } 575 576 577 enum GNUNET_GenericReturnValue 578 TALER_JSON_contract_seed_forgettable (const json_t *spec, 579 json_t *contract) 580 { 581 if (json_is_object (spec)) 582 { 583 const char *key; 584 json_t *val; 585 586 json_object_foreach ((json_t *) spec, 587 key, 588 val) 589 { 590 json_t *cval = json_object_get (contract, 591 key); 592 593 if (0 == strcmp ("$forgettable", 594 key)) 595 { 596 json_t *xval = json_deep_copy (val); 597 598 if (GNUNET_OK != 599 seed_forgettable (xval)) 600 { 601 json_decref (xval); 602 return GNUNET_SYSERR; 603 } 604 GNUNET_assert (0 == 605 json_object_set_new (contract, 606 "$forgettable", 607 xval)); 608 continue; 609 } 610 if (NULL == cval) 611 continue; 612 if (GNUNET_OK != 613 TALER_JSON_contract_seed_forgettable (val, 614 cval)) 615 return GNUNET_SYSERR; 616 } 617 } 618 if (json_is_array (spec)) 619 { 620 size_t index; 621 json_t *val; 622 623 json_array_foreach ((json_t *) spec, 624 index, 625 val) 626 { 627 json_t *ival = json_array_get (contract, 628 index); 629 630 if (NULL == ival) 631 continue; 632 if (GNUNET_OK != 633 TALER_JSON_contract_seed_forgettable (val, 634 ival)) 635 return GNUNET_SYSERR; 636 } 637 } 638 return GNUNET_OK; 639 } 640 641 642 /** 643 * Parse a json path. 644 * 645 * @param obj the object that the path is relative to. 646 * @param prev the parent of @e obj. 647 * @param path the path to parse. 648 * @param cb the callback to call, if we get to the end of @e path. 649 * @param cb_cls the closure for the callback. 650 * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed. 651 */ 652 static enum GNUNET_GenericReturnValue 653 parse_path (json_t *obj, 654 json_t *prev, 655 const char *path, 656 TALER_JSON_ExpandPathCallback cb, 657 void *cb_cls) 658 { 659 char *id = GNUNET_strdup (path); 660 char *next_id = strchr (id, 661 '.'); 662 char *next_path; 663 char *bracket; 664 json_t *next_obj = NULL; 665 char *next_dot; 666 667 GNUNET_assert (NULL != id); /* make stupid compiler happy */ 668 if (NULL == next_id) 669 { 670 cb (cb_cls, 671 id, 672 prev); 673 GNUNET_free (id); 674 return GNUNET_OK; 675 } 676 bracket = strchr (next_id, 677 '['); 678 *next_id = '\0'; 679 next_id++; 680 next_path = GNUNET_strdup (next_id); 681 next_dot = strchr (next_id, 682 '.'); 683 if (NULL != next_dot) 684 *next_dot = '\0'; 685 /* If this is the first time this is called, make sure id is "$" */ 686 if ( (NULL == prev) && 687 (0 != strcmp (id, 688 "$"))) 689 { 690 GNUNET_free (id); 691 GNUNET_free (next_path); 692 return GNUNET_SYSERR; 693 } 694 695 /* Check for bracketed indices */ 696 if (NULL != bracket) 697 { 698 char *end_bracket = strchr (bracket, 699 ']'); 700 json_t *array; 701 702 if (NULL == end_bracket) 703 { 704 GNUNET_free (id); 705 GNUNET_free (next_path); 706 return GNUNET_SYSERR; 707 } 708 *end_bracket = '\0'; 709 *bracket = '\0'; 710 bracket++; 711 array = json_object_get (obj, 712 next_id); 713 if (0 == strcmp (bracket, 714 "*")) 715 { 716 size_t index; 717 json_t *value; 718 int ret = GNUNET_OK; 719 720 json_array_foreach (array, index, value) { 721 ret = parse_path (value, 722 obj, 723 next_path, 724 cb, 725 cb_cls); 726 if (GNUNET_OK != ret) 727 { 728 GNUNET_free (id); 729 GNUNET_free (next_path); 730 return ret; 731 } 732 } 733 } 734 else 735 { 736 unsigned int index; 737 char dummy; 738 739 if (1 != sscanf (bracket, 740 "%u%c", 741 &index, 742 &dummy)) 743 { 744 GNUNET_free (id); 745 GNUNET_free (next_path); 746 return GNUNET_SYSERR; 747 } 748 next_obj = json_array_get (array, 749 index); 750 } 751 } 752 else 753 { 754 /* No brackets, so just fetch the object by name */ 755 next_obj = json_object_get (obj, 756 next_id); 757 } 758 759 if (NULL != next_obj) 760 { 761 int ret = parse_path (next_obj, 762 obj, 763 next_path, 764 cb, 765 cb_cls); 766 GNUNET_free (id); 767 GNUNET_free (next_path); 768 return ret; 769 } 770 GNUNET_free (id); 771 GNUNET_free (next_path); 772 return GNUNET_OK; 773 } 774 775 776 enum GNUNET_GenericReturnValue 777 TALER_JSON_expand_path (json_t *json, 778 const char *path, 779 TALER_JSON_ExpandPathCallback cb, 780 void *cb_cls) 781 { 782 return parse_path (json, 783 NULL, 784 path, 785 cb, 786 cb_cls); 787 } 788 789 790 enum TALER_ErrorCode 791 TALER_JSON_get_error_code (const json_t *json) 792 { 793 const json_t *jc; 794 795 if (NULL == json) 796 return TALER_EC_GENERIC_INVALID_RESPONSE; 797 jc = json_object_get (json, "code"); 798 /* The caller already knows that the JSON represents an error, 799 so we are dealing with a missing error code here. */ 800 if (NULL == jc) 801 { 802 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 803 "Expected Taler error code `code' in JSON, but field does not exist!\n"); 804 return TALER_EC_INVALID; 805 } 806 if (json_is_integer (jc)) 807 return (enum TALER_ErrorCode) (int) json_integer_value (jc); 808 GNUNET_break_op (0); 809 return TALER_EC_INVALID; 810 } 811 812 813 const char * 814 TALER_JSON_get_error_hint (const json_t *json) 815 { 816 const json_t *jc; 817 818 if (NULL == json) 819 return NULL; 820 jc = json_object_get (json, 821 "hint"); 822 if (NULL == jc) 823 return NULL; /* no hint, is allowed */ 824 if (! json_is_string (jc)) 825 { 826 /* Hints must be strings */ 827 GNUNET_break_op (0); 828 return NULL; 829 } 830 return json_string_value (jc); 831 } 832 833 834 enum TALER_ErrorCode 835 TALER_JSON_get_error_code2 (const void *data, 836 size_t data_size) 837 { 838 json_t *json; 839 enum TALER_ErrorCode ec; 840 json_error_t err; 841 842 json = json_loadb (data, 843 data_size, 844 JSON_REJECT_DUPLICATES, 845 &err); 846 if (NULL == json) 847 return TALER_EC_INVALID; 848 ec = TALER_JSON_get_error_code (json); 849 json_decref (json); 850 if (ec == TALER_EC_NONE) 851 return TALER_EC_INVALID; 852 return ec; 853 } 854 855 856 void 857 TALER_deposit_policy_hash (const json_t *policy, 858 struct TALER_ExtensionPolicyHashP *ech) 859 { 860 GNUNET_assert (GNUNET_OK == 861 dump_and_hash (policy, 862 "taler-extensions-policy", 863 &ech->hash)); 864 } 865 866 867 char * 868 TALER_JSON_canonicalize (const json_t *input) 869 { 870 char *wire_enc; 871 872 if (NULL == (wire_enc = json_dumps (input, 873 JSON_ENCODE_ANY 874 | JSON_COMPACT 875 | JSON_SORT_KEYS))) 876 { 877 GNUNET_break (0); 878 return NULL; 879 } 880 TALER_rfc8785encode (&wire_enc); 881 return wire_enc; 882 } 883 884 885 json_t * 886 TALER_JSON_currency_specs_to_json ( 887 const struct TALER_CurrencySpecification *cspec) 888 { 889 json_t *ca; 890 891 ca = json_array (); 892 GNUNET_assert (NULL != ca); 893 for (unsigned int i = 0; i<cspec->num_common_amounts; i++) 894 GNUNET_assert ( 895 0 == 896 json_array_append_new ( 897 ca, 898 TALER_JSON_from_amount (&cspec->common_amounts[i]))); 899 return GNUNET_JSON_PACK ( 900 GNUNET_JSON_pack_string ("name", 901 cspec->name), 902 /* 'currency' is deprecated as of exchange v18 and merchant v6; 903 remove this line once current-age > 6*/ 904 GNUNET_JSON_pack_string ("currency", 905 cspec->currency), 906 GNUNET_JSON_pack_array_steal ("common_amounts", 907 ca), 908 GNUNET_JSON_pack_uint64 ("num_fractional_input_digits", 909 cspec->num_fractional_input_digits), 910 GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits", 911 cspec->num_fractional_normal_digits), 912 GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits", 913 cspec->num_fractional_trailing_zero_digits), 914 GNUNET_JSON_pack_object_incref ("alt_unit_names", 915 cspec->map_alt_unit_names)); 916 } 917 918 919 /* End of json/json.c */