use same canonicalization of JSON as for contract hashes when doing normal JSON hashing
This commit is contained in:
parent
41cb79c685
commit
ffd4057c61
168
src/json/json.c
168
src/json/json.c
@ -61,170 +61,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.
|
* Dump the @a json to a string and hash it.
|
||||||
*
|
*
|
||||||
@ -262,7 +98,7 @@ dump_and_hash (const json_t *json,
|
|||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
len = rfc8785encode (&wire_enc);
|
len = TALER_rfc8785encode (&wire_enc);
|
||||||
if (NULL == salt)
|
if (NULL == salt)
|
||||||
{
|
{
|
||||||
GNUNET_CRYPTO_hash (wire_enc,
|
GNUNET_CRYPTO_hash (wire_enc,
|
||||||
@ -1031,7 +867,7 @@ TALER_JSON_canonicalize (const json_t *input)
|
|||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
rfc8785encode (&wire_enc);
|
TALER_rfc8785encode (&wire_enc);
|
||||||
return wire_enc;
|
return wire_enc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
169
src/util/util.c
169
src/util/util.c
@ -25,6 +25,7 @@
|
|||||||
#include "taler_util.h"
|
#include "taler_util.h"
|
||||||
#include "taler_attributes.h"
|
#include "taler_attributes.h"
|
||||||
#include <gnunet/gnunet_json_lib.h>
|
#include <gnunet/gnunet_json_lib.h>
|
||||||
|
#include <unistr.h>
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
@ -204,6 +205,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
|
* Hash normalized @a j JSON object or array and
|
||||||
* store the result in @a hc.
|
* store the result in @a hc.
|
||||||
@ -221,11 +386,11 @@ TALER_json_hash (const json_t *j,
|
|||||||
cstr = json_dumps (j,
|
cstr = json_dumps (j,
|
||||||
JSON_COMPACT | JSON_SORT_KEYS);
|
JSON_COMPACT | JSON_SORT_KEYS);
|
||||||
GNUNET_assert (NULL != cstr);
|
GNUNET_assert (NULL != cstr);
|
||||||
clen = strlen (cstr);
|
clen = TALER_rfc8785encode (&cstr);
|
||||||
GNUNET_CRYPTO_hash (cstr,
|
GNUNET_CRYPTO_hash (cstr,
|
||||||
clen,
|
clen,
|
||||||
hc);
|
hc);
|
||||||
free (cstr);
|
GNUNET_free (cstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user