Subject: [Webpush] AD Review of draft-ietf-webpush-vapid

From: Adam Roach <[email-masked]>
Date: Tue, 13 Jun 2017 19:21:00 -0500

VAPID authors --

This is my AD review for draft-ietf-webpush-vapid-02.

I think the document may be ready for IETF last call, but I'd like some 
clarifications before sending it out.

The first issue I'd like to have clarified regards agility of the crypto 
suite. This document hard-codes the signing algorithm as ES256. I'm 
familiar with the fact that documents will frequently do this kind of 
hardcoding, and then normatively update allowed algorithms in future 
documents; however, for all such cases I'm familiar with, there is a 
negotiation involved that allows for bilateral transition from one 
algorithm to another. For example, RFC7616 was able to include new 
algorithms because of the challenge/response nature of its 
authentication scheme. Since VAPID specifically does not include a 
challenge, application servers have no way of reasonably knowing what 
the push server might be capable of handling. I think the security 
section really needs a treatment of how this can be handled, since the 
obvious solutions with the current design are less than elegant.

The second issue entails application server key rotation, especially 
when used without the Subscription Restriction mechanism described in 
section 4. My reading of the document (and I'll note, as a nit, that 
this is implied but not particularly explicit) is that the public key 
used to identify a server is a TOFU token; and that the only means a 
server has to detect impersonation is verifying that the public key is 
identical to previous uses. What is the system behavior intended to be 
when an application server needs to change its VAPID key gracefully; and 
what is the behavior intended to be when an application server loses its 
key unexpectedly? For subscription restriction purposes, I can see how 
servers could just change the key used for the subscription request; but 
when this mechanism is being used solely for the purposes of continuity 
of an application server's identity, it seems problematic.

Finally, I'm curious about whether there was any discussion regarding 
the use of "application/json" rather than using the syntax defined by 
RFC6839 (e.g., "application/vapid+json"). My concern is that the use of 
a semantic-free syntactic designation here makes it more complicated to 
use push subscription requests for anything *other* than conveying a 
VAPID key in the future. If the intention is that push subscription 
bodies generically contain a JSON object with potentially myriad keys 
for a variety of unrelated purposes, please spell that out clearly (and 
I would still encourage the use of something less generic than 
"application/json" even in such a case).

Nits:

Although "vapid" appears in the protocol elements and section headers, 
it is never put next to its expansion in the document. Please consider 
changing the title to "Voluntary Application Server Identification 
(VAPID) for Web Push".

The abstract's phrasing of "This can used to reduce the secrecy for push 
subscription URLs..." seems quite awkward. While this is necessarily one 
result of employing the described technique, it could hardly be 
construed as a goal. I suggest rephrasing.

The JWT shown in the Authorization header field has an expiration date 
of 1453523768, while the JSON that claims to be its expansion shows an 
expiration date of 1453341205. Please make these match: implementors are 
likely to use the examples as part of testing their implementations, and 
this may cause unnecessary confusion. Please also double-check that the 
signature in the example is valid after performing this adjustment.

Thanks!

/a

---

From: Martin Thomson <[email-masked]>
Date: Wed, 14 Jun 2017 08:34:42 +0100

Hi Adam,

Thanks for looking at this.

On 14 June 2017 at 01:21, Adam Roach <[email-masked]> wrote:
> suite. This document hard-codes the signing algorithm as ES256. I'm familiar
> with the fact that documents will frequently do this kind of hardcoding, and
> then normatively update allowed algorithms in future documents; however, for
> all such cases I'm familiar with, there is a negotiation involved that
> allows for bilateral transition from one algorithm to another. For example,
> RFC7616 was able to include new algorithms because of the challenge/response
> nature of its authentication scheme. Since VAPID specifically does not
> include a challenge, application servers have no way of reasonably knowing
> what the push server might be capable of handling. I think the security

The decision we made here, as with other documents in this series, is
to define a single profile rather than allow flexibility in the
scheme.  The rationale for this being that it is better to have fewer
points of articulation in a protocol and where we already rely on one,
which is the authentication scheme.  We do have the option to change
to (for example) Ed25519 by changing the JWT header and tweaking the
definition of the k= parameter, but I think that the general idea is
that we would define a new authentication scheme in preference to
doing that.

As you say, an application server doesn't really have any way of
determining that the push service supports a given algorithm.  That
means we need to be very careful about how we signal these things.
Using the authentication scheme (in this document, "vapid") as the
extension point means that we can use the existing mechanisms in HTTP
to signal which scheme is supported if it ever comes to the point
where we want to or are forced to deploy a new algorithm.

In this case, that's probably going to depend on the rather ugly 401
(Unauthorized) status code and a WWW-Authenticate header field.  We
also have the option of replicating the supportedContentEncodings
parameter of PushManager in the API
(https://w3c.github.io/push-api/#pushmanager-interface) so that
applications might avoid that round trip.

> The second issue entails application server key rotation, especially when
> used without the Subscription Restriction mechanism described in section 4.
> My reading of the document (and I'll note, as a nit, that this is implied
> but not particularly explicit) is that the public key used to identify a
> server is a TOFU token; and that the only means a server has to detect
> impersonation is verifying that the public key is identical to previous
> uses. What is the system behavior intended to be when an application server
> needs to change its VAPID key gracefully; and what is the behavior intended
> to be when an application server loses its key unexpectedly? For
> subscription restriction purposes, I can see how servers could just change
> the key used for the subscription request; but when this mechanism is being
> used solely for the purposes of continuity of an application server's
> identity, it seems problematic.

This isn't TOFU as much as it is a delegated credential.  The server
designates a sender that can speak for it.  The API ultimately relies
on server authentication.

The model that the current draft assumes is that an application server
that wants to roll keys would need to create new subscriptions.  This
is always possible, though it requires contacting every user agent to
do so.  See https://github.com/webpush-wg/webpush-vapid/pull/33

We could change the single key to a list of keys, but it would require
making similar changes to the API.  That would potentially allow
application servers the option of using updated keys more quickly
without creating new subscriptions provided that they do sufficient
preparation (which I suspect is unlikely).  It does change the storage
models on push services, and I'd be a little cautious about doing so
given how widely deployed this is already.

> Finally, I'm curious about whether there was any discussion regarding the
> use of "application/json" rather than using the syntax defined by RFC6839
> (e.g., "application/vapid+json"). My concern is that the use of a
> semantic-free syntactic designation here makes it more complicated to use
> push subscription requests for anything *other* than conveying a VAPID key
> in the future. If the intention is that push subscription bodies generically
> contain a JSON object with potentially myriad keys for a variety of
> unrelated purposes, please spell that out clearly (and I would still
> encourage the use of something less generic than "application/json" even in
> such a case).

There was no discussion on this point.  I'm happy to add a new media
type registration, but I would probably make it a generic push
subscription options type than restrict it to this narrow use.  My
initial thought is "application/webpush-options+json", but there's a
bike shed hidden in there.

I need to catch a plane right now.  I'll write up a proposal for this
(and the nits) as soon as I am able.

> Nits:
>
> Although "vapid" appears in the protocol elements and section headers, it is
> never put next to its expansion in the document. Please consider changing
> the title to "Voluntary Application Server Identification (VAPID) for Web
> Push".
>
> result of employing the described technique, it could hardly be construed as
> a goal. I suggest rephrasing.
>
> The JWT shown in the Authorization header field has an expiration date of
> 1453523768, while the JSON that claims to be its expansion shows an

---

From: Adam Roach <[email-masked]>
Date: Wed, 14 Jun 2017 19:09:50 -0500

> where we want to or are forced to deploy a new algorithm.

Sure. Can the document say this?

> (Unauthorized) status code and a WWW-Authenticate header field.

Yes, that's the "less than elegant" solution I mention above...

> We also have the option of replicating the supportedContentEncodings

...and that's much better (presuming you intend to *add* something 
rather than shoehorning signature algorithms into a list intended for 
encryption algorithms). Is there anything we can do now to lay the 
groundwork for that?

Basically, what I'm looking to see here is breadcrumbs for whomever 
picks this work up in the future to extend it when ES256 reaches the end 
of its useful life. It sounds like the authors and WG have given some 
thought to the topic, and we can either capture those thoughts or lose them.

> given how widely deployed this is already.

For use with Subscription Restrictions, I think it's even easier than 
you propose: if all you're trying to do is ensure that the server is 
authorized to trigger a push, and the way you're doing that is by 
matching the public key from the subscription with the public key in the 
push, then all the application server needs to do is keep track of which 
key is associated with each subscription, and start using a new key for 
new subscriptions. I mean, technically, it could use a different key for 
each subscription and everything would work fine (although the system 
would clearly not scale as well) -- right?. This doesn't bear on the 
protocol, but I agree that it should be described in the security 
section to ensure that both implementors and operators understand what's 
supposed to happen here.

But that's the case I wasn't asking about.

Before I repeat the question, I realize now that perhaps the problem is 
that I'm reading something into the document that wasn't intended. I 
might be able to clear this up with a single yes-or-no question:

Is the application server identification mechanism described in this 
document intended to *ever* be useful WITHOUT using the Subscription 
Restriction mechanism described in section 4?

> bike shed hidden in there.

I don't care about the name, and what you propose is a fine shade for 
this shed. It would be worth noting that future documents may add more 
fields to the schema, and that they will do so by updating this document 
(along with the requisite "ignore fields you don't know" language).

/a

---

From: Costin Manolache <[email-masked]>
Date: Thu, 15 Jun 2017 00:07:01 -0700

On Tue, Jun 13, 2017 at 5:21 PM, Adam Roach <[email-masked]> wrote:

> algorithms because of the challenge/response nature of its authentication
> scheme. Since VAPID specifically does not include a challenge, application
> servers have no way of reasonably knowing what the push server might be
> capable of handling. I think the security section really needs a treatment
> of how this can be handled, since the obvious solutions with the current
> design are less than elegant.
>

I think the 'negotiation' must happen much earlier - at subscribe time (and
in general case - out of band). At the time of auth, when VAPID
is used, the caller must have an endpoint that is bound to the server
public key.

If a EC256 public key is used at the time of endpoint creation - it
determines the signing algorithm as well.

So the 'challenge' happens long in advance.

> identity, it seems problematic.

The endpoints are supposed to expire after some time, and need to be
periodically rotated. That would be the best point to do graceful rotation,
as
the endpoints are refreshed.

If a server loses the key - at least in the case of webpush it is possible
to update the web application with the new key and recover.
If the key is stolen: the endpoint secrecy may provide some protection
while the web app is updated. If both private key and
endpoint database are stolen - I think right now the only option is to
contact the provider and have it blacklisted, or to
update the application to stop accepting messages from that key.

It may be good to add more mechanisms to simplify this - but probably
better in separate documents.

> in the future. If the intention is that push subscription bodies
> generically contain a JSON object with potentially myriad keys for a
> variety of unrelated purposes, please spell that out clearly (and I would
> still encourage the use of something less generic than "application/json"
> even in such a case).
>

I think the intent was to allow other attributes in the json, besides the
vapid key, including vendor-specific attributes. The vapid just
defines the 'vapid' key in the subscription json.

Costin

>
> Nits:
>
> Although "vapid" appears in the protocol elements and section headers, it
> is never put next to its expansion in the document. Please consider
> changing the title to "Voluntary Application Server Identification (VAPID)
> for Web Push".
>
> result of employing the described technique, it could hardly be construed
> as a goal. I suggest rephrasing.
>
> _______________________________________________
> Webpush mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/webpush
>

---

From: Adam Roach <[email-masked]>
Date: Thu, 15 Jun 2017 11:20:58 -0500

On 6/15/17 02:07, Costin Manolache wrote:
> I think the 'negotiation' must happen much earlier - at subscribe time 
> (and in general case - out of band). At the time of auth, when VAPID

This makes sense, but it is a substantially different answer than Martin 
gave. I'll note that the subscription request doesn't indicate the 
algorithm to which the key corresponds, so the push server doesn't seem 
to have any ability to detect an algorithm mismatch until it's way too 
late to do anything about it.

I'm not too caught up on what the details of the plan are, but I think 
that whatever is intended should be documented. I don't want to have 
this protocol painted into a corner when we decide to move on to other 
algorithms, and when I combine your and Martin's answers, it's not clear 
whether that's the case. I do get the impression, however, that this 
aspect of the system design hasn't yet been discussed by the working 
group. It should be.

/a

---

From: Costin Manolache <[email-masked]>
Date: Thu, 15 Jun 2017 12:54:50 -0700

On Thu, Jun 15, 2017 at 9:20 AM, Adam Roach <[email-masked]> wrote:

> algorithm to which the key corresponds, so the push server doesn't seem to
> have any ability to detect an algorithm mismatch until it's way too late to
> do anything about it.
>
> that whatever is intended should be documented. I don't want to have this
> protocol painted into a corner when we decide to move on to other
> whether that's the case. I do get the impression, however, that this aspect
> of the system design hasn't yet been discussed by the working group. It
> should be.

I don't think Martin's answer is very different, the draft reflects what we
all agree on - but there are different ways to
extend it. The perspective is a bit different - our system still support a
'legacy' sender authentication scheme, based
on project IDs, which works using the subscribe parameters.

We've also seen few application servers migrate the 'sender id' and auth
scheme, as well as cases where app servers
ran into problems authenticating.

Costin

---

From: Martin Thomson <[email-masked]>
Date: Fri, 16 Jun 2017 12:41:14 +1000

> Sure. Can the document say this?

https://github.com/webpush-wg/webpush-vapid/pull/35

> ...and that's much better (presuming you intend to *add* something rather
> than shoehorning signature algorithms into a list intended for encryption
> algorithms). Is there anything we can do now to lay the groundwork for that?

https://github.com/w3c/push-api/pull/262

That's not this document, but it closes the loop.

> Restriction mechanism described in section 4?

The document addresses two use cases: subscription restriction and
self-identification.  The former most certainly relies on the
signature.  The latter is almost served by having the JWT payload in
the request, but we did agree that key continuity is an part of that
use case.  That means that the push service relies on the signature
for establishing continuity of identity.  It's hard to build up a
reputation as an upstanding application server when anyone can
trivially pretend that they are you.

Those two use cases are intended to be exhaustive.

For the reputation part, I believe that it is acceptable for key
rotation to result in loss of reputation, but it's probably worth
making an explicit note of the consequences:

https://github.com/webpush-wg/webpush-vapid/pull/36

> I don't care about the name, and what you propose is a fine shade for this
> shed. It would be worth noting that future documents may add more fields to
> the schema, and that they will do so by updating this document (along with
> the requisite "ignore fields you don't know" language).

https://github.com/webpush-wg/webpush-vapid/pull/34

---

From: Adam Roach <[email-masked]>
Date: Fri, 16 Jun 2017 09:35:19 -0500

These all look like good changes. Drop a new version of the document, 
and I'll push it forward.

Thanks!

/a

---

From: Martin Thomson <[email-masked]>
Date: Sun, 18 Jun 2017 16:31:33 +1000

On 17 June 2017 at 00:35, Adam Roach <[email-masked]> wrote:
> These all look like good changes. Drop a new version of the document, and
> I'll push it forward.

Posted -03.