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 26322 - Definitions "algorithm" and "usages" properties of CryptoKey make no sense
Summary: Definitions "algorithm" and "usages" properties of CryptoKey make no sense
Status: RESOLVED FIXED
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: Ryan Sleevi
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-07-13 04:29 UTC by Boris Zbarsky
Modified: 2014-11-08 03:33 UTC (History)
2 users (show)

See Also:


Attachments

Description Boris Zbarsky 2014-07-13 04:29:28 UTC
See thread starting http://lists.w3.org/Archives/Public/public-webcrypto/2014Jul/0053.html
Comment 1 Mark Watson 2014-09-26 15:46:37 UTC
Is this something that WebIDl could or should solve for us ? That is, does (or could) WebIDL provide a pattern that we can just reference ?

What I believe we want to achieve is 
1) from a read / inspection perspective, that the script can treat these attributes as if there were a JS object and Array respectively
2) writing to these attributes or into the object / Array doesn't affect the behaviour of the CryptoKey object or clones of the CryptoKey object. In fact in my view it should throw an exception, but I'm not sure if that is a supported pattern ?

Ideally there would be a way we could define this without having to refer to language-internal concepts like 'internal slots'.

As for issues like when functions on the Object and Array prototypes (which may have been modified by the script) are called during the construction and use of CryptoKey objects, I don't think we much care, except that it should be consistent across implementations (and ideally consistent across different platform objects following similar patterns).

What is the simplest way to achieve that consistency ? The [[exposed_algorithm]] thing seems a little clunky.
Comment 2 Boris Zbarsky 2014-09-26 16:13:53 UTC
If you haven't read https://www.w3.org/Bugs/Public/show_bug.cgi?id=23682#c0 and https://github.com/whatwg/notifications/issues/18#issuecomment-50470249 you probably should.

It sounds like you want a readonly attribute returning an object.  Since it's an attribute, you want to return the same object each time.  You want mutations to that object to not affect your internal state (or possible to just be impossible).

The reason you need the "internal slot" stuff is because the requirement that the same object be returned each time requires you to internally cache this object-to-be-returned somewhere.  That's all an "internal slot" is: some place to put some data.  In this case, your CryptoKey will have two internal slots related to "usages", for example: one for storing the actual usages and one for storing the cached object it created.

If you want to prevent mutations, you can also freeze the JS Array you return, though some people consider this an API antipattern.  Even without this, mutations won't affect your internal state, obviously, but will affect what page JS consumers see if one of them decides to mutate the array.

If/when we add something like [Cached] to Web IDL, the part about storing the cached value will be handled by the IDL itself.  This is what Gecko has right now, for example.  The IDL for "usages" in Gecko is:

  [Cached, Constant, Frozen] readonly attribute sequence<KeyUsage> usages;

Here [Constant] is something akin to the spec's [SameObject], [Cached] is the thing that causes the binding layer to automatically cache the value on get, and [Frozen] means to freeze the array after converting the sequence to a JS value....

That doesn't help you right this second, sadly, since Web IDL doesn't have [Cached] yet, though depending on schedules you could try using it and hoping it grows it by the time you need to be advancing in the process...

> I don't think we much care

_I_ care.  They shouldn't be called!

> and ideally consistent across different platform objects following similar
> patterns

You want consistency with ES built-ins that create arrays, with array literals, and with methods that return sequence values.  That means not calling anything page-observable during creation of the array.
Comment 3 Mark Watson 2014-10-06 16:09:15 UTC
Thanks, that's very helpful.

Regarding the [Cached, Constant, Frozen] approach:
1) Is there a concept of Frozen objects (maps) as well as of Frozen arrays ?
2) Is it important that the JS array / object is created when the attribute is first accessed, rather than when the thing implementing the interface that contains that attribute is created ?

Another approach, I guess, would be to use the new maplike IDL, so then the algorithm attribute would have a readonly maplike interface that returns the members of the object in the [[algorithm]] internal slot (except that, if a member is itself an object we'd want to return something with a maplike interface that returned the members of that inner object and so on).

The difference, IIUC, is that if we use maplike there is no JS object for this thing and I suppose there may be things you might expect to be able to do with a (frozen?) object that you cannot do with a readonly maplike (anything that does not rely on duck-typing, I suppose).

It seems there is no arraylike ?
Comment 4 Boris Zbarsky 2014-10-06 22:58:46 UTC
> 1) Is there a concept of Frozen objects (maps) as well as of Frozen arrays ?

There's a concept of frozen objects.  Frozen means that you can't add or remove properties or change the values of existing properties.

It does NOT mean that accessors or methods cannot manipulate internal slots.  So for example, given a frozen ES Date you could still setMonth() on it.

Also, please don't conflate "objects" and "maps".  An ES Map can be frozen, but since all mutation happens via methods operating on an internal slot that does nothing to prevent mutation of the Map.

> 2) Is it important that the JS array / object is created when the attribute is
first accessed, rather than when the thing implementing the interface that
contains that attribute is created ?

Is the difference between the two observable?

If you rely on IDL to create the object for you, then it'll get created on access, because that's when IDL knows to do the dictionary-to-object or sequence-to-object conversion.  But afaict that's black-box identical to creating it sometime earlier, as long as the state the dictionary is based on is immutable.

> Another approach, I guess, would be to use the new maplike IDL,

Yes.

> is that if we use maplike there is no JS object for this thing

I have no idea what you mean there.  For which thing?

> It seems there is no arraylike ?

There's [ArrayClass], which is fairly similar because all the array methods are generic.
Comment 5 Mark Watson 2014-10-07 02:05:29 UTC
(In reply to Boris Zbarsky from comment #4)
> > 1) Is there a concept of Frozen objects (maps) as well as of Frozen arrays ?
> 
> There's a concept of frozen objects.  Frozen means that you can't add or
> remove properties or change the values of existing properties.
> 
> It does NOT mean that accessors or methods cannot manipulate internal slots.
> So for example, given a frozen ES Date you could still setMonth() on it.
> 
> Also, please don't conflate "objects" and "maps".  An ES Map can be frozen,
> but since all mutation happens via methods operating on an internal slot
> that does nothing to prevent mutation of the Map.

Ok, so a frozen object, that was created by conversion from an IDL dictionary, might do what we want, but a maplike interface would not. 

> 
> > 2) Is it important that the JS array / object is created when the attribute is
> first accessed, rather than when the thing implementing the interface that
> contains that attribute is created ?
> 
> Is the difference between the two observable?
> 
> If you rely on IDL to create the object for you, then it'll get created on
> access, because that's when IDL knows to do the dictionary-to-object or
> sequence-to-object conversion.  But afaict that's black-box identical to
> creating it sometime earlier, as long as the state the dictionary is based
> on is immutable.

Ok, I was under the impresssion, mistaken it seems, that construction of the JS object could have observable side-effects, so it was important to define when it happened. I see that at least if we're talking about an object created as a result of WebIDL conversion from a dictionary, this is not the case, so it makes no difference.

What about [ArrayClass] ? If we were to define our usages attribute to follow the ImmutableItemList example in WebIDL does the process of creating the object implementing that interface call the Array() constructor ?

> 
> > Another approach, I guess, would be to use the new maplike IDL,
> 
> Yes.
> 
> > is that if we use maplike there is no JS object for this thing
> 
> I have no idea what you mean there.  For which thing?

Hmmm, that my suggestion makes no sense tells me something. So I did some reading. Ignore this one.
Comment 6 Boris Zbarsky 2014-10-07 02:41:06 UTC
> What about [ArrayClass] ? If we were to define our usages attribute to follow
> the ImmutableItemList example in WebIDL does the process of creating the object
> implementing that interface call the Array() constructor ?

No, it does not.  All [ArrayClass] means is that you have Array.prototype on your proto chain.

However, note that there are some compat concerns about using things like that which are not true Array instances, because of libraries doing weird stuff with concat().  As a result, Chrome, at least, has been pushing back on implementing ArrayClass at all.  :(
Comment 7 Mark Watson 2014-10-07 14:13:44 UTC
Is there any reason we cannot convert from IDL dictionary to frozen JS object at CryptoKey creation time and store the result in the [[algorithm]] internal slot.

The algorithm attribute would then simply return the contents of the [[algorithm]] internal slot.

This doesn't work for usages, as the frozen Array object can still be modified by the script.

Ryan, what is your opinion on [ArrayClass] ? This would seem to do what we want for usages.
Comment 8 Boris Zbarsky 2014-10-08 03:39:26 UTC
> Is there any reason we cannot convert from IDL dictionary to frozen JS object
> at CryptoKey creation time and store the result in the [[algorithm]] internal
> slot.
>
> The algorithm attribute would then simply return the contents of the
> [[algorithm]] internal slot.

That seems fine.  Again, this is not black-box distinguishable from doing it on first get, so browsers could still do it lazily.

> This doesn't work for usages, as the frozen Array object can still be modified
> by the script.

You can't modify a frozen array object.  That's the point of freezing.

What you can do is throw it out and create a new array object.
Comment 9 Mark Watson 2014-10-08 15:03:33 UTC
(In reply to Boris Zbarsky from comment #8)
> 
> You can't modify a frozen array object.  That's the point of freezing.

Oh, I thought freezing meant you could not add/modify/delete properties, but the object could still change if it has member functions that change it.

Can I call push() on a frozen Array ?
Comment 10 Boris Zbarsky 2014-10-08 15:24:55 UTC
> but the object could still change if it has member functions that change it.

If it has member functions that work with the object's internal slots and modify them.

> Can I call push() on a frozen Array ?

No, because Array does not have any special internal slots (other than the ones all objects have, like [[Prototype]] and [[Extensible]]).  All its state is stored directly in its properties.

If you look at what push() does, it just does an assignment to an indexed property (via Put(); see http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.push step 7), which would fail with a frozen array.
Comment 11 Mark Watson 2014-10-08 15:47:26 UTC
Ok, good.

So, what I suggest then is that we modify our text so that what is placed into the [[algorithm]] and [[usages]] internal slots when a CryptoKey is created are a frozen JS object and frozen Array respectively.

For [[algorithm]] this object is obtained by IDL type conversion from a Dictionary.

For [[usages]] we will explicitly state the values of the members of the Array.

The algorithm and usages attributes, rather than 'reflecting' the contents of the ... internal slot will simply 'return' the contents of that slot.

I guess we should then refer to 'properties' of the [[algorithm]] internal slot rather than 'members'.

Does this work ? Is there a reference we should use for the process of 'freezing' an object ?
Comment 12 Boris Zbarsky 2014-10-08 16:15:34 UTC
> For [[usages]] we will explicitly state the values of the members of the Array.

Or create it from an IDL sequence.  That would make sure that the array is created in the right way (the one that's side-effect-free).  Just stating the values of the Array members doesn't define how those members get defined on the Array, which is important here.

> The algorithm and usages attributes, rather than 'reflecting' the contents of
> the ... internal slot will simply 'return' the contents of that slot.

Yep.

And changing usages (if that's possible) will throw the array in [[usages]] away and create a new one?

> Does this work ?

I think so, yes.

> Is there a reference we should use for the process of
> 'freezing' an object ?

I would say something like "Call the initial value of Object.freeze on X" for freezing X, possibly with a link to http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.freeze
Comment 13 Ryan Sleevi 2014-10-08 21:25:08 UTC
(In reply to Boris Zbarsky from comment #12)
> > For [[usages]] we will explicitly state the values of the members of the Array.
> 
> Or create it from an IDL sequence.  That would make sure that the array is
> created in the right way (the one that's side-effect-free).  Just stating
> the values of the Array members doesn't define how those members get defined
> on the Array, which is important here.
> 
> > The algorithm and usages attributes, rather than 'reflecting' the contents of
> > the ... internal slot will simply 'return' the contents of that slot.
> 
> Yep.
> 
> And changing usages (if that's possible) will throw the array in [[usages]]
> away and create a new one?
> 
> > Does this work ?
> 
> I think so, yes.

I don't think it does, or at least, I'd like to understand if I'm misunderstanding something.

Putting a non-IDL primitive into the internal slot is something I was trying to avoid, precisely because any non-IDL (e.g. ES object) can be mutated externally (e.g. via the prototype chain), as well as all accesses externally visible (i.e. when I get an item at index 2, that can be noticed through the prototype)

Object.freeze solves the mutation issue, but it doesn't solve the fact that I'm going through the prototype.

I thought the proposed solution here was to:
1) Set an internal slot for the IDL/internal representation of an object, so that it can be accessed and/or mutated without any externally-visible (to ES) effects
2) Set an ADDITIONAL internal slot for the "public" representation, which would be the "cached" object

I also don't understand how "cached" object is compatible with object freezing. I definitely got the feedback that "freezing is the anti-pattern", especially for this set of problems. A cached object - where script mutations (if any) are externally visible but not internally visible - seemed consistent with the existing DOM objects.
Comment 14 Boris Zbarsky 2014-10-08 21:30:58 UTC
> 1) Set an internal slot for the IDL/internal representation of an object, so
> that it can be accessed and/or mutated without any externally-visible (to ES)
> effects
> 2) Set an ADDITIONAL internal slot for the "public" representation, which would
> be the "cached" object

Yes.  I assumed that's what Mark was talking about.  Did I misunderstand?
Comment 15 Ryan Sleevi 2014-10-08 22:06:06 UTC
(In reply to Boris Zbarsky from comment #14)
> > 1) Set an internal slot for the IDL/internal representation of an object, so
> > that it can be accessed and/or mutated without any externally-visible (to ES)
> > effects
> > 2) Set an ADDITIONAL internal slot for the "public" representation, which would
> > be the "cached" object
> 
> Yes.  I assumed that's what Mark was talking about.  Did I misunderstand?

My understanding was that the proposed solution was to set [[usages]] (e.g. what affects internal consumption), rather than introduce a [[usages_exposed]] that reflects the attribute value in a cached manner, but is not used for any access checks.

I don't understand why we'd Object.freeze if doing a [[usages_exposed]] - don't the existing [Cached] IDL objects already reflect any ES modifications to them (directly or via prototype chain)? That is, they always return the same ES object - which may have been mutated.
Comment 16 Mark Watson 2014-10-08 23:02:56 UTC
(In reply to Ryan Sleevi from comment #15)
> (In reply to Boris Zbarsky from comment #14)
> > > 1) Set an internal slot for the IDL/internal representation of an object, so
> > > that it can be accessed and/or mutated without any externally-visible (to ES)
> > > effects
> > > 2) Set an ADDITIONAL internal slot for the "public" representation, which would
> > > be the "cached" object
> > 
> > Yes.  I assumed that's what Mark was talking about.  Did I misunderstand?
> 
> My understanding was that the proposed solution was to set [[usages]] (e.g.
> what affects internal consumption), rather than introduce a
> [[usages_exposed]] that reflects the attribute value in a cached manner, but
> is not used for any access checks.
> 

Yes, that was what I proposed. But it only works if that freezing that object really means it cannot be mutated by the script and if internal access to the properties / array elements doesn't have any script-visible side-effects.

> I don't understand why we'd Object.freeze if doing a [[usages_exposed]] -
> don't the existing [Cached] IDL objects already reflect any ES modifications
> to them (directly or via prototype chain)? That is, they always return the
> same ES object - which may have been mutated.

If that's what developers expect, I guess we should do that. However to me it seems very odd that I can modify the algorithm attribute of a CryptoKey - odd that I can modify it at all and more odd that once I do these changes have no effect on the CryptoKey's behavior.

Equally for usages: isn't it at least confusing that I can modify the usages Array of a CryptoKey but this does not affect what it can be used for ?
Comment 17 Boris Zbarsky 2014-10-09 00:19:40 UTC
> I don't understand why we'd Object.freeze if doing a [[usages_exposed]]

That's an API design decision.  The main reason would be to keep scripts on the page from changing it and then getting confused...

> But it only works if that freezing that object really means it cannot be
> mutated by the script

Freezing guarantees the following invariants:

1)  Properties cannot be added.
2)  Properties cannot be removed.
3)  The values of value properties cannot change.
4)  The getters/setters of accessor properties cannot change.

Given those invariants, as long as you only access properties you know are on the object (so you don't fall through the proto chain) and you know they're either value properties or have accessors that you control and hence know have no side-effects, property accesses on the object are side-effect-free.
Comment 18 Mark Watson 2014-10-09 01:07:42 UTC
(In reply to Boris Zbarsky from comment #17)

> Freezing guarantees the following invariants:
> 
> 1)  Properties cannot be added.
> 2)  Properties cannot be removed.
> 3)  The values of value properties cannot change.
> 4)  The getters/setters of accessor properties cannot change.
> 
> Given those invariants, as long as you only access properties you know are
> on the object (so you don't fall through the proto chain) and you know
> they're either value properties or have accessors that you control and hence
> know have no side-effects, property accesses on the object are
> side-effect-free.

Thanks. What is the definition of 'value property' ? If the value of a property of a frozen object is itself an object, does that get frozen too, or would we have freeze that explicitly ?
Comment 19 Boris Zbarsky 2014-10-09 05:29:54 UTC
> What is the definition of 'value property' 

EcmaScript has two different kinds of properties.  Either a property has a getter (and maybe a setter): that's an accessor property.  Or it just has a value; that's a value property.

> If the value of a property of a frozen object is itself an object, does that
> get frozen too

No.  You'd have to recursively freeze the object graph if you wanted that sort of behavior.
Comment 20 Boris Zbarsky 2014-10-09 05:31:00 UTC
So to be clear, if you do "var foo = {}; foo.bar = 5", then "foo" now has a value property named "bar" whose value is 5 (assuming no one stuck a property named "foo" on Object.prototype, at least).
Comment 21 Mark Watson 2014-10-22 21:42:41 UTC
It seems that my proposal in comment#11 would work after all, modified by Boris's comment that the [[usages]] Array should be constructed from an IDL sequence and that we should recursively freeze members of the [[algorithm]] that are themselves objects.

Ryan's concerns were that creation of the objects or internal access to them could have side-effects, but this is not the case if they are created from IDL objects / sequences (respectively) and immediately frozen.

Any objections ?
Comment 22 Ryan Sleevi 2014-10-22 21:49:56 UTC
(In reply to Mark Watson from comment #21)
> It seems that my proposal in comment#11 would work after all, modified by
> Boris's comment that the [[usages]] Array should be constructed from an IDL
> sequence and that we should recursively freeze members of the [[algorithm]]
> that are themselves objects.
> 
> Ryan's concerns were that creation of the objects or internal access to them
> could have side-effects, but this is not the case if they are created from
> IDL objects / sequences (respectively) and immediately frozen.
> 
> Any objections ?

To reiterate, I don't think your solution works. That is, having security checks gated on ES objects, versus internal objects, frozen or not.

The advice of the TAG, and our folks, was that if we're making internal decisions based on the state of the objects - and we are - then it shouldn't be exposed using ES objects.

So no, -1 to frozen.
Comment 23 Mark Watson 2014-10-22 22:42:06 UTC
(In reply to Ryan Sleevi from comment #22)
> (In reply to Mark Watson from comment #21)
> > It seems that my proposal in comment#11 would work after all, modified by
> > Boris's comment that the [[usages]] Array should be constructed from an IDL
> > sequence and that we should recursively freeze members of the [[algorithm]]
> > that are themselves objects.
> > 
> > Ryan's concerns were that creation of the objects or internal access to them
> > could have side-effects, but this is not the case if they are created from
> > IDL objects / sequences (respectively) and immediately frozen.
> > 
> > Any objections ?
> 
> To reiterate, I don't think your solution works. That is, having security
> checks gated on ES objects, versus internal objects, frozen or not.
> 
> The advice of the TAG, and our folks, was that if we're making internal
> decisions based on the state of the objects - and we are - then it shouldn't
> be exposed using ES objects.

Can you explain why, or point me at the advice ? Based on the discussion above, reading from the objects has no visible effects. Or is that wrong ?

I certainly see the problem in the case of objects where the prototype may be or may have been modified, since script functions on the prototype may be called as a result of the access (if it is through accessor properties). But that is not the case here.
Comment 24 Mark Watson 2014-10-30 16:27:43 UTC
Agreed at f2f that reading the attributes returns the same, mutable, JS object every time. We will need text to create this object on first access and store it in a new internal slot to be returned again on subsequent access.
Comment 25 Mark Watson 2014-10-30 23:19:15 UTC
I have implemented a solution here: https://dvcs.w3.org/hg/webcrypto-api/rev/7ef23133ecff

I'd welcome feedback on whether this is sufficient. Specifcally:
- is it sufficient simply to reference WebIDL for the conversion from the WebIDL type in the internal slot to ECMAScript object as I have done ?
- is the text for type and extractable ok, or do we need to be more specific to convert the data in the internal slot to a primitive ECMAScript type ?
Comment 26 Boris Zbarsky 2014-10-31 03:56:40 UTC
> is it sufficient simply to reference WebIDL for the conversion

Imo, yes, as long as the thing being converted has an unambiguous Web IDL type associated with it somehow.

> or do we need to be more specific to convert the data in the internal slot to a
> primitive ECMAScript type

You're returning an IDL type.  Web IDL will then convert it to an ES value the way you want.  The only reason have to do manual conversion for "algorithm" and "usages" is that the IDL says "object", which means "already an ES object".
Comment 27 Mark Watson 2014-11-03 16:05:46 UTC
Thanks Boris!

https://dvcs.w3.org/hg/webcrypto-api/rev/34df8cbba360 ensures that [[algorithm]] and [[usages]] have unambiguous WebIDL type.
Comment 28 Boris Zbarsky 2014-11-05 02:03:34 UTC
> I don't understand why we'd Object.freeze if doing a [[usages_exposed]]

Actually, I just realized that we (Mozilla) do in fact want to Object.freeze here.  We're doing it now and will likely continue to do so for the foreseeable future.

The reason is to handle the case of security proxies that are supposed to provide an "unmodified" view of an object.  For types defined in Web IDL this is simple: the proxy knows what things are supposed to be on the prototype by default and makes sure to only expose those things on the object.  But for ES types like Array, that doesn't really work.  The proxy can guarantee that you get the right array object, but not that its contents haven't been messed with by the page.  Freezing the array, on the other hand, guarantees the latter property, allowing the proxy to work correctly.

That approach obviously won't help with .algorithm, but that's what you get for using dictionaries... (imo not so correctly here; I pretty much agree with http://lists.w3.org/Archives/Public/public-script-coord/2014JanMar/0201.html in terms of whether to use dictionaries or interfaces in API design).
Comment 29 Ryan Sleevi 2014-11-08 02:55:55 UTC
(In reply to Boris Zbarsky from comment #28)
> > I don't understand why we'd Object.freeze if doing a [[usages_exposed]]
> 
> Actually, I just realized that we (Mozilla) do in fact want to Object.freeze
> here.  We're doing it now and will likely continue to do so for the
> foreseeable future.
> 
> The reason is to handle the case of security proxies that are supposed to
> provide an "unmodified" view of an object.  For types defined in Web IDL
> this is simple: the proxy knows what things are supposed to be on the
> prototype by default and makes sure to only expose those things on the
> object.  But for ES types like Array, that doesn't really work.  The proxy
> can guarantee that you get the right array object, but not that its contents
> haven't been messed with by the page.  Freezing the array, on the other
> hand, guarantees the latter property, allowing the proxy to work correctly.
> 

Boris,

As discussed in the F2F, can you provide any example of any other Web Platform API that uses Freeze? Part of the objection here to freezing is about matching developer expectations through consistency of the platform, rather than implementor preference.

Absent some TAG push for it (ala Promises), my inclination is that freeze is the wrong thing here precisely because it violates developers expectations compared to other objects - the huge number of interfaces with "readonly attributes" that fundamentally aren't readonly seems a prime example of this.

http://w3c.github.io/deviceorientation/spec-source-orientation.html#devicemotion (readonly attributes in DeviceMotionEvent that aren't)
http://w3c.github.io/performance-timeline/#sec-PerformanceEntry-interface (readonly attributes for name/entryType that aren't)
http://w3c.github.io/dom/#interface-event ( readonly attributes for type that aren't)

Note that the reason I say that "they aren't" is that even though Web IDL requires an error be thrown on mutation ( http://heycam.github.io/webidl/#dfn-read-only ), you can certainly mess with the String.prototype.

I can see there's bikeshed elsewhere (e.g. http://w3c.github.io/webappsec/specs/content-security-policy/#dom-securitypolicysourcelistdirective / http://w3c.github.io/webappsec/specs/content-security-policy/#dom-securitypolicy-directives ), but it's also inconsistently applied in other specs (for example, http://w3c.github.io/webrtc-pc/#idl-def-RTCPeerConnectionIceEvent - 'candidate' is a readonly attribute of type RTCIceCandidate, which itself is an interface with non-readonly attributes)

My utmost goals are to
1) Match consistency with developers' expectations
2) Do the right thing

Yes, that's a nasty ordering, but I don't see how I can do otherwise, given http://www.w3.org/TR/html-design-principles/#priority-of-constituencies , until/unless we make a coordinated effort to ensure "Do the right thing" also "matches consistency with developers expectations"
Comment 30 Boris Zbarsky 2014-11-08 03:02:37 UTC
> can you provide any example of any other Web Platform API that uses Freeze

Can you provide any example of any other Web Platform API that has an attribute that returns JS arrays?  Fundamentally we're on new ground here.

> the huge number of interfaces with "readonly attributes" that fundamentally
> aren't readonly

More precisely that don't return immutable objects.  I did explain in my comment why this case is fundamentally different, no?

We'll continue to ship this with frozen arrays until we figure out a way to make them mutable that doesn't introduce security bugs from our point of view, I guess.  We have some ideas for how to maybe make it work, but no ETA on when we might be able to do it, so given the choice between not shipping webcrypto at all and shipping with frozen arrays here, frozen arrays it is.
Comment 31 Boris Zbarsky 2014-11-08 03:04:46 UTC
> More precisely that don't return immutable objects.

Or even more precisely, that returns objects that have immutable internal state but can have that shadowed from naive JS in the usual way.  But since they have the immutable internal state, one can provide ways of getting at that state.  ES arrays have no such internal state, hence no way to get at it.
Comment 32 Ryan Sleevi 2014-11-08 03:09:55 UTC
(In reply to Boris Zbarsky from comment #30)

> We'll continue to ship this with frozen arrays until we figure out a way to
> make them mutable that doesn't introduce security bugs from our point of
> view, I guess.  We have some ideas for how to maybe make it work, but no ETA
> on when we might be able to do it, so given the choice between not shipping
> webcrypto at all and shipping with frozen arrays here, frozen arrays it is.

I'm definitely concerned here to understand what "security bugs" you see?

From the discussion at the F2F, the proposed resolution was to embody in the spec (via internal slots) what UAs do today for most web APIs (DOM being a special case in so many ways).

That is, there is a 'canonical' internal slot that contains the true value (e.g. what is used for all security checks), that is never exposed to callers. There is a 'cached' slot that contains the external value, which is exposed to callers, and follows all the normal "You can mess with this object in weird ways if you're weird" that things like WebRTC demonstrate, but without affecting the internal state/security checks.

Yes, it means that an object may 'lie' to an user, even if it doesn't affect the internal operation. However, an object can be made to lie many ways (Prototypes being the canonical way, even for Built-ins), and it seems like it's one of those things that is expected of the platform, even if it's "weird and smelly".
Comment 33 Ryan Sleevi 2014-11-08 03:12:57 UTC
(In reply to Boris Zbarsky from comment #30)
> > can you provide any example of any other Web Platform API that uses Freeze
> 
> Can you provide any example of any other Web Platform API that has an
> attribute that returns JS arrays?  Fundamentally we're on new ground here.

I haven't looked in depth (because there's _so many_ disparate specs in various states), but WebRTC at least is an example of a similar problem, and the sequence situation with CSP(3?) seems similar.

(In reply to Boris Zbarsky from comment #31)
> > More precisely that don't return immutable objects.
> 
> Or even more precisely, that returns objects that have immutable internal
> state but can have that shadowed from naive JS in the usual way.  But since
> they have the immutable internal state, one can provide ways of getting at
> that state.  ES arrays have no such internal state, hence no way to get at
> it.

The updated language has Key with the immutable internal state, and it returns the cached state. I'm not entirely sure why the exposed attribute itself needs to have immutable internal state, since its internal state is not used by the Key implementation.
Comment 34 Boris Zbarsky 2014-11-08 03:33:35 UTC
> I'm definitely concerned here to understand what "security bugs" you see?

In our case, Firefox extensions touching these objects would end up seeing page-modified values, which is likely to be a problem.

> there is a 'canonical' internal slot that contains the true value

Yes, but the canonical getter doesn't actually return that value, after the first time it's called.

The security proxies in Gecko that are used by extensions ensure that when getting a property on a Web IDL object the canonical getter is invoked.  This guarantees that the correct thing is returned in cases when the getter just returns the value of an internal slot (as it does with DOM nodes, say).  In the case of CryptoKey this will mean invoking the canonical getter, which then returns the value it's cached, which is an array that it's potentially handed out to untrusted script before and that the untrusted script may have modified.

> and follows all the normal "You can mess with this object in weird
> ways if you're weird" 

You can mess with it in ways in which you can't mess with Web IDL objects, because the array itself does not have internal state.

> Yes, it means that an object may 'lie' to an user

Yes, and if the "user" is a privileged browser extension that constitutes a security bug.

> However, an object can be made to lie many ways (Prototypes being the
> canonical way

Our security wrappers ensure that the canonical prototype chain is walked.

> but WebRTC at least is an example of a similar problem

Where, exactly?  I see nothing along these lines in the WebRTC IDL.

> and the sequence situation with CSP(3?) seems similar

You mean CSP 2?  The IDL for that was just proposed; no one implements it yet.  It's explicitly punting on the arraylike bits for now until they can be sorted out.

In fact, the only case in which I see something similar in Gecko is the Gamepad API, but we return frozen arrays there.

In any case, us freezing the array is likely temporary until https://bugzilla.mozilla.org/show_bug.cgi?id=946906 is fixed.  Just thought you'd want a heads-up that we plan to do it at least until then...