This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 29139 - Allow specifying numbers in place of BigInteger?
Summary: Allow specifying numbers in place of BigInteger?
Status: RESOLVED MOVED
Alias: None
Product: Web Cryptography
Classification: Unclassified
Component: Web Cryptography API Document (show other bugs)
Version: unspecified
Hardware: PC All
: P2 minor
Target Milestone: ---
Assignee: Ryan Sleevi
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-22 18:50 UTC by Eric Roman
Modified: 2016-05-24 00:35 UTC (History)
3 users (show)

See Also:


Attachments

Description Eric Roman 2015-09-22 18:50:27 UTC
This is feature request to re-define BigInteger from:
  typedef Uint8Array BigInteger;
To:
  typedef (unsigned long or Uint8Array) BigInteger


Motivation:

Often small valued numbers are passed in places that take a BigInteger.

For instance 65537 is a common value for publicExponent when generating RSA keys. Currently callers need to express this as:

   publicExponent: new Uint8Array([0x01, 0x00, 0x01])

Whereas it would be simpler if they could write:

   publicExponent: 65537

This is strictly a convenience wrapper, as was added to some other WebCrypto types.

This feature request was lifted from:
  https://github.com/w3c/webrtc-pc/issues/310

In which WebRTC has a spec bug where they use the simplified (unsupported) syntax

In terms of compatibility, if this change were adopted by WebCrypto it would not break existing usages of the API. However it would obviously cause problems if support was not universal across implementations, since using the numeric flavor might fail.
Comment 1 Ryan Sleevi 2015-09-22 19:08:23 UTC
(In reply to Eric Roman from comment #0)
> This is feature request to re-define BigInteger from:
>   typedef Uint8Array BigInteger;
> To:
>   typedef (unsigned long or Uint8Array) BigInteger

I think this would be a very dangerous change, and not desirable, even though appealing for a convenience wrapper.

Because such a type would go through normalization in the JS<->WebIDL conversion, it would also allow things like "65537" or "no" to be accepted as inputs, or perhaps even more confusingly, { "toString": function() { return "0"; } }.

This is because of the ToNumber(v) step in http://heycam.github.io/webidl/#es-unsigned-long . "no" would be NaN, which would raise a TypeError in this specific case, while "65537" would be directly converted.

It's also of questionable utility that a generic BigInteger should be convertible from a Number, given the precision issues that various ES implementations have (although admittedly, perhaps those issues are resolved in ES5/ES6, and I'm operating on old knowledge). As it relates to WebCrypto's usage, it only really seems to come up with publicExponent - the prime/base of the DhKeyGenParams / DhKeyAlgorithm / DhImportParams don't lend themselves to expressions as Numbers (they're necessarily large integers)

The publicExponent for RSA is the interesting one, because that's the only real place this would be useful. Unfortunately, the API itself is quite dangerous here that it's exposed directly as a BigInteger. In hindsight, it may have made more sense to do an enum of the Fermat primes (65537 is also known as F_4 in many implementations). The shape of the API was driven by the at-the-time concern of the need to support smart cards / existing crypto, which necessitated support for F_1 (aka 3), although using 3 as the exponent for an RSA key makes Bleichenbacher's Attack a more pen-and-paper exercise ( http://cryptopals.com/sets/6/challenges/42/ ). Alternatively, leaving publicExponent as an unsigned long (since 65537 is the only sane value) would also have made sense.

But I don't support changing the definition of BigInteger as a whole. I think that just makes the bad situation worse.
Comment 2 Boris Zbarsky 2015-09-22 19:30:16 UTC
> "no" would be NaN, which would raise a TypeError in this specific case,

Only if the IDL specified [EnforceRange].  Otherwise NaN becomes 0.
Comment 3 Eric Roman 2015-09-22 20:04:42 UTC
Thanks for the response Ryan!

I agree this may be more relevant to just publicExponent rather than BigInteger in its general use. I am also fine with leaving things as they are for the resolution.

That said I think the argument for disallowing it is inconsistent with our use of numbers elsewhere in WebCrypto.

 > "it would also allow things like "65537" or "no" to be accepted as inputs,"

Correct.

I agree with you this is completely bonkers. Nevertheless this is idiomatic Ecmascript/WebIDL, and a behavior that callers expect. Moreover it is a behavior that WebCrypto inherits elsewhere for places that take numbers.

If we are going to argue that Ecmascript/WebIDL deals with numbers poorly (which I wholeheartedly agree with), then we need to look carefully at other places which already inherit this unsafe behavior for security critical parameters.

Why should it be OK for other parameters to have this unsafe behavior, and yet not BigInteger?

For instance key lengths, modulus sizes, a KDF's iterations, salt length, etc are all taken as numbers, and can be abused in the same manner. Should we not then disallow unsafe integer casting here too? For instance if you call PBKDF2 with "iterations: false" implementations will happily set iterations to 1. Or worse if you call "iterations: null", we will set iterations=0 (in fact I need to follow-up on this behavior in implementations...)

Admittedly supporting a union allows for more incorrect usages (all the ways Ecmascript's ToNumber() lets you shoot a hole in your foot). The one that concerns me more is the handling of null, since it seems an easy mistake to pass an (accidentally) null uint8array, and now that would be auto-magically interpreted as 0.
Comment 4 Ryan Sleevi 2015-09-22 20:19:05 UTC
(In reply to Eric Roman from comment #3)
> Why should it be OK for other parameters to have this unsafe behavior, and
> yet not BigInteger?

So, while I agree "JS Numbers are awful" (at least, from my POV, which is often wrong), a big motivation here with the explicit BigInteger type not having numeric conversions was about ensuring a consistent developer experience about "When is the right time to use a primitive Number versus a BigInteger". That is, how does one know that "65537" will not run in to any conversion issues with an implementation (ok, this is a bad example, but given the definition of Number from ES6 is http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-number-value , it is a valid concern about 'integral' representations)

The design consideration for "When to use a number" and "When to use a BigInteger" - relevant for examples like key size vs exponent - was predicated based on "What is most aligned to the underlying type". In this case, since the RSA exponent is arbitrary precision, it was exposed as such, 'even though' the most commonly-used values will be within the range of an [EnforceRange]'d unsigned long.

I won't lie, in many ways, I tried to suggest a design that was most aligned to the underlying types, rather than an opinionated design. That's because my opinions are usually awful, but I also feel the same way about the opinions of most cryptography API designers, and since we were going for something at the 'subtle', low-level, 'correct' API, I erred on the side of type accuracy rather than developer convenience.

While I think WebRTC's exposure of/reuse of AlgorithmIdentifier is perhaps *too* low-level for their use case (especially as they suggest MTI), my hope is that in practice, few developers actually run in to these issues, as they are handled by libraries that compose the underlying subtle primitives into safe, easy to use constructs appropriately narrow for the use cases and users of said libraries.
Comment 5 Mark Watson 2016-05-24 00:35:59 UTC
Moved to https://github.com/w3c/webcrypto/issues/83