This repository is not active and does not accurately reflect what Let's Encrypt currently implements. It's retained only for history.
All new work happens here: https://github.com/ietf-wg-acme/acme/
ACME Specification
This repository is not active and does not accurately reflect what Let's Encrypt currently implements. It's retained only for history.
All new work happens here: https://github.com/ietf-wg-acme/acme/
see also issue #19.
practical examples:
https://proxy.example.com:8080/;
port 8080
is commonly used but 8080 is not a privileged port.
running multiple services on the same host
SSL endpoint not being apache/nginx but the app
uwsgi
tomcat
/ jetty
/ winstone
servletCross post from https://github.com/letsencrypt/node-acme/issues/15
I haven't tried this yet, I just peeked at some of the node code and the question came to mind, so right now I'm just making note of it for something to come back to later.
Scenario: Consider trusted peer devices A & B. If device A requests a cert from the ACME server and the ACME server responds with a challenge to device B (via round-robin DNS) then that responding device has not yet received the token and the validation would fail.
Use case: I'm working on a distributed peer home cloud in which each app may have it's own domain name and may run on multiple authorized boxes - like a mini-CDN.
For example: https://aj.myhomemusic.com may run on a device in my home, my sister's home, and my girlfriend's home. If the power is out at my house or there's other network trouble, my custom DNS server will know that within a few seconds of the outage and will remove the device that is out from the round-robin.
This will be the first time in history that peer-to-peer encrypted https can be accomplished in a non-cost-prohibitive fashion, so I'm going to push to make sure we have support for it on Launch Day.
https://tools.ietf.org/html/draft-nottingham-http-problem
Might make it easier to handle errors.
Right now we specify certificate refresh as a GET URL, in response to which the server may choose to provide a refreshed certificate.
It's not specified if the server would issue the refreshed certificate in real-time. I suggest that we should specify that the server will never generate the refreshed certificate in response to /acme/cert/asdf.
Instead, the server may choose at its discretion to periodically refresh certain certificates and have them ready to respond to GET /acme/cert/asdf. Response time would be more or less constant and there would be no risk that third party could mutate state with a GET request.
A CSR basically duplicates the information that this protocol carries: the intended identity, the public key and the signature (which #23 seems to be moving to JWS). A CSR on its own doesn't contain any binding to this protocol interaction, so it's not as though the CSR is an effective substitute for anything that the protocol provides.
Unless I've missed something, a CSR is only used as an artifact of the toolchain. This protocol doesn't need to use them. The only consequence is that you can't generate a CSR if your toolchain demands it.
One advantage of not using the CSR is that you don't have any vector for clients to introduce a distinguished name or other supplementary information. That means that certificates won't include unvalidated content.
(Or, at least, it's not obviously sound.)
In section 5.2, an nonce is defined as
A signer-provided random nonce of at least 16 bytes, base64-encoded. (For anti-replay.)
That suggests that the nonce's length is >= 16 bytes. Later, the input to the signature algorithm is defined as:
signature-input = nonce || content
This means that, if I capture a signature with nonce n
and contents abc
then I can create a signature of any suffix of abc
by appending the unwanted prefix to the nonce.
For example, a signature of nonce "0123456789012345" and content "Hello, world" is also valid as a signature of "world" if I set the nonce to "0123456789012345Hello, ", it appears.
I suggest that the length of the nonce be fixed at 16 bytes and not controlled by the signature submitter.
(Also consider other situations in the protocol where values are simply concatenated before signing and ponder the ambiguity that arises.)
Lastly, please consider requiring that TLS server key and the ACME "Authorized Key Pair" are not equal. Some clients might save a key generation by doing that because it doesn't seem obviously wrong. However, a key installed as a TLS server key will sign an attacker's chosen 32-byte prefix at will via the TLS ServerKeyExchange message. That gives an attacker a worrying amount of control if the TLS key were also an "Authorized Key Pair" in this protocol.
There is one worrying use of the word "nonce" for a re-used value in the draft, in the "Domain Validation with Server Name Indication" section:
"The ACME server MAY re-use nonce values, but SHOULD periodically refresh them. ACME clients MUST NOT rely on nonce values being stable over time."
Please either change this to "...MUST NOT re-use nonce values..." or use a different word instead of "nonce". Nonce has a special meaning, and some one thinking about the security of the protocol might be fooled by the word "nonce" to expect a value only ever used once.
Anyway, allowing the attacker to learn the secret value (sometimes) used for following transactions seems a bit dangerous to me.
I haven't read closely; this may be true already but if not we should add it.
I'm interested in using ACME with services that are found via DNS SRV records. These services may not be on privileged ports and the ACME client may have a different hostname to the service it is providing.
Using XMPP as an example, a service would be found by retrieving a record such as:
_xmpp-server._tcp.userdomain.example. 0 IN SRV 0 0 5269 xmpp-host.example.
Wherein xmpp-host.example.
would be expected to provide a certificate for userdomain.example.
and 5269
is the unprivileged default port used by XMPP servers.
As I understand the spec the client (xmpp-host.example.
) could successfully request a certificate if it is only given a DNS Challenge and if it can manipulate _acme-challenge.userdomain.example. IN TXT
. In my case answering that challenge wouldn't be an issue however if the other challenges were employed in addition to or in place of the DNS Challenge the client wouldn't be able to proceed.
That seems a narrow window for success. Is this use-case in scope for the project?
For the autorenewal feature in the client, we want a way for a CA to indicate whether a cert has been revoked (which could conceivably be OCSP, except that we also want this other functionality...) and also whether a cert is about to be revoked. The idea there is that if the client is checking frequently enough, it can receive a warning ahead of time prior to some revocation events (typically hours before) and proceed with the renewal request before the revocation takes effect.
Should this be done in ACME? We could extend ACME to do it, or create a new protocol mechanism entirely.
Another policy question is whether the general public should be able to learn about intent-to-revoke this way, or only the affected subscriber. I was thinking that this might mean that we risk tipping off the attacker when we detect misissuance events, for example -- but in that case the attacker is the subscriber, so limiting notifications to subscribers-only won't usually help anything.
(mentioning @pde)
The Proof of Possession of a Prior Key section of the spec includes the following example:
{
"type": "proofOfPossession",
"nonce": "eET5udtV7aoX8Xl8gYiZIA",
"signature": {
"alg": "RS256",
"nonce": "eET5udtV7aoX8Xl8gYiZIA",
"sig": "KxITJ0rNlfDMAtfDr8eAw...fSSoehDFNZKQKzTZPtQ",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"n": "KxITJ0rNlfDMAtfDr8eAw...fSSoehDFNZKQKzTZPtQ"
}
}
}
From reading the text surrounding this sample, I get the impression that both "nonce" should be different and that this should be reflected in the sample.
Thanks.
First, thanks for putting this together, it's a fantastic step forward!
I noticed that there are currently assumptions about the gender of the humans referenced in the spec (using words like him/he/his, etc). This is not ideal, as it can come across as unintentionally exclusive. One common option is to instead use the pronouns they/their/them. The Django style guide has some examples. I'd send a pull request, but just wanted to establish consensus on the approach before moving forward.
In relation to #66
It is feasible to get an demo client working with commandline tools?
I think it would be easier for me (and the general programming community) to grok. The node code I've been looking at is way more intricate than I would have expected. It's also really slow and even buggy on the newest versions (not sure whether the bugs are in the code, node, or due to incompatible API changes).
In any case knowing how this is corresponding to openssl commands would really help me out with the debugging (assuming that there even is a 1:1 mapping).
What is the proposed mechanism to prevent state actors from subverting the certificate authority, compelling the disclosure of information and generation of forged certificates?
Will the list of certificates published by this service be publicly available to validate that fake certs for sites such as mail.google.com are not being produced?
When performing domain ownership validation, what DNS service will the CA rely upon to ensure it is actually hitting the real host?
...in both places that I see it. Just an editorial thing. Kramdown doesn't like character references, I suspect.
As @kuba pointed out, the certs (optional array) should be specified as DER + base64 (jose) encoded rather than being PEM encoded in order to be consistent with the rest of the spec.
Could be significantly better. It would require some fairly major structural changes though.
As of RESTification merge, spec states:
The JWS MUST use the Flattened JSON Serialization
This inhibits code/library reuse.
Suppose a certain JOSE library serialises a JWS with a single signature
using the General JWS JSON Serialization Syntax. That library cannot
be used with ACME.
According to the JWS draft there is no requirement or recommendation for an implementation
to serialise a single-signature JWS using the Flattened syntax, nor is there
a requirement or recommendation to provide users a knob to control how to deal with this
ambiguous case.
So if there is no important (i.e. security) reason to have this requirement in ACME,
please remove it.
Please consider advertising:
If there is a linkage (and there might be sometimes), then tuples of these make sense.
As PHB notes, this could be useful in determining whether to pursue a request with a CA that offers this protocol.
While you're listing unacceptable JWS signature algorithms, I think it's worthwhile to disallow the "none" algorithm.
Hello,
In the DNS Challenge (section 6.6) it is specified that the token MUST contain only ASCII characters:
In response to this challenge, the client first MUST verify that the token contains only ASCII characters.
It may be good to reduce the characters permissible in the token to only alphanumeric ones (or possibly also other used in Base64). Full ASCII range is really unnecessary here.
There have been instances of people doing strange things with DNS records. Note: that blog post details XSS in PTR records and is not directly relevant here.
I have big concerns about the choice of JSON for this. It's probably fine for the CA side of things, but this choice basically (over)kills small embeddable servers.
People choose my project because it's small, fast and has no dependencies. If I want to add support for this protocol by default, I need to depend on an HTTP client and a JSON parser. Both together are bigger than the size of my project.
Considering the protocol looks fairly simple with few possible requests and responses, it should be possible to do something much simpler that runs on plain TLS connections and could be handled in a couple hundred lines of code instead of the thousands that an HTTP client and JSON parser requires.
If you make that protocol strict, you will also avoid the madness that derives from not only loosely implemented JSON encoders and parsers, but also avoid dealing with weird UTF-8 issues.
It sounds like a good idea in theory, and I would like to include it by default, but the technical choices made so far make that impossible.
Copying and pasting from letsencrypt/boulder#21
According to a presentation by Seth Schoen and according to brief inspection of the CA source code, Let's Encrypt is planning on not issuing wildcard certificates. IIRC, the reason given by Schoen was the lack of a method of checking that the ACME client really speaks for the whole domain subspace. Furthermore, it was observed that being able to quickly meant non-wildcard certificates for a particular host names in an automated fashion without payment makes wildcard certificates less necessary.
This doesn't address the wildcard use case that Sandstorm (https://sandstorm.io/) has: Minting randomly-generated host names all the time in order to generate new unguessable origins. In order for newly-minted origins to work immediately, it doesn't make sense to wait even for fast automatic certificate issuance. Also, I would imagine that as long as the Baseline Requirements don't exempt short-lived certificates from revocation infrastructure requirements, Let's Encrypt might not be too keen to have servers generate certs for throw-away hostnames all the time.
To address this use case, I suggest that Let's Encrypt issues a wildcard certificate when the ACME client can demonstrate that it speaks for several hostnames that are randomly generated by the Registration Authority. For some reasonable value for "several", the RA should be able to convince itself that there exists a DNS wildcard that makes hostnames that would match the requested wildcard certificates point to the server running the ACME client.
This issue is to request an ACME protocol addition for the RA to be able to present the client the sort of challenge described in the above paragraph.
(CONTRIBUTING.md says I should email a mailing list, but the list name is a placeholder. Please let me know if I should email this somewhere.)
On many embedded devices which are perfectly capable of serving https at reasonable speeds, key generation can take anywhere from 10s of seconds even to several minutes.
I know it's a stretch, but could there be consideration for allowing the server to provision the private keys in such cases?
At the moment we do this in the client only, but the Terms of Service may be changing serverside. Also explicit agreement in the protocol is neater under the BRs.
unless you are sure this is immutable, perhaps a version number in the pdu headers
Ryan Sleevi pointed out recently that a Proof of Possession challenge can be risky because a malicious server can ask a client to sign some string that collides with or looks like a pre-master secret for an SSL handshake.
Additionally, the PoP challenge can be simplified to use the existing certificate validation mechanisms built into TLS. Proposal: amend PoP challenge to say:
This challenge is the same as the SimpleHTTPS challenge, with the additional constraint the the verification request must occur over a validated TLS connection with a non-revoked certificate that contains the requested identifier.
Section 5 (Certificate Management) starts "In this section, we describe the four certificate management functions that ACME enables:" and then lists only three items (Key Authorization, Certificate Issuance, Certificate Revocation). This should be adjusted one way or the other (is 5.2 Signatures the fourth item? Or perhaps 5.3.1 Recovery tokens? Or should "four" simply be replaced with "three"?)
https://letsencrypt.github.io/acme-spec/ is still at v00, and draft is already v02.
...is bad.
A URL the client may poll to determine if the user has successfully clicked a link or completed other tasks specified by the recovery message. This URL will return a 200 success code if the required tasks have been completed. The client SHOULD NOT poll the URL more than once every three seconds.
But I realize that it might be useful in some circumstances. Use Retry-After
instead of a "SHOULD NOT" at a minimum. You could even try a long-poll with Prefer: wait=10
.
The spec mandates, that a endpoint should ignore all unknown properties. This is fine, however makes it very hard for extension writers to actually specify a method for validating different types of identifiers. The extension either adds a new identifier field email and then the server which is not enabled with this extension would receive a dummy/malformed identifier in the old field or has to parse the content of the identifier to pick a type. So I think a default identifier type with a value for TLS (Web) server should be added. In my PR #20 I propose
identifierType (required, string); "dnsname"(,"email")
It would be good to see some threat modeling for this protocol. What assumptions are being made (especially with regard to challenges)? What attack vectors exist and what does the protocol provide to ensure they cannot be exploited?
Hi,
Thanks for authoring this draft. I'll continue to submit minor editorial changes, I haven't found a flaw so far.
I have a suggestion though: at no point does the document mention key pinning (it mentions HTTPS explicitly w.r.t. DV certs. though). It might be a good idea to support TACK (or HPKP in the case of HTTP) by design. I've looked through all issues/PRs and could not find appropriate discussion on this topic.
The only mention I see is in #17 - with @martinthomson refering to refresh rates. Does this refer to short-lived certificates?
edit:
One of the deployment issues I see with key pinning techniques in general is that administrators might get the pinning wrong and basically lock-out their users for good. To people working a lot with crypto and it's toolchain it's easy, to a run-of-the-mill admin probably not so much. If that part would be automated as well, I think key pinning would see real adoption in the future.
Thanks,
Aaron
Hi,
Reading through the document I was wondering if it makes sense to make not one but two of the validation schemes mandatory for people trying to get their CSR signed.
Aaron
I noted this when reviewing #48. I think that this needs a better design, since it would be good if the information hosted in the authorization resource could be all completely public.
If the design of the recovery keys is such that they could be used just once (and I think that's probably fair), then you don't need to worry about redacting anything.
Clients create an authorization resource with a recovery key by adding a "recoveryKey" challenge when they request that the resource be created. This includes a hash value:
hash = HMAC(recoveryKey, 'acme-recovery\0' || identity.type.length || identity.type || identity.value.length || identity.value)
(I'm not sure what sort of HMAC discriminator you might want to use throughout, so details can vary.)
If a client wants to use the recovery key, it provides the value of recoveryKey.
Now, to the separate question of why it might want to have this capability at all...
On page 26 of the Sept 2014 draft, it is specified that a DVSNI challenge must go to port 443. However, the verification process given completes from just the TLS session without needing to issue any HTTP packets. So, the only thing keeping ACME from performing validation of other services such as SMTP/TLS, IMAP/TLS or POP3/TLS (commonly ports 465, 993 and 995) is that the client can't specify to go to a different port number. The only limitation on port should be that the service must be running on a port below 1024 at the time of validation to prove administrative control.
For authorization requests and possibly other interactions in the protocol, there will have to be timeouts. For instance, a client may need to present a challenge response within 15 minutes, or the challenge will expire and need to be restarted. The spec should make these timeouts more explicit, and specify behavior and error codes.
To avoid aggressive timing attacks, the Server should validate that Indexing (Directory Listing) is NOT allowed in the .well-known/ path under which it has been requested by the Client to find the Client's proof of SimpleHTTPS Identifier Validation (a file containing the nonce sent by the Server).
I theorize that an aggressive attacker could repeatedly attempt to index the Client website, and if the Client website permits directory browsing, then the attacker could find the nonce in the .well-known/ subpath.
In theory, a nonce is usable only once, and the real Client will immediately use this nonce in its response to the Server to prove the Client's claim, making a timing attack unlikely.
If the ACME protocol design or a Server's implementation would permit the attacker-Client, now having the Server's nonce, to authenticate as the Client, this might be a real threat.
In any case, it's a useful extra security step to help the Client administrator avoid common configuration errors such as allowing directory browsing in places where it should not be allowed, which often result in security breaches. (Although this could be preferred to be kept out of the ACME protocol design, as being out of scope).
If I've missed something totally ignorant and my concern or suggestion here are completely useless, I'll take my lumps, and I apologise in advance!
Step 4 in the "simpleHttps" challenge demands a self-signed certificate. That makes this challenge unusable for certificate renewal.
I would have thought that this is still a valuable thing to use for renewal requests, but you would then need to ensure that the certificate is valid for the domain. Given that the nonce you retrieve would be confidential (and probably time-limited), I see no reason that you can't just rely on the proof-of-possession that was attached to the original request for the certificate.
Hi, would a challenge based on knowing the host ssh keys be possible ?
(or even a good idea?)
Scenario: host is configured with puppet, puppet knows/generates host ssh keys ahead of time and we want to run the client & generate certs ahead of time.
Spec example from https://github.com/letsencrypt/acme-spec/blob/master/draft-barnes-acme.md#authorization-resources uses a strange hybrid between a list and a dict syntax: "challenges": [ "simpleHttps": {}, ... ]
, while later in https://github.com/letsencrypt/acme-spec/blob/master/draft-barnes-acme.md#key-authorization "challenges": [{"type":"simpleHttps", ...}, ...]
, proper syntactically, is used.
Use https://github.com/martinthomson/i-d-template for building and such. I can prepare a PR if you like.
Two links in CONTRIBUTING.md
appear to be placeholders:
(|WG-HOMEPAGE|)
(https://www.ietf.org/mailman/listinfo/|WG-NAME|)
I'm not sure where the former is supposed to go. The later should be https://www.ietf.org/mailman/listinfo/acme
.
Hi there,
In 5.4, the current version of the spec contains a 'refresh'-URI where the client can fetch a new certificate via plain GET.
I think this is a great feature to prevent the abuse of stolen certificates/private keys, but currently it's not clear how the response should look like.
a) a PEM-encoded certificate could be send
b) a plain DER certificate could be send
c) the whole 'certificate'-Message could be send, containing a new certificate.
d) a HTTP-404/301/whatever could be sent.
e) According to the content-type, different types can be sent.
I definitely prefer c). This makes it easier for CAs (they may change the CA-Chain and/or refresh-URI if they perform changes on their infrastructure) and even the Client development (the 'certificate'-responder may be reused).
Additionally, I'm wondering what will happen if the certificate was revoked in the meanwhile.
To specify this, I'd suggest adding that the server may send the following status codes:
a) 200 (everything's ok)
b) 304 (the certificate was not changed)
c) 302/303 (the cert can be temporarily fetched from there)
d) 307/308 (the cert can be fetched from there & the refresh-uri should be set to the value)
e) 404 (like everywhere else)
g) 403/410 (if the certificate was revoked)
f) 503 (the client should retry later)
This protocol uses certain features of HTTP (methods, headers, etc.), and not others. To bound attack surface in security-critical environments, it would be useful for deployments to be able to enforce this profile of HTTP at some outer, less trusted boundary point. For example, a load balancer might apply whitelists to methods or headers before passing the request to the real ACME server. This document should specify this minimal HTTP profile as a recommendation to deployments.
https://github.com/letsencrypt/acme-spec/blob/master/draft-barnes-acme.md#authorization-resources gives an example involving "validated". It's not described (narratively) or even referenced anywhere else in the spec. What is the semantics? Can the field be omitted? Do we even need it?
Same for "status".
An ACME server should probably limit the time over which it will accept a single account key. This prevents account key compromise from being a problem. This requires tracking the time that a given account key was first seen. Tracking across identifier authorizations is probably sufficient as long as authorization were marked as expired when the key also expires.
I don't know if it's worth considering any account key suicide options. If an ACME client could relinquish any rights to an account key, that might also be a good idea.
The current step 5 and 6 in simpleHttps need to better handle Unicode.
Yes, it sucks that JSON followed JavaScript in choosing not-UTF-16, but no need to make this harder than it needs to be. If you invite the whole string interpretation thing, it gets complicated.
Both challenge and response read:
type (required, string):
The string “recoveryToken”
while the examples show:
{
"type": "dns"
...
}
Presume the examples are correct and the spec should read:
type (required, string):
The string “dns”
DNS TXT record data is a series of one or more character-strings that themselves consist of 0 to 255 bytes.
The DNS Challenge doesn't impose a minimum or maximum length for the token, cover how a token longer than 255 bytes should be handled, or how multiple character-string records should be compared to the token.
Limiting the challenge to a single character-strings seems reasonable to me. Concatenating character-strings and setting an upper limit would be another option. (DNS record data can theoretically be up to 64KB but in practice it's well below that).
The validation section also doesn't mention how to handle the presence of multiple TXT records. It's unlikely that multiple challenges would provision records simultaneously but validators should be expected to check through multiple records all the same.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.