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

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.

If we support parallel formats, it should be because we believe the
ArrayBuffer case will be as significant a use case as with Object. 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.

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. 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:00:42 UTC