- From: Mark Watson <watsonm@netflix.com>
- Date: Fri, 21 Mar 2014 12:59:47 -0700
- To: Richard Barnes <rlb@ipv.sx>
- Cc: Ryan Sleevi <sleevi@google.com>, "public-webcrypto@w3.org" <public-webcrypto@w3.org>
- Message-ID: <5766396306815608459@unknownmsgid>
Sent from my iPhone On Mar 21, 2014, at 12:41 PM, Richard Barnes <rlb@ipv.sx> wrote: On Fri, Mar 21, 2014 at 1:17 PM, Mark Watson <watsonm@netflix.com> wrote: > > > > On Fri, Mar 21, 2014 at 7:50 AM, Richard Barnes <rlb@ipv.sx> wrote: > >> On Tue, Mar 11, 2014 at 9:08 PM, Mark Watson <watsonm@netflix.com> wrote: >> >>> >>> >>> >>> 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. >>> >> >> It seems abundantly silly to have two options here, when there's a >> trivial conversion between them. >> >> Object -> json.stringify() -> TextEncoder -> ABV >> ABV -> TextDecoder -> json.parse() -> Object >> >> Whichever one we choose here, a small JS shim can emulate the other. So >> we should really just choose one. >> > > This is fine if you have TextEncoder. It doesn't appear on caniuse.com. > Does anyone have information about browser support of this ? > Even if you don't have TextEncoder, it's a small polyfill. See, e.g.: http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt http://polycrypt.net/common/util.js Object -> json.stringify() -> utf16to8() -> somethingLike_str2abv() --> ABV ABV -> something_like_abv2str() -> utf8to16() -> json.parse() --> Object How efficient is the polyfill for large messages ? ...Mark --Richard > > ...Mark > > > >> >> As to which we should choose, I'm pretty strongly with Ryan here that we >> should return an object. ECMAScript objects are what get returned from any >> other web API that returns a structured object. The only exceptions we see >> to this are when some binary format is used for backward compatibility; >> that applies for "spki", "pkcs8", but not to "jwk". >> >> As far as implementation, I would be pretty shocked to see >> implementations making these object in any way other than (1) building and >> object and (2) calling json.stringify(). So from an implementation >> complexity point of view, the only change here is to remove the call to >> json.stringify(). >> >> 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. >>> >> >> As noted above, even if your application does this, it's a small shim to >> make an object-based API look like an ArrayBuffer-based one. >> >> I would also point out that there are potentially pretty big down-sides >> to providing a pre-serialized JWK, in contexts where that JWK fits into a >> larger protocol. For example, if the overall protocols uses UTF-16 (e.g., >> based on sending ECMAScript strings without re-encoding), then the >> pre-serialized JWK can't just be pasted into the protocol, since it's in >> UTF-8. But there are also enough protocols that use UTF-8 that we can't >> just switch to UTF-16. Better to just give the application the object and >> let it serialize it into whatever form works. >> >> --Richard >> >> >> >> >>> >>> ...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 Friday, 21 March 2014 20:00:19 UTC