Subject: [jose] Question about minimual unsigned big endian representation of JWK parameters

From: "Berry, Matt" <[email-masked]>
Date: Mon, 14 Apr 2014 21:35:59 +0000

Throughout JWA Section 6.3 "Parameters for RSA Keys" the following phase occurs repeatedly:

> The octet sequence MUST utilize the minimum number of octets to represent the value.

I understand the rationale for such a phase, which is to minimize the overall size of JWKs. 
This is a core tenant of the JSOE working group. However I have concerns about the practice
of striping leading zeroes from RSA parameters.

The benefit of stripping these leading zeroes is likely negligible. Consider this RSA key I 
just generated (included below). The total benefit of stripping the leading zeroes is 5 bytes 
before base64 encoding.

Although I believe the attempt to reduce the overall size of the JWK is commendable, I think
this will introduce more confusion and non-compliance than anything. An example would be
Google, who currently does not strip the leading zeroes (or even base64url-encodes).

> https://www.googleapis.com/oauth2/v2/certs

I suggest rewording relevant sections to the following, to allow for the minimum amount of
padding octets required to make the keys unambiguous.

> The octet sequence MUST utilize the minimum number of octets to represent the value 
> as if it was a signed integer.

Sincerely,
Matt Berry

== The referenced RSA Private key. ==

Generating RSA private key, 2048 bit long modulus
.........................................................+++
..................................+++
e is 65537 (0x10001)
Private-Key: (2048 bit)
modulus:
    00:ba:5c:82:f9:26:34:e3:4b:e3:d2:d4:81:5a:c6:
    ...
publicExponent: 65537 (0x10001)
privateExponent:
    00:9d:23:3c:5c:90:d6:af:81:62:0c:77:9a:ca:cb:
    ...
prime1:
    00:ee:b8:c9:5f:ca:8d:9e:1a:a8:9b:6c:34:2f:c4:
    ...
prime2:
    00:c7:d9:8d:57:17:6c:a4:46:1a:9a:c0:2d:93:da:
    ...
exponent1:
    54:c8:b4:5c:9d:27:e6:fb:38:de:da:73:3e:74:08:
    ...
exponent2:
    00:c7:7f:c6:f6:5f:ad:d6:37:1d:2b:ca:18:35:76:
    ...
coefficient:
    74:a4:07:7c:4f:04:be:40:62:2e:af:ff:37:b5:9d:
    ...
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

---

From: Mike Jones <[email-masked]>
Date: Mon, 14 Apr 2014 21:48:42 +0000

According to a crypto expert who spoke up at an in-person JOSE meeting when this was discussed (I think it was Russ Housley), the high-order bit of a correctly formed RSA mantissa must always be 1.  (If it weren't then the key pair would contain less than the required number of bits of information.)  Thus, there are no leading zeroes to strip, for what it's worth.

Also the value is unsigned, not signed.

				Best wishes,
				-- Mike

-----Original Message-----
From: jose [mailto:[email-masked]] On Behalf Of Berry, Matt
Sent: Monday, April 14, 2014 2:36 PM
To: [email-masked]
Subject: [jose] Question about minimual unsigned big endian representation of JWK parameters

I understand the rationale for such a phase, which is to minimize the overall size of JWKs. 
This is a core tenant of the JSOE working group. However I have concerns about the practice of striping leading zeroes from RSA parameters.

The benefit of stripping these leading zeroes is likely negligible. Consider this RSA key I just generated (included below). The total benefit of stripping the leading zeroes is 5 bytes before base64 encoding.

Although I believe the attempt to reduce the overall size of the JWK is commendable, I think this will introduce more confusion and non-compliance than anything. An example would be Google, who currently does not strip the leading zeroes (or even base64url-encodes).

> https://www.googleapis.com/oauth2/v2/certs

I suggest rewording relevant sections to the following, to allow for the minimum amount of padding octets required to make the keys unambiguous.

> The octet sequence MUST utilize the minimum number of octets to 
> represent the value as if it was a signed integer.

Sincerely,
Matt Berry

Generating RSA private key, 2048 bit long modulus .........................................................+++
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

_______________________________________________
jose mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/jose

---

From: "Berry, Matt" <[email-masked]>
Date: Mon, 14 Apr 2014 22:52:40 +0000

I wholly agree that the value is both unsigned and should have a one in the highest bit. The trick of it is, when working with unsigned integers, there is a tendency to put and extra zero byte in front so it is not incorrectly interpreted by signed libraries. This was the point in adding the OpenSSL output. These are unsigned values, but OpenSSL still adds a zero to any value with a one in the highest bit.

Although the minimal unsigned representation of a 1024 bit RSA modulus is always 1024 bits, many libraries will encode either 1024 bits or 1032 bits in the case that the highest byte is 8 through f. I argue that following suit costs only a few bytes and that consistency trumps efficiency in this case. It will also reduce the number accidentally incorrect JWKs found in the wild. If an implementer doesn't carefully read and implement the spec, they will likely encode 1032 bits in some cases, an example of which is Google.

> https://www.googleapis.com/oauth2/v2/certs

-Matt

-----Original Message-----
From: Mike Jones [mailto:[email-masked]] 
Sent: Monday, April 14, 2014 2:49 PM
To: Berry, Matt; [email-masked]
Subject: RE: Question about minimual unsigned big endian representation of JWK parameters

				Best wishes,
				-- Mike

-----Original Message-----
From: jose [mailto:[email-masked]] On Behalf Of Berry, Matt
Sent: Monday, April 14, 2014 2:36 PM
To: [email-masked]
Subject: [jose] Question about minimual unsigned big endian representation of JWK parameters

Sincerely,
Matt Berry

-----BEGIN RSA PRIVATE KEY-----
...

---

From: Mike Jones <[email-masked]>
Date: Tue, 15 Apr 2014 00:35:16 +0000

I get your point, but the Google example isn't a good one, because it's not actually a JWK in one other important way as well - the values are base64 encoded, rather than base64url encoded.  (Note the presence of '+' and '/' characters.)

To me this topic seems like a fine place for Postel's Law: "Be liberal in what you accept, and conservative in what you send."  I have no problem with JWT readers that can read malformed input prefixed with extra zeros.  But anyone emitting a key representation should do it in the standard representation.

The standard one is that way both for compactness but also for simplicity.  It would be more complicated to specify rules for when extra zeros need to be prefixed than to not prefix them at all.

<hack>For what it's worth, if you're worried about your implementation of a JWK reader treating the high-order bit incorrectly and you're willing to parse extra zeros, you could always prefix anything received with three bytes of zeros by prefixing the content with "AAAA".</hack>

				Cheers,
				-- Mike

-----Original Message-----
From: jose [mailto:[email-masked]] On Behalf Of Berry, Matt
Sent: Monday, April 14, 2014 3:53 PM
To: [email-masked]
Subject: Re: [jose] Question about minimual unsigned big endian representation of JWK parameters

-Matt

-----Original Message-----
From: Mike Jones [mailto:[email-masked]]
Sent: Monday, April 14, 2014 2:49 PM
To: Berry, Matt; [email-masked]
Subject: RE: Question about minimual unsigned big endian representation of JWK parameters

				Best wishes,
				-- Mike

-----Original Message-----
From: jose [mailto:[email-masked]] On Behalf Of Berry, Matt
Sent: Monday, April 14, 2014 2:36 PM
To: [email-masked]
Subject: [jose] Question about minimual unsigned big endian representation of JWK parameters

Sincerely,
Matt Berry

-----BEGIN RSA PRIVATE KEY-----
...

---

From: Richard Barnes <[email-masked]>
Date: Mon, 14 Apr 2014 22:23:01 -0400

On Mon, Apr 14, 2014 at 8:35 PM, Mike Jones <[email-masked]>wrote:

> I get your point, but the Google example isn't a good one, because it's
> not actually a JWK in one other important way as well - the values are
> base64 encoded, rather than base64url encoded.  (Note the presence of '+'
> and '/' characters.)
>
> To me this topic seems like a fine place for Postel's Law: "Be liberal in
> what you accept, and conservative in what you send."  I have no problem
> with JWT readers that can read malformed input prefixed with extra zeros.
>  But anyone emitting a key representation should do it in the standard
> representation.
>

This is the right answer.  Note the corresponding text in the WebCrypto
spec, which says pretty much the same thing (consume extra 0 octets, but
don't produce them):
"""
The BigInteger typedef is a Uint8Array that holds an arbitrary magnitude
unsigned integer in big-endian order. Values read from the API SHALL have
minimal typed array length (that is, at most 7 leading zero bits, except
the value 0 which shall have length 8 bits). The API SHALL accept values
with any number of leading zero bits, including the empty array, which
represents zero.
"""

--Richard

>
> The standard one is that way both for compactness but also for simplicity.
>  It would be more complicated to specify rules for when extra zeros need to
> be prefixed than to not prefix them at all.
>
> <hack>For what it's worth, if you're worried about your implementation of
> a JWK reader treating the high-order bit incorrectly and you're willing to
> parse extra zeros, you could always prefix anything received with three
> bytes of zeros by prefixing the content with "AAAA".</hack>
>
>                                 Cheers,
>                                 -- Mike
>
> I wholly agree that the value is both unsigned and should have a one in
> the highest bit. The trick of it is, when working with unsigned integers,
> there is a tendency to put and extra zero byte in front so it is not
> incorrectly interpreted by signed libraries. This was the point in adding
> the OpenSSL output. These are unsigned values, but OpenSSL still adds a
> zero to any value with a one in the highest bit.
>
> Although the minimal unsigned representation of a 1024 bit RSA modulus is
> always 1024 bits, many libraries will encode either 1024 bits or 1032 bits
> in the case that the highest byte is 8 through f. I argue that following
> suit costs only a few bytes and that consistency trumps efficiency in this
> case. It will also reduce the number accidentally incorrect JWKs found in
> the wild. If an implementer doesn't carefully read and implement the spec,
> they will likely encode 1032 bits in some cases, an example of which is
> Google.
>
> > modulus:
> According to a crypto expert who spoke up at an in-person JOSE meeting
> when this was discussed (I think it was Russ Housley), the high-order bit
> of a correctly formed RSA mantissa must always be 1.  (If it weren't then
> the key pair would contain less than the required number of bits of
> information.)  Thus, there are no leading zeroes to strip, for what it's
> worth.
>
> represent the value.
> This is a core tenant of the JSOE working group. However I have concerns
> about the practice of striping leading zeroes from RSA parameters.
>
> The benefit of stripping these leading zeroes is likely negligible.
> Consider this RSA key I just generated (included below). The total benefit
> of stripping the leading zeroes is 5 bytes before base64 encoding.
>
> Although I believe the attempt to reduce the overall size of the JWK is
> commendable, I think this will introduce more confusion and non-compliance
> than anything. An example would be Google, who currently does not strip the
> leading zeroes (or even base64url-encodes).
>
> I suggest rewording relevant sections to the following, to allow for the
> minimum amount of padding octets required to make the keys unambiguous.
>