Re: ISSUE-3: Algorithm discovery

On Tue, Jul 10, 2012 at 9:09 AM, David Dahl <ddahl@mozilla.com> wrote:

> Perhaps we should change it to an async method. I think there is value in
> being able to avoid long/costly operations.
>
> I can imagine some use of the API would begin with a test and inside the
> test oncomplete handler you begin the long running operation...
>
> var key = localStorage.ALICE_KEY;
>
> var message = "s3kr3t m3ssag3";
>
> function onEncryptComplete(aCipherData) {
>   // send message to server, etc...
> }
>
> function onAlgTestComplete(isSupported) {
>   if (isSupported) {
>     var stream = window.crypto.encrypt("RS256", key);
>     stream.oncomplete = onEncryptComplete;
>     stream.processData(message);
>     stream.complete();
>   }
> }
>
> var supportTest = window.crypto.supports("RS256", key);
> supportTest.oncomplete = onAlgTestComplete;
> supportTest.verify();
>
>
> So the IDL might be:
>
> [Constructor, Constructor(Algorithm algorithm, Key? key)]
> interface AlgSupport : EventTarget {
> attribute [TreatNonCallbleAsNull] Function? onerror;
> attribute [TreatNonCallableAsNull] Function? oncomplete;
> void verify();
> };
>
> Does this help? Does anyone think we do not need a "supports" API at all?
> Is there a better approach?
>
> Cheers,
>
> David
>

The above API is one way to approach it, but it still fails to address the
other point that I raised - that operations (sign/verify/encrypt) are not
considered when determining 'support'. I'm also at a high-level concerned
with the introduction of too many interfaces, in that each has their own
state machine with their own complexities, and for every asynchronous
object we provide, we need to consider the possibility of synchronous
interfaces for use on Workers.

I'm more inclined to believe that an explicit .supports method may not be
appropriate, and it might be better to consider an explicit
.start()/.initialize() method on the CryptoStream instead, along with an
oninitialized event.

This would have the pseudo-code:
var stream = window.crypto.encrypt("RSA256", key);
stream.oninitialized = function() {
  // Positive support is determined; begin operation.
  stream.processData(...);
  stream.complete();
}
stream.initialize();

The question with the above approach is how should/will user-agents behave
if "key" has one or more ACLs associated with it, or if they need to prompt
(whether "Please insert smart card" or "Please confirm you wish this site
to use this key").

Should such prompting happen during .initialize() or should it happen
during the first .processData()?

If during .initialize(), consumers will have a 'strong' guarantee that the
use of the stream object "should" succeed without error. However, it means
testing for support may involve prompting, and that may not be desirable
for simple feature probing.
If during .processData(), then sites can create streams, .initialize() to
determine support, and then discard them, all without requiring user
interaction nor requiring data be available. However, it means at the time
of .processData(), an operation may still fail.




>
> ----- Original Message -----
> > From: "Ryan Sleevi" <sleevi@google.com>
> > To: public-webcrypto@w3.org
> > Cc: "David Dahl" <ddahl@mozilla.com>, "Michael Jones" <
> Michael.Jones@microsoft.com>
> > Sent: Monday, July 9, 2012 8:26:47 PM
> > Subject: ISSUE-3: Algorithm discovery
> >
> > In the original straw-man and current draft, I proposed an API
> >
> > bool supports(Algorithm algorithm, optional Key key);
> >
> > This was to allow determining whether or not a given algorithm was
> > supported, without having to actually create a CryptoStream object.
> > The
> > intent was to provide a way to discover whether the necessary
> > complete set
> > of ciphers was available for an application, before beginning
> > potentially
> > expensive operations (key generation, data download, key discovery
> > that may
> > result in user interaction, etc).
> >
> > However, as some have pointed out, there are implicit facilities for
> > algorithm discovery, by virtue of the fact that
> > .encrypt/.decrypt/.sign/.verify need to have some well-defined
> > behaviour
> > for handling invalid or unsupported Algorithms. It has also been
> > raised
> > that whether or not a given algorithm is supported is dependent upon
> > the
> > key being used, although I believe I addressed that point via the
> > optional
> > "Key" parameter, since it allows a user optionally to determine if a
> > particular key supports the algorithm, rather than just whether or
> > not an
> > implementation exists.
> >
> > However, I'm now thinking that the currently defined synchronous
> > interface
> > is neither desirable nor sufficient. It seems to me that, for at
> > least some
> > key storage types, determining whether or not a particular algorithm
> > is
> > supported may involve some form of user interaction or, in the case
> > where
> > key storage is backed by hardware, some form of hardware
> > communication. For
> > example, if using PKCS#11, this may involve calls to
> > C_GetMechanismInfo,
> > which may involve talking to a token/slot.
> >
> > These calls may be slow - especially if other programs are using the
> > token
> > or key storage mechanism (including software storage systems that
> > need to
> > have locks) - so it would seem like this should be an asynchronous
> > call. It
> > would also seem that my straw man proposal fails to distinguish the
> > uses of
> > a particular algorithm - for example, a key may only support
> > verification,
> > but not signatures. These sorts of scenario arises even if raw keying
> > material is exposed and implementations are fully software, I
> > believe,
> > since there are still limitations on how a key may be used.
> >
> > Ultimately, this means that the current proposed synchronous API is
> > likely
> > insufficient.
> >
> > Based on what was proposed in the strawman-now-draft, this would seem
> > to
> > imply that the error/exception for an invalid Algorithm would not be
> > able
> > to be raised until the first call to .processData on the
> > CryptoStream.
> >
> > eg:
> > try {
> >   var stream = window.crypto.encrypt("RS256", key);
> > } catch (err) {
> >   if (err instanceof InvalidAlgorithmException) {
> >     // "RS256" does not parse as a valid Algorithm
> >   }
> > }
> > stream.onerror = function(err) {
> >   if (err instanceof UnsupportedAlgorithmException) {
> >     // "RS256" is parsed, but either the key or the underlying
> > implementation doesn't support it.
> >   }
> > }
> > // Until this is called, it's unknown whether or not "stream" will
> > actually
> > work. If it ends up failing, stream.onerror will be called.
> > stream.processData(...);
> >
> >
> > Note that none of the above semantics would necessarily be altered by
> > a
> > MUST-IMPLEMENT registry (ISSUE-1), since there would still need to be
> > some
> > form of error handling for invalid constants/strings and for
> > unsupported
> > key+algorithm+operation tuples.
> >
> > Further, attempting to discover an algorithm by sending 'junk' data
> > (constants or random) may result in user agents having to interact
> > with the
> > user, since there may be security concerns about even calling
> > .processData() on an object (regardless of .complete()), which is
> > some of
> > what ISSUE-2 may be related to.
> >
> > As an implementer, the above semantics look both undesirable and
> > limiting
> > to potential consumers. How do others in the WG feel? Should there be
> > an
> > explicitly asynchronous call to determine whether or not an
> > algorithm/algorithm+key pair/algorithm+key+operation tuple is
> > supported,
> > without requiring .processBytes()? Are there alternate proposals that
> > would
> > simplify or could replace the above API?
> >
> > Cheers,
> > Ryan
> >
>

Received on Tuesday, 10 July 2012 16:30:26 UTC