letsencrypt / pebble

A miniature version of Boulder, Pebble is a small RFC 8555 ACME test server not suited for a production certificate authority.
Mozilla Public License 2.0
625 stars 150 forks source link

Order includes different number of names than CSR specifies (for CSR without subjectAltName) #233

Closed znerol closed 5 years ago

znerol commented 5 years ago

Given a CSR which only has the CN field set without any subjectAltName, pebble returns Order includes different number of names than CSR specifies. This is likely because the check in FinalizeOrder only takes values rfom CSR subjectAltName into account and disregards the CSR CN.

This happens whenever a CSR is generated from the command line using the -subj without -addext:

openssl req -new -subj "/CN=example.com"  -newkey rsa:2048 -nodes -keyout key.pem -out req.pem

In order to work around this issue, one has to generate a CSR which repeats the CN in subjectAltName. Older versions of openssl req are missing the -addext flag and hence one need to resort to a tmplate. E.g. (minimal):

[ req ]
distinguished_name  = req_dn
req_extensions      = req_ext

[ req_dn ]
commonName          = Common Name (eg, YOUR name)
commonName_default  = example.com

[ req_ext ]
subjectAltName      = DNS:example.com
cpu commented 5 years ago

Hi @znerol,

Thanks for opening an issue. I'm afraid this is the expected behaviour. The subject common name field is deprecated and all CSRs should contain subject alternate names.

I believe Pebble has the same behaviour here as Boulder and so this also matches the production Let's Encrypt ACME v2 API.

In order to work around this issue, one has to generate a CSR which repeats the CN in subjectAltName.

You could also avoid the duplication by omitting the deprecated Subj. CN entirely and just providing the SAN.

Older versions of openssl req are missing the -addext flag and hence one need to resort to a tmplate:

Typically ACME clients handle the details of generating a CSR themselves and don't require the user to interact with openssl to generate one manually. It is unfortunate that old versions of openssl make it quite cumbersome to generate a CSR with SANs but I don't think that justifies changing Pebble's behaviour (especially since it won't match Boulder).

I hope that helps explain the situation! I'm going to close this issue since there isn't a change to be made based on the report.

Thanks!

znerol commented 5 years ago

I am operating live Let's Encrypt certificates without any subjectAltName, so thanks for the heads-up in this regard.

munnerz commented 4 years ago

@cpu sorry to dig up an old issue, but we're feeling a bit of pain with this at the moment too in cert-manager.

Is this behaviour (ignoring CNs altogether) mandated by the ACME spec? We've got a number of other ACME servers now being used with cert-manager, and we're cautious to implement/modify behaviour if it risks breaking other implementations. If it's mandated by the spec, we can at least tell them to go fix it 😄

I couldn't see any references to the terms 'CN', 'common name', 'SAN' or 'subject alternative' that seemed relevant in RFC8555.

cc @JoshVanL

jsha commented 4 years ago

RFC 2818 from May 2000 deprecates Common Name: https://tools.ietf.org/html/rfc2818#page-5

Also BRs 1.6.6 section 7.1.4.2.2: Subject Distinguished Name Fields: https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.6.6.pdf

munnerz commented 4 years ago

:+1: but they are still used, and most CAs don't just ignore the CommonName field (and that's evidenced by boulder not just blindly signing certificates with the CommonName field set, as presumably browsers also use this field still).

My question is, is ignoring the CN here an ACME spec property, or could some ACME servers choose to sign a CSR that has CN: example.com and dnsNames: www.example.com if the account holder holds authorizations for example.com and www.example.com?

munnerz commented 4 years ago
Otherwise, the (most specific) Common Name
   field in the Subject field of the certificate MUST be used. Although
   the use of the Common Name is existing practice, it is deprecated and
   Certification Authorities are encouraged to use the dNSName instead.

I see this in section 3.1 of rfc2818 - this implies to me that if a CSR does not specify any DNS SANs, the common name should be used instead. It seems the nature of the deprecation and exact, specific advice isn't particularly clear from my PoV though, as it does acknowledge that the field is deprecated and encourages CAs to use DNS SANs instead. Given that ACME already copies dnsNames[0] over to commonName, it just seems a bit inconsistent is all.

Given our ACME client (cert-manager) also works with other CAs, we've simply added additional validation that is run ahead of interacting with the ACME server to ensure that if a user requests a specific commonName, it must be present on the list of dnsNames (and if it isn't, we bail out before creating the order/interacting with the server).

My concern is that some CAs might request we relax this validation, although perhaps I'm wrong 😄

cpu commented 4 years ago

My question is, is ignoring the CN here an ACME spec property, or could some ACME servers choose to sign a CSR that has CN: example.com and dnsNames: www.example.com if the account holder holds authorizations for example.com and www.example.com?

Yes, some ACME server could choose to do that and there is no mechanism for advertising that policy with RFC 8555. Like @jsha mentioned if the certificate that was issued from that CSR chains to a root participating in the traditional browser root programs then it would be considered a misissuance by the baseline requirements (CN MUST be present as a dNSName SAN) but ACME deliberately doesn't encode/mandate CA policy where possible.

I think since this isn't a question specific to Pebble it would probably be better suited to the community forum's client development section, or the ACME mailing list. Does my answer sufficiently clarify things or does someone want to spin up a new thread to continue to talk it though?

Thanks!

jvanasco commented 4 years ago

@cpu i'm fine with the behavior, but shouldn't this be added to the divergences doc?

https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md

cpu commented 4 years ago

@jvanasco I think this is better discussed as a Boulder issue but my opinion at the moment is that since there's not any text in RFC 8555 that discusses this topic there isn't a divergence from specification.

jvanasco commented 4 years ago

@cpu Sorry for the confusion on this. I didn't realize the RFC only covered Acme v2. Acme V1 (and the production Boulder/Letsencrypt) allowed for the CSR subject to be "/CN=example.com" (possibly required it?); the Acme V2 only accepts the CSR subject as "/".

my client's acme-v1 test server was a custom app; i'm using pebble as I upgrade to v2 and all these small changes are popping up.

cpu commented 4 years ago

I didn't realize the RFC only covered Acme v2

Indeed, there's no spec for what's colloquially known as ACME v1. It co-evolved with the spec and so there's always been just a reference implementation and a list of divergences against a fixed draft.

Acme V1 (and the production Boulder/Letsencrypt) allowed for the CSR subject to be "/CN=example.com" (possibly required it?); the Acme V2 only accepts the CSR subject as "/".

@jvanasco Can you file a Boulder issue with full request logs from V1 and V2 showing what you're saying? Please include the CSRs. I'm not aware of a change in the CSR CN handling between protocol versions in Boulder.

Thanks,