- From: Mark Watson <watsonm@netflix.com>
- Date: Fri, 21 Mar 2014 10:17:06 -0700
- To: Richard Barnes <rlb@ipv.sx>
- Cc: Ryan Sleevi <sleevi@google.com>, "public-webcrypto@w3.org" <public-webcrypto@w3.org>
- Message-ID: <CAEnTvdDQTCVKnC4-vQg1H15SbtRFsm3M3EZy9CLqS0uH0UcRbw@mail.gmail.com>
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 ? ...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 17:22:40 UTC