Subject: [Webpush] Application server authentication new years edition

From: Martin Thomson <[email-masked]>
Date: Wed, 6 Jan 2016 14:35:31 +1100

With Peter's help, I've just submitted a new version of a draft that
attempts to enumerate the options for application server
authentication (issue #44).

  https://tools.ietf.org/html/draft-thomson-webpush-vapid-01

This assumes the following requirements:

1. A push service would like to be able to correlate requests from a
particular application server over time.

2. A push service would like to be able to contact the
operator/developer of an application server.

This takes the position that any correlation or contact information is
provided voluntarily by an application server and that we don't
require strong authentication for application servers.

Both Ben and Costin have suggested that we could (SHOULD?) construct a
scheme to strongly authenticate servers.  Ben observed that most web
push consumers will have HTTPS endpoints with valid server
certificates and we could use that to construct a system that strongly
authenticates senders.  That might be possible, but it's likely to be
a complicated system that introduces a whole new set of technical,
operational and privacy problems.

The voluntary authentication incrementally improves the situation and
allows us to build stronger authentication systems on top in future.
I think that we should look at doing that, but I would be opposed to
anything that made a more heavyweight authentication system mandatory
to use.

So I come to the question:  what levels of authentication do we want
to support for application servers?

  A. anonymous/none - push without being authenticated

  B. voluntary authentication - as proposed in the draft

  C. strong - proposal TBD

---

From: Costin Manolache <[email-masked]>
Date: Tue, 5 Jan 2016 20:55:23 -0800

It is important to define what "voluntary" means :-). My understanding is
that it involves
a choice made by an entity, either the app server and push service.

The only 'voluntary' choice an app server has is to not use
a push service and UAs that requires authentication/authorization.

Separate comments on the 3 elements - authentication, authorization and
contact info.

For authentication:  2.1(certificate) would be my preference, and is a well
known and established
mechanism, followed by 2.6, 2.3.
-2.4 doesn't cover authentication,
-2.5 seems too complicated (2.5 maps to Oauth1, 2.3 to Oauth2 - we know the
outcome)
-2.2 is what we use now, but doesn't work well with 3. - subscription
association - if
public keys are used.

For authorization - or "subscription association" - big +1 :-)
I like using the public key of the sender - in which case authentication
must use 2.1, 2.6 or 2.3.
Using an ID provided by the push service will be complicated if multiple
push services are used.
I don't see any other option - whatever the subscriber uses needs to be
verifiable by the push service
when send happens.

For contact - each of the authentication schemes in the draft provide a way
to include contact info, and
the choice for senders is to include it or not, and the choice for push
services is to throttle/reject
 or not. The tricky part is if any additional verification will be done by
push services.
I guess some providers (in particular free services) may be ok with a more
relaxed verification
or even allow some rate-limited sending without contact info, I personally
don't mind it - if we
can't contact a sender in case of problems we just block it.

Costin

>   B. voluntary authentication - as proposed in the draft

On Tue, Jan 5, 2016 at 7:35 PM, Martin Thomson <[email-masked]>
wrote:

> _______________________________________________
> Webpush mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/webpush
>

---

From: Martin Thomson <[email-masked]>
Date: Wed, 6 Jan 2016 20:16:32 +1100

> a choice made by an entity, either the app server and push service.

I hope that the draft makes it clear enough: "voluntary" refers to the
choice at the app server whether to provide this information.

> a push service and UAs that requires authentication/authorization.

Right, and I don't think that this is a choice we want to force people
into making.  That has some fairly dire market effects.

> mechanism, followed by 2.6, 2.3.

Both 2.1 (certs) and 2.6 (token binding) require access to the TLS
connection.  Token binding has the added concern that it is a new
mechanism that might not be well deployed.

When I inquired, certs did seem possible, but Mozilla folks (JR can
speak to this better than I), had some operational concerns.  JWT
hoists the authentication information up into HTTP, which was a lot
easier to manage.

> -2.5 seems too complicated (2.5 maps to Oauth1, 2.3 to Oauth2 - we know the

I agree.  We don't really know how to solve the signing problem, and
not from a lack of trying.

> For authorization - or "subscription association" - big +1 :-)

Yeah, I like the subscription association feature too.  I think that
it's an important consideration in choosing a mechanism.

> can't contact a sender in case of problems we just block it.

That's the policy that we've discussed having.  I think that it is
very important to allow requests from all comers, even without
authentication.  Of course, services should be prepared to cut off
those unauthenticated requests very quickly as load increases.

---

From: Costin Manolache <[email-masked]>
Date: Wed, 6 Jan 2016 08:28:20 -0800

---

From: jr conlin <[email-masked]>
Date: Wed, 6 Jan 2016 08:33:26 -0800

> hoists the authentication information up into HTTP, which was a lot
We are currently deployed on Amazon Web Services (AWS) using Elastic 
Load Balancers (ELBs) to terminate TLS connections for both cost and 
performance reasons. The ELBs act as a simple proxy, consume the 
certificate and provide no certificate information. AWS has no plans to 
modify ELB software to relay the cert information as part of the proxied 
connection. It is not possible for any AWS based service to use any cert 
information to show authentication, since it is impossible to get that 
information.

---

From: Costin Manolache <[email-masked]>
Date: Wed, 6 Jan 2016 10:01:57 -0800

> into making.  That has some fairly dire market effects.

At the same time you can't force push service providers to accept
 unauthenticated/unauthorized sending either. Or require them to
provide unlimited (and free) service to everyone regardless of how much
they're abusing/hurting users or networks.

> > mechanism, followed by 2.6, 2.3
>

How about 2.1 AND 2.3 ? Push servers should support both, clients should
use what they can.

I think there are some benefits in 2.1.

> it's an important consideration in choosing a mechanism.

And it may be the way to allow the choice on app server side - either by
having an 'isAuthorizationRequired()' or an error code when attempting to
subscribe without a public key.

If they subscribe without the sender id, than on some push services send
will fail - and they can't do anything about it.

> those unauthenticated requests very quickly as load increases.

Of course, you have the choice and I'm very curious to know how it works,
but based on our experience we are not ready to make the same choice :-)

I'm personally ok to not require contact info ( with understanding that if
it is missing
the sender accepts some limitations ). Unfortunately it's not my choice,
people who
support the service may have a different opinion, and each service provider
may
make a choice or another.

However authorization and authentication are a different story than contact
info.

Costin

---

From: Costin Manolache <[email-masked]>
Date: Wed, 6 Jan 2016 11:29:59 -0800

Understood - I assume other push services may have similar restrictions,
and in general TLS client
auth is tricky on both client and server side.

That leaves 2.3 only ? I think it's ok - it relies on the same thing as TLS
client auth, the sender
signing with the private key, and push service checking it against the
public key provided at subscribe time.
Can we at least make it consistent with the the encryption - i.e. use the
same type of key ?
In particular it would be nice if an app instance (A) could even use the
public key of another instance (B),
to allow B to send messages directly to A, without using the app server (
for a future version of the
standard, of course - but we should keep it in mind ).

Costin

On Wed, Jan 6, 2016 at 8:33 AM, jr conlin <[email-masked]> wrote:

> We are currently deployed on Amazon Web Services (AWS) using Elastic Load
> Balancers (ELBs) to terminate TLS connections for both cost and performance
> reasons. The ELBs act as a simple proxy, consume the certificate and
> provide no certificate information. AWS has no plans to modify ELB software
> to relay the cert information as part of the proxied connection. It is not
> possible for any AWS based service to use any cert information to show
> authentication, since it is impossible to get that information.
>
>
>

---

From: Benjamin Bangert <[email-masked]>
Date: Wed, 6 Jan 2016 14:24:21 -0800

2.3 would allow us to get the data, but it doesn't address strongly
authenticate senders.

Discussing this earlier with my manager, there are two additional schemes
that we could consider instead of or in addition to 2.3 on a voluntary
basis for app-servers.

- DKIM: Re-use DKIM in some manner so that an app-server can claim a domain
its sending notifications on behalf of. Since DKIM also includes a body
hash, it could be used instead of JWT if an app-server wishes to strongly
authenticate.
- Lets Encrypt Domain Validation: The Lets Encrypt folks have a scheme and
tools that automate Domain Validation to prove ownership of a domain
(though it unfortunately needs to be tied into a webserver, DKIM is nicer
in that aspect of only requiring a DNS addition).

Both of these would allow an app-server to change the JWT secret being used
if needed with no interaction needed with the push service.

Cheers,
Ben

On Wed, Jan 6, 2016 at 11:29 AM, Costin Manolache <[email-masked]> wrote:

> That leaves 2.3 only ? I think it's ok - it relies on the same thing as
> TLS client auth, the sender

---

From: Costin Manolache <[email-masked]>
Date: Wed, 6 Jan 2016 17:43:07 -0800

> 2.3 would allow us to get the data, but it doesn't address strongly

2.3 is not authenticating the contact info provided by senders, just that
sender is the same that
the UA requested.

The subscribe in the UA includes the public key of the sender, and 2.3
AFAIK strongly authenticate
the fact that the sender has access to the private key.

The contact information they chose to include in the JWT is not
authenticated at all  the push
service can only verify the sender is what the UA authorized, and can
block/throttle that sender without
affecting other senders.

> - DKIM: Re-use DKIM in some manner so that an app-server can claim a
> domain its sending notifications on behalf of. Since DKIM also includes a
> body hash, it could be used instead of JWT if an app-server wishes to
> strongly authenticate.
> Both of these would allow an app-server to change the JWT secret being
> used if needed with no interaction needed with the push service.
>

Yes, they would also verify contact info - I have a feeling we're trying to
avoid relying too much on
the contact info ( i.e. domain name of the app server ). If the contact
info is voluntary - I don't think we need
to make it too complex by adding verification.

Rotating the identity and keys used by sender normally happens when the app
is updated, the sender can subscribe with the new key, and can use 2
subscriptions while migrating. The fact that subscriptions can be
rotated or can expire helps. Would be good to mention in the draft that a
push service that requires or accepts subscription
association (== authorization) should also allow multiple subscriptions for
an app.

I would expect verification of the sender to be useful for non-free
services - in which case the public key
 of the sender will need more than verification (i.e. will need to be
associated with a credit card :-)

Costin

---

From: Benjamin Bangert <[email-masked]>
Date: Wed, 6 Jan 2016 18:11:13 -0800

> block/throttle that sender without

Right, that this is not strongly authenticated means we can't do something
like build a developer dashboard that might expose notification traffic
information associated with the JWT. ie, if a Push Service wanted to
provide developers with a diagnostic dashboard similar to what GCM
Diagnostics provides GCM users.

>> - Lets Encrypt Domain Validation: The Lets Encrypt folks have a scheme
>> and tools that automate Domain Validation to prove ownership of a domain
> Yes, they would also verify contact info - I have a feeling we're trying
> to avoid relying too much on
> Rotating the identity and keys used by sender normally happens when the
> app is updated, the sender can subscribe with the new key, and can use 2
> association (== authorization) should also allow multiple subscriptions
> for an app.
>
Ah, in our case we were thinking of providing some basic diagnostic
information in a dashboard free-of-charge. I didn't think the GCM
Diagnostic panel required payment, but it uses the strong authentication by
requiring a sign-up process and such.

I was hoping that there would be some way push service providers could
provide a higher degree of authentication in a standard way that wouldn't
require app developers to go through extensive sign-up processes at each
push service, but perhaps that's just wishful thinking.

Cheers,
Ben

---

From: Martin Thomson <[email-masked]>
Date: Thu, 7 Jan 2016 14:29:43 +1100

Mega-multi-response.

> they're abusing/hurting users or networks.

The authorization question is challenging, particularly when it comes
to abuse of limited resources (user attention, battery power, push
service capacity).  It would be good to understand what the invariants
are on each service.

If Google are unwilling to allow completely unauthenticated requests,
then I think that we could insist on something voluntary.  I'm
reluctant to do that because it makes it more difficult for
application server developers to get a start, but that can be mitigate
with good tooling, I guess.

On the other hand, if there are cases where a small number of requests
can be made without extra authentication, then the proposed option
would be ideal.  That would allow people to experiment a little before
having to tool up.

> How about 2.1 AND 2.3 ? Push servers should support both, clients
> should use what they can.

I'd like to avoid that situation because it hurts a lot more all
around.  We like to save that option for the really tough problems
(video codecs, for example).

> subscribe without a public key.

Again, that makes it more difficult to use the API, and I'd be very
reluctant to take that option unless the alternatives are untenable.

> Can we at least make it consistent with the the encryption - i.e. use the

We can certainly use P-256 for that as well; that's what is proposed.
However, it would need to be a different key pair, since all the
experts recommend against using the same key for signing and key
exchange.  (There isn't an actual attack, but the dual use isn't
provably safe.)

On 7 January 2016 at 12:43, Costin Manolache <[email-masked]> wrote:
> the contact info ( i.e. domain name of the app server ). If the contact info
> is voluntary - I don't think we need

I very much agree with this sentiment.  That contact information can
be verified, though I think that we should probably start out by
relying on manual processes for that.  We can layer other mechanisms
on top.

I'm not particularly fond of the idea of using something as
heavyweight as what Ben suggested.  Something much simpler might work,
but I don't think that we need that.  An absolute requirement to use
something that that would be a big problem.

On 7 January 2016 at 13:11, Benjamin Bangert <[email-masked]> wrote:
> information associated with the JWT. ie, if a Push Service wanted to provide
> developers with a diagnostic dashboard similar to what GCM Diagnostics
> provides GCM users.

If this is your concern, why not ask the dashboard user to prove that
they have access to the JWK private key when logging in?  That's
relatively easy to do.  You don't actually need to know who they are
in that case.  (Though you could use the dashboard UI to do things
like email verification, as many sites do.)

---

From: Costin Manolache <[email-masked]>
Date: Wed, 6 Jan 2016 21:21:20 -0800

> Diagnostics provides GCM users.

That shouldn't be a problem - there are many ways you can associate a real
developer account with the public key,
using the private key to sign a statement.

Or you could exchange a JWT with a cookie or token that allows access to
the dev tools, without requiring a separate
account.

>
>
>
>>
>>
>>
>>>
>>> Discussing this earlier with my manager, there are two additional
>>> schemes that we could consider instead of or in addition to 2.3 on a
>>> voluntary basis for app-servers.
>>>

GCM doesn't require payment for diagnostic or anything else, but there are
providers that charge, and for them
the 'contact info' would be more important and need to be more specific.

> push service, but perhaps that's just wishful thinking.

It is not impossible - once we have the auth defined, it can be used to
access other endpoints - debugging, etc.
But probably their definition will need to be in a separate future draft.

Costin

---

From: Costin Manolache <[email-masked]>
Date: Wed, 6 Jan 2016 21:43:15 -0800

> would be ideal.  That would allow people to experiment a little before

Completely unauthenticated requests would be an extremely hard sell, and
I suspect other push services will be in the same position (at least after
some
time).

Also I don't think developers would benefit much - generating a signed
JWT token is much simpler than encryption, and it already has plenty of
libraries.

And it won't benefit them too much to start an app without authentication,
than
get random rejections or errors - or worse, launch it and than realizing it
doesn't work.
We had a period of 'free quota/contact us if you need more' - it was not
fun.

> (video codecs, for example).

I think the fact TLS client auth doesn't work on some providers is enough
to kill it
at least for this version, I didn't know it's not supported.

That leaves 2.3 only.

> reluctant to take that option unless the alternatives are untenable.

I agree - IMHO just passing the sender key for all providers is cleanest
and least
risky option.

> exchange.  (There isn't an actual attack, but the dual use isn't

I know it's recommended, but it would be very convenient for device2device
 to be able to use the public key generated by subscribe.

In any case, the UA will need to provide some special API to send() or just
an API to
sign or generate JWT token - it could generate a second key for
authentication.

> something that that would be a big problem.

Agreed, and while his suggestion would work for checking the contact info,
it will still
not be enough for possible charging providers, or for providers offering
dashboards or
other tools. Better to keep verification and association of the public key
with a
'real' account as out of scope of this draft.

Costin

> provide

---

From: Martin Thomson <[email-masked]>
Date: Thu, 7 Jan 2016 18:53:13 +1100

> That leaves 2.3 only.

It looks like we're mostly in agreement for something like 2.3.
Should I take some time and flesh out the details?  Does anyone
disagree?

---

From: Benjamin Bangert <[email-masked]>
Date: Thu, 7 Jan 2016 08:59:17 -0800

2.3 sounds fine.

I'm curious what thoughts there are around charging providers, but that can
wait for a separate thread.

---

From: Costin Manolache <[email-masked]>
Date: Thu, 7 Jan 2016 10:59:48 -0800

> Should I take some time and flesh out the details?  Does anyone

Sounds good, but I have few questions/comments on the details.

1. Key identifiers ('kid') - for normal JWT, the key is known from the
issuer or
'sub'. Since in our case we'll have self-generated keys, and we want to
avoid
having each key registered with all providers - all that a push service
will know
when seeing a JWT token the first time will be the content of the token.
So we need a way to find the public key needed to verify the content - and
the only one I know is to use something like the SHA of the public key.
On subscribe - the provider can store the public key, with the kid as
lookup key, than
on send it can verify. For example kid == (SHA1 or SHA256 truncated to
64bits) would work.

2. 'aud' field - not sure what would be the right value, maybe the domain
of the push provider ?

3. Going back to the 'voluntary'/optional part: I'm not sure if encryption
is going to be required or
optional in the final version ?

4. I think we can have the sender key optional in the subscribe operation,
in particular for cases
like low end IOT - not including it would give permission to anyone with
the URL and pubkey
of the device to send messages. There is another case where it helps -
pairing, in cases of D2D -
but with restrictions ( either time, or binding the subscription to the
sender at first use ).
In other words: I'm not opposed to having 'optional' on the subscribe (and
on contact info).

5. This may be a bit controversial :-), if we require the developers to use
a JOSE library to
generate JWT tokens, signed with a ES256 - wouldn't make sense to also
allow them to use
the same library to encrypt the payload for the e2e ? There is already a
content type defined, so easy to
differentiate.

Costin

---

From: Benjamin Bangert <[email-masked]>
Date: Thu, 7 Jan 2016 12:56:11 -0800

> on send it can verify. For example kid == (SHA1 or SHA256 truncated to

If an app-server has a private key leak and needs all its users to rotate
sender keys, that will also tie up a substantial amount of server resources
having such a large unsubscribe/subscribe cycle.

Key rotation for private keys is common in many cases already, it'd be nice
if such a thing wasn't expensive for the server.

> 2. 'aud' field - not sure what would be the right value, maybe the domain

I know it doesn't seem popular to include stronger authentication at this
layer.... but if 'aud' was the domain (or sub-domain for per-push-provider
public keys), and there was a DNS TXT record that contained the JWT public
key then the push service would have a way to lookup the key. It'd also
allow the app-server to rotate keys used without all the push clients
needing to resubscribe.

This would bump the authentication to domain verified, while remedying the
issue of how to get the public key to the push service and reducing server
resources needed to handle sender key rotation.

> 5. This may be a bit controversial :-), if we require the developers to
> use a JOSE library to

+1 on simplifying this for developers.

Cheers,
Ben

---

From: Costin Manolache <[email-masked]>
Date: Thu, 7 Jan 2016 13:33:17 -0800

On Thu, Jan 7, 2016 at 12:56 PM, Benjamin Bangert <[email-masked]>
wrote:

>> On Wed, Jan 6, 2016 at 11:53 PM, Martin Thomson <[email-masked]
>> > wrote:
>>
> Key rotation for private keys is common in many cases already, it'd be
> nice if such a thing wasn't expensive for the server.
>
>

Key rotation can be spread over a long interval - normal subscriptions
expire anyways and need to be rotated,
 so for a periodic rotation it shouldn't add extra load. The push service
itself may rotate its keys (assuming that
the URLs are generated using keys) - which will also likely be staged with
the periodic expiration of subscriptions.

If only the private key is leaked - I assume it's a tradeoff, users are
still protected by
the secrecy of the URL/secret-public key.

For 'my private key AND the database of subscription have been stolen' - I
don't think there
are many options except taking the extra load hit (for the general case).
Some providers may
allow additional options - in particular if the public key is linked to
some developer account
(for tools or other purposes).

( we discussed in the past the case of 'private keys of the push service
leaking', and at least the js API
has support for handling it )

> resources needed to handle sender key rotation.

Audience is one of the most confusing concepts :-). My understanding is
that it means 'identifies who will
process/consume the JWT token', in our case the push service provider. The
draft defines it as 'full push resource URL',
meaning developer needs to generate a new token for each message. I think
using just the domain name
is more efficient ( less overhead on client, possible caching on server ) -
and it's what Oauth2 is doing as well.

Using DNS TXT records or any other mechanism for verifying the 'contact
info' - i.e. the domain of the
sender is tricky, and on top there is strong opposition to even include
contact info in requests.
I suggest leaving this for a separate discussion/standard. But I agree, if
a 'contact info' is provided, it
would be good to use DNS TXT records or even a "well known" URL to fetch
the current public key.

>
>
>> 3. Going back to the 'voluntary'/optional part: I'm not sure if
>> encryption is going to be required or
>> 4. I think we can have the sender key optional in the subscribe
>> operation, in particular for cases
>> In other words: I'm not opposed to having 'optional' on the subscribe
>> (and on contact info).
>>

---

From: Martin Thomson <[email-masked]>
Date: Fri, 8 Jan 2016 08:57:07 +1100

On 8 January 2016 at 05:59, Costin Manolache <[email-masked]> wrote:
> having each key registered with all providers - all that a push service will
> know
> On subscribe - the provider can store the public key, with the kid as lookup
> key, than

The push service is going to need the public key, so that means
including a JWK in the message, I think.  Knowing a hash of the public
key isn't enough.

I think that we can avoid using key identifiers.  We could include one
and use that to reference another header field, but it is easier to
say that there is exactly one JWT and exactly one JWK and that one
depends on the other.

> 2. 'aud' field - not sure what would be the right value, maybe the domain of
> the push provider ?

I specified URL at the suggestion of Chris, but I had the same thought
you did.  Maybe we can trim it to origin.  That reduces portability
considerably and also shortens the token somewhat.

> optional in the final version ?

The protocol won't absolutely require it, though it will strongly
recommend it.  (I'd prefer to require it, but there you have it.)  The
W3C API will require encryption.  Does that make sense?

> like low end IOT - not including it would give permission to anyone with the
> URL and pubkey

I agree.  Making the JWT mandatory on the subscription would introduce
some operational problems for the cases where one endpoint has to be
used by several different application servers too.

> generate JWT tokens, signed with a ES256 - wouldn't make sense to also allow
> them to use

I don't know of any way to do that without also massively inflating
the size of the payload.  There is a mapping to JWE already in the
encryption draft for those who would prefer to reuse their library.
The tricky part is key derivation, but I think that's largely
unavoidable in this case.

---

From: Costin Manolache <[email-masked]>
Date: Fri, 8 Jan 2016 00:06:56 -0800

On Thu, Jan 7, 2016 at 1:57 PM, Martin Thomson <[email-masked]>
wrote:

> will
> lookup

The push service can store the key when subscribe() is called.

I think we can make it work without a key ID - the send URL will decode
to the registration, which would include the authorized public key. But
I think it would still be a bit cleaner and simpler if the JWT key could be
verified
without having to use the URL.

> say that there is exactly one JWT and exactly one JWK and that one

That would work too, but the push service still need to verify that the
key in subscribe is the same as the key in JWT. If you load the
subscription -
using either the URL or the key id - there is no need to send the JWK.

> W3C API will require encryption.  Does that make sense?

Yes.

> the
> (and
It shouldn't be mandatory - just recommended that subscribe indicates who
is authorized
to send.

A push service that doesn't require authentication can just ignore it.

> use
> allow

Yes, it doesn't seem possible to convert from JWE to the binary format,
so UAs would need to support both, I don't think this would work. And it
may be
more confusing in the end.

Costin

---

From: Martin Thomson <[email-masked]>
Date: Sat, 9 Jan 2016 06:25:19 +1100

On 8 January 2016 at 19:06, Costin Manolache <[email-masked]> wrote:
> It shouldn't be mandatory - just recommended that subscribe indicates who is
> authorized
> to send.
>

I don't think that ignoring is a good option.  I think that the user
agent should be able to expect that the push service is enforcing
access control if it provides an application server key.