- From: Ryan Sleevi <sleevi@google.com>
- Date: Fri, 25 Apr 2014 15:44:57 -0700
- To: Matt Miller <mamille2@cisco.com>
- Cc: "public-webcrypto-comments@w3.org" <public-webcrypto-comments@w3.org>
- Message-ID: <CACvaWvbw4c8H7ZRJUku30ALdNKFGA4R4ifNX9oLS28YnUrDWCQ@mail.gmail.com>
On Thu, Apr 24, 2014 at 1:38 PM, Matt Miller <mamille2@cisco.com> wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA512 > > Hello all, > > Below are my comments after reading the current draft of WebCryptoAPI. > I apologize if I've repeated anything stated before; I've not really > followed the discussion leading up to this document's current state. > > > > Potential Defects: > ============================================== > > The definition for "PBKDF2" includes an editor note that does not > appear to be relevant. It discusses a "password" field that is not > present in any of the immediately surrounding content. > > Thanks for highlighting. Will fix. > > Comments: > ============================================== > > Key Storage/Retrieval > - ---------------------------------------------- > > The draft discusses "retrieving keys" -- distinct from import/unwrap > - -- but does not in any other way indicate how this is dealt with. It > would help to explicitly mention that key storage/retrieval can be > done with mechanisms that support structured cloning, such as IndexedDB. > > Is there a particular section you have a concern of? The only mention of this is in Section 4.4 of the "out of scope". > > KeyPairs and Extractability > - ---------------------------------------------- > > Assuming that when generateKey returns a KeyPair that the public key > is always extractable, this should be explicitly stated somewhere > separate from the individually registered algorithms. At a minimum, > this ought to be stated in § 18.3. "Defining an Algorithm", but it > could also be helpful for have it stated at or around § 14.3.6. "The > generateKey method" from the perspective of an API user. > > I don't agree with this. I've tried very hard to specifically avoid listing algorithm-specific concerns in generic sections. > > "Defining an algorithm" Guidelines > - ---------------------------------------------- > > If the to-be-defined algorithm supports the "importKey" operation, the > definition ought to clearly specify how [extractable] applies. > Examples > - ---------------------------------------------- > > It would be nice to a somewhat non-trivial deriveKey example. For my > own edification, I put together a mythical example (included below) to > see if I'm understanding the API interactions correctly. And, please, > correct my misconceptions of how the API works if my example has > egregious errors. > > Key Lifetimes > - ---------------------------------------------- > > I suspect this is controversial. It would be nice if a generated Key > could have some sort of lifetime that the user agent enforces. At a > minimum, I would highly desire the ability to specify that a Key > should not be used for more than a browser session (similar to > sessionStorage), but would value having a fixed expiration date/time > or a certain amount of time after generateKey's promise is fulfilled. > > I realize that this can complicate things (e.g., how does this > interact with importKey?), and can live with some restrictions (e.g., > limited-life Keys are never extractable). I think it's also > acceptable for the lifetime to be tied to just the private Key of a > KeyPair, if it helps simplify things at all. > > Yeah, controversial. WebCrypto provides no statements about all about Key Storage - this is very important, least of all for its security concerns. You already have the ability to specify that a Key should not be used more than a browser session - don't persist it anywhere! I disagree with the premise that there's any security benefits to be had here - it's fully in the control of the site author to control the lifetime of their key, with either method. The proposal you make provides some syntactic sugar, but notably complicates things - including forcing WebCrypto to make explicit statements about Key Storage that simply cannot or should not be made. > > Thank you, > > - - m&m > > Matt Miller < mamille2@cisco.com > > Cisco Systems, Inc. > > - -----BEGIN EXAMPLE----- > > // Agree to a session key with another user > var promise, > us = {}, > them = {}, > sessionKey = null; > > // helper for prefixing data with a length encoding > function __UINT32(value) { > var output = new Uint8Array([ > (value >>> 24) & 0xff, > (value >>> 16) & 0xff, > (value >>> 8) & 0xff, > value & 0xff > ]); > } > > // Generate an EC Key for ECDH > var params = { > name: "ECDH", > namedCurve: "P-256" > }; > promise = window.crypto.subtle.generateKey(params, > false, > [ "deriveKey" ]); > promise = promise.then(function (keypair) { > // remember the generated key for right now > us.pivateKey = keypair.privateKey; > us.publicKey = keypair.publicKey; > > // set our identifier > var ident = new TextEncoding("utf-8").encode("me@example.com"); > us.info = new Uint8Array(4 + ident.byteLength); > us.info.set(__UINT32(ident.byteLength)); > us.info.set(ident, 4); > > // export public key as JWK > return window.crypto.subtle.exportKey("jwk", us.publicKey); > }); > > promise = promise.then(function(jwk) { > // exchange public keys with 'them'; > // returns a promise with the other user's public key, > // it could use XMLHttpRequest or WebSocket for the actual exchnage > return exchangePeerInfo({ > publicKey: jwk, > info: us.info > }); > }); > > promise = promise.then(function (other) { > them = other; > > // import the key > return window.crypto.subtle.importKey("jwk", > them.key, > { name: "ECDH" }, > true, > [ "deriveBits" ]); > }); > > promise = promise.then(function (theirKey) { > // remember their Key object > them.publicKey = theirKey; > > // generate the shared secret "Key" > var params = { > name: "ECDH", > public: their.publicKey > }; > > return window.crypto.subtle.deriveKey(params, > us.privateKey, > { name: "CONCAT" }, > false, > [ "deriveKey" ]); > }); > Concat only supports deriveBits, as currently specified. Filed https://www.w3.org/Bugs/Public/show_bug.cgi?id=25468 > > promise = promise.then(function (secret) { > // construct the algorithmId UINT32(algorithm.length) || algorithm > var algName = new TextEncoder("utf-8").encode("A128GCM"); > var algId = new Uint8Array(4 + algName.byteLength); > algId.set(__UINT32(algName.byteLength)); > algId.set(algName, 4); > > var params = { > name: "CONCAT", > hash: "SHA-256", > algorithmsId: algId, > partyUInfo: us.info, > partyVInfo: them.info > }; > > var derived = { > name: "AES-GCM", > length: 128 > }; > return window.crypto.subtle.deriveKey(params, > secret, > derived, > false, > [ "encrypt", "decrypt" ]); > }); > > The above certainly strikes me as somewhat dangerous (re-using the same key for encryption and decryption). I would presume you would be generating separate keys here - an encryption key that uses { partyUInfo: us.info, partyVInfo: them.info }, and a decryption key that uses { partyUInfo: them.info, partyVInfo: us.info } Otherwise, yes, that looks correct.
Received on Friday, 25 April 2014 22:45:28 UTC