Security concerns with "http-01" and "tls-sni-01"


i found some security concerns with both methods:

  • http-01 here the server only show that he know the public key of the client. Token + Hash(publicUserKey)
    At least the server have the information for which domain he is proving.
  • tls-sni-01 here the only task is that the server have to reply with and certificate with specified subjectAlternativeName

The simpleHTTP not only check that the server handle the domain, it also checked that the server knows the privateUserKey so why not using simpleHTTP via HTTP if there are HTTPS-Concerns about stupid admin with default Servers?

Option 1)

For tls-sni we could request .<encoded(token)>.<encoded(userPublicKey)>.acme.invalid
And the server response should contain two alternative names.

encoded(SHA1withRSA(.<encoded(token)>.<encoded(userPublicKey)>.acme.invalid , userKey)).SHA1withRSA.acme.invalid
So he proves that he have ht private user key and he know for which domain he is proving:

Option 2)
signature = HEX(SHA1withRSA(fqdn|’.’|token, userKey))
http := http:///.well-known/acme-challenge//
Reply: text/plain ,

tls-sni: ...acme.invalid
Reply: SubjectAlternativeName: ...acme.invalid

So in this case the server does not require to have access to the private user key.
He only need access to the public key but than can verify that the request was issued by some person who have the users private key. That mean we have an two way identification.

well if the server didnt have the private key he wouldnt even have the token, so that’s that…

Hi, this is wrong. The token is transited in the verification. So it is no problem for example with an PHP Script
to replay to any challenge without knowing the private user key at all.
http01 only require knowledge of public key
tls-sni-01 require no knowledge at all to fulfill the challenge.

I dont think a replay is that easy, when I tried to request the same domians later I got a completely different text (assuming manual relies on htttp01) so it cant be just the pure hash of the pubkey.

Request: GET http://{domain}/.well-known/acme-challenge/{token}

thumbprint := base64UrlEncode(sha256({“e”:"{pub.e}",“kty”:“RSA”,“n”:"{pub.n}"}))

Content-Type: text/plain

Yes it is that easy.

Hmm, sounds interesting. But I think the best place for this discussion is the ACME mailing list (

@klk maybe but why do not use one place for discussion letsencrypt relevant topic’s?
Personal i do not like to follow different mail lists, forums and irc for one topic.

Because it’s not specific to LE.

Yes, but for a replay you need the token, the public key and the private account key to answer the challenge to the CA.

1 Like

Where do you need the private account key on the webServer side ?

You don’t need it on the server for which the certificate is issued, but you need it to answer a challenge, see table below that heading:

1 Like

With http-01 you prove knowledge of the private key when you accept a challenge (you send a JWS with your keyAuthorization value). So I don’t see the need of additional data in the http-01 response file itself.

1 Like

keyAuthorization is just the same content as the file. Ownership of the domain private key is proven by the submitted CSR only.

Yes, I also meant the account key (the JWS is signed with the private key of the account key pair). The certificate key doesn’t play any role.

The problem is that there is an missing link.

  1. Bad User Request DOMAIN-X were he was able to install an Script or the Server auto replay with matching SAN.
    Mean if DOMAIN-XY is requested he generate an “one time cert” with SAN Entry DOMAIN-XY same would happen with
    So this is no prove that the hoster wan’t to authorize the CSR from someone.
  2. With PHP injection someone can request authorization without that the domain owner can get the private key.

Could you please rephrase it and cover the complete attack scenario?

I will explain it for tls-sni-01.

  1. You have an HTTPS Server that will response to any SNI with an Matching Selfsigned Certificate.
  • This is used for debuging or for example for some types of fw devices that use non official CA’s.
    This Device also Host the domain
  1. Now i as an attacker place an request for “” and select “tls-sni-01” challenge.
    LE will now connect to the ip for “” and say hostnameInfo ..acme.invalid
  2. The returned certificate will contain ..acme.invalid (Challenge OK)
  3. Know i can request Cert for “” and was never in hold or had access to the server

well probably it would be more helpful if LE just spits out a cert from for example our Happy hacker fake CA which should then be put into the server and if that cert is found then it’s okay.

1 Like

@My1 yeah this would be one option. Because this show at least that the requester have access to the system.

The other would be to include the requested FQDN and expected an second SAN entry that prove the possession of the users private key. Maybe even an third with prove of possession of private key for the new cert.

well I personally like the way of the manual as it is now the best: get a file throw it on your server and finished.

and even if somebody replays an attack without having my private key, the challenge is linked to my account, so the private key is needed later again.