Re: JWK import/export as ECMAScript objects, rather than ArrayBuffer

On Tue, Mar 11, 2014 at 6:00 PM, Ryan Sleevi <sleevi@google.com> wrote:

>
> On Mar 11, 2014 5:44 PM, "Mark Watson" <watsonm@netflix.com> wrote:
> >
> > Hi Ryan,
> >
> > This looks good with the following comments:
> >
> > (1) Why not add this capability, whilst keeping the existing JWK import
> / export ? For example add a new format "jwk-obj". This would keep things
> simple for the other use-case where the JWK is just being written to / read
> from a wire protocol. Supporting both is hardly arduous since UAs must
> support the serialization / de-serialization for wrap / unwrap anyway.
> >
>
> We should prioritize the common case. Dealing with ArrayBuffers for JSON
> or JS Objects is not the common case for any other Web API.
>
We might disagree about which is the common case. Since we already have
the actual JWKs (and several browsers have implemented these and they are
being used) it seems sensible to add functionality here. There is no
additional work to add rather than replace, so there is no need to
prioritize.

> If we support parallel formats, it should be because we believe the
> ArrayBuffer case will be as significant a use case as with Object.
>
No, it's sufficient that they are both significant and useful. They don't
need parity.

> In either event, if we do support both, I believe the ArrayBuffer case
> should be separately named (eg: JWKS) - precisely because JWK will
> naturally yield or be manipulated as Objects, not octets, within JS.
>
The J in JWK stands for JSON. JSON is a wire format. Seems obvious that
format "jwk" should produce a JWK, not a Javascript representation of one.

> You keep saying "written to or read from a wire protocol", so I'd simply
> ask that you back that assertion up with script demonstrating this use case.
>
This is what our application does today. I'll see if I can extract the
relevant code.

...Mark

> The most likely candidates - XHR and WebSockets - are naturally inclined
> towards JSON and DOMString-ified JSON. Equally true for structured
> inter-origin postMessage (which may not be suitable as a Key object if the
> source is replaying a message from the server to the peer). These are all
> cases served by a natural object - especially when it reduces repeated
> conversions / copies.
>
> Equally, if we believe that really, the use case is only for importing an
> ArrayBuffer, we could let the "jwk" importKey handle both cases
> transparently, while always yielding an object for export key.
>
> TL:DR; What is a precise use case or demonstrable snippet where
> ArrayBuffer would be more preferable or natural compared to an Object?
>
> > (2) WebIDL appears to be a little ambiguous with respect to unions of
> Dictionaries. Section 14.2.25 says "If types includes a dictionary type,
> then return the result of converting V to that dictionary type.
> > ", which pointedly neglects to say which dictionary type in types, if
> there is more than one.
> >
>
> Sure. We could just as well deal with it as we deal with algorithm -
> object and coercion.
>
> I agree this has to be solved meaningfully before adding to the spec.
>
> > (3) We need a
> > JwkKeyDictionary subclass for symmetric keys:
> >
> > JwkSecretKeyDictionary : JwkKeyDictionary {
> >   DOMString k;
> > };
> >
> > (4) usages in JwkKeyDictionary should be "key_ops"
> >
> > (5) Do we want to include the "use" member ? I thought we checked that
> for consistency ?
> >
>
> All oversights of mine, as a result of basing on JWA without reading all
> of our additions/registrations.
>
> Answer is yes, yes, and yes.
>
> > ...Mark
> >
> >
> > On Tue, Mar 11, 2014 at 5:22 PM, Ryan Sleevi <sleevi@google.com> wrote:
> >>
> >> The motivation:
> >>
> >> * Provide a means of easy interchange with Web Sockets (eg: by allowing
> Text Frame, rather than imposing Binary Frame, as done by send(ArrayBuffer)
> )
> >> * Provide a means of easy interchange of JWK with postMessage (eg: by
> not requiring a Key object itself be posted)
> >> * Provide a means of easy integration with larger JSON-backed messages
> >>
> >> That is, presume a structure
> >> {
> >>   'larger_message': 'something',
> >>   'jwk': [{
> >>     'kid': 'foo',
> >>     'alg': 'RSA',
> >>     'kty': 'RSA1_5',
> >>     'n': '....',
> >>     'e': '....'
> >>   }]
> >> }
> >>
> >> Under the current API, one has two options - depending on UA support
> for http://encoding.spec.whatwg.org/#api
> >>
> >> With Encoding support:
> >>
> >> // Makes 3 additional copies of message.jwk
> >> // 1 for the .stringify
> >> // 1 for the TextEncoder
> >> // 1 for the importKey (cloning the ArrayBuffer)
> >> // By definition, this copies *all* fields of message.jwk, including
> those not used by importKey (eg: 'kid')
> >>
> >> message = JSON.parse(message);
> >> jwkBuf = (new TextEncoder("utf-8")).encode(JSON.stringify(message.jwk));
> >> window.crypto.subtle.importKey("jwk", jwkBuf, { name:
> "RSAES-PKCS1-v1_5" }, [ "encrypt", "decrypt"] );
> >>
> >> Without Encoding support:
> >> It's necessary to do something like strToUTF8Arr (
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding)
> >>
> >> Under the proposed API, one simply does
> >>
> >> // Makes 1 additional copy of message.jwk
> >> // 1 for the importKey (cloning message.jwk)
> >> // By definition, this *does not* copy all fields of message.jwk - only
> those fields used for the import (eg: 'kid' is NOT copied)
> >> window.crypto.subtle.importKey("jwk", message.jwk, { name:
> "RSAES-PKCS1-v1_5" }, [ "encrypt", "decrypt" ]);
> >>
> >>
> >> Types used:
> >>
> >> dictionary JwkKeyDictionary {
> >>   DOMString kty;
> >>   DOMString alg;
> >>   boolean ext;
> >>   DOMString[] usages;
> >> };
> >>
> >> dictionary JwkEcKeyDictionary : JwkKeyDictionary {
> >>   DOMString crv;
> >>   DOMString x;
> >>   DOMString y;
> >>   DOMString d;
> >> };
> >>
> >> dictionary JwkRsaOtherPrimeDictionary {
> >>   DOMString r;
> >>   DOMString d;
> >>   DOMString t;
> >> };
> >>
> >> dictionary JwkRsaKeyDictionary : JwkKeyDictionary {
> >>   DOMString n;
> >>   DOMString e;
> >>   DOMString d;
> >>   DOMString p;
> >>   DOMString dp;
> >>   DOMString dq;
> >>   DOMString qi;
> >>   JwkRsaOtherPrimeDictionary[] oth;
> >> };
> >>
> >>
> >>
> >> Changes to signatures:
> >> Old:
> >> Promise<any> importKey(KeyFormat format, CryptoOperationData keyData,
> AlgorithmIdentifier? algorithm, boolean extractable, KeyUsage[] keyUsages);
> >> Promise<any> exportKey(KeyFormat format, Key key);
> >>
> >> New:
> >> Promise<any> importKey(KeyFormat format, (CryptoOperationData or
> JwkRsaKeyDictionary or JwkEcKeyDictionary), AlgorithmIdentifier algorithm,
> boolean extractable, KeyUsage[] keyUsages);
> >> Promise<any> exportKey(KeyFormat format, Key key);
> >>
> >>
> >> Changes to algorithms:
> >> Wrap Key ( 14.3.1 /
> https://dvcs.w3.org/hg/webcrypto-api/raw-file/3f7df730b2c7/spec/Overview.html#SubtleCrypto-method-wrapKey)
> >>
> >> 12.
> >> * If format is "spki":
> >>   - Let bytes be the result of performing the export key operation
> specified the algorithm attribute of key using key and format.
> >> * If format is "pkcs8"
> >>   - Let bytes be the result of performing the export key operation
> specified the algorithm attribute of key using key and format.
> >> * If format is "jwk"
> >>   - Let object be the result of performing the export key operation
> specified by the algorithm attribute of key using key and format.
> >>   - Let stringifiedJwk be the result of invoking the JSON.stringify
> method specified in Section 15.12.3 of [ECMA-252], with /object/ as /value/.
> >>   - Let bytes be the UTF-8 encoding of stringifiedJwk
> >>
> >>
> >> From the algorithm-specific import key sections eg: using
> https://dvcs.w3.org/hg/webcrypto-api/raw-file/3f7df730b2c7/spec/Overview.html#rsassa-pkcs1-operationsas an example
> >>
> >> 4. If format is "jwk"
> >>   1. If /keyData/ is not an instance of a JwkRsaKeyDictionary, return
> an error ...
> >>   2. Let /jwk/ be /keyData/
> >>
> >> From the algorithm-specific export key sections - eg: using again
> RSASSA-PKCS1
> >>
> >> 4. If format is "jwk"
> >>   * Let /jwk/ be a new ECMAScript object created as if by the
> expression ({})
> >>   * _Set the property "n" of /jwk/_ to the _base64url-encoded_ modulus
> of the RSA public key represented by /key/, as specified by Section 6.3.1
> of [JWA]
> >>   * _Set the property "e" of /jwk/_ to the _base64url-encoded_ big
> integer exponent representation of the RSA public key represented by /key/,
> as specified by Section 6.3.1 of [JWA]
> >>   ...
> >>   * Let /result/ be /jwk/
> >>
> >> Terminology:
> >> When this specification says Set the property /name/ of /object/ to
> /value/, call the [[DefineOwnProperty]] internal method of /object/ with
> property name /name/, the Property Descriptor { [[Writable]]: true,
> [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: /value/ }, and the
> Boolean flag false.
> >>
> >>
> >>
> >
> >
>

Received on Wednesday, 12 March 2014 01:08:58 UTC