Re: ACTION-84: Finishing support for key derivation/key agreement (take 2)

On Mon, Jul 22, 2013 at 3:41 PM, Jim Schaad <ietf@augustcellars.com> wrote:
>
>
>> -----Original Message-----
>> From: Ryan Sleevi [mailto:sleevi@google.com]
>> Sent: Monday, July 22, 2013 11:57 AM
>> To: Vijay Bharadwaj
>> Cc: public-webcrypto@w3.org; Richard Barnes; Jim Schaad; Israel Hilerio
>> Subject: Re: ACTION-84: Finishing support for key derivation/key agreement
>> (take 2)
>>
>> On Tue, Jun 4, 2013 at 12:03 AM, Vijay Bharadwaj
>> <Vijay.Bharadwaj@microsoft.com> wrote:
>> > Following up on the previous thread (see
>> http://lists.w3.org/Archives/Public/public-webcrypto/2013May/0106.html),
>> here is a more fully-fleshed-out proposal based on the latest working
> draft.
>> Please let me know if I missed anything from the previous discussion, or
> if you
>> have new comments.
>> >
>> > Notes:
>> > - I am leaving out MQV from the algorithm definitions for now. If there
> is
>> interest, this can be added. I'd like to point out that Windows and
> OpenSSL at
>> least do not implement it and adoption may be low due to IPR-related
>> concerns such as Ryan expressed on the earlier thread.
>> > - This is defined with reference to Futures. This is for consistency
> with the
>> current draft. To the extent that open issues remain with Futures in the
> spec,
>> those issues apply here as well.
>> > - This is also subject to the existing open issues around separation of
>> operational and algorithm parameters.
>> > - Naming is hard. Existing methods are named <verb> or <verb><noun>.
>> However agreeSecret and computeSecretAgreement sound clunky to me. If
>> you have a better idea please share.
>> >
>> > Section 11:
>> > Add a new value "secretAgreement" to enum KeyUsage.
>> >
>> > Section 14:
>> >
>> > Add to interface SubtleCrypto:
>> >
>> > Future<any> secretAgreement(Key localPrivateKey, Key peerPublicKey,
>> > AlgorithmIdentifier agreementAlgorithm, AlgorithmIdentifier
>> > derivationAlgorithm, bool extractable = false);
>> >
>> > Future<any> deriveBits(AlgorithmIdentifier kdfAlgorithm, Key baseKey,
>> > unsigned long bitLength);
>> >
>> > Section 14.2:
>> >
>> > Add new subsections describing the above methods:
>> >
>> > 14.2.x. The secretAgreement method
>> >
>> > When invoked, secretAgreement MUST perform the following steps:
>> >
>> > 1. Let normalizedAgreementAlgorithm be the result of processing
>> agreementAlgorithm according to the algorithm normalizing rules.
>> >
>> > 2. If normalizedAgreementAlgorithm does not describe a registered
>> algorithm that supports the secretAgreement operation, throw a
>> NotSupportedError and terminate the algorithm.
>> >
>> > 3. Let normalizedDerivationAlgorithm be the result of processing
>> derivationAlgorithm according to the algorithm normalizing rules.
>> >
>> > 4. If normalizedDerivationAlgorithm does not describe a registered
>> algorithm that supports the derive operation, throw a NotSupportedError
> and
>> terminate the algorithm.
>> >
>> > 5. Let future be a new Future object and resolver its associated
> resolver.
>> >
>> > 6. Return future and continue executing the remaining steps
>> asynchronously.
>> >
>> > 7. If an error occurs, run these substeps and then terminate the
> algorithm:
>> >         1. Let result be null.
>> >         2. Execute resolver's reject(value) algorithm, with result as
> the value
>> argument.
>> >
>> > 8. If localPrivateKey, peerPublicKey,
> agreementAlgorithm.localPrivateKey2
>> (if present), agreementAlgorithm.localPublicKey2 (if present), and
>> agreementAlgorithm.peerPublicKey2 (if present) are not all keys of type
>> normalizedAgreementAlgorithm, terminate this algorithm with an error.
>> >
>> > 9. If localPrivateKey, peerPublicKey,
> agreementAlgorithm.localPrivateKey2
>> (if present), agreementAlgorithm.localPublicKey2 (if present), and
>> agreementAlgorithm.peerPublicKey2 (if present) do not all contain the
>> "secretAgreement" KeyUsage in their keyUsage properties, terminate this
>> algorithm with an error.
>> >
>> > 10. Let secret be the result of executing the secret agreement algorithm
>> defined by the algorithm indicated in normalizedAgreementAlgorithm.
>> >
>> > 11. Let result be the result of executing the importKey algorithm, with
> "raw"
>> as format, with secret as keyData, with normalizedDerivationAlgorithm as
>> algorithm, with extractable as extractable, and "derive" as keyUsages.
>> >
>> > 12. If the key import algorithm failed, terminate this algorithm with an
> error.
>> >
>> > 13. Execute resolver's resolve(value) algorithm, with result as the
> value
>> argument.
>> >
>> >
>> > 14.2.y The deriveBits method
>> >
>> > When invoked, deriveBits MUST perform the following steps:
>> >
>> > 1. Let normalizedKdfAlgorithm be the result of processing kdfAlgorithm
>> according to the algorithm normalizing rules.
>> >
>> > 2. If normalizedKdfAlgorithm does not describe a registered algorithm
> that
>> supports the derive operation, throw a NotSupportedError and terminate the
>> algorithm.
>> >
>> > 3. Let future be a new Future object and resolver its associated
> resolver.
>> >
>> > 4. Return future and continue executing the remaining steps
>> asynchronously.
>> >
>> > 5. If an error occurs, run these substeps and then terminate the
> algorithm:
>> >         1. Let result be null.
>> >         2. Execute resolver's reject(value) algorithm, with result as
> the value
>> argument.
>> >
>> > 6. If baseKey.keyUsage does not contain the "derive" KeyUsage, terminate
>> this algorithm with an error.
>> >
>> > 7. Let result be an ArrayBuffer object containing the result of
> executing the
>> key derivation algorithm defined by the algorithm indicated in
>> normalizedKdfAlgorithm, with baseKey as the base key, to generate
> bitLength
>> bits of output. If bitLength is not a multiple of 8, set the unused bits
> in the last
>> byte of result to zero.
>> >
>> > 8. Execute resolver's resolve(value) algorithm, with result as the value
>> argument.
>> >
>> >
>> > Section 18
>> >
>> > 18.8. ECDH
>> >
>> >
>> > 18.8.1. Description
>> >
>> > This describes using Elliptic Curve Diffie-Hellman (ECDH) for key
> generation
>> and key agreement, as specified by X9.63.
>> >
>> >
>> > 18.8.2. Registration
>> >
>> > The recognized algorithm name for this algorithm is "ECDH".
>> >
>> >
>> > Operation               Parameters                      Result
>> > generateKey             EcKeyGenParams          KeyPair?
>> > secretAgreement EcdhSecretAgreementParams       Key?
>> >
>> >
>> > 18.8.3. EcdhSecretAgreementParams dictionary
>> >
>> > IDL
>> >
>> > dictionary EcdhSecretAgreementParams : Algorithm {
>> >   // The caller's secondary (ephemeral) private key, if used
>> >   Key? localPrivateKey2;
>> >   // The peer's secondary (ephemeral) public key, if used
>> >   Key? peerPublicKey2;
>> > };
>> >
>> > 18.8.4. Operations
>> > *Generate Key
>> > *Secret Agreement
>> > Perform the appropriate ECDH secret agreement scheme from SP 800-56A
>> Section 6, depending on whether localPrivateKey2 and peerPublicKey2 are
>> specified. The result is a Key object created by importing the shared
> secret Z.
>> >
>> > Note: X9.63 Section 5.4.2 and NIST SP 800-56A Section 5.7.1.2 specify a
>> modified ECDH primitive that multiplies the shared secret value by the
>> cofactor of the curve. The cofactor of the NIST recommended curves P-256,
>> P-384, and P-521 is 1, so the standard and modified ECDH primitives are
>> equivalent for those curves.
>> >
>> >
>> > 18.15. Diffie-Hellman
>> >
>> > 18.15.1. Description
>> >
>> > This describes using Diffie-Hellman for key generation and key
> agreement,
>> as specified by PKCS #3.
>> >
>> > 18.15.2. Registration
>> >
>> > The recognized algorithm name for this algorithm is "DH".
>> >
>> > Operation               Parameters                      Result
>> > generateKey             DhKeyGenParams          KeyPair?
>> > secretArgeement DhSecretAgreementParams Key?
>> >
>> > 18.15.3. DhKeyGenParams dictionary
>> >
>> > IDL
>> >
>> > dictionary DhKeyGenParams : Algorithm {
>> >   // The prime p.
>> >   BigInteger prime;
>> >   // The base g.
>> >   BigInteger generator;
>> > };
>> >
>> > 18.15.4. DhSecretAgreementParams dictionary
>> >
>> > IDL
>> >
>> > dictionary DhSecretAgreementParams : Algorithm {
>> >   // The caller's secondary (ephemeral) private key, if used
>> >   Key? localPrivateKey2;
>> >   // The peer's secondary (ephemeral) public key, if used
>> >   Key? peerPublicKey2;
>> > };
>> >
>> > 18.15.5. Operations
>> > *Generate Key
>> > *Secret Agreement
>> > Perform the appropriate DH secret agreement scheme from SP 800-56A
>> Section 6, depending on whether localPrivateKey2 and peerPublicKey2 are
>> specified. The result is a Key object created by importing the shared
> secret Z.
>>
>> Sorry for the delays in getting back on this - as I worked through all the
> other
>> ongoing discussions.
>>
>> Let me make sure I understand all the appropriate synthesis.
>> 1) Concat, HDKF, and PBKDF2 are all updated to support 'deriveKey' and
>> 'deriveBits'. If you wish to derive a set of four keys (ex: client write
> key, server
>> write key, client hmac key, server hmac key), the only acceptable thing is
> to
>> use deriveBits.
>> 2) DH & ECDH are updated to only support secretAgreement (eg: no
>> deriveKey, no deriveBits)
>>
>> If that's a correct understanding, then I'm not sure if this will work for
>> supporting polyfills.
>>
>> For example, consider the ZRTP (RFC 6189) case. ZRTP describes its own KDF
> -
>> one that is (arguably) compatible with SP800-56A 6.1.2.1 (DH
>> Ephemeral/Ephemeral agreement). If an application wished to polyfill this,
>> they would also have to implement the DH algorithm in JS, since there is
> no
>> way for an application to obtain Z (what is currently returned by
> deriveKey).
>> That seems much less flexible.
>
> Just for my edification.  Is the problem that the built in version of DH
> would be unable to make the call to the polyfill KDF function?

Correct - but it was based on a misunderstanding of Vijay's proposal.

I understood the original proposal was that Z would be fed directly
into the KDF, and the key returned was the derived key. However, after
reading this again, I see that the Key returned wraps Z as a 'raw'
key.

So the only issue here is that the algorithm (derivationAlgorithm) may
be something being polyfilled - in which case, a native implementation
cannot execute the algorithm normalization parameters or handle it for
a polyfilled case.

Normally, a JS application would use any of the ES5/ES6 methods
available to intercept and/or wrap window.crypto.subtle's prototype
with its own extensions. However, in this case, it can't intercept the
derivedKey algorithm.

However, this issue exists in the current ED as well - the
derivedAlgorithm parameter (which isn't even specified fully - oops!)
has the same issues.

Off the top of my head (eg: not having fully considered the
implementation complexities/realities), I can see a couple solutions,
but they all feel a bit gross:
- Expose a meta 'raw' algorithm to allow a Key object to be created
that can then be exported
- Expose a meta 'raw' KDF, for which deriveBits() just exposes the key bits
- Expose some 'secret agree bits' function

Of this, I'm inclined to go for a 'raw' KDF, but if anyone else has
better suggestions, I'm all for it.

>
> The value of Z appears to be to be passed to the importKey algorithm, but it
> is not clear what is returned in the resolve since that is saying value not
> result.
>

I don't understand what you mean here. Vijay's text seemed clear on this point:

11.  Let result be the result of executing the importKey algorithm [...]
12. [...]
13. Execute resolver's resolve(value) algorithm, with result as the
value argument.

Received on Monday, 22 July 2013 22:57:59 UTC