Coder Social home page Coder Social logo

Comments (11)

peterbourgon avatar peterbourgon commented on July 18, 2024 2

So, Coze defines iat and rvk as integers, and assumes implementations are able to represent those values as integers to at least 2^53-1. That's fine! Just throw it in the docs and all good.

from coze.

peterbourgon avatar peterbourgon commented on July 18, 2024 1

This specification allows implementations to set limits on the range and precision of numbers accepted. Since software that implements IEEE 754 binary64 (double precision) numbers (IEEE754) is generally available and widely used, good interoperability can be achieved by implementations that expect no more precision or range than these provide . . .

Note that when such software is used, numbers that are integers and are in the range [-(253)+1, (253)-1] are interoperable in the sense that implementations will agree exactly on their numeric values.

If you want to make this assumption, that's fine! Just worth some documentation :)

from coze.

peterbourgon avatar peterbourgon commented on July 18, 2024 1

When I receive the JSON string {"iat":1680217459} it is not guaranteed that my in-memory value of iat will be precisely the uint32/uint64 integer 1680217459. If I model iat as a int16 it may be 65535, if I model it as a float64 it may be 1680217459.0001. So when I generate the sign bytes there is no guarantee that I will re-create {"iat":1680217459} precisely, I could generate {"iat":65535} or {"iat":1680217459.000} or {"iat":1680217459.0000009} or whatever else and it would be totally JSON valid. JSON numbers are always approximations. If you want reliably reproducible values you can't use numbers. Strictly speaking.

from coze.

zamicol avatar zamicol commented on July 18, 2024

The spec currently reads for rvk:

Coze requires rvk to be an integer with a maximum value of 9,007,199,254,740,991 (2^53 – 1), which is Javascript's MAX_SAFE_INTEGER. Checking for revoked when rvk's value is a non-integer or value past MAX_SAFE_INTEGER must error.

The Go implementation currently does not apply this rule (and probably should).

The numbers section from the RFC says:

Note that when such software is used, numbers that are integers and
   are in the range [-(2**53)+1, (2**53)-1] are interoperable in the
   sense that implementations will agree exactly on their numeric
   values.

I believe that works and I don't think time values needs to be a string. As long as the integer is smaller than 2^53 – 1 it would generally consider it to be interoperable. Most modern systems use 64 bits for Unix timestamps and those that don't are migrating to 64 bits.

I think a good change would be for Coze to define iat with the same constraints as rvk.

from coze.

zamicol avatar zamicol commented on July 18, 2024

It seems that this is from the discussion on Lobste.rs

As far as rvk and iat, I think the above covers that well.

Yes, it would be ideal for Coze to be bijective, but we may consider it outside
of our purview. Systems that do weird things with JSON may not expect to be
interoperable or bijective with other systems and constraining JSON in such a way could fall
outside the scope of Coze. We can however rigidly apply requirements to fields
that Coze defines.

Alternatively, we can just apply the I-JSON standard, which
includes good constraints on numbers. Bray has a lot of great advice for best practices for JSON.

from coze.

zamicol avatar zamicol commented on July 18, 2024

@peterbourgon, I've followed your works for a while and I'm thrilled that Coze has interested you. Thank you!

I'm re-reading the I-JSON spec at the moment. It might be a good idea for Coze to apply it entirely.

from coze.

peterbourgon avatar peterbourgon commented on July 18, 2024

I mean, the easiest solution here is to represent your times not as integer UNIX seconds-since-epoch, but as string RFC3339 timestamps as UTC. What's the downside?

from coze.

zamicol avatar zamicol commented on July 18, 2024

I might be missing something. What's wrong with a Unix timestamp, UTC?

Cozies are UTF-8 encoded. {"iat":1680217459} always encodes as the same byte string which is what is signed.

from coze.

zamicol avatar zamicol commented on July 18, 2024

Coze implicitly assumes that systems can at least represent 32 bit numbers by
defining iat and rvk as integer Unix time stamps. The
Go
and Javascript implementations both use sufficiently large integers internally
when storing the timestamp. Presently, any system that's capable of representing
32 bit numbers is compatible with cozies that use current time Unix timestamps.
In the future systems suffering from the Year 2038 problem may experience issues,
but that's not a problem specific to Coze.

This is only an issue for implementers that do not internally use a lossless
datatype for 32 bit integers. We could require Coze to specify system must
support integers up to 9,007,199,254,740,991 (2^53 – 1) for rvk and iat. I
believe that would resolve the bijective encoding concerns for all reasonable
timestamps. Implementations that don't have a 53 bit integer type available can
simply internally store those integers as strings, but that doesn't have to be
something specified by Coze as that is a problem for the implementations to
resolve.

So to summarize, we can add this line to the spec:

`iat` and `rvk` must be an integer of value up to 9,007,199,254,740,991 (2^53 – 1).

rvk I believe already meets these requirements, at least implicitly. The
constraint just needs to be expanded to include iat.

from coze.

zamicol avatar zamicol commented on July 18, 2024

Concerning only iat, there is another concern that we came across today.

Function Verify may verify a digest that over a pay with an
invalid iat and there is no way to know. This means VerifyCoze and Verify
will have inconsistent behavior for the same payload. For this reason, I think
it's a bad idea to require iat to adhere to the MAX_SAFE_INTEGER rule and
instead the specification can specify iat "should adhere" to the rule.

It's easy to implement the "iat must be less than 2^53 - 1" rule. The check can exist in func (p *Pay) UnmarshalJSON(b []byte) error, which is then called by VerifyCoze()

const MAX_SAFE_INTEGER = 9007199254740992
...
if iat > MAX_SAFE_INTEGER{
	return fmt.Errorf("UnmarshalJSON: iat value over 2^53 - 1 (9,007,199,254,740,991)")
}

The difference boils down to Coze interpreting iat, which seems overbearing,
while requiring interpreting rvk seems reasonable. For revoke messages, rvk
is always known and checkable, so a "must adhere" continues to seem reasonable.
Critically, a "must" for rvk ensures systems agree what keys are revoked. For
iat, if system verify digest only messages (they might not even have access to
the original payload), there is no way to tell. Downstream system need to be
aware of this difference between iat and rvk and appropriately handle this
edge case if they desire a "must adhere" for iat. I don't think hiding this complexity in Coze libraries is the
correct answer for iat.

In view of the above, the Coze specification should be updated with the following:

`rvk` must and `iat` should be an integer less than 9,007,199,254,740,991 (2^53
– 1), which is the integer precision limit specified by IEEE754 minus one.
Revoke checks must error if `rvk`'s is not an integer or larger than 2^53 - 1.

More generally, Coze must make no rule requiring any sort of interpretation of
the contents of pay. alg and tmb are the only exceptions since this
information must be at least implicitly known by Verify. No other information is needed to verify a given digest.

from coze.

zamicol avatar zamicol commented on July 18, 2024

This is addressed by commit e279528 and I consider this concern resolved.

from coze.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.