- 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