Subject: [Acme] On multiple CAs and contact-based recovery

From: Karthik Bhargavan <[email-masked]>
Date: Wed, 23 Mar 2016 23:33:49 +0100

Dear All,

Recently, after being asked by Josh Aas, I wrote a formal model of the ACME protocol 
in ProVerif and analyzed it for various properties. I am still in the process of cleaning
up the model and writing up a proper report, but with the next IETF being so close,
here’re some early comments that may be useful for the group to discuss. 
These notes are inspired by my model of the -01 draft and some of it may be out of date.

Summary:
-------------

Against a classic symbolic protocol adversary, ACME achieves most of its security goals.
Notably, it prevents many more attacks than traditional CAs through its use of client signatures,
and specifically through the strong binding between the client’s account key and the validated domain.

However, there are two scenarios of concern that should be studied more carefully:
(1) if an ACME client supports multiple CAs or ACME servers and one of them may be malicious or compromised;
(2) if the contact channel is used for account recovery or, in the future, if an email channel is used for domain validation.

In both these cases, the protocol as it is currently specified (in -01) is not strong enough to provide the desired guarantees,
but the good news is that it can be easily strengthened to prevent abuse.

We describe 3 issues, in increasing order of seriousness. The first two are closely related and may have been discussed
in the list before. Issue 3 seems to be new and should probably be considered an attack on the stated goals of the ACME -01 spec.

Model:
---------

Our model consists of four kinds of principals:
- Domain Owners (who can answer domain validation challenges)
- ACME clients (who own account keys)
- ACME servers (who own HTTPS certificates acceptable to ACME clients)
- CAs (who own CA signing certificates)

An ACME client can talk to any number of ACME servers over three kinds of channels:

- HTTPS channels, which are treated as server-authenticated request-response channels
  That is:	anybody can send a request but only the server can read it, 
    		only the server can send a response, 
		and furthermore only the client who sent the request can read the response.

- DNS/HTTPS/SNI validation channels, which are treated as sender-authenticated asynchronous channels
  That is: 	only the domain owner(s) can write on the channel, but anybody can read it

- Contact/Email channels, which are treated as receiver-authenticated asynchronous channels
  That is:	anybody can write messages on the channel, but only the domain owner(s) can read it.

In our model, we can experiment with the compromise of various combinations of principals.
When a principal is compromised, all the channels they control become available to the adversary.
For example, if an ACME HTTPS server is malicious or compromised, then its  HTTPS certificate 
signing key is known to the adversary, and consequently the ACME channel is compromised.

The ACME spec informally assumes that at most one channel is compromised.
In the rest of this email, we primarily consider compromise of the HTTPS channel
between ACME clients and servers. We assume that the CA signing key and the
honest client’s account key remains secure.

Issue 1: No Mutual Authentication
---------------------------------------------

The first issue already appears when we model the ACME HTTPS channel.
We would have expected to model this as a mutually-authenticated channel
since the client always signs its messages with the account key.
However, although the client’s signature is tunnelled inside HTTPS, the
signature itself is not “bound” to the HTTPS channel.

This means that a message from an ACME client C to a server S
can be forwarded by S to a different ACME server S’ (as long as S’ is also willing
to accept C’s account key). This is a classic “credential forwarding” attack
that is typically mitigated by channel binding.

For example, ACME could rely on the Token Binding specifications
to securely bind the client signature to the underlying channel:
https://datatracker.ietf.org/wg/tokbind/documents/ <https://datatracker.ietf.org/wg/tokbind/documents/>

Alternatively, all ACME messages could include the identity of the ACME server
(this could, for example, be the SNI or server domain name that the ACME client 
 checks in the certificate when it connects to the server.)

Either of these choices would make the HTTPS channel truly mutually-authenticated,
simplifying a lot of the subsequent analysis.

Issue 2: Certificate Request not bound to CA
------------------------------------------------------------

Suppose an ACME client C connects to an ACME server S, 
and suppose that S’s HTTPS private key is compromised (or that S is malicious,
or a man-in-the-middle has compromised the ACME channel or that the
attacker has obtained a mis-issued certificate for S, or that the attacker
has fooled the client into accepting its certificate).

Now, the attacker can intercept authorization and certificate requests from C to S,
and instead forward them to another ACME server S’. If S’ requests domain
validation with a token T, the attacker forwards the token to the client, who
will dutifully place its account key K and token T on its validation channel.
S’ will check this token and accept the authorization and issue a certificate
that the attacker can forward to C.

This means that C asked for a certificate from S, but instead received a certificate from S’.
Moreover, it may have paid S for the service, but S’ might have done it for free.
This request forwarding “attack” can be prevented if C checks the certificate 
it gets to make sure it was issued by the expected CA. It can also be prevented
by channel binding.

An alternative mitigation would be for ACME to extend the Key Authorization string to include the CA’s identifier. E.g.:

key-authz = token || '.' || base64url(JWK_Thumbprint(accountKey)) || ‘.’ || base64url(server_id)

Where server_id could be the ACME server’s SNI or certificate-hash.
In other words, the domain validation challenge currently includes the client’s identity and the server’s challenge,
but it does not include the server’s identity, allowing the challenge response to be used with multiple servers.
This may well be a privacy feature (?) but if not then adding further context to the challenge response will add protection
in the multiple CA use case

Issue 3: Contact-based Recovery can be Hijacked
-------------------------------------------------------------------

The use of sender-authenticated channels in ACME (HTTPS/SNI/DNS) seems to  be relatively secure.
However, more attention needs to be paid to the receiver-authenticated channels like email, because they are
easy to get wrong. For example, if the ACME server (in some future draft) uses the website administrator’s email
address to send the domain validation token, a naive implementation of this kind of challenge would be vulnerable to attack. 

In the -01 specification, the contact channel (typically email) is used for account recovery
when the ACME client has forgotten its account key. We show how the careless 
use of this channel can be vulnerable to attack, and propose a countermeasure.

Suppose an ACME client C issues an account recovery request for account A with a new key K to the ACME server S.
A network attacker blocks this request and instead sends his own account recovery request for account A (pretending to be C)
with his own key K’. The server S will then send C an email asking to click on a link. 
C will think this is a request in response to its own account recovery request and will click on it.
S will think that C has confirmed account recovery and will transfer the account A to the attacker’s key K’.

In the above attack, the attacker did not need to compromise the contact channel (or for that matter, the ACME channel).
This seems to directly contradict the security considerations in 9.3, unless I am reading something wrong.
The key observation here is that on receiver-authenticated channels (e.g. email) the receiver does not get to
bind the token provided by the server with its own account key. Consequently, we need to add further checks.

The email sent from S to C should contain a fresh token + C’s new account key (e.g. within a key-authz field)
Instead of clicking on the link (out-of-band), C should cut and paste the token into the ACME client which
can first check that the account key provided by the server matches the one in the ACME client and only
then does it send the token back to the server. 

Alternatively, if we don’t want to change ACME too much, we must require that the email recipient at C
visually confirms that the account key (thumbprint) provided by the server matches the one displayed
in the ACME client. 

The attack described here is on account recovery, but a similar attack appears if we allow email-based
domain validation. A malicious ACME server or man-in-the-middle can then get certificate issued for C’s 
domains with its own public key, without compromising the contact/validation channel. The mitigation
for that attack would be very similar to the one proposed above. 

Emails with clickable links are *BAD*; we should enhance their security by linking them better with
the ACME account key.

Proposal
---------------

I notice that -02 has removed account recovery completely. I would recommend that we can 
include account recovery, by piggybacking on the account roll-over mechanism and using MACs
instead of bearer tokens sent in emails.

The proposal that came up in discussions with Richard Barnes is as follows.

Currently, account roll-over does something like the following: It signs the roll-over request with the old key, where the request itself contains a signature of the old key with the new key.
Note that it would be fine to flip the order of these signatures: It could sign the roll-over request with the new key, where the request itself contains a signature of the new key with the old key.

We further observe that account recovery is a form of roll-over where you are expected to know a secret that has been delivered out-of-band.
So, let’s assume that when the ACME client initiates account recovery, the server will somehow out-of-band authenticate the user’s request
and issue the user with a MAC key (e.g. it may email a MAC key to the contact email address, but it would be better advised to ask the user some questions first.)

Now, the ACME client can complete the account recovery by sending a message as follows: It signs the recovery request with a new account key, and the request itself
contains a MAC of the new key with the recovery MAC key.

To make this fully uniform with account roll-over, it would also be attractive to flip the order of signatures in the roll-over request, as described above, so that the outer
signature is always with the new key, and the inner JWS is either a signature with the old account key or a MAC with the recovery key.
account key, and the request itself contains a signature of the old key with the new key.

Best,
Karthik

---

From: Ted Hardie <[email-masked]>
Date: Wed, 23 Mar 2016 15:54:35 -0700

Hi Karthik,

Thanks for your message.  Will you or your co-authors be in Buenos Aires
for the IETF?  Would you like to present this work to the working group
there, if so?

thanks,

Ted

On Wed, Mar 23, 2016 at 3:33 PM, Karthik Bhargavan <
[email-masked]> wrote:

> (2) if the contact channel is used for account recovery or, in the future,
> if an email channel is used for domain validation.
>
> In both these cases, the protocol as it is currently specified (in -01) is
> not strong enough to provide the desired guarantees,
> We describe 3 issues, in increasing order of seriousness. The first two
> are closely related and may have been discussed
> in the list before. Issue 3 seems to be new and should probably be
> considered an attack on the stated goals of the ACME -01 spec.
>
> Model:
> ---------
>
> - DNS/HTTPS/SNI validation channels, which are treated as
> sender-authenticated asynchronous channels
> https://datatracker.ietf.org/wg/tokbind/documents/
>
> An alternative mitigation would be for ACME to extend the Key
> Authorization string to include the CA’s identifier. E.g.:
>
> In other words, the domain validation challenge currently includes the
> client’s identity and the server’s challenge,
> but it does not include the server’s identity, allowing the challenge
> response to be used with multiple servers.
> This may well be a privacy feature (?) but if not then adding further
> context to the challenge response will add protection
> address to send the domain validation token, a naive implementation of
> this kind of challenge would be vulnerable to attack.
>
> A network attacker blocks this request and instead sends his own account
> recovery request for account A (pretending to be C)
> In the above attack, the attacker did not need to compromise the contact
> channel (or for that matter, the ACME channel).
> bind the token provided by the server with its own account key.
> Consequently, we need to add further checks.
>
> domains with its own public key, without compromising the
> contact/validation channel. The mitigation
> Currently, account roll-over does something like the following: It signs
> the roll-over request with the old key, where the request itself contains a
> signature of the old key with the new key.
> Note that it would be fine to flip the order of these signatures: It could
> sign the roll-over request with the new key, where the request itself
> contains a signature of the new key with the old key.
>
> We further observe that account recovery is a form of roll-over where you
> are expected to know a secret that has been delivered out-of-band.
> So, let’s assume that when the ACME client initiates account recovery, the
> server will somehow out-of-band authenticate the user’s request
> and issue the user with a MAC key (e.g. it may email a MAC key to the
> contact email address, but it would be better advised to ask the user some
> questions first.)
>
> Now, the ACME client can complete the account recovery by sending a
> message as follows: It signs the recovery request with a new account key,
> and the request itself
> To make this fully uniform with account roll-over, it would also be
> attractive to flip the order of signatures in the roll-over request, as
> described above, so that the outer
> signature is always with the new key, and the inner JWS is either a
> signature with the old account key or a MAC with the recovery key.
> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme
>
>

---

From: Karthik Bhargavan <[email-masked]>
Date: Wed, 23 Mar 2016 23:56:57 +0100

Hi Ted,

Unfortunately, we wont be in Buenos Aires. But I plan to communicate the details to Richard, who may decide to present some of it.

Best,
Karthik

> On 23 Mar 2016, at 23:54, Ted Hardie <[email-masked]> wrote:
> 
> Hi Karthik,
> 
> Thanks for your message.  Will you or your co-authors be in Buenos Aires for the IETF?  Would you like to present this work to the working group there, if so?
> 
> thanks,
> 
> Ted
> 
> On Wed, Mar 23, 2016 at 3:33 PM, Karthik Bhargavan <[email-masked] <mailto:[email-masked]>> wrote:
> Dear All,
> 
> [email-masked] <mailto:[email-masked]>
> https://www.ietf.org/mailman/listinfo/acme <https://www.ietf.org/mailman/listinfo/acme>
> 
>

---

From: Stephen Farrell <[email-masked]>
Date: Thu, 24 Mar 2016 01:58:10 +0000

Excellent! It's really great to see this kind of analysis
being done on our security protocols whilst they're in
development.

Many thanks,
S

---

From: Martin Thomson <[email-masked]>
Date: Thu, 24 Mar 2016 16:45:06 +1100

> Emails with clickable links are *BAD*; we should enhance their security by

FWIW, I think that a clickable link could be possible, it just
wouldn't be able to point to the server.  If, as you suggest, the
point is to give the ACME client a fresh secret, then the link could
be changed from:

https://acme.server.example/recover/<secret>

to

acme:recover:<secret>

Most operating systems understand how to invoke local software in
response to that and your proposed flow behaves much the same from a
user perspective.

That isn't *as* good as your proposal, I don't think, but it might
have some usability advantages.

---

From: Ron <[email-masked]>
Date: Thu, 24 Mar 2016 20:12:40 +1030

> https://acme.server.example/recover/<secret>

Personally, I like the idea of moving best practice away from clickable 
links in plaintext email ...

But if integration with existing email infrastructure is desirable,
the other option to consider there might be PGP/MIME.

The downside is you add yet another key to manage and all the things
which come with that.

The upsides are, we get to reinvent fewer wheels, we can have end to
end security for the email exchange (to the point where the entire
exchange could be a signed and encrypted reply to the challenge email),
and the 'exceptional' recovery mechanism requires proof of ownership
of a key which can be kept entirely separate from the normal 'day to
day' use of an acme client - and which might be more likely to be
protected by a strong passphrase than the keys used for automated
acme renewals.

(maybe the reason I lost my account key and need to recover is that
someone broke in and stole the machine it was on, so having something
which can trump that to let me recover and revoke it does seem like a
desirable thing in its own right - but that then poses the problem of
what proof do I need to show to securely change my trump card ...)

In theory, the server and client keys could also be cross-signed,
but that probably doesn't scale to having 7 billion signatures on
the server key :)

All the client would need to do is publish their PGP key on a keyserver
and add the fingerprint of that key as part of their contact details.

But that said, I do also like the simplicity of making this congruent
with the account roll-over process.

> have some usability advantages.

The main downside I see to this, is that if I need to fully automate
the acme client to perform certificate renewals every few weeks,
then it's unlikely to be running on the same machine where I read
email.

Ideally it's going to be running in a sandbox that has very limited
access to or from anything but the acme server, the machines where
certificates need to be deployed, and the people who are authorised
to administer it.

If I was going to add a way to allow people to perform admin actions
on it via email, it probably would be by having them send PGP signed
control messages to it ...

  Ron

---

From: Richard Barnes <[email-masked]>
Date: Thu, 24 Mar 2016 11:07:08 -0400

On Thu, Mar 24, 2016 at 5:42 AM, Ron <[email-masked]> wrote:

> > > Emails with clickable links are *BAD*; we should enhance their
> security by
> > > linking them better with
> > > the ACME account key.
> >

I think it's safe to say that any system which is designed to support
re-validation with any frequency cannot involve email.

However, note that ACME supports renewal of certificates without
re-validation.

--Richard

---

From: Richard Barnes <[email-masked]>
Date: Thu, 24 Mar 2016 11:33:18 -0400

Hey Karthik,

Thanks so much for this analysis.  Couple of comments inline.

> These notes are inspired by my model of the -01 draft and some of it may

You might want to consider one additional nuance here.  The threat model
we're considering includes the ability for the CA to use a CDN that
terminates TLS.  So this particular entity is able to forge responses from
the server and block messages to the server.  (And of course, it can act as
a client if it wants to.)  That is the reason, for example, that the
keyAuthorization includes the account key being authorized, so that the
intermediary can't swap tokens to cause a domain holder to authorize its
own key pair.  I have pretty good confidence that we're OK in this model,
but the attacks can be subtle, so some modeling would be really helpful.

> Issue 1: No Mutual Authentication

I think we had considered this in some pre-WG analyses of ACME.  At that
point, it seemed that these risks were not so severe, since the attacker
cannot cause the CA to assert a name/key binding that the domain owner
didn't intent; he can only cause that binding to be asserted by a CA other
than the one that the client expects.

However, if there's an easy way to to fix this, is seems worth nailing down.

> simplifying a lot of the subsequent analysis.

Between these two options, I would be more attracted to the latter.  It's
always been a bit of a sore point that the request URI was not covered by
the client's signature, but to avoid the complexity of URL comparison, we
did the "resource" thing instead.  But maybe it makes sense to include the
whole URL after all.

OLD: { "resource": "new-reg", ... }
NEW: { "url": "https://example.com/acme/new-reg", ... }

Now that I look at that, there's one more additional property, in addition
to mitigating issues (1) and (2) here.  In cases where the server might
have multiple ACME services running (e.g., for different CAs), it prevents
a TLS MitM like a CDN from switching requests between them.

Do folks have opinions on whether we should do this?

> Issue 2: Certificate Request not bound to CA

I think channel binding, in the form discussed above, is a more elegant
solution to this.  IIUC, with channel binding, the token would implicitly
tie in the server's identity, since it was issued in response to a request
for that server.

> Issue 3: Contact-based Recovery can be Hijacked

I agree that this is worth doing.  It's worth having some recovery
mechanism in here to avoid CAs having to invent their own (and possibly
introduce vulns).  I would propose we do this in 2-3 pull requests:

1. Swap the order of the signatures in account key roll-over

OLD: Sign(K_old_priv, Sign(K_new_priv, Fingerprint(K_old_pub)))
NEW: Sign(K_new_priv, Sign(K_old_priv, Fingerprint(K_new_pub)))

2. Add a section on how to do account recovery if you have a recovery key
provisioned, namely:

NEW: Sign(K_new_priv, MAC(K_recovery, Fingerprint(K_new_pub)))

(We can benefit from JWS's conflation of signature and MAC here.)

3. (Optional) Define a way to provision a client with a recovery key.

I mark (3) as optional because neither of the options for how to do it are
especially nice.  On the one hand, if you do it in-band, then you have to
add a lot of complexity to encrypt the recovery key so that only the client
can read it (in order to keep it out of the hands of a TLS MitM).   On the
other hand, if you do it out-of-band, then you're vulnerable to hijacking
via compromise of the contact channel.  Between those two, my preference
would be for the latter, just for simplicity, but I'm open to suggestions.

--Richard

---

From: Ron <[email-masked]>
Date: Fri, 25 Mar 2016 13:29:16 +1030

Keeping this whole message intact for now, feel free to trim it if we
split this into threads on the individual parts.

> However, if there's an easy way to to fix this, is seems worth nailing down.

It possibly could be used to trick an inattentive client to propagate
assertions that S’ is authorised to issue certificates for the owner.

Which might not pose a viable attack on ACME itself, but could be a
lever for one against the owner in some other corner.

> a TLS MitM like a CDN from switching requests between them.

I think, all else being equal, I prefer the latter for its simplicity too.

How about: { "resource": "https://example.com/acme/new-reg", ... }

The distinction being, we don't assert it is a URL, and it should not be
compared using the rules for URI equivalence.  It's still just a simple
string that must compare exactly to be accepted.

It just now specifies exactly _which_ resource is requested, rather than
_what_ resource is requested.

For clients that shouldn't be a major change, they already need to do
the mapping "new-reg" <-> directory resource URI anyway, and boulder
can allow a grace period where either is accepted while the existing
client software is being updated and deployed.

I like the idea of using that field to contain a more specific request,
including information which we already know but would otherwise discard
in the JWS.

This seems worth doing to me.

> would be for the latter, just for simplicity, but I'm open to suggestions.

I am still fond of leveraging the existing PGP infrastructure for out of
band recovery.

That could work something like:

I register my PGP key fingerprint (or the key itself) as part of my
contact details.

In the event of out of band recovery, I request the server email me a
token.  It mails that to the registered recovery address (perhaps also
allowing it to be sent to the contact address registered with whois or
the role contact addresses accepted by CAB forum) - encrypted to my
PGP key, and signed with the CA's role key.

I then either follow the process above, using the ACME protocol with
that token, or alternatively, I email back a verification, signed with
my PGP key and encrypted to the CA's key.

This way, hijacking the contact channel is limited to someone who has
stolen my PGP key and been able to crack or otherwise bypass the strong
passphrase on it.

And if they've done that, then realistically, you've all already lost
because with that, they'd also be able to upload a trojaned ACME client
to Debian in my name, and compromise everyone who used it until that
got noticed ...  (among other packages, including some which could
potentially be used to compromise the CA's servers directly too!).

  Ron

---

From: Ron <[email-masked]>
Date: Fri, 25 Mar 2016 13:48:42 +1030

> re-validation with any frequency cannot involve email.

Right, what I meant to indicate there was that the acme client with
the key for my CA account was unlikely to be "local software" to the
email client I read mail in.  So being able to click on something in
an email to launch an acme client is of limited use, even for the
case of emergency recovery.

[though 'cannot' might be a bit strong.  Email does have the advantage
of being already resilient to temporary network disruptions, which is
something alternative methods would need to reimplement. This probably
could work quite well with email, but I'm not suggesting we go there
except for emergency out of band recovery. ;]

> However, note that ACME supports renewal of certificates without

That was one of the nits I pointed out earlier which it would be
nice to fix.  In the current text, the only way to find out if a
server supports that or not is to try it and see if it fails.

Which realistically means, the only 'reliable' thing to automate
without out of band knowledge about the server, is to do a full
new-certificate transaction.

It would be nice if the server did return some indication that it
was prepared to support renewal with a simple GET request that
didn't require access to the account key.  Being able to drop that
privilege for routine renewals does seem like a useful feature if
we want to keep the validity period short.

  Ron

---

From: Karthik Bhargavan <[email-masked]>
Date: Sat, 26 Mar 2016 09:45:07 +0100

> Between these two options, I would be more attracted to the latter.  It's always been a bit of a sore point that the request URI was not covered by the client's signature, but to avoid the complexity of URL comparison, we did the "resource" thing instead.  But maybe it makes sense to include the whole URL after all.
> 
> NEW: { "url": "https://example.com/acme/new-reg <https://example.com/acme/new-reg>", ... }
> 
> Now that I look at that, there's one more additional property, in addition to mitigating issues (1) and (2) here.  In cases where the server might have multiple ACME services running (e.g., for different CAs), it prevents a TLS MitM like a CDN from switching requests between them.
> 
> I think channel binding, in the form discussed above, is a more elegant solution to this.  IIUC, with channel binding, the token would implicitly tie in the server's identity, since it was issued in response to a request for that server.

I’ll plug this kind of binding into the model and run the analysis again.

Best,
Karthik

> I agree that this is worth doing.  It's worth having some recovery mechanism in here to avoid CAs having to invent their own (and possibly introduce vulns).  I would propose we do this in 2-3 pull requests:
> 
> 2. Add a section on how to do account recovery if you have a recovery key provisioned, namely:
> 
> I mark (3) as optional because neither of the options for how to do it are especially nice.  On the one hand, if you do it in-band, then you have to add a lot of complexity to encrypt the recovery key so that only the client can read it (in order to keep it out of the hands of a TLS MitM).   On the other hand, if you do it out-of-band, then you're vulnerable to hijacking via compromise of the contact channel.  Between those two, my preference would be for the latter, just for simplicity, but I'm open to suggestions.
> 
> --Richard
> 
> 
> 
> Best,
> Karthik
>