Subject: Re: [Cbor] Canonical CBOR

From: Laurence Lundblade <[email-masked]>
Date: Tue, 5 Jun 2018 00:27:39 +0000

So I’ve had some think time on this.

Rather than asking about implementations, I should have asked about CBOR-based protocol designs that need or benefit from canonicalization.  I’m familiar with CWT and COSE so let’s see about canonicalization in them.

CWT doesn’t require canonicalization and that all seems fine.  The main benefit I can see canonicalization bringing is the testing benefit that you mention. For the same set of input claims, you can binary compare the output of two implementations and know they match (at least that is the testing benefit I think you are mentioning).  My feeling is that requiring canonicalization for CWT for this reason would not be a good design trade-off. 

COSE on the other hand does require canonicalization in some places and (maybe) not in others.

Section 3 says that protected headers are bstr wrapped so they don’t have to be canonicalized.

Section 14 requires canonicalization for Sig_structure,  Enc_structure, and MAC_structure.  I interpret this as requiring canonicalization for any / all of the maps in these structures including sorting. I have a few issues with this requirement:

- This seems at odds with the statement Section 3 especially as the protected parts of these structures are bstr wrapped.

- This canonicalization seems unnecessary. I just can’t see what could go wrong if you don’t canonicalize. Canonicalize of the payload is not required and that works OK.  It seems like COSE would be better by just deleting section 14.

It feels like maybe this was put in when there was some thinking that canonicalization was good for signing, but now that turned out not to be true? Pardon if I’m dense and missing something. However, I really am trying to be constructive.

To go a bit further, it’s the sorting for the purpose of duplicate detection that really bothers me because the cost of implementation of that can be a bit high. It might require sorting variable length chunks of memory in RAM (by comparison, the smallest-possible length / int encoding is not difficult to implement). 

You can do duplicate detection on the COSE headers efficiently even if the input is not sorted. When initialize the key, IV and other header vars to empty. If you try to set one that is not empty you can error out.  I think maybe sorting while encoding might be more complex than doing duplicate detection on an unsorted map during decoding.

LL

> On May 30, 2018, at 12:10 PM, Carsten Bormann <[email-masked]> wrote:
> 
> Hi Laurence,
> 
> thank you for bringing this subject up again.
> 
> In 2013, we knew what we were up to when we wrote the original section 3.9 of RFC 7049.
> Essentially, canonicalization (14n) is a mine field where the only way to win is to not play.
> 
> However, we got a few things right, I think:
> 
> (1) we acknowledged that c14n is to a certain extent application-specific.  So the RFC gives some guidance, but does not define a single hard and fast set of rules.
> 
> (2) the serialization provides little intrinsic incentive for gratuitous variation.  Apart from definite vs. indefinite lengths (which is an example of something that depends on application requirements), the obvious rule to use the shortest of several possible encodings is natural and easy to implement.  [One design alternative, to only ever allow the shortest encoding, is problematic for some other applications.]  Implementations already do this naturally (except sometimes for floating point — implementers of serialization layers often know little about floating point and are rightfully scared by it.  That’s why we have the example code in the appendix… and it is easy to do exhaustive testing at least for binary16!).
> 
> We also got one thing extremely wrong:
> 
> (A) the canonical ordering for keys based on lengths first, then byte-wise lexicographical order, is violating the principle of least surprise and poses some performance disadvantages.  This probably should be fixed to pure byte-wise lexicographical order.  Applications that already have decided to use the existing map order guidance can do that by invoking (1) above.
> 
> 
> So what are the use cases?  Signing information expressed at the data model level is often given as one, but it is not very convincing.  What I consider much more interesting is to be able to do byte-wise comparison of instances to establish a certain degree of data model level equality/inequality.  This is really useful for testing and for matching information in a database.
> 
> Several of the 50 implementations of CBOR listed at cbor.io do some form of c14n, sometimes as an add-on.  (E.g., for cbor-ruby, there is a separate gem cbor-canonical that provides canonical encoding.  There is no decode checker — you check by canonical-encoding again and then doing a bytewise comparison.)  I never got around to collecting feature lists for the implementations on cbor.io, so I don’t know how many of them do canonical.
> 
> 
> We discussed c14n in some detail at IETF 101.
> Please search for “c14n” in:
> https://datatracker.ietf.org/meeting/101/materials/minutes-101-cbor-00
> and read up to “implementation matrix”.
> 
> While we didn’t make a final determination at the meeting, it seems to me that the best way forward is to keep c14n at the “proposed standard” level, by splitting it out to a separate document, while the rest of CBOR goes to Internet Standard.  This also reflects the lower levels of implementation experience we have with c14n, and the desire to fix the map order.
> 
>> Here’s a few ideas for what to do:
>> 
>> #1 Require all integers and lengths to always be in shortest form and always the same.
> 
> We already do this for c14n.  (Do you mean to always require this?  Not so sure about that.)
> 
>> Do the same for floating point,
> 
> (But only weakly so for floating point.)
> 
>> dates and as many other of the types defined in the spec as possible.  
> 
> These often have way more application semantics than you can handle in a generic canonicalizer.
> Try canonicalizing URIs, Regexps, etc.  Do you canonicalize RFC 3339 dates to UTC?
> I think we have to be open about the limitations of what can be done here.
> 
>> For a lot of data types, this is not that hard to implement and it eliminates a variability in the spec that seems unnecessary. Then you don’t have to define a canonical format for these types. They are always canonical.
> 
> I sure like that approach.
> 
>> #2 If not #1, then make a clear subsection of the document that sharply defines the canonical format for all data types that have multiple representations. This is specially called “Canonical CBOR” and anyone claiming to implement it, MUST implement all aspects of it.  We also highly recommended that every implementation use it.  Move this to section 3 so it is not in the recommendations for creating protocols.
> 
> That would be the separate document proposed above?
> 
>> Leave the sorting order and use of definite lengths requirements out of this section because they are costly to implement.
> 
> Er, now you lost me.
> 
>> #3 Rename section 4.9 to something like “recommendations for uniform CBOR” (or “invariant”, or “consistent” CBOR). This text is non-normative recommendations only. The sorting order can be part of this.
> 
> “Consistent CBOR” sounds good to me.  (As a name for the new version with the fixed map sorting order…)
> 
>> Basically, the less work we leave to CBOR protocol designers, the better. It’ll be easier for protocol designers to do there work, they’ll get it right more often and there’ll be less interop problems.
> 
> I can’t argue with that.  Prematurely nailing down details can also be very costly, though.
> 
>> Last, I think the names “Canonical Encoded CBOR” and “Strict CBOR Decoding” would be really helpful. 
> 
> With what semantics?
> 
> Grüße, Carsten
>

---

From: Carsten Bormann <[email-masked]>
Date: Tue, 5 Jun 2018 07:25:06 +0200

On Jun 5, 2018, at 02:27, Laurence Lundblade <[email-masked]> wrote:
> 
> This canonicalization seems unnecessary.

Hi Laurence,

we need consistent encoding (“canonicalization”) of those structures that are *not* actually transferred.

In many protocols, we construct signing inputs and other crypto parameters from various sources.  This computation is so much easier to describe (and correctly implement!) if it uses the same encoding machinery that we use for the data that does get transferred.

The difference here is that we can carefully construct (and constrain) these signing inputs so that consistently encoding them becomes trivial.  That’s what COSE did.

Thank you for reminding us that RFC 8152 actually refers normatively to Section 3.9 of RFC 7049.  If we excise that from CBORbis, we need to retain a section about consistent encoding to the level that COSE requires it.  Again, this should be trivial, but we need to do it.

(It is maybe unfortunate that Section 14 of RFC 8152 addresses “encoder restrictions” for both consistent encoding and for the need to avoid duplicate keys in maps.  The latter is not a requirement about consistent encoding — COSE is careful to not use maps in building those crypto input data structures.  Duplicate keys are bad within the actually transferred data structures as well.)

Grüße, Carsten

---

From: Michael Richardson <[email-masked]>
Date: Tue, 05 Jun 2018 10:57:54 -0400

Laurence Lundblade <[email-masked]> wrote:
    > Section 14 requires canonicalization for Sig_structure,  Enc_structure,
    > and MAC_structure.  I interpret this as requiring canonicalization for
    > any / all of the maps in these structures including sorting. I have a
    > few issues with this requirement:

I'm a bit puzzled by this.
Sig_structure, Enc_structure and MAC_structure are CBOR arrays, and the
contents are fully specified.  There aren't any choices, so I don't
understand why we can talk about canonicalization?

    > - This canonicalization seems unnecessary. I just can’t see what could
    > go wrong if you don’t canonicalize. Canonicalize of the payload is not
    > required and that works OK.  It seems like COSE would be better by just
    > deleting section 14.

The restrictions of section 14 seem self-evident, but they seem to be there
just to cover all our bases.

-- 
]               Never tell me the odds!                 | ipv6 mesh networks [ 
]   Michael Richardson, Sandelman Software Works        | network architect  [ 
]     [email-masked]  http://www.sandelman.ca/        |   ruby on rails    [

---

From: Carsten Bormann <[email-masked]>
Date: Tue, 5 Jun 2018 17:09:54 +0200

> On Jun 5, 2018, at 16:57, Michael Richardson <[email-masked]> wrote:
> 
> 

I failed to say in my previous message
https://mailarchive.ietf.org/arch/msg/cbor/EcX4hHT7yKyFsCnwUmcm6eIcH2U
there is a theoretical choice between shortest (e.g., 01) and not-so-short (e.g., 1801 or 190001) encoding of the heads of the items.
There is no good reason to use not-so-short for these internal encodings, so it really is a bit of a theoretical discussion.
But it needs to be officially defined that way…

> just to cover all our bases.

Pretty much so — that’s how the encoding of the structures was chosen.

Grüße, Carsten

---

From: Thiago Macieira <[email-masked]>
Date: Tue, 5 Jun 2018 08:38:03 -0700

On Tuesday, 5 June 2018 08:09:54 PDT Carsten Bormann wrote:
> there is a theoretical choice between shortest (e.g., 01) and not-so-short
> (e.g., 1801 or 190001) encoding of the heads of the items. There is no good
> reason to use not-so-short for these internal encodings, so it really is a
> bit of a theoretical discussion. But it needs to be officially defined that
> way…

Actually, there is. This was exactly the stumbling block I had when attempting 
to implement COSE with a single-pass zero-allocation solution for constrained 
systems. Long story short: I failed and abandoned the project.

One of my attempted solutions was to reserve 5 or 9 bytes (32- or 64-bit) for 
size of the Byte String containing the payload, so the contents could be 
stored elsewhere while calculating the cryptographic data. The idea was to use 
something like struct iovec[3], where the CBOR data would be split into three 
parts: what came before the crypto data and including the data size, the 
crypto data, then what came after.

The requirement to have canonical encoding would have forced me to go back to 
the byte stream and re-encode the length, which in turn changed the length of 
the "pre" block.

PS: since I didn't complete the project, I can't say whether there were 
further problems or solutions I didn't think of.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

---

From: Laurence Lundblade <[email-masked]>
Date: Tue, 5 Jun 2018 15:56:14 +0000

> we need consistent encoding (“canonicalization”) of those structures that are *not* actually transferred.

Ahhh, that’s what I was missing. Thanks for your patience.

LL

---

From: Michael Richardson <[email-masked]>
Date: Tue, 05 Jun 2018 14:09:51 -0400

> systems. Long story short: I failed and abandoned the project.

oh.

    > the byte stream and re-encode the length, which in turn changed the length of 

I see the problem that you had...

It seems that the goal wasn't just single-pass (you didn't have to revisit
the payload!), but being able to stream-write the data out, and not have to
buffer it all in memory before sending.  This would also make it easier to
do things like take some of the content from ROM.

---

From: Thiago Macieira <[email-masked]>
Date: Tue, 5 Jun 2018 11:29:43 -0700

> do things like take some of the content from ROM.

Yes, and it was very difficult to do stream-writing too, another reason for my 
abandoning the project. The structures that are found in the COSE payload are 
similar to but still different from the structures used as additional data for 
the cryptographic routines.

I could not find a way to perform this with zero-allocation streaming.

I don't know if a different protocol design could have done it, but that was 
clearly not a goal for COSE. So I gave up adding support for it in TinyCBOR. 
It's now left for a higher layer to implement.

---

From: Jim Schaad <[email-masked]>
Date: Tue, 5 Jun 2018 15:01:40 -0400

> -----Original Message-----
> From: CBOR <[email-masked]> On Behalf Of Laurence Lundblade
> Sent: Monday, June 4, 2018 8:28 PM
> To: Carsten Bormann <[email-masked]>
> Cc: [email-masked]
> Subject: Re: [Cbor] Canonical CBOR
> 
> Rather than asking about implementations, I should have asked about CBOR-
> based protocol designs that need or benefit from canonicalization.  I’m
> familiar with CWT and COSE so let’s see about canonicalization in them.
> 
> CWT doesn’t require canonicalization and that all seems fine.  The main
> benefit I can see canonicalization bringing is the testing benefit that you
> mention. For the same set of input claims, you can binary compare the
> output of two implementations and know they match (at least that is the
> testing benefit I think you are mentioning).  My feeling is that requiring
> canonicalization for CWT for this reason would not be a good design trade-
> off.
> 
> Section 14 requires canonicalization for Sig_structure,  Enc_structure, and
> MAC_structure.  I interpret this as requiring canonicalization for any / all of
> the maps in these structures including sorting. I have a few issues with this
> requirement:

There are no maps in these structures so there is no requirement for sorting of maps anyplace in the document.

> 
> - This seems at odds with the statement Section 3 especially as the protected
> parts of these structures are bstr wrapped.
> 
> - This canonicalization seems unnecessary. I just can’t see what could go
> wrong if you don’t canonicalize. Canonicalize of the payload is not required
> and that works OK.  It seems like COSE would be better by just deleting
> section 14.

Parts of these structures are not transmitted on the wire and thus doing a bstr wrapping is not helpful to think in terms of it being transmitted.

The canonization done for COSE is very limited.  It looks a arrays, text strings (of a set of well-known constants) and binary strings.  Doing canonicalization on this set of things is not only easy but not controversial.  There is a re-iteration of don't do duplicate headers which is a general problem and is stated several times.

> 
> It feels like maybe this was put in when there was some thinking that
> canonicalization was good for signing, but now that turned out not to be
> true? Pardon if I’m dense and missing something. However, I really am trying
> to be constructive.
> 
> 
> To go a bit further, it’s the sorting for the purpose of duplicate detection that
> really bothers me because the cost of implementation of that can be a bit
> high. It might require sorting variable length chunks of memory in RAM (by
> comparison, the smallest-possible length / int encoding is not difficult to
> implement).
> 
> You can do duplicate detection on the COSE headers efficiently even if the
> input is not sorted. When initialize the key, IV and other header vars to
> empty. If you try to set one that is not empty you can error out.  I think
> maybe sorting while encoding might be more complex than doing duplicate
> detection on an unsorted map during decoding.
> 
> LL
> 
> 
> 
> 
> 
> > (1) we acknowledged that c14n is to a certain extent application-specific.
> So the RFC gives some guidance, but does not define a single hard and fast
> set of rules.
> >
> > (2) the serialization provides little intrinsic incentive for gratuitous variation.
> Apart from definite vs. indefinite lengths (which is an example of something
> that depends on application requirements), the obvious rule to use the
> shortest of several possible encodings is natural and easy to implement.
> [One design alternative, to only ever allow the shortest encoding, is
> problematic for some other applications.]  Implementations already do this
> naturally (except sometimes for floating point — implementers of
> serialization layers often know little about floating point and are rightfully
> scared by it.  That’s why we have the example code in the appendix… and it is
> easy to do exhaustive testing at least for binary16!).
> >
> > (A) the canonical ordering for keys based on lengths first, then byte-wise
> lexicographical order, is violating the principle of least surprise and poses
> some performance disadvantages.  This probably should be fixed to pure
> byte-wise lexicographical order.  Applications that already have decided to
> use the existing map order guidance can do that by invoking (1) above.
> >
> >
> > So what are the use cases?  Signing information expressed at the data
> model level is often given as one, but it is not very convincing.  What I
> consider much more interesting is to be able to do byte-wise comparison of
> instances to establish a certain degree of data model level
> equality/inequality.  This is really useful for testing and for matching
> information in a database.
> >
> > Several of the 50 implementations of CBOR listed at cbor.io do some form
> of c14n, sometimes as an add-on.  (E.g., for cbor-ruby, there is a separate
> gem cbor-canonical that provides canonical encoding.  There is no decode
> checker — you check by canonical-encoding again and then doing a bytewise
> comparison.)  I never got around to collecting feature lists for the
> implementations on cbor.io, so I don’t know how many of them do canonical.
> >
> >
> > While we didn’t make a final determination at the meeting, it seems to me
> that the best way forward is to keep c14n at the “proposed standard” level,
> by splitting it out to a separate document, while the rest of CBOR goes to
> Internet Standard.  This also reflects the lower levels of implementation
> experience we have with c14n, and the desire to fix the map order.
> >
> >> For a lot of data types, this is not that hard to implement and it eliminates
> a variability in the spec that seems unnecessary. Then you don’t have to
> define a canonical format for these types. They are always canonical.
> >
> >> #2 If not #1, then make a clear subsection of the document that sharply
> defines the canonical format for all data types that have multiple
> representations. This is specially called “Canonical CBOR” and anyone claiming
> to implement it, MUST implement all aspects of it.  We also highly
> recommended that every implementation use it.  Move this to section 3 so it
> is not in the recommendations for creating protocols.
> >
> >> Leave the sorting order and use of definite lengths requirements out of
> this section because they are costly to implement.
> >
> > Er, now you lost me.
> >
> >> #3 Rename section 4.9 to something like “recommendations for uniform
> CBOR” (or “invariant”, or “consistent” CBOR). This text is non-normative
> recommendations only. The sorting order can be part of this.
> >
> >> Basically, the less work we leave to CBOR protocol designers, the better.
> It’ll be easier for protocol designers to do there work, they’ll get it right more
> often and there’ll be less interop problems.
> >
> _______________________________________________
> CBOR mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/cbor

---

From: Jim Schaad <[email-masked]>
Date: Tue, 5 Jun 2018 15:03:46 -0400

> From: CBOR <[email-masked]> On Behalf Of Carsten Bormann
> Sent: Tuesday, June 5, 2018 1:25 AM
> To: Laurence Lundblade <[email-masked]>
> Cc: [email-masked]
> In many protocols, we construct signing inputs and other crypto parameters
> from various sources.  This computation is so much easier to describe (and
> correctly implement!) if it uses the same encoding machinery that we use for
> the data that does get transferred.
> 
> The difference here is that we can carefully construct (and constrain) these
> signing inputs so that consistently encoding them becomes trivial.  That’s
> what COSE did.
> 
> Thank you for reminding us that RFC 8152 actually refers normatively to
> Section 3.9 of RFC 7049.  If we excise that from CBORbis, we need to retain a
> section about consistent encoding to the level that COSE requires it.  Again,
> this should be trivial, but we need to do it.

For the level of canonization that is required by RFC 8152, it matters not which canonical encoding is referred to and could be cut into a revision of that document in the future if really needed.

Jim

> 
> (It is maybe unfortunate that Section 14 of RFC 8152 addresses “encoder
> restrictions” for both consistent encoding and for the need to avoid duplicate
> keys in maps.  The latter is not a requirement about consistent encoding —
> COSE is careful to not use maps in building those crypto input data structures.
> Duplicate keys are bad within the actually transferred data structures as
> well.)
> 
> Grüße, Carsten
>

---

From: Laurence Lundblade <[email-masked]>
Date: Wed, 6 Jun 2018 04:49:14 +0000

In 5.3, the COSE Enc_structure includes:

    protected : empty_or_serialized_map

This  is described as:

   The protected attributes from the body structure encoded in a bstr type.    

I assume these are protected headers parameters as described in section 3. The ones that are part of the Headers in the COSE_Encrypt that will specify the alg. (It's a bit confusing because of the use of the word "attribute"; section 3 mostly refers to them as "parameters").

My question is:  does the canonicalization requirement apply to the protected headers because they are included in the Enc_structure?  Do protected headers have to be sorted? 

My first thought was "yes", but thinking some more, they are transmitted and they are bstr wrapped, so probably "no". Thus, there is very little to canonicalize in the Enc_strucutre. 

Sound right?

LL

________________________________________
From: Michael Richardson <[email-masked]>
Sent: Tuesday, June 5, 2018 7:57 AM
To: [email-masked]; Laurence Lundblade
Subject: Re: [Cbor] Canonical CBOR

---

From: Kio Smallwood <[email-masked]>
Date: Wed, 06 Jun 2018 11:17:13 +0100

Speaking as someone who has implemented canonical encoding, I did so
without knowing what I could use it for, assuming that the need for it
would become clear in time as more CBOR-based protocols used it. 

I had originally considered using canonical encoding to create a file
encryption header similar to https://github.com/diafygi/myLock  which
uses JSON as the file header format. However since it is good practice
to use authenticated encryption or encrypt-then-mac on the serialized
header, the order of keys in the header is not significant. The content
of an encrypted file header would be unique every time the file was
re-encrypted since a new ephemeral key would be used. 

In the cbor2 python implementation, canonicalizing dictionaries doubles
the memory for the keys (we have to maintain a sorted list of encoded
keys) but leaves the values alone. It also makes iterating through the
collection less efficient, since Python has special methods that iterate
through key-value pairs in a single operation which we can't use on
canonical maps. Duplicate keys are also not an issue for dynamic
languages since they will simply use the last value encountered. 

Hope that helps. 

Kio 

On 2018-05-30 17:06, Laurence Lundblade wrote:

> To be a bit direct here, canonical CBOR seems only about 2/3 baked to me. I have a couple of ideas on what to do about and may volunteer to write some text, but first I want to ask about use cases for it.  I've seen some described, but they really aren't compelling to me.
> 
> I think the important question is this: has anyone actually implemented it and put it to use? 
> 
> One use case mentioned is to be able to reconstruct the encoded CBOR to verify a signature after decoding. If that is to be supported we should specify canonical encoding for every type in the RFC. Right now there is a good specification for some types (integers), but only suggestions for others (floating point). 
> 
> Another use case is that map sorting allows for fast detection of duplicate labels. I don't know why duplicate detection is needed. If you can't trust the sender and/or transport to not add duplicates, you can't really trust them to not make other worse mistakes. 
> 
> But the real question is about implementations. If now one has implemented in the years that 7049 has been around it seems questionable.
> 
> Here's a few ideas for what to do:
> 
> #1 Require all integers and lengths to always be in shortest form and always the same. Do the same for floating point, dates and as many other of the types defined in the spec as possible.  For a lot of data types, this is not that hard to implement and it eliminates a variability in the spec that seems unnecessary. Then you don't have to define a canonical format for these types. They are always canonical.
> 
> #2 If not #1, then make a clear subsection of the document that sharply defines the canonical format for all data types that have multiple representations. This is specially called "Canonical CBOR" and anyone claiming to implement it, MUST implement all aspects of it.  We also highly recommended that every implementation use it.  Move this to section 3 so it is not in the recommendations for creating protocols. Leave the sorting order and use of definite lengths requirements out of this section because they are costly to implement.
> 
> #3 Rename section 4.9 to something like "recommendations for uniform CBOR" (or "invariant", or "consistent" CBOR). This text is non-normative recommendations only. The sorting order can be part of this. 
> 
> Basically, the less work we leave to CBOR protocol designers, the better. It'll be easier for protocol designers to do there work, they'll get it right more often and there'll be less interop problems.
> 
> Last, I think the names "Canonical Encoded CBOR" and "Strict CBOR Decoding" would be really helpful. 
> 
> LL
>

---

From: Jim Schaad <[email-masked]>
Date: Wed, 6 Jun 2018 07:39:44 -0400

> Sent: Wednesday, June 6, 2018 12:49 AM
> To: Michael Richardson <[email-masked]>; [email-masked]
> I assume these are protected headers parameters as described in section 3.
> The ones that are part of the Headers in the COSE_Encrypt that will
specify
> the alg. (It's a bit confusing because of the use of the word "attribute";
> section 3 mostly refers to them as "parameters").
> 
> My question is:  does the canonicalization requirement apply to the
> protected headers because they are included in the Enc_structure?  Do
> protected headers have to be sorted?
> 
> My first thought was "yes", but thinking some more, they are transmitted
> and they are bstr wrapped, so probably "no". Thus, there is very little to
> canonicalize in the Enc_strucutre.

No they do not because of the bstr wrap.  This was done specifically so that
the map was not needed to be canonically encoded but to be used as
transported.

Jim

> LL
understand
> why we can talk about canonicalization?
> 
>     > - This canonicalization seems unnecessary. I just can't see what
could
>     > go wrong if you don't canonicalize. Canonicalize of the payload is
not