Re: New Editor's Draft

On Tue, Aug 14, 2012 at 9:32 AM, Vijay Bharadwaj
<Vijay.Bharadwaj@microsoft.com> wrote:
> I agree with Arun that we should support key neutering of some sort.
>
> Keys are in fact significantly expensive objects to set up. For example, keys in secure elements need a construct to convey PIN caching lifetime, while AES and HMAC keys require fairly expensive key expansion to be done up front. So it is useful to have a Key object that can last across operations for an application-controlled amount of time. This seems to necessitate a destroy or neuter operation for keys.

Sure, but isn't this already handled by the existing JS GC semantics?

The "set-up" argument seems like one that argues in favour of
reference cloning, but that should already be possible:
var key1 = /* get some key */;
var key2 = key1;  /* key2 is now a reference/clone of key1 */

My understanding was that Blob neutering was a way of addressing Blobs
that were Transferrable. Because Worker memory allocation is different
than the JS "main thread", there needed to be a way to safely pass
memory "ownership" over to the Worker - hence, Transferrable.

It seems like the arguments being made here are to have some form of
"destructor", which seems counter-intuitive towards the design of JS
as a language. If we're concerned that JS will leak the objects,
rather than GC, what guarantees do we have that app developers will
remember to explicitly dispose their keys?


>
> One may argue that this is not what WebCrypto key objects are for; that these are very lightweight objects that are unburdened with such semantics, and therefore should be treated as more disposable. The problem is that we would then need a different construct to hang the above semantics off of; they are too important to performance and possibly UX. We don't have any other object to serve this purpose, so it seems simpler just to do it with Key.
>
> Did you have an alternative construct in mind to serve as a "key context holder" in the above examples?

Conceptually, I was thinking that the "real key" would be something
that the implementation itself would be managing and controlling
access to. As long as at least one Key object existed that referred to
"the real key", then "the real key" would be kept alive. Once all Keys
disappeared, the U-A could release the resources associated with "the
real key".

This is similar to the existing DOM bindings (for better or worse -
opinions vary), as well as to the existing exposure of JS objects.

AFAIK, neutering is used for two purposes:
- To implement Transferrables "safely" - an object sent over a
MessagePort is cloned and the original neutered
- When the object may have attributes/bindings that keep more of the
DOM tree alive than desired.

I'm not sure either of those applies to keys, and the "resources are
expensive" problem doesn't seem to necessitate neutering.

>
> -----Original Message-----
> From: Ryan Sleevi [mailto:sleevi@google.com]
> Sent: Thursday, August 9, 2012 2:08 PM
> To: Arun Ranganathan
> Cc: public-webcrypto@w3.org; GALINDO Virginie; Wan-Teh Chang; David Dahl; Arun Ranganathan; Wendy Seltzer; Harry Halpin
> Subject: Re: New Editor's Draft
>
> On Thu, Aug 9, 2012 at 1:50 PM, Arun Ranganathan <aranganathan@mozilla.com> wrote:
>> On Aug 9, 2012, at 3:42 PM, Ryan Sleevi wrote:
>>
>>> On Thu, Aug 9, 2012 at 12:29 PM, Arun Ranganathan
>>> <aranganathan@mozilla.com> wrote:
>>>> Ryan,
>>>>
>>>> A few comments and observations based on the latest Editor's draft:
>>>>
>>>> 1. You raise the issue (within an Editor's Note) about CryptoOperation being clonable or transferable.  It would seem to me that CryptoOperation objects are "readonly" objects, which suggests that there's no point invalidating them on the sending side.  It may be possible for the implementation to share data between two threads anyway.
>>>>
>>>> The Key object, a readonly attribute of the CryptoOperation, *should* be close-able.  This ties into Issue 16 (https://www.w3.org/2012/webcrypto/track/issues/16).  Additionally, if we think of the Key object as a sort of special-case file, we may want to crib some of the semantics of Blob, which is close-able.  I think my vote is for"Application Semantics" *and* "Implementation Semantics."  We can have a lifetime stipulation on Keys, as well as a close().  I'm not sure what that lifetime should be exactly, but this is something we should discuss.  I wonder if Keys should last past a microtask checkpoint.
>>>>
>>>> Of course, having both an init() and a close() is unusual, but I
>>>> think I can stomach it :)
>>>
>>> If Key were simply a DOMString (referencing some identifier), would
>>> these same concerns apply?
>>
>>
>> I still think so.
>>
>>
>>> My thinking of the Key object is that it's really just a lightweight
>>> property bag - more expressible than a DOMString, but lighter weight
>>> than a File - more akin to a Blob URI
>>> (eg: DOMString) than the Blob itself.
>>>
>>
>> A Blob URI can be revoked.  Do you disagree that we should be able to revoke a Key?  In fact, a Blob URI can be revoked by default (autoRevoke is now true by default).
>>
>>
>>> Of course, I'm not sure the best way to prose this concept up, or if
>>> it's the right approach, so I definitely agree more discussion re:
>>> ISSUE-16 is good.
>>
>>
>> Yes, programmatic revocation of objects in JS is sticky.  If we can arrive at:
>>
>> 1. A safe implementation default which includes an application
>> semantics default AND 2. An optional application semantics mechanism
>> that works in addition to 1. above then
>>
>> that's probably good.  This is like autoRevoke and URL.revokeObjectURL.
>
> At a terminology level, "revoke" is going to be problematic, since "revoking keys" often means a very different thing than I think you mean here.
>
> As I understand it, revocation is only meant for certain objects that may consume significant resources. I'm not yet convinced Key (for any sane implementation) fits those criteria, at least not from the perspective of JS, which is why I have trouble understanding the necessity.
>
> I think this may be an open issue that will require implementation feedback to see if there is a perf bottleneck that /must/ be solved at the application side. I think the only concern where this even becomes remotely meaningful is for smart cards / secure elements, and since I don't think the first implementations will even be supporting those, I'm sort of hesitant to add complexity for them.
>
>>
>>>
>>>>
>>>> 2. Is it worth overloading processData to take a Blob argument?  And, should we allow "result" to return a Blob argument?  This would then mean, of course, that in order to process a "payload" you'd have to read* it as a certain type.  Which may be overly complex, but it does allow us to work at the level of more things other than ArrayBuffers.
>>>
>>> I think this question is related to the concerns raised in ISSUE-18.
>>
>>
>> Indeed!
>>
>>
>>>
>>> Perhaps I've misunderstood the File API spec, but my concern with
>>> taking a Blob is that the Blob, AIUI, has no defined canonical format
>>> (hence the "readAs" methods). In particular, it opens up the
>>> possibility for lossy transformations (due to creating a Blob from
>>> DOMStrings).
>>
>>
>> No, your understanding is spot-on.  A Blob has no canonical format, and *can* result in lossy transformations (notably, forcing an enctype on a stream of bytes and reading them as a string may result in garbled characters, by design).  But, that looseness is now at the programmer's behest -- he/she can read as a string now, or anything else.
>>
>> Of course, the only way to guarantee lossless-ness is an ArrayBuffer, which may mean my brief flirtation with allowing Blobs as both payloads and as results may be over.
>>
>>
>>>
>>>>
>>>> 3. We may wish to define init() in terms of the lifetime of a Key.  How we define init() might be useful for expiration questions.
>>>
>>> I'm not sure I understand this comment. Were you talking init() on a
>>> Key object (as described in point 1), or init() on the
>>> CryptoOperation object? If the latter, then I'm definitely confused.
>>
>> In fact, I was referring to the CryptoOperation object, which is the only place where init() is defined.  What I meant was something like this:
>>
>> 1. Developer calls init() and thus initiates an asynchronous cryptographic operation.
>>
>> 2. The Key affiliated with this operation, if any, now has a ticking clock associated with it.  Or perhaps the entire CryptoStream has a ticking clock.
>>
>> "Ticking clock" is truly bad phraseology.  What I mean is: some sort of lifetime stipulation, akin to autoRevoke on Blob URIs.  Basically, when does the Key become invalidated?  Is a microtask checkpoint (used in HTML5) a useful concept here?
>
> I was thinking that the
> 1) The Key is not neutered; that is, passing it to a CryptoOperation does not invalidate the caller's existing Key object
> 2) The Key may be used for any number of further operations
> 3) At any point, a caller can clone the Key from the CryptoOperation and, along with say, the .algorithm (or other suitable attributes), create a new, equivalent CryptoOperation in an initial state.
>
> As I understand, having the "ticking clock" (or neutering) would prevent this, right?
>
>>
>>>
>>>>
>>>> 4. If dictionary members like "label" are to be interpreted as an opaque series of bytes, we should just use ArrayBuffer.  This is applicable for RsaOaepParams.  I don't think we gain that much more simplification with Base64 or with char conversions.
>
>
>>>
>>> ArrayBuffer or Blob? :)
>>
>>
>> Touché :)  Again, I touted Blob as an option for CryptoOperation payloads and results *only to the extent* that it might lead to programmer convenience by not being bound to a canonical type (and thus sparing a developer a trip into ArrayBuffer land).   But in the case of things that have to be garbled by design, it seemed prudent to just go into ArrayBuffer land anyway (after all, if you have to Base64 something, it may as well be a sequence of bytes).  This might be too arbitrary a distinction, though.
>
>
>>
>> -- A*
>
> Right, one thing I've been wondering about stylistically (and reflected in ISSUE-14/rawKey) is whether to use ArrayBuffer, ArrayBufferView, or Uint8Array as the 'canonical' "bag o bytes" type.
> It would seem like Uint8Array is the uniformly correct type - is this correct?
>
>

Received on Friday, 17 August 2012 21:48:57 UTC