RE: Use case classification, and associated security models

I agree with Ryan on this.

There are two problems IMO with introducing the notion of crypto providers:

1.       You have to standardize (and maintain) a set of well-known provider names across all platforms. Once you do that, scripts start to code in assumptions about the capabilities associated with each provider name, and you can no longer evolve the capabilities of a specific provider without breaking compatibility. So in effect a provider becomes just a fixed collection of cipher suites, and it's unclear that such an abstraction is needed.

2.       There is no security assurance associated with a provider name. Nothing stops a client environment from presenting a "smart card provider" which actually stores keys in the clear on disk, and nothing enables a server to detect that this is the case.

From: Mitch Zollinger [mailto:mzollinger@netflix.com]
Sent: Tuesday, June 12, 2012 7:55 PM
To: Ryan Sleevi
Cc: public-webcrypto@w3.org
Subject: Re: Use case classification, and associated security models

On 6/12/2012 3:58 PM, Ryan Sleevi wrote:

On Tue, Jun 12, 2012 at 3:30 PM, Mitch Zollinger <mzollinger@netflix.com<mailto:mzollinger@netflix.com>> wrote:
On 6/12/2012 2:29 PM, Ryan Sleevi wrote:

On Tue, Jun 12, 2012 at 1:31 PM, Mitch Zollinger <mzollinger@netflix.com<mailto:mzollinger@netflix.com>> wrote:
On 6/12/2012 12:53 PM, Ryan Sleevi wrote:


On Tue, Jun 12, 2012 at 12:38 PM, Mitch Zollinger <mzollinger@netflix.com<mailto:mzollinger@netflix.com>> wrote:
On 6/12/2012 1:07 AM, Vijay Bharadwaj wrote:

<snip>


In all the above cases, once a key is obtained, all the actual crypto operations are pretty much the same. So is we define all operations in the API which require a key such that they take a key object as a parameter, then the only difference between the above scenarios (from an API perspective) is the operations used to instantiate that key object. The above 3 scenarios would then correspond to 3 different instantiation methods for key objects:


1.       GenerateKey - create a new key for use with a specific algorithm. Choice of crypto provider left up to the platform.

2.       ImportKey - take a key blob obtained from key agreement and create a key object from it. Choice of crypto provider left up to the platform.

3.       OpenKey - Locate a key on the host system that matches a set of criteria. Choice of crypto provider to be made by platform depending on the location of the key.

There is also a fourth primitive which is often used with scenario 3 - credential enrollment. This would be the operation where the user employs the trusted key to obtain a credential (e.g. enrolling for a smart card certificate by signing a request using one's existing smart card key).

Does that seem reasonable? Any other families of use cases that I'm overlooking?

Good write up.

I would like to better understand what you (and the group) think about "crypto providers". When I think about crypto providers, I think of the JCE (Java Cryptography Extensions) Crypto Providers & OpenSSL "engines". In that context, it would seem to me that the app has varying behavior with regard to crypto provider selection that may be orthogonal to the type of the key. One example:

* If my app detects that a smart card is plugged in & I can use keys on the smart card for service authentication, I will not ask the user a security question when they connect to my webapp. However, if I'm using another crypto provider (likely the default provided by the browser) -- with the same keys that would have been stored in the smart card if the user had it plugged in -- then I will ask my security question.

Mitch

I think that any app that would do what you propose, without any other additional proof, would be making a naive assumption that doesn't really improve the security. I certainly do not want to expose any such concept to the web API for exactly that reason.

In your example, you're relying on the user agent to honestly answer "smart card" or "not smart card" for where the key is stored, and then making a server side security decision based on that.

I should have been more explicit. I'll echo much of what you say below (I agree with you):

When I say "same key" I'm referring to a key with the same *key name* in both contexts, not actually the same keying material or same UUID (I'm taking the liberty of assuming the UUID exists for now.)

The point is that the running web app / web service is making a decision on further authentication steps based on the provenance of the key: was it distributed out-of-bound and considered pre-shared or was it something I made up at webapp runtime?



Such a decision seems a lot like sticking form validation code in the client to prevent against SQL injection. Browsers can be mislead or manipulated, so I don't think it can be reasonably assumed to give an answer that is reliably accurate.

No reliance on trustworthiness of client side JS code assumed here.




Using Vijay's ontology, if you want to make the distinction between secure element or not, you, as a service provider, would do so based upon whether or not you (as a service provider) were responsible for the provisioning ceremony of those keys. If you controlled the ceremony, you know the provenance of those keys, and you know how and where they're stored.

Absolutely agree.




Whether this means mailing out a smart card, using some other application/protocol/platform. Examples might be GlobalPlatform, with it's proof of possessions, some work product of the IETF's KeyProv WG, something like Anders Rundgren's Keygen2, etc. However, the size and scope of work, and the many competing interests involved, seem very much out of scope for this WG (although admittedly very interesting and perhaps parallel work to solve)

To modify your scenario into something that I think would provide some reasonable assurances:
* If your app detects that the user has a (pre-provisioned Key ID X), then you can allow that user to authenticate using Key X.
* If your app does not detect Key X, but detects a (previously generated via <keygen> or the ephemeral API Vijay proposed), then it uses Key Y, plus some form of challenge/security question.
* If your app detects neither Key X nor Key Y, it offers the user the chance to (online enroll a Key Y, contact you to obtain a smart card with Key X)

Yep. No disagreement from me with this approach. I would rewrite this as:
* My app wants to use "AuthKey" to authenticate the client, wherever "AuthKey" may be.
* The app attempts to use "HSMProvider" as the crypto provider; if that provider does not work or is not available, it falls back to "DefaultProvider". (For the moment, I'm ignoring the bootstrap of "AuthKey" into each of these providers.)
* The app authenticates using "AuthKey", which has an associated UUID which allows me to map the key to one of (a) a key that I provisioned into an HSM (and accessible via "HSMProvider") or (b) a key entrusted to the "Default" provider.
* The server side decides, based on Provider/UUID whether to initiate further authentication steps.
Mitch

I'm not sure the providers are necessary here, which is part of why I'm somewhat opposed to them.

Using the KeyQueryList sort of example from the other thread, I would think you'd simply set a KQL for "some criteria" (admittedly, hand-wavey), and you would get back (assuming the user approved/pre-approved) two keys.

At that point, you have two keys you're interested in. The question is which (or perhaps both) you want to use for the signing operation. Your web app may make a query to the server and say "I have these two keys, which would you like to use" - at which point, the server might say "Use this one, I know because I presided over the ceremony".

Your web app may have already sent that list to the client, and the client JS then knows that key X is preferable over key Y, and upon seeing that it has both Key X and Key Y, attempts the authentication protocol first with Key X.

You may even show a UI (using your web apps branding) to allow the user to select which key they wish to use, similar to sites that offer multi-login or oauth/saml style workflows.

At no point does the application need to be exposed to the crypto provider or how the key is backed - it's simply a key handle that it can use.

My guess (perhaps completely unfounded, based on our current participants) is that most applications using this API will not care about "DefaultProvider" or "HSMProvider", and certainly, I think it introduces a whole host of new, cross-browser standardization issues. For example, consider if we have two implementations, one based on PKCS#11 (eg: Mozilla Firefox, Chrome for Linux) and one based on CryptoAPI/CNG (eg: Internet Exporer, Chrome for Windows, Safari for Windows). Both OS-level APIs may be talking to the same logical smart card/key store/secure element, but because of the very different nature of the APIs, have very different naming schemes to identify them.

Using the above example, is there a scenario/workflow where "Try to find Key X, then try to find Key Y", in application logic, is more desirable than "Query for Key X or Key Y", and then in application logic making a decision based upon the response you got?

We can work with either mechanism. What I've described (the two keys have the same "name" and the provenance is implied by the UUID) fits better conceptually with what we're doing today, but I could just as easily query for the two keys and use whatever one I got back without worrying explicitly about provenance.

I guess I'm not seeing how KeyQueryList would be used. Given that you and Wan-Teh are advocating for something along these lines, it's clear I'm missing something. (I know very little about smart card usage, so this is not surprising.) Could you give an example? In other words, could you fill in the [Some, Criteria, Here] portion of your pseudo code example?


var kql = window.crypto.queryKey([Some, Criteria, Here]);

Mitch

Wan-Teh hasn't quite chimed in here on KQL, so I don't presume to speak for him :-)

The [Some, Criteria, Here] is, in part, dependent upon the ontology of key types we're talking about. Whether Vijay's notation or my original suggestion of "ephemeral, persistent, and high-value", it does seem like we agree on some distinction between "shared" (between origins / between other services) and "origin bound" (as the charter and original discussions focused on). The parameters to queryKey are going to necessary reflect whatever dimensions we determine are both relevant for key management and within the scope of the charter.

There needs to be symmetry between the create/derive functions and the query functions, although understandably there will be some slight differences since you can't create pre-provisioned keys :)

// Find all RSA keys that are usable for OAEP. Additionally, the keying material must be available for
// the script to use (perhaps it implements some custom scheme that builds atop OAEP) and it must not
// be a key that is cleared when the user clears their browsing data (eg: it must be 'long-lived/persistent',
// which is conceptually similar but slightly different than Vijay's 'pre-provisioned' category)
var kql = window.crypto.queryKey(
  {
    'algorithm': 'RSA',
    'mode': 'OAEP',
    'extractable': true,
    'temporary': false,
  });

// Retrieve all AES keys available for use with CBC mode. They may be temporary keys or
// persistent keys, it may be keys that were randomly generated and it may include keys that
// were derived from some other algorithm (eg: an ECDHE exchange). No particular expression
// about how it is stored is made.
var kql = window.crypto.queryKey(
  {
    'algorithm': 'AES',
    'mode': 'CBC',
  });

// Retrieve all keys (See [1]) that are backed by a certificate, whose issuer is one of IssuerName 1 or
// IssuerName 2. This may return both RSA and ECC keys, since no 'algorithm' has been specified. The
// key must be usable for signing (which may be ascertained as part of the key store or may need to
// be inferred from the KU/EKU of the associated certificate(s))
var kql = window.crypto.queryKey(
  {
    'operation': 'sign',
    'certificate': {
      'issuer': [
        [ ArrayBuffer of DER IssuerName 1],
        [ ArrayBuffer of DER IssuerName 2],
      ],
    },
  });

[1] This opens the general API discussion about whether or not asymmetric algorithms return one key handle (for a public/private key /pair/) or two key handles (one for public, one for private). For example, by constraining the operation to 'sign', we imply a private key (since 'verify' would be public key), 'encrypt' implies public and 'decrypt' implies private. However, it may be better to explicitly specify rather than implicitly specify.


If we adopt some form of UUID notation (which I still need to mull over the privacy risks), one might further expand to

var kql = window.crypto.queryKey(
  {
    'id': [ 'UUID_1', 'UUID_2' ],
  })

or with an origin-specified naming scheme:

var kql = window.crypto.queryKey(
  {
    'name': 'NetFlixAuthenticationKey',
  });


Thanks for the examples. This makes sense to me now. It is a much more comprehensive querying mechanism relative to the simple "named" credentials approach. Either approach will work for us.

Mitch

Received on Wednesday, 13 June 2012 14:14:15 UTC