- From: Ryan Sleevi <sleevi@google.com>
- Date: Tue, 23 Dec 2014 10:43:56 -0800
- To: Richard Barnes <rlb@ipv.sx>
- Cc: public-webcrypto@w3.org, public-webrtc@w3.org
- Message-ID: <CACvaWvYReJNWk1iWUVEMNPXsv8StP6W0bHOs=B1mR0yecmwh7A@mail.gmail.com>
On Dec 23, 2014 6:21 AM, "Richard Barnes" <rlb@ipv.sx> wrote: > > As the originator of the idea that Ryan's pleading against, I feel like I should provide some response here. In the spirit of long messages for the holidays, ... > > First, Ryan, thanks for taking the time to lay out the overall context. Your characterization of the high-level requirements and the arguments for reusing CryptoKey are pretty much accurate. Though I reserve the right to disagree with them on some points :) > > If I were to summarize your proposal for WebRTC in a sentence, it would be, "Create a custom key pair object that is specific to WebRTC". If you look at this just in the context of WebRTC, that doesn't sound all that bad. However, > I'm concerned about the bigger direction for APIs. > > I want to live in a world where cryptographic security is easy and ubiquitous. WebRTC and WebPush are both good examples of new APIs that build security in from the start, and indeed make it a core component. I want it to be easy for future APIs to do that too. At the risk of saying that "I, too, like freedom and apple pie", I am very much looking at the big picture and thinking of developers. Bluntly, your proposal: - Undoes three years of hard work to design some semblance of security guarantees regarding what is usable and exposed. - Introduces unnecessary ontological confusion by attempting to overlay a high-level semantic onto the notion of keys that the WG *repeatedly* has rejected - attempts to redefine the charter and scope of a WG and its key deliverable > > Forcing each API to make a new "LimitedUseKey" construct is inimical to that objective. Different APIs have different event structures, but we don't make developers learn a new event system for each API -- we map the API to DOM Events or Promises. So whatever we end up with, it should be re-usable across at least WebRTC and WebPush, and hopefully future things as well. In other words, the choices here are one key object or two -- CryptoKey or CryptoKey+ApplicationUsableKey -- not O(#apis) different versions. No. This is a deeply flawed argument. We have ArrayBuffer, File, Blob and Stream. We do not try to shape these things to fit some broken and ill-fitting concept because of ideological purity, we recognize they serve different purposes and express - both to developers and at an implementation level - that there are differences. Even when there are similarities - e.g. Files and Blobs exposed as Streams - we still keep separate types with well-defined hierarchies. Your parallel to Keys as Promises or Events is deeply flawed and again hearkens back to an approach that was repeatedly rejected as out of scope by the Web Crypto WG; that is, the notion that keys should be some high level API. No, they aren't. Now, we could certainly recharter Web Crypto WG, redefine the deliverables, and introduce a base "opaque key" type for which both Web Crypto and WebRTC can build upon, but that would be deeply silly. That is because it is entirely irrelevant to the developer that both Web Crypto and WebRTC are built upon an opaque type, and to an implementation, all you're doing is copying one line of hand-wave between the two: "Key represents an opaque platform type that is implementation specific". > > The main question, then, is how big the difference is between CryptoKey and ApplicationUsableKey. The base requirements we're seeing are for public and private key objects with the following properties No, there is zero need for WebRTC to treat these concepts as separable. That is, WebRTC *always* deals in Identities - a public and private key pair that *together* define a representation to the user. You could express this with a singular object, because for WebRTC, it is a singular idea. > (to refine your requirements list a bit, with a separate numbering space): > > [Requirement A=1,2] Private keys are protected from application access (browser-locked) > [Requirement B=3] Private keys can be scoped to specific uses > [Requirement C=4] Private keys can be persisted > [Requirement D=5] Public keys can be serialized to different formats > > CryptoKey provides these properties. No, it does not. I am sorry that I have to take this apart point by point, but: - Your notion of browser-locked (A/1,2) is unique to your case. You have explicitly stated in the past that you wish to deny the import of keys and distinguish them from those generated in the browser. This is contrary to the CryptoKey, which explicitly does not track this. - B/3 is an artificial requirement that you have introduced precisely BECAUSE you're trying to overload the concept. That is, specifying your own object makes it intrinsically unnecessary to have this requirement, because it is there by definition. - C/4 is as simple as structured clone. - D/5 is simply incorrect. That is, there is no reason to express this as a fundamental requirement - it is pure syntactic sugar that can be layered upon choosing a canonical key form for the API. Put differently, you can express a JWK-via-API as an SPKI purely through script; expressing it via API is thus sugar. Per the Extensible Web Manifesto [1] that so many of your colleagues are signatories to, this is unnecessary. [2] > Any ApplicationUsableKey construct would have to duplicate at least that much of CryptoKey. This gets us down to the question of what harm there would be in re-using CryptoKey. > > It seems like there are a couple of things that are making you sad about the idea of re-using CryptoKeys for applications outside of WebCrypto. > > [Objection 1] If other apps use CryptoKeys, they won't be usable with WebCrypto methods. > [Objection 2] WebCrypto's algorithms align poorly with TLS > > Both of these arguments seem to miss the fact that WebCrypto itself is an application of CryptoKeys. It's the first, and one that was co-designed with CryptoKeys, but it need not be the only. In fact, it's a *set* of applications -- sign, verify, encrypt, and decrypt. Each of these has separate processing for keys. In light of that, Objection 1 looks kind of funny: We *already* have WebCrypto keys that are usable for one application and not another, e.g., sign() and not decrypt(). It's baked into the design. Oh, come on. You're arguing apples and oranges are the same thing because they're both fruit. You're rewriting history - and a long set of debate - to suggest that the WebCrypto WG was at all chartered or intended to make CryptoKey some generic object like Blobs or Streams. You know full well this was a non-goal that was rejected. Again, CryptoKey is designed and expresses a set of concepts deeply linked to window.crypto.subtle, and is NOT some generic high level representation. > > Objection 2 misses another important underlying fact: While CryptoKey expresses constraints, it's up to the application to enforce that constraint in a manner appropriate to that application. Each of the WebCrypto algorithm descriptions describes different processing for the "algorithm" dictionary on the key. A TLS usage could do likewise, e.g., ignoring the "hash" parameter on an RSASSA-PKCS1-v1_5 algorithm if present. This here is a deeply disturbing line of thinking. If I can rephrase Objection 2, it would be that "WebRTC proposes to ignore the security protections of CryptoKeys". Now you can see why it smells so bad and engenders such a strong negative reaction from me. You cannot argue that ignoring the restrictions upon which the entire security analysis of the API rests makes any sense at all. It is truly trying to make a square hole fit a round peg, just because the API concepts share a noun. > > It may be that the requirements from other applications lead to some changes to the CryptoKey structure, e.g., to make the "hash" parameter not required by the syntax (it can still be enforced by sign()). I'm OK with that. It's not monkey-patching, it's discovering weaknesses in CryptoKey that prevent it from being reusable. And it's a natural, healthy process for APIs to go through. > No, no, no. This is just wrong and dangerous. It is not a "weakness" that your use was intentionally not supported - it is intentional! That is the point - you're reopening a debate that was settled some time ago, and doing it through another WG, and for no real benefit to developers. Luckily, we have the TAG to provide guidance on these sorts of design decisions, but I cannot stress enough that you are taking an ill-fitting API and trying to apply it to a problem in a way that is hostile to both developers AND implementors. We need not do that. If your proposal was adopted, let's look at the very real sharp edges and developer missteps introduced: - If I want to use a CryptoKey object with WebRTC, I must create it with some WebRTC-specific API. The canonical wag to create CryptoKey's leaves me with a key I cannot use. - If we choose to instead rewrite the WebCrypto spec to fit your vision (which you know it would require breaking API changes to do), then even though generateKey yields a key I can use, I cannot use importKey - How I specify an algorithm now depends on context. If I want to use it for signing, I have to specify a hash, but if I want to use it for WebRTC, I don't, even though both follow the same structure and pattern. - Any key I export contains redundant information (e.g. usages, of which there is only ever one, 'webrtc') or unnecessary restrictions ('alg') None of these are positive outcomes at all for developers. Do the right thing. Use the right type. Not every Blob has to be a File, not every ArrayBuffer is aspiring to semantically be a Stream, and not every RTCIdentity is trying to be a CryptoKey. Consider the use of DTLS methods that might use SRP or other non-certificate forms of authentication - they now become inexpressible. You're fundamentally looking for an API to express the identity you present your peer, with a secondary goal of being able to provision some of those. Whether this relies on bare keys, certificates, or zero-knowledge proofs should be entirely opaque to your API. Not only is your proposal bad for the security of Web Crypto, bad for developers who use either, but it artificially limits you to expressing the concepts with an imprecise and incomplete vocabulary. > Happy holidays, > --Richard > [1] https://extensiblewebmanifesto.org [2] I am avoiding a discussion of why Web Crypto does so within the body, only to note that it is very much an unpolyfillable security feature derived from a particular threat model for wrap/unwrap that is not relevant for Web RTC.
Received on Tuesday, 23 December 2014 18:44:25 UTC