Re: ACTION-22: Key export

On Wed, Aug 22, 2012 at 1:23 AM, Mitch Zollinger <mzollinger@netflix.com> wrote:
> Sorry for the slow response on this issue. I'm currently on business travel
> in Asia.
>
> Responses below.
>
>
> On 8/17/12 3:50 AM, Vijay Bharadwaj wrote:
>
> No, I was thinking of authorization and export as separable issues.
>
>
>
> -          You can only see keys that you are authorized for.
>
> -          Of the keys you can see, you can potentially export the
> exportable ones without UI.
>
>
> Ok. This matches my understanding.
>
>
>
>
> Regarding the DH+KDC model, I wonder if this isn’t getting real close to a
> high-level API. It feels like it’s a hop and a skip away from a generic
> box/unbox API. This is not to say that it isn’t a worthy goal, just that it
> may be hard to generalize to a low-level API.
>
>
> When I first read your response, my initial reaction was actually to agree
> with this. If I assume that there is no possibility of protected key
> exchange + key derivation, then I know that if my JS app is compromised, the
> session key is exposed. But if a security attack happens (and let's assume I
> hear about it!), I *could* actually fall back to using pre-shared keys to
> "recover" my secure session with the device.
>
> But, after a bit more thought, I actually believe that there is a reason to
> push for protected key exchange / derivation based on:
> * We have explicitly stated that we want key protection; that is, in some
> instances of keys, the JS is not allowed access to the keying material.
> * We have explicitly stated that we want session keys as the product of some
> key exchange mechanism.
> * Taken together, there's no way to satisfy the above two goals without a
> protected key exchange / key derivation, correct?

Probably not as you'd like, but the existing spec does cover this, so
I think it'd be helpful if it was understood why this would be
unacceptable.

As discussed on the phone call, you could generate a DH key pair with
a KeyGenerator (with the DH private key/value that is "opaque" to
content script, but not necessarily the U-A) and derive a shared
secret key with a KeyDeriver (passing the peer's DH public value). If
there was a need for more rounds, you could use multiple KeyDerivers,
passing in different Key objects as appropriate. For example, an RFC
2631 scheme that has a single round to expand the DH shared secret
into an appropriate symmetric key, or an RFC 6189 style exchange that
derived expanded ZRTP Confirm1/Confirm2 into an SRTP session key.

>
> What if we were to simplify the last proposed mechanism to this instead:
>
> ProtectedKeyExchange kex = ProtectedKeyExchange(/*algorithm*/"foo");
> kex.init(/*algorithm specific params*/);
> while(! kex.done()) {
>   Uint8Array client_data = kex.getNext();
>   /* ...send client_data to server... */
>   /* ...get server_data from server... */
>   kex.step(server_data);
> }
> /* get a handle to the protected key that was exchanged */
> Key key = kex.getKey();
>
> ?
>
> The net effect is that we don't have to declare any sort of first class key
> exchange + key derivation concepts at the WebCrypto API level; we simply
> exchange keys where the end result is a handle to a non-exportable key.
>
> This "ProtectedKeyExchange" could simply be thought of as short-hand for
> something like:
>
> KeyExchange kex = KeyExchange(/*algorithm*/"foo", /*exportable*/false);
>
> The difference being that we may want to specify ProtectedKeyExchange as a
> simplification. (What if exportable is "true"? Also, the algorithm names for
> ProtectedKeyExchange will be different from KeyExchange.) But, that's really
> more of a style question.
>
> Would the above better meet the goal of avoiding a "high level API"?
>
>
> Mitch

- If the only purpose of "ProtectedKeyExchange" is to imply a default
value for KeyExchange (/*extractable*/ false), then that's a
non-starter. The implementation overhead of bindings for that,
especially for what is nominally just a parameter value, would not be
acceptable.

- I'm not sure how a "KeyExchange" interface avoids having to declare
a first class key exchange. It seems the very presence of an interface
for key exchange, as proposed, inherently makes it 'first class'. Are
you saying "You avoid having to specify the algorithm?" If so, I think
that would also be a non-starter, as it's inherently not implementable
by open, standards compliant browsers. If you do specify the
algorithm, then I'm confident it's something we could express as a
series of primitive steps without having to resort to opaque "here's
some blob" exchanges.

- More fundamentally, I think I have trouble with the idea of key
exchange as a GSS-API like mechanism, which this appears to
effectively be. The concept of these opaque bytes going through the
application is, on some deep API level, a bit troubling. The fact that
no such equivalent exists in any of the standards or APIs that I think
are worth considering (PKCS#11 and CDSA as 'true standards',
CryptoAPI, CNG, OpenSSL, BSafe - as "standard" APIs, to name a few) I
think also highlights the specialist nature of this.

While I understand this may be how you're currently doing things, I'm
not sure this is something that should be supported - or at least, be
considered as something under the 'optional' category that we wait to
address until after we make sure the base level primitives are
acceptable to everyone and implementable.

Fundamentally, I recognize that this is closely related to key
wrap/unwrap, which are not yet specified, due to first needing to make
sure that key import/export are the correct APIs, due to the close
relationship between the two. I understand that key transport
(import/export) and key agreement (which I believe is already
accomodated) are part of our primary API features. And I can
appreciate the desire for 'secure provisioning' of keys. However, my
concern is that the practical use cases for such an API are more
closely related to secure elements, smart cards, or other device
specific behaviours, at least as I understand your proposal.

Similar to the aforementioned APIs, I would rather expose the
primitives (eg: DH phase 1, DH phase 2, ZRTP part 1, ZRTP part 2),
then trying to describe an entire flow, with all of the
protocol-specific parameters (eg: all the data that flows into an RFC
6189 3.1.1 exchange). Trying to define an API for an entire ZRTP flow,
as an example, is something that I think is the essential definition
of high-level.

Regards,
Ryan

>
>
>
> From: Mitch Zollinger [mailto:mzollinger@netflix.com]
> Sent: Wednesday, August 15, 2012 10:28 PM
> To: Vijay Bharadwaj
> Cc: public-webcrypto@w3.org
> Subject: Re: ACTION-22: Key export
>
>
>
> On 8/14/12 9:38 AM, Vijay Bharadwaj wrote:
>
> Mitch> As described during our f2f: we would like to use a KDF on a
> Diffie-Hellman negotiated shared secret to create a session key (or session
> keys) where the raw session key is never allowed to be accessed by the
> webapp.
>
>
> I agree with the aim, but as discussed earlier I don’t know of a way to make
> this work in general. In general, the output of a KDF is “just bytes” as far
> as the algorithm is concerned, so it’s hard to see a way to pick some bytes
> from that output and designate them as “special” (i.e. key material). I
> suppose this case could be made to work if we applied additional
> restrictions, but that may require a different API that takes in key or
> secret handles rather than an ArrayBuffer.
>
>
> Exactly. As described in the Netflix use case document, the idea is that the
> shared secret created by a DH exchange is one which the app is never allowed
> to access. There are clearly some pitfalls of implementation in this model;
> if a generic Diffie-Hellman was compatible with this DH+KDC model of key
> creation, the server would not know the difference between a client which
> was using DH with exportable shared secret and the special DH+KDC model.
>
> This requires a bit more design; there are ways of doing this that depend on
> other types of attestation (imagine that the underlying implementation
> created a signature on the DH public component sent by the client to the
> server only when the special DH+KDC model was invoked, for example), but in
> general, I still believe that the API can allow for this type of exchange
> without even specifying the actual algorithms.
>
> ProtectedKeyExchange kex = KeyExchange("KeyExchange Algorithm Foo");
> Uint8Array client_pub = kex.getPublic();
> /* ...send client_pub to server... */
> /* ...get server_pub from server... */
> /* complete exchange, created keying material precursor inside of kex */
> kex.exchange(server_pub);
> /* get handle to shared secret */
> Handle handle = kex.getSharedSecret();
> /* derive a session key */
> Key key = Key.create(KDC.get("MyKDCAlgorithm"), handle);
>
> I know in our offline conversation, you brought up some good points around
> FIPS compliance & only using the shared secret for a single key derivation.
> Despite that cautionary advice, is there something that would prevent us
> from accomplishing the above?
>
>
>
>
> Mitch> In terms of expected user interaction in a browser, is there some
> idea of a key store password, where the user has to enter the password to
> explicitly export a wrapped key? Or is this a click-through dialog box where
> the user simply clicks "Ok" and the webapp gains access to the raw key?
>
>
>
> I was imagining a situation where this is determined by the key itself. Most
> exportable keys would be exported with no user interaction at all, and
> non-exportable keys would just fail. Keys stored on smart cards for example
> may require UI but that is imposed by the card not the UA.
>
>
> Ok. I was getting this mixed up with Ryan's & Mark's conversation around
> domain bound vs. domain authorized sites. With "domain authorization"
> though, in your model, if the site that created the key created it with
> exportable=true, then the second site could just export the key without any
> user interaction? (I don't think this is what you meant.)
>
> Mitch
>
>
>
>
> From: Mitch Zollinger [mailto:mzollinger@netflix.com]
> Sent: Monday, August 13, 2012 5:52 PM
> To: public-webcrypto@w3.org
> Subject: Re: ACTION-22: Key export
>
>
>
> On 8/13/2012 7:54 AM, Vijay Bharadwaj wrote:
>
>
> We’ve gone around on this a few times, including at the f2f, so here is a
> concrete proposal. I’m trying to find a balance between extensibility and
> not loading up the API with a bunch of stuff, so feedback is welcome.
>
>
>
> I see the following use cases for key import/export:
>
> -          Create session key object from derived key bytes (using either
> KDF or secret agreement): this would require raw key import
>
>
> I would add:
>  - Create session key object from derived key bytes, using KDF of underlying
> keying material, which does not allow raw key import / export.
>
> As described during our f2f: we would like to use a KDF on a Diffie-Hellman
> negotiated shared secret to create a session key (or session keys) where the
> raw session key is never allowed to be accessed by the webapp.
>
>
>
> -          Create key object from public key received from peer (for
> asymmetric encryption or signature verification): this would require public
> key import, where the public key is likely ASN.1 encoded in many apps
>
> -          Export/import (wrapped) content encryption key for data
> encryption: this could be just the wrapped key or something like a PKCS#7
> RecipientInfo (which is ASN.1 encoded). Import/export requires a handle to
> the wrapping key.
>
> -          Export/import of private keys for distribution, with formats like
> PKCS#8.
>
>
>
> From an API perspective, supporting export seems to be straightforward. The
> Key object needs an export (or wrap) method, which takes a target format and
> potentially a wrapping key as parameters.
>
>
> In terms of expected user interaction in a browser, is there some idea of a
> key store password, where the user has to enter the password to explicitly
> export a wrapped key? Or is this a click-through dialog box where the user
> simply clicks "Ok" and the webapp gains access to the raw key?
>
>
>
>
>
> It seems to me there are two API models to support import. Either have an
> ability to create an empty Key object, then invoke an import method on that
> object, or make it part of the construction of the Key object. I propose the
> latter, so that we don’t complicate the state model of the Key object.
>
>
>
> So in WebIDL,
>
>
>
> interface Crypto {
>
>
>
> … other stuff …
>
>
>
> KeyGenerator importKey(DOMString format, ArrayBuffer keyBlob, optional Key
> wrappingKey=null);
>
> }
>
>
>
> interface Key {
>
>
>
> … other stuff …
>
>
>
> KeyExporter exportKey(DOMString format, optional Key wrappingKey=null);
>
> }
>
>
>
> Where KeyExporter is exactly like KeyGenerator but returns a value instead
> of a Key object.
>
>
>
> One big issue is what key formats should be supported. For symmetric keys it
> makes sense to support a raw format, but for asymmetric keys things are more
> complex. As has been brought up on other threads, many commonly-used formats
> are ASN.1 based and so it seems like supporting that would really help
> interoperability. However, I’d like to avoid a repeat of the mandatory
> algorithms discussion. Any ideas here are welcome.
>
>
>
>
>
>

Received on Wednesday, 22 August 2012 19:12:27 UTC