Named key access (was Re: ISSUE-31 Re: KeyStorage and Pre-provisioned Keys: A proposal )

On Tue, Nov 20, 2012 at 6:14 PM, Mark Watson <watsonm@netflix.com> wrote:
> All,
>
> Some Holiday (for those in the US) reading as promised ...
>
> Following the decision at the Lyon face-to-face, KeyStorage is no longer required for the storage of "temporary" keys generated or imported by the page (these can be stored in IndexedDB or in future storage mechanisms). However, KeyStorage provides the only mechanism in the FPWD to obtain Key objects for pre-provisioned keys.
>
> ISSUE-31 describes a few problems with KeyStorage. Below are two proposals to address these:
>
> Proposal (A): remove KeyStorage and define a new key import algorithm for this purpose

I don't believe Proposal (A) is intuitive or right for the web
platform at all. You're not importing a key. The key already exists.
You're discovering a key which you know exists but do not have access
to.

> Proposal (B): remove KeyStorage and define a new method to create Key objects (provisionally called createKeyAccessor, because we are "accessing" a key, not "importing" the key itself.) and then define an algorithm for use with this method.

Beyond naming concerns (Accessor is quite generic), I *strongly*
disagree with the use of AlgorithmIdentifier and AlgorithmParameters
here. You're not describing a cryptographic algorithm. You're
describing a vendor-specific extension. Let's call a spade a spade,
but not call everything a "tool" just because you can argue the label
fits.

I feel this encourages the exact design pattern that I repeatedly
expressed concerns about - namely, it creates and encourages an
arbitrary set of key discovery mechanisms. I strongly disagree with
that. I believe we should have a single key discovery mechanism.

Let's put it a different way. This is the quintessential definition of
Vijay's "void dovoid(void*)" API. The "KeyAccessor" hides completely
different functions via a single function stub - making it more or
less impossible for developers to reasonably determine feature
support. This runs counter to every JS API. It's bad enough that
algorithms do it - but as was discussed at length, this is because
algorithm capabilities are not gated on user agent, but on the Key
object itself. This functionality is entirely gated on the user agent
- thus there is no reason that it should be an API like the other
algorithms.

While I appreciate the effort to bring text, I think this highlights
what I was afraid of about trying to find something that is right for
the web platform.

If we're going to have a "DoVoid" function (a design decision I
strongly disagree with), just make the parameters themselves the
"DoVoid". That is, getKeys(some param dict, some callback). There's no
need to create a separate object to hold state, there's no need to try
to wrap the param dict in the aegis of
AlgorithmIdentifier/AlgorithmParameters.

My biggest concern remains what I've expressed repeatedly -
introducing (more) optional functionality into the core spec, whether
it's disguised in the terms of AlgorithmIdentifier/AlgorithmParameters
or in the DoVoid via a set of optional-to-implement parameters, is
deeply concerning for us. It just kicks the can of the API design down
the road - by not making any of the hard decisions necessary - but
then makes it further complex for desktop/mobile browsers to develop
or implement an API that's friendly to the open web platform, because
"The web crypto API already has a means for key discovery, why invent
another"

IF we're going to tackle key discovery (a point that, based on
timelines and interest from desktop/mobile browser vendors), then I
there should be *one* set of mandatory-to-implement key discovery
parameters, with a single MTI key discovery API. If you are going to
support arbitrary forms of key discovery, do it in a way that's right
for the web - new methods that can easily be feature tested, not one
giant API.

Certainly, as repeatedly expressed during the F2F, I think trying to
match the current API is an inherently bad idea, given that the
current API is (as repeated by every browser vendor) quite unusable at
this point and needs to be fixed.

>
> Briefly, the pros and cons of the two proposals are:
>
> (A)
>         pros: the new text is restricted to a new algorithm section. The same pattern could be used in future for tokens, smart cards etc.
>         cons: "import" is a misnomer because the key itself is not moved into the UA. We have to overload the key parameter of createKeyImporter to specify the key name
>
> (B)
>         pros: cleaner (addresses the cons above). The same pattern could be used in future for tokens, smart-cards etc.
>         cons: more text (new KeyOperation object, new Crypto method)
>
> Note that I also plan to bring improved privacy text based on the discussions at the face-to-face and subsequently.
>
> Proposal (A)
> =========
>
> 1) In Section 10 (Key interface), remove the id attribute
>
> 2) Delete Section 17 (KeyStorage)
>
> 3) Section 18, Crypto interface: remove keys attribute and section 18.1.10
>
> 4) Add a new section:
>
> "23.3.X Origin-specific named key access
>
> 23.3.X.1 Description
>
> The string "OriginNamedKey" is used to identify the origin-specific named key access algorithm. UAs may support access to named origin-specific keys, for example pre-provisioned keys. These may be external to the UA. Naming schemes are out-of-scope of this specification. As examples, UAs may provide access to UA or platform provided pre-provisioned keys for specific origins, named according to the requirements of that origin. Another example would be a UA-specific capability to provide one or more origin-specific keys to any origin, with UA-defined names.
>
> 23.3.X.2 Registration
>
> The recognized algorithm identifier for this algorithm is "OriginNamedKey".
>
> Operation | Parameters   | Result
> ----------------------------------------
> importKey | None         | Key?
>
> 23.3.X.3 Operations
>
> Import Key
>
>   When importing a key, the resulting KeyImporter shall behave as follows:
>
>     1. Upon invoking import:
>       1. If no key exists with a name equal to the contents of the key parameter to the createKeyImporter call raise an error and terminate the operation.
>       2. Let result be a Key object providing access to the key with the specified name. The temporary attribute of the Key shall be false. The extractable attribute shall be true if and only if both the extractable parameter to the createKeyImporter call was true and the key supports extraction. The key usages shall be the intersection of the key usages specified in the keyUsages parameter of the createKeyImporter call and the key usages supported by the key."
>
> NOTE: we may instead simply require that the usages equal those supported by the key.
>
> 5) Add example code, tbd
>
> Proposal (B)
> ==========
>
> 1) In Section 10 (Key interface), remove the id attribute
>
> 2) Delete Section 17 (KeyStorage)
>
> 3) Add new Section X, after existing Section 16
>
> "Section X: KeyAccessor interface
>
> interface KeyAccessor : KeyOperation
> {
>   void get();
> };"
>
> 4) Section 18, Crypto interface:
> - remove keys attribute
> - add new method
>
> KeyAccessor createKeyAccessor( AlgorithmIdentifier? algorithm,
>                      bool extractable = false,
>                          KeyUsage[] keyUsages = []);
>
> 5) Add new section after 18.1.9
>
> "18.1.Z The createKeyAccessor method
>
> The createKeyAccessor method returns a new KeyAccessor object that will provide access to keys not originally created using the Crypto API (i.e. not created with import, generation or derive methods.) It must act as follows:
>
>   1. If algorithm is specified, let normalizedAlgorithm be the result of processing algorithm according to
>      the algorithm normalizing rules.
>   2.  If algorithm is specified and if normalizedAlgorithm does not describe a registered algorithm throw a
>      NotSupportedError and terminate the operation.
>   5. Return a new KeyAccessor object S with the following characteristics:
>      1. S.result = null
>
> Keys created with this method SHALL be subject to the extraction and usage constraints of the key
> itself. The extractable argument SHALL NOT be honored if the key itself does not allow extraction of the key data. The
> key's usages SHALL consist of the intersection of the keyUsages argument
> and the usages supported by the key itself."
>
> NOTE: we may instead simply require that the usages equal those supported by the key.

Both keyUsages and extractable should be parameters for discovery.
Asking for keys of (X AND Y) but getting keys of (Y OR X) is
inherently error prone.

If they are discovery parameters, then they should be in the
parameters dictionary - not as standalone args. This applies for both
KeyUsage and extractable.

>
> 4) Add a new section:
>
> "23.3.X Origin-specific named key access
>
> 23.3.X.1 Description
>
> The string "OriginNamedKey" is used to identify the origin-specific named key access algorithm. UAs may support access to named origin-specific keys, for example pre-provisioned keys. These may be external to the UA. Naming schemes are out-of-scope of this specification. As examples, UAs may provide access to UA or platform provided pre-provisioned keys for specific origins, named according to the requirements of that origin. Another example would be a UA-specific capability to provide one or more origin-specific keys to any origin, with UA-defined names.
>
> 23.3.X.2 Registration
>
> The recognized algorithm identifier for this algorithm is "OriginNamedKey".
>
> Operation | Parameters           | Result
> ----------------------------------------
> accessKey | NamedKeyAccessParams | Key?
>
> 23.3.X.3 ExtKeyImportParams dictionary
>
> dictionary NamedKeyAccessParams : AlgorithmParameters
>  {
>
> // The key name
>
>   ArrayBufferView keyname;
> };

Why not DOMString? This just furthers the comments of the "void*"
part, since ArrayBufferView is a not only a fully opaque series of
bytes, but regrettably developer-hostile (as shown in the example
code).

Naming wise, the addition of "Origin" seems redundant - the entire
security premise of the API is origin-based keys.

>
>
> 23.3.X.3 Operations
>
> Access Key
>
>   When importing a key, the resulting KeyImporter shall behave as follows:
>
>     1. Upon invoking get:
>       1. If no key exists with a name equal to the contents of the name parameter raise an error and terminate the operation.
>       2. Let result be a Key object providing access to the key with the specified name."

Redundant? Or how do you see this working, given that "name" is unclear here.

>
> 5) Add example code, tbd
>
> ...Mark
>
> On Nov 19, 2012, at 1:14 PM, Mark Watson wrote:
>
>>
>> On Nov 19, 2012, at 11:30 AM, Ryan Sleevi wrote:
>>
>>> On Mon, Nov 19, 2012 at 10:27 AM, Mark Watson <watsonm@netflix.com> wrote:
>>>>>
>>>>> As mentioned previously, this does not sound like a suitable approach
>>>>> to addressing the technical concerns raised.
>>>>
>>>> You mentioned that you did not like overloading the existing import/export, but I didn't see any comments from you against the idea of casting different query/discovery mechanisms as 'algorithms'. Do you object to that approach generally ? Could you elaborate ?
>>>>
>>>> …Mark
>>>
>>> Every browser vendor that has commented has (rightfully) raised
>>> concerns about optional algorithms. "Optional" is generally seen as
>>> bad for the web platform. I've already received suggestions from some
>>> that the way to address algorithm regulatory/technical concerns
>>> motivating algorithm optionality would be the wholesale
>>> enabling/disabling of the feature, rather than having algorithms be
>>> optional. This is conceptually similar to WebGL, in which if a video
>>> card does not support feature X, the entire WebGL suite is disabled
>>> (or the browser software-fills it in). While not wanting to re-open
>>> the algorithm debate at this point, I provide it as a reasonable point
>>> to demonstrate the growing concern about how effective the API will be
>>> with optionality, and why more optionality is a non-starter.
>>>
>>> As related previously, I've hopefully made it clear my own view that a
>>> model of optionality - modeled after algorithms or otherwise - is
>>> pretty much a non-starter for the main spec from an implementer's
>>> perspective, for reasons such as above. If the WG reaches consensus to
>>> going further down the rabbit hole of "optionality", then we should be
>>> talking modules and separate specs (each of which MUST be wholly
>>> implemented), rather than a giant mix-and-match free for all in a
>>> single spec.
>>>
>>> Regardless though, given the significant (complete?) overlap between
>>> pre-provisioned and pre-existing keys, it seems like a single, common,
>>> mandatory API is absolutely possible to devise.
>>
>> Ok. I think in this case most of what you say above about "optionality" becomes moot. If a device doesn't have, doesn't support, doesn't care about some particular kind of key, then any kind of key query is going to return "not found". If it reduces "optionality" we can specify that this is what should be returned in all cases where a Key object can't be returned, and don't break out "algorithm not supported" as a separate case.
>>
>> I appreciate that we should not introduce optionality through our work on the API, but there do exist things that are beyond our control, like devices with different capabilities.
>>
>> …Mark
>>
>>>
>>
>>
>>
>
>

Received on Wednesday, 21 November 2012 02:55:42 UTC