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 29437 - Parsing a JWK can have side-effects if not done very carefully
Summary: Parsing a JWK can have side-effects if not done very carefully
Status: RESOLVED MOVED
Alias: None
Product: Web Cryptography
Classification: Unclassified
Component: Web Cryptography API Document (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Mark Watson
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-08 22:18 UTC by Boris Zbarsky
Modified: 2016-05-24 00:41 UTC (History)
2 users (show)

See Also:


Attachments

Description Boris Zbarsky 2016-02-08 22:18:51 UTC
The algorithm in https://www.w3.org/TR/WebCryptoAPI/#concept-parse-a-jwk will, if executed in the page global, generally run getters from Object.prototype for any fields missing in the JSON during the IDL dictionary type conversion.  Is this the intended behavior?  Or is the intent that this parsing happens in some global other than the page global, where things like this won't be observable?  Clearly defining this, either way, would be a good idea.
Comment 1 Ryan Sleevi 2016-02-08 23:13:35 UTC
Latest ED is https://github.com/w3c/webcrypto

The intent was without depending on any external state (including the page global), hence the distinction of "internal function" trying to clarify, but apparently, poorly. Any suggestions for how to clarify that global? (The best answer I got from the Chrome folks was just hand-wave and say "internal function for everything")
Comment 2 Boris Zbarsky 2016-02-09 01:46:39 UTC
As in bug 29438, Gecko currently implements this by doing the JSON.parse and then the conversion from an object to a dictionary in a clean global.

Another option is to do JSON.parse in the normal global (or really any global of your choice), but create all the objects and arrays involved with null prototypes instead of Object.prototype.

I think these options are black-box distinguishable from each other if the JSON has an object where our dictionary expects a string, because String(Object.create(null)) throws, while String(Object.create(Object.prototype)) does not.

Speccing the null prototype thing might be a little more difficult because http://www.ecma-international.org/ecma-262/6.0/#sec-json.parse step 5 is a bit hard to monkeypatch.  It's possible that a black-box-identical effect could be produced with a carefully written reviver function, though (and UAs would be free to optimize if desired).

I'm somewhat interested in _not_ requiring creation of a separate global here, honestly...  It seems like a good bit of overhead for no particularly good reason.
Comment 3 Ryan Sleevi 2016-02-09 02:02:05 UTC
(In reply to Boris Zbarsky from comment #2)
> I'm somewhat interested in _not_ requiring creation of a separate global
> here, honestly...  It seems like a good bit of overhead for no particularly
> good reason.

The carefully written reviver function would be black-box indistinguishable from a separate global, right?

(Apologies, I don't fully understand the intricacies of the JS state at play here)

The main goal was to ensure that the JWK handling (for wrapping or unwrapping) didn't require a round-trip back into the caller's script, since they may (or the JWK sender may) have sent with an extractable=false, and a round-trip through user code/state would end up violating that.

Well, that, and to fully ensure that the JWK handling could be fully run on another thread (or more aptly, arbitrary threads) without having to worry about blocking on the main task loop of the page.
Comment 4 Boris Zbarsky 2016-02-09 02:13:49 UTC
The carefully written reviver function I've though of so far would be black-box indistinguishable from giving all the dictionaries and arrays null prototypes.  At least I think I can do that with a reviver function.

It's possible we could come up with a carefully written reviver function that is black-box indistinguishable from a separate global, but I haven't managed to come up with such a beast yet, even prospectively.

I agree with your goals: ideally the black-box behavior here would be something that could run wherever you feel like...
Comment 5 Boris Zbarsky 2016-03-03 18:03:44 UTC
I was wrong: there is no way to create a carefully written reviver function that is black-box indistinguishable from a separate global.  In fact, even the null prototypes approach is black-box distinguishable from a separate global (more on this below).  Also, the null prototypes approach can't handle a JsonWebKey that has an "oth" or "key_ops" property, as far as I can tell: a null proto on the array would mean that conversion to sequence would fail because it would not be iterable, because the Symbol.iterator lives on Array.prototype.  And you can't even put it on the instance because the array iterator prototype would still be under control of whoever controls the global...

Anyway, for the basic black-box distinguishability bits, consider this JSON:

  { "crv": {} }

If we create objects as normal and then init a JsonWebKey with this object, we will get "[object Object]" for crv.  If we create objects with null prototypes, we will get an exception instead.  This is mostly a theoretical problem, I think, though I did not examine all the string members of JsonWebKey.  The array problem is a bigger deal.
Comment 6 Mark Watson 2016-05-24 00:41:44 UTC
Moved to https://github.com/w3c/webcrypto/issues/87