[Bug 23369] Provide hooks for Typed Arrays (ArrayBuffer and friends)

https://www.w3.org/Bugs/Public/show_bug.cgi?id=23369

--- Comment #22 from Ryan Sleevi <sleevi@google.com> ---
(In reply to Allen Wirfs-Brock from comment #21)
> For example, in the WebCrypot API I notice that the encrypt and decrypt
> methods both are specified to clone their data parameters. Why? It certainly
> doesn't make any sense to modify the data buffer after the initial call and
> before processing starts, but is there any integrity or other essential
> reasons that must be actively guarded against with the cost of forcing a
> copy of a potentially large buffer? 

Since this is core to the discussion on this bug, I'll address it. There are
several questions that are more specific to WebCrypto that, for sake of those
following this bug, I've not answered. I'm more than happy to follow-up on
public-webcrypto@ if you want to continue the discussion/API concerns there.

As it relates to this, the Promise vended by these operations (and it's not
just encrypt/decrypt but *all* of the SubtleCrypto operations, save for
exportKey), the user agent continues asynchronously processing the data 'in the
background'.

As such, we need to ensure that the user does not mutate data at the same time
the implementation is reading data, and that implementations afford consistency
to script authors. There is not, within Promise-using ES6, seemingly any
requirement for synchronizing access to data to the task queue; indeed, that
could be quite bad for some cases (example being networking events).

Cryptographic operations can be costly, not just in CPU terms, but in some
implementations, may result in IO waits. Many cryptographic APIs are blocking
APIs themselves. Even a small buffer (of 20 bytes) can, for some operations,
cause multi-second stalls if backed by hardware.

This API was designed to support both hardware and software-backed operations,
even if we expect most of the first implementations are software-backed (as
that's what the spec currently favours in description). Because of the hardware
requirements, we don't want to pause the ES microtask pool / HTML task pool in
order to synchronously invoke these methods; we would instead prefer to treat
them like networking events (eg: dispatch data to some API, receive
asynchronous notification of completion).

The output of the cryptographic operation should be consistent with its inputs.
If we allowed arbitrary modification, we can run into situations like:

var a = new Uint8Array(4);
a.set([0, 1, 2, 3]);

var promise = crypto.subtle.encrypt(.., a, ...);
// At this time slice, the UA has not yet begun the encryption operation,
// because the underlying subsystem may only support a single pending
operation,
// and the encrypt() is still pending
a[0] = 4

promise.then(result => { 
  // Does result contain ciphertext for [0, 1, 2, 3] or for [4, 1, 2, 3]
});

This is why an explicit copy is noted; the actual transformation of the input,
plaintext buffer (A) is, in almost all cases (hardware or software), not going
to happen synchronously before the return of the Promise and continuation of
the task pool. So callers should have a reasonable expectation of what the
transformation of the data will look like. Since objects - such as ArrayBuffer
- are passed by reference, callers can fully mutate the object throughout the
lifetime of the Promise, so it's necessary, as spec authors, to indicate at
what point in execution the state is accessed.

In Web Crypto's case, we try to make it clear that any and all state that will
be accessed before the return of the Promise object. Other specs (Web Audio and
Web Font Loading come to mind), have not, and as such, have subtle issues in
their spec that can lead to user-observerable, non-interoperable behaviours.

> Also, is the a reason that the CryptoKey
> parameter objects aren't cloned (probably deeply) to ensure that it isn't
> mutated at the same time a buffer might be mutated?

Let's follow up on public-webcrypto@. TL;DR: CryptoKey's are immutable holders
of an internal object ( [[handle]] ). All ops work on the internal slots, which
cannot be mutated.

> If we're talking about any sort of real object graph (for example, a
> CryptKey??) a generalized clone operation is much more problematic. 

We aren't, or more specifically, I'm not, and certainly not in this bug. I
agree that other Promise-returning APIs may accept other forms of mutable
objects, and those APIs may need to define at what timeslice/task event
snapshots (if any) are taken of the object state for working with the API, and
when/how object state is accessed.

However, for fundamental ES types - those for which Web IDL spends significant
time dealing with (in terms of the ES <-> IDL type conversions) - it would be
nice to see %TypedArray% - which is as primitive as %Array%, %String%,
%Boolean%, or %Number% are in ES6 - to have specific language in Web IDL to
explain how it's used with Web IDL, and to afford Spec Authors ways to hook or
customize that behaviour (eg: copies), if necessary.

> BTW, on a pretty much separate matter I'm not really convinced
> that you need to allow either an ArrayBuffer or a typed array
> for all of these data arguments. 

A better fora for this is public-webcrypto@ / public-webcrypto-comments@ (or
our WebCrypto bug tracker), where I'd be happy to address this feedback.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Received on Tuesday, 17 June 2014 21:39:59 UTC