diafygi / acme-tiny

A tiny script to issue and renew TLS certs from Let's Encrypt
MIT License
4.73k stars 571 forks source link

Dump intermediate certificate #77

Closed PhrozenByte closed 8 years ago

PhrozenByte commented 8 years ago

Let's Encrypt doesn't guarantee the use of a specific intermediate certificate for signing. Therefore it's currently not possible for a user of acme-tiny to create a chain.pem and fullchain.pem without the risk of breaking his setup when Let's Encrypt (suddenly) switches to Let’s Encrypt Authority X2. To solve this problem, a ACME server must send a Link: <https://example.com/acme/ca-cert>;rel="up";title="issuer" header when retrieving a signed certificate.

A possible solution I can think of is, that acme-tiny follows this link, appends all intermediate certificates to the signed certificate and therefore actually outputs/returns a fullchain.pem.

trunneml commented 8 years ago

Here is a fork of @neurobin that has this feature may be it is possible to merge it? https://github.com/neurobin/letsacme

drybjed commented 8 years ago

Hello. I'm using acme-tiny as a component of an Ansible role that manages a PKI infrastructure. i'm mentioning this, because the idea of acme-tiny appending an intermediate certificate automatically to the signed certificate would possibly break a lot of setups.

My Ansible role handles the certificate chaining itself, when a suitable intermediate certificate is provided. As for Let's Encrypt/ACME intermediate certificates, currently their retrieval is done by downloading a file from specific URL. However, the certificates themselves contain an URL to the issuer certificate, which I'll probably start using to retrieve the intermediate certificate, so that will most likely eliminate the issue at hand.

trunneml commented 8 years ago

Interessting ansible role. It should only download the chain with an extra parameter like --chain or --fullchain. This way it would break anything.

drybjed commented 8 years ago

@trunneml If you like it, I suggest that you check out the documentation as well. It explains how the PKI is structured, among other things.

trunneml commented 8 years ago

@drybjed Can you give me an example how to download the certificate chain using the embedded URL you mentioned?

drybjed commented 8 years ago

@trunneml Getting the URI should be pretty easy:

openssl x509 -in cert.pem -text -noout -certopt ca_default,no_validity,no_serial | grep -E '^\s+CA\s+Issuers\s+-\s+URI:' | awk '{print $4}' | sed -e 's/^URI://'

Although this might be limited, because you don't really know if a certificate is an intermediate or a root CA, so I don't plan on generating a general solution just yet, only an ACME-intermediate specific.

neurobin commented 8 years ago

@trunneml

It should only download the chain with an extra parameter like --chain or --fullchain

It's available, though in another way:

By default letsacme prints a full chain on stdout, but you can prevent that with --no-chain option. With this option appended, letsacme will behave like acme-tiny.

may be it is possible to merge it?

I don't think so. The author of acme-tiny is pretty strict about the restriction in line numbers. My fork became larger because I inserted some paranoid checks on the token retrieved from CA (as a file needs to be created for it) and added some other additional features like using a json configuration file to pass the options and another method of providing the challenge directory. Though, the particular codes for retrieving the chain can be copied and the acme-tiny source can be modified accordingly, which may increase the size approx. 10~15 lines or so.

trunneml commented 8 years ago

@neurobin I know. I'm currently looking around which client to use. As the default letsencrypt client isn't easy to automate.

PhrozenByte commented 8 years ago

acme-tiny doesn't have to return a fullchain by default, a --fullchain option is completely sufficient and breaks no BC. The difference to other suggestions is, that you simply can't use acme-tiny for automatic certificate renewable at the moment. Despite this is one of acme-tiny's main goals.

You can't solve this problem by adding a single command to a renewable wrapper script (if this were true, I wouldn't suggest this). There are various solutions, most of them add more complexity than acme-tiny itself has (e.g. SSLMate/mkcertchain). That's no satisfactory solution. acme-tiny can solve this problem by adding ~10 lines of code, staying below 200 lines of code in total is still possible.

diafygi commented 8 years ago

I feel like building the chain is outside the scope of this project. This script gets certs signed, that's it. It doesn't do anything to install them for you (that's up to you).

PhrozenByte commented 8 years ago

@diafygi So, what's your suggestion for auto renewal? Auto renewal is supported by acme-tiny, isn't it (at least the README.md tells so...)?

kelunik commented 8 years ago

Your description says:

A tiny script to issue and renew TLS certs from Let's Encrypt

To be usable for renewal, there must be an option to dump the intermediate certificate. Installation of the intermediate is another thing, but it should be provided so another script can stitch the things together then.

rspeed commented 8 years ago

Clients can fetch any missing certs, so it isn't actually necessary for servers to provide the full chain. It's just an optimization step.

sebastianw commented 8 years ago

That's a bit optimistic. Most clients WILL fail without the intermediate. I added support for fetching the intermediate in my fork at https://github.com/sebastianw/acme-tiny which works for me but I'd be quite happy to see it upstream. Without it there will be problems whenever the intermediate changes (which happened a few days ago).

rspeed commented 8 years ago

What browser fails with LE without the intermediate certs?

kelunik commented 8 years ago

I guess most browsers currently fail if no intermediate is sent.

haarp commented 8 years ago

In addition to browsers, ssllabs will also complain if the cert chain is incomplete. For a good reason.

kelunik commented 8 years ago

@haarp For exactly that reason: Most clients will fail.

rspeed commented 8 years ago

SSL Labs will only issue an error if it can't establish the chain on its own. For LE it should only issue a warning.

samuellb commented 8 years ago

Just a clarification: The clients will cache the intermediate cert, so if you've already visited a site that contains the intermediate cert then it will succeed. But it can fail at the first time.

haarp commented 8 years ago

Isn't a warning and the fact that it breaks browsers enough to include it?

I made the mistake of skipping the intermediate at first and wondered why my site fails half the time. The fact is, the browser only trusts the root cert and NEEDS the intermediate to know if it can trust the leaf cert.

neurobin commented 8 years ago

Just created a new repo with the acme_tiny code and added chain retrieving feature (~20 line). New features are:

  1. --chain-file will save the chain to a specified file
  2. --cert-file will save the cert to a specified file
  3. --full-chain will print full chain on stdout.

mixing the above three, chain, cert and full-chain can be obtained separately at the same time.

The code is untested. If someone tests it for me I would appreciate that :smile:

iBobik commented 8 years ago

Why not to include this feature if it is at least useable and people already implemented it in forks?

asokani commented 8 years ago

@sebastianw Your fork should be accepted pull request in the ideal world.

rspeed commented 8 years ago

The actual warning from SSL Labs about a missing intermediate certificate:

This server's certificate chain is incomplete. Grade capped to B.

I tried it in a virgin browser (and also checked that the LE certs weren't already on the system) against both X1 and X3 as the intermediate and got the same result. No errors, no warnings. It simply worked.

I don't know what the actual mechanism is, but it seems clear that browsers have the ability to look up and fetch a missing intermediate certificate.

Edit: Apparently it doesn't work in Firefox. Safari, Chrome, and IE will fetch the missing cert, which represent the vast majority of browser market share.

Edit 2: Aaaaand apparently it fails in both Safari and Chrome on iOS. So I'm not really sure what should be done. Maybe a flag to automatically combine it with the intermediate certificate?

kelunik commented 8 years ago

See also https://github.com/alexpeattie/letsencrypt-fromscratch#missing-certificate-chain

mmitch commented 8 years ago

An example of a client failing would be k9mail - an Android mail client. The chances to get the intermediate cached from visiting another site like in a web browser are really small here.