Our goal is to eliminate the non-constructible KeyAlgorithm
interface, and all its derived counterparts (e.g. RsaKeyAlgorithm
). We can just use plain JavaScript objects instead, represented by their counterpart Algorithm
dictionaries (e.g. RsaKeyParams
).
As WebIDL is lacking in technology for manipulating JS objects, this will require a line or two of prose.
One problem with the existing spec that makes formalizing this difficult is that the spec sets readonly attributes on instances, which should be impossible. E.g. section 18.4.5, Generate Key, step 12 says "Set the algorithm attribute of publicKey to be algorithm": but the algorithm
attribute is readonly, and so it cannot be set.
We can work around this, without having to make extensive disruptive changes to the spec, by granting the spec special powers to set readonly attributes. We need to specially call out the interaction of these special powers with normal attribute semantics, however. We'll see that in action below.
(The correct, more extensive fix is to describe the internal slots of the object, which are mutable, and describe the object's getters, i.e. readonly attributes, as returning the values of those internal slots. I'll include that as an appendix.)
Remove section 11.
In section 12, change readonly attribute KeyAlgorithm algorithm
to readonly attribute object algorithm
.
In section 12.3, change the description of algorithm
to "An object representing the key algorithm used to generate the key. After being set, which is only possible by specification text, it should return the set object for each getter invocation. In practice, this member will have the shape specified by one of the Algorithm
dictionaries."
Remove section 18.4.4.
In section 18.4.5, Generate Key:
- Removes steps 6-9
- Change step 12 to be "Set the algorithm attribute of publicKey to be normalizedAlgorithm."
In section 18.4.5, Import Key:
- Change step 3 to be "Let algorithm be a new RsaKeyParams."
To properly formalize the setting of readonly attributes, which is not actually possible in JavaScript semantics—nor in WebIDL, from what I can tell—you'd have to resort to prose again, as Boris points out.
In the definition of the Key
interface, you would say something like: Key
instances have the internal slots [[type]]
, [[extractable]]
, [[algorithm]]
, and [[usages]]
.
In the definition of each attribute, e.g. type
, you would say: "returns the value of this instance's [[type]]
internal slot."
In any spec algorithms which need to mutate the internally-held state of a Key
instance, e.g. section 18.4.5 Generate Key step 12, you would say "Set the [[algorithm]]
internal slot of publicKey to be normalizedAlgorithm."
Most objects which expose a bunch of getters (readonly attributes) are meant to be "immutable," i.e. created with a given set of values, then return those values in perpetuity. This is usually done with a constructor.
To do this, modify the approach in Appendix A by defining a constructor for Key
, e.g. new Key(type, extractable, algorithm, usages)
. It should be fairly straightforward, e.g. it contains four simple steps of the form "Set this instance's [[type]]
internal slot to the value of the type argument." WebIDL's overload resolution algorithm will ensure the correct types end up in the internal slots, so there are no worries there.
Once this is done, then instead of creating initially-invalid Key
instances and mutating their internal state until they become valid, as in section 18.4.5 Generate Key, you could replace that whole sequence, from steps 10 through 14, with:
- Let usages be the usage intersection of usages and
["encrypt", "wrapKey"]
. - Let _privateKey be a new
Key
object created as if bynew Key("public", true, normalizedAlgorithm, usages)
.
Similarly steps 15 through 19 would be subsumed, and of course KeyPair
could be done the same way. (Although, to be honest, KeyPair
looks like a dictionary to me.)
Regarding Appendix B:
Your proposal does nothing to solve the "initially-invalid Key instance and mutating internal state until they become valid".
There is a hidden property here - that is never exposed to JS (nor can it be) - at best called
keyHandle
- that represents a discrete resource managed by the user agent. This is no different than the File API.In the File API,
File
has a constructor that allows it to be created from application-supplied data. However, the UAs do not use that constructor - because they createFile
objects with internal snapshot state that represent the file on disk.With
Key
s, they have an internalhandle
that is an opaque committment to some key material being available via underlying storage. Exposing a constructor, that takes keying material, isn't possible - because the implementation needs to be asynchronous (for a variety of reasons). So we only have a single way to construct aKey
object - with a handle that cannot be exposed to the Web Application.