diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-05-02 17:29:41 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-05-02 17:29:41 +0200 |
commit | ffd4057c61a1c507e348b76d1df10641c7ed64b1 (patch) | |
tree | 96754a5de2d3468f2ad361771d4127e9979b3f5c | |
parent | 41cb79c685b25bcf2c3e566f25c386c89442cbeb (diff) |
use same canonicalization of JSON as for contract hashes when doing normal JSON hashing
-rw-r--r-- | src/json/json.c | 168 | ||||
-rw-r--r-- | src/util/util.c | 169 |
2 files changed, 169 insertions, 168 deletions
diff --git a/src/json/json.c b/src/json/json.c index 7d7e4ecba..832863f31 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -62,170 +62,6 @@ contains_real (const json_t *json) /** - * Dump character in the low range into @a buf - * following RFC 8785. - * - * @param[in,out] buf buffer to modify - * @param val value to dump - */ -static void -lowdump (struct GNUNET_Buffer *buf, - unsigned char val) -{ - char scratch[7]; - - switch (val) - { - case 0x8: - GNUNET_buffer_write (buf, - "\\b", - 2); - break; - case 0x9: - GNUNET_buffer_write (buf, - "\\t", - 2); - break; - case 0xA: - GNUNET_buffer_write (buf, - "\\n", - 2); - break; - case 0xC: - GNUNET_buffer_write (buf, - "\\f", - 2); - break; - case 0xD: - GNUNET_buffer_write (buf, - "\\r", - 2); - break; - default: - GNUNET_snprintf (scratch, - sizeof (scratch), - "\\u%04x", - (unsigned int) val); - GNUNET_buffer_write (buf, - scratch, - 6); - break; - } -} - - -/** - * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). - * - * @param[in,out] inp pointer to string to re-encode - * @return number of bytes in resulting @a inp - */ -static size_t -rfc8785encode (char **inp) -{ - struct GNUNET_Buffer buf = { 0 }; - size_t left = strlen (*inp) + 1; - size_t olen; - char *in = *inp; - const char *pos = in; - - GNUNET_buffer_prealloc (&buf, - left + 40); - buf.warn_grow = 0; /* disable, + 40 is just a wild guess */ - while (1) - { - int mbl = u8_mblen ((unsigned char *) pos, - left); - unsigned char val; - - if (0 == mbl) - break; - val = (unsigned char) *pos; - if ( (1 == mbl) && - (val <= 0x1F) ) - { - /* Should not happen, as input is produced by - * JSON stringification */ - GNUNET_break (0); - lowdump (&buf, - val); - } - else if ( (1 == mbl) && ('\\' == *pos) ) - { - switch (*(pos + 1)) - { - case '\\': - mbl = 2; - GNUNET_buffer_write (&buf, - pos, - mbl); - break; - case 'u': - { - unsigned int num; - uint32_t n32; - unsigned char res[8]; - size_t rlen; - - GNUNET_assert ( (1 == - sscanf (pos + 2, - "%4x", - &num)) || - (1 == - sscanf (pos + 2, - "%4X", - &num)) ); - mbl = 6; - n32 = (uint32_t) num; - rlen = sizeof (res); - u32_to_u8 (&n32, - 1, - res, - &rlen); - if ( (1 == rlen) && - (res[0] <= 0x1F) ) - { - lowdump (&buf, - res[0]); - } - else - { - GNUNET_buffer_write (&buf, - (const char *) res, - rlen); - } - } - break; - default: - mbl = 2; - GNUNET_buffer_write (&buf, - pos, - mbl); - break; - } - } - else - { - GNUNET_buffer_write (&buf, - pos, - mbl); - } - left -= mbl; - pos += mbl; - } - - /* 0-terminate buffer */ - GNUNET_buffer_write (&buf, - "", - 1); - GNUNET_free (in); - *inp = GNUNET_buffer_reap (&buf, - &olen); - return olen; -} - - -/** * Dump the @a json to a string and hash it. * * @param json value to hash @@ -262,7 +98,7 @@ dump_and_hash (const json_t *json, GNUNET_break (0); return GNUNET_SYSERR; } - len = rfc8785encode (&wire_enc); + len = TALER_rfc8785encode (&wire_enc); if (NULL == salt) { GNUNET_CRYPTO_hash (wire_enc, @@ -1031,7 +867,7 @@ TALER_JSON_canonicalize (const json_t *input) GNUNET_break (0); return NULL; } - rfc8785encode (&wire_enc); + TALER_rfc8785encode (&wire_enc); return wire_enc; } diff --git a/src/util/util.c b/src/util/util.c index 96d791912..7cd4b0c35 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -25,6 +25,7 @@ #include "taler_util.h" #include "taler_attributes.h" #include <gnunet/gnunet_json_lib.h> +#include <unistr.h> const char * @@ -205,6 +206,170 @@ TALER_denom_fee_check_currency ( /** + * Dump character in the low range into @a buf + * following RFC 8785. + * + * @param[in,out] buf buffer to modify + * @param val value to dump + */ +static void +lowdump (struct GNUNET_Buffer *buf, + unsigned char val) +{ + char scratch[7]; + + switch (val) + { + case 0x8: + GNUNET_buffer_write (buf, + "\\b", + 2); + break; + case 0x9: + GNUNET_buffer_write (buf, + "\\t", + 2); + break; + case 0xA: + GNUNET_buffer_write (buf, + "\\n", + 2); + break; + case 0xC: + GNUNET_buffer_write (buf, + "\\f", + 2); + break; + case 0xD: + GNUNET_buffer_write (buf, + "\\r", + 2); + break; + default: + GNUNET_snprintf (scratch, + sizeof (scratch), + "\\u%04x", + (unsigned int) val); + GNUNET_buffer_write (buf, + scratch, + 6); + break; + } +} + + +/** + * Re-encode string at @a inp to match RFC 8785 (section 3.2.2.2). + * + * @param[in,out] inp pointer to string to re-encode + * @return number of bytes in resulting @a inp + */ +size_t +TALER_rfc8785encode (char **inp) +{ + struct GNUNET_Buffer buf = { 0 }; + size_t left = strlen (*inp) + 1; + size_t olen; + char *in = *inp; + const char *pos = in; + + GNUNET_buffer_prealloc (&buf, + left + 40); + buf.warn_grow = 0; /* disable, + 40 is just a wild guess */ + while (1) + { + int mbl = u8_mblen ((unsigned char *) pos, + left); + unsigned char val; + + if (0 == mbl) + break; + val = (unsigned char) *pos; + if ( (1 == mbl) && + (val <= 0x1F) ) + { + /* Should not happen, as input is produced by + * JSON stringification */ + GNUNET_break (0); + lowdump (&buf, + val); + } + else if ( (1 == mbl) && ('\\' == *pos) ) + { + switch (*(pos + 1)) + { + case '\\': + mbl = 2; + GNUNET_buffer_write (&buf, + pos, + mbl); + break; + case 'u': + { + unsigned int num; + uint32_t n32; + unsigned char res[8]; + size_t rlen; + + GNUNET_assert ( (1 == + sscanf (pos + 2, + "%4x", + &num)) || + (1 == + sscanf (pos + 2, + "%4X", + &num)) ); + mbl = 6; + n32 = (uint32_t) num; + rlen = sizeof (res); + u32_to_u8 (&n32, + 1, + res, + &rlen); + if ( (1 == rlen) && + (res[0] <= 0x1F) ) + { + lowdump (&buf, + res[0]); + } + else + { + GNUNET_buffer_write (&buf, + (const char *) res, + rlen); + } + } + break; + default: + mbl = 2; + GNUNET_buffer_write (&buf, + pos, + mbl); + break; + } + } + else + { + GNUNET_buffer_write (&buf, + pos, + mbl); + } + left -= mbl; + pos += mbl; + } + + /* 0-terminate buffer */ + GNUNET_buffer_write (&buf, + "", + 1); + GNUNET_free (in); + *inp = GNUNET_buffer_reap (&buf, + &olen); + return olen; +} + + +/** * Hash normalized @a j JSON object or array and * store the result in @a hc. * @@ -221,11 +386,11 @@ TALER_json_hash (const json_t *j, cstr = json_dumps (j, JSON_COMPACT | JSON_SORT_KEYS); GNUNET_assert (NULL != cstr); - clen = strlen (cstr); + clen = TALER_rfc8785encode (&cstr); GNUNET_CRYPTO_hash (cstr, clen, hc); - free (cstr); + GNUNET_free (cstr); } |