What is the valid content to accept acme-challenge?

Hi. I am following instructions here:

but nowhere is specified what I should answer when certbot CLI calls my server for validation here:

https://portal.cotech.co/.well-known/acme-challenge/nPanbertTXMzsQedTld-zzqU02ooNZJWVizClmUzR94:

I answer "ok" cause the docs do not specify anything, but I am getting this error:

Detail: The key authorization file from the server did not match

Maybe I am missing something, or maybe the doc is lacking this information?

Thanks for any help.

As I understand it, you’re using the webroot plugin. What this plugin does is write a file to the path you provide, under the assumption that your web server is configured to serve files under this path as-is, like you’d expect something like apache or nginx to do with its stock configuration.

If that is not the case for you, maybe because you’re running some kind of application server that doesn’t do that by default, there are a couple of options. If you’re running some kind of reverse proxy (nginx, etc.) in front of your application server, you could configure requests that match the path /.well-known/acme-challenge/* to be served from your filesystem instead. Another approach would be to implement the reading of that file in your application code, with the HTTP response being the file contents.

Alternatively, you could use one of the various low-level ACME libraries and essentially implement your own ACME client. This option would be the most involved. ACME is the internet standard that’s used by Let’s Encrypt to automate issuance and validation. The relevant specification would be the acme-01 draft. This is also where the format and content of the response is specified (under 7.1 Key Authorizations).

Thanks for answer. I was able to make it work using DNS validation.
Honestly, I still do not understand how this method work, but is not important, the DNS solution makes so much more sense to me.

Now I have another similar issue.
It seem I have to use --csr command in order to have certbot verify a certificate I self signed.
I’m following this: Using certbot with --csr

This is what I get:

$ certbot certonly --csr unifi_certificate.csr.pem --staging --standalone
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Performing the following challenges:
tls-sni-01 challenge for portal.cotech.co
Waiting for verification...
Cleaning up challenges
An unexpected error occurred:
The request message was malformed :: Error parsing certificate request: asn1: syntax error: sequence truncated
Please see the logfiles in /var/log/letsencrypt for more details.

Again, I face a similar issue: what is my server at portal.cotech.co supposed to answer and where?

This error indicates that the CSR itself is malformed. This could be due to anything from using the wrong format (should be DER or PEM) to a bug in the software used to generate the CSR.

Can you successfully read the CSR using OpenSSL? For example, using this command:

openssl req -in unifi_certificate.csr.pem -noout -text

If you can’t find anything, feel free to post the CSR here - someone in the community might find a non-obvious issue that causes the CA server to trip over it.

As a side note, the challenge mechanism in dns-01 works quite similar to the HTTP challenge. The only difference is that instead of the key authorization itself, the response (i.e. the content of the TXT record) should be the hash of the key authorization.

Certificate Request:
Data:
Version: 0 (0x0)
Subject: C=UK, ST=London, L=Teddingdon, O=Pipelean, OU=unifi.cotech.co, CN=unifi.cotech.co
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:9c:68:e4:e1:c3:da:57:84:ae:ed:d8:b9:5a:65:
56:b2:30:71:88:a1:34:5e:94:7e:71:2c:ad:d4:a5:
36:24:ca:07:1d:3c:67:96:d0:29:23:55:1b:17:b2:
bc:32:9b:92:d6:68:ec:4d:cc:1d:fc:88:a1:e0:f9:
ce:7d:57:51:a8:af:63:f9:f1:cd:53:72:37:d8:b0:
98:d3:93:07:0f:a3:2c:93:6f:4c:ef:2b:f1:bb:19:
10:21:1b:66:e6:5e:a8:ec:f1:bc:9b:ac:6d:af:15:
5a:03:66:18:b3:7d:b5:58:eb:1f:14:34:82:dc:f8:
b4:6a:52:aa:c5:bb:da:86:f7:1c:72:7c:05:ae:89:
4a:5a:82:c6:b1:9a:7e:8c:1e:cc:ea:62:39:dd:73:
cc:2c:4a:ea:a3:e5:5d:e0:df:6a:99:2a:59:9b:b1:
a0:02:a6:3c:e2:54:73:1a:a6:0e:d4:59:5e:a7:ef:
ee:9e:4d:21:f3:16:8c:d9:6c:39:b9:07:f4:17:58:
32:9d:30:be:6f:fe:37:9b:59:fe:70:eb:27:7a:e6:
4c:99:e7:f8:82:71:76:94:0d:59:f2:75:62:83:d4:
5f:47:c7:36:0a:5b:8d:0d:42:a7:50:3d:01:30:dd:
08:5a:7c:f5:72:96:05:c4:66:b6:de:e1:79:60:3a:
10:cb
Exponent: 65537 (0x10001)
Attributes:
Signature Algorithm: sha256WithRSAEncryption
91:a4:b5:03:c9:c5:f1:f8:2a:7d:7c:d2:9c:b5:48:c5:f9:2b:
2f:d8:25:43:94:6e:bb:11:cb:66:c9:f8:2f:8c:8e:6f:43:ca:
1d:fc:09:7c:5a:34:2c:b4:94:78:b2:0f:1c:9c:96:d4:ca:95:
45:b8:d4:25:91:ef:ab:cf:d4:dd:8b:da:43:d5:e2:ba:a2:77:
fd:70:55:44:62:ad:21:12:ad:e7:a6:f5:14:5e:5b:62:91:68:
1c:b5:1a:6c:0e:98:21:ad:06:0c:2f:c4:97:e7:fa:c1:88:e5:
0a:bd:a1:70:3f:e4:62:88:7a:a1:2b:ea:96:14:c1:b8:c6:40:
4b:5a:74:ba:70:11:94:7f:03:35:5f:69:71:56:63:3f:35:62:
ec:3a:fd:76:b4:8c:15:68:2e:6b:73:dc:e0:33:68:5f:a1:18:
bc:e6:23:13:43:db:fa:b0:b5:e5:55:92:e4:70:e3:7a:14:77:
a2:6b:c7:0d:60:d6:d6:db:54:4d:f1:70:e0:67:b1:c1:83:f1:
db:5d:3c:b7:b5:88:c1:70:90:89:50:f8:cf:d1:b4:6c:4a:ac:
3c:ed:50:91:78:72:93:7e:18:47:4a:52:57:cd:49:10:aa:a0:
28:26:ce:31:03:f8:94:ed:17:da:42:bd:6c:ea:1a:90:21:04:
c0:93:26:68

thanks @pfg
I do not understand, I do not have to do any action on unifi.cotech.co? What call is certbot doing against the domain?

With the --standalone option, certbot handles the challenge verification for you. In your particular case, it spawns a web server on port 443 and responds with a special certificate that demonstrates domain ownership. Note that this option will not continue to work if you ever start running your own web server on port 443 - in that scenario, you would have to either stop your web server for renewal (so that certbot can listen on the port), or use one of the other methods (webroot, etc.) that work with existing, running web servers.

Regarding the CSR you posted, is that the output of the OpenSSL command I posted, or is that the actual file? If it’s the latter: That’s not a PEM or DER file. Otherwise, would you mind posting the file itself?

ok, one thing at a time :slight_smile:

  1. I’m running certbot from a virtual machine that is indeed the one running the server that answer to unifi.cotech.co. After your description, I understand is mandatory to run certbot from the machine linked to the domain I am trying to verify, right?
  2. on that machine, the server is a java webapp, that do NOT use port 443 for HTTPS (java convention is 8443) so I do not need to turn it off
  3. I posted the output of the openssl command against the .pem.
  4. this is the output of cat against the .pem

-----BEGIN CERTIFICATE REQUEST-----
MIICvTCCAaUCAQAwejELMAkGA1UEBhMCR0IxDzANBgNVBAgTBkxvbmRvbjETMBEGA1UEBxMKVGVk
ZGluZ3RvbjERMA8GA1UEChMIUGlwZWxlYW4xGDAWBgNVBAsTD3VuaWZpLmNvdGVjaC5jbzEYMBYG
A1UEAxMPdW5pZmkuY290ZWNoLmNvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnqKT
9cJHa3FIgHlx/MM9sjO0MSZtdPKmw38/+ewPRg8urIeyZL3p5RpqezGiLoD9XwnrUdFUlfwG+9n8
pup2LJcQiKVdfVJi3vKBk32X3LzFsw5zBG9ryo5kqr64GH3HY6kPZwcLca7D3JWLPwn/wvs7kshO
SF5CT+HR0ZhdNVtwz/5FnBNEQ2KYeEXYvBppDvMVAQCh/TpgELZSi5nIpYCDzWrMRIYNnwO+toq5
/ON/s+cYaH+u/sOWOTCtRqHCpP8QUyL7R+e4VW6GXZn4FBqo2Dz6R8Qq6IYkLXIE5nTiUvK+5IQP
BPMgqFSclEfMltJC5Srs70+AykVTOBbOTQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAVV7xguo7L
B3NcgC0JZmTfCXYokkr7xOpJKDCg/DO7+APxXGj+PeLR+fqnBA4frmhCTah33PZ7jsPWAFX/dMEk
hXT+h3mRmgb16bjna2AvKa35F4MwS4ARFH+K7pp9J+JjVxsqQa7wxdFzVVKsxT0uZY+S6WuQ5EoA
FVSDlDkjme+vnMl6VLYvcLW7OUHezMR7gLOhIp1MeP6jMwxlqOKnXoxAQ5KkETVj4qgjCwdcbJDu
VYvBPhICEkIc3Mm5C15UTrm+A0AwyAwdNEeCyTs0sHoOxhPPmjee9GJmB8ehoXK8aHJ0++/+hQhw
IiI4D+2pWCAEFyyyMOKhdPHVEUbv
-----END CERTIFICATE REQUEST-----

Why do you want to reuse a CSR? Why not let Certbot generate a new private key and CSR?

because that’s the only supported way for unifi controller software: https://help.ubnt.com/hc/en-us/articles/212500127-UniFi-SSL-certificate-error-upon-opening-controller-page
Support also say is the only method. Maybe they’re wrong,…

That's correct, at least in standalone mode.

Correct, if you don't use port 443, you can continue to use standalone.

I was able to verify that Go's x509 library (which is what the CA server uses) chokes on this particular CSR: Go Playground - The Go Programming Language

I had a bit of a déjà vu while doing this and eventually found this thread, where someone else was experiencing the same problem with a CSR generated by unifi:

Unfortunately, it doesn't look like a solution was posted. There's either an issue in unifi that produces invalid CSRs, or Go's ASN.1 parser has a bug. I tried to find the problem using various ASN.1 parsers, but couldn't find anything. Perhaps someone with more of an understanding of ASN.1 will find the problem.

@allrik: Did you ever find a solution for this? Thanks!

FWIW, the UniFi CSR bug doesn’t just affect Go; other software rejects it too.

This thread describes how to import a certificate already created without a CSR (such as those generated by certbot) into the UniFi Controller:

You can either use the Java keytool command or the GUI Keystore Explorer program.

[You can also just use PKCS12 files directly as long as you set the password the same, but for some reason most people find the Java keystore gymnastics to be easier, why idk.]

3 Likes

I was in the middle of doing that. I did generate PKCS12 file like this:

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out pkcs.p12 -name {name} -passout pass:{pass}

Now I have 2 options: 1) import the keystore using keytool or 2) use PKCS12 directly.

For this option #2, @Patches you have some advice? I would love to avoid the Java keystore gymnastic :slight_smile:

Option #1 [BIG EDIT]
I tried to to everything using the same password when generating the PKCS12 fle and when importing. It seem to be the solution also this guy got and works for him

keytool -importkeystore -deststorepass {keystorepass} -destkeypass {keystorepass} -destkeystore /path/to/my/keystore -srckeystore /etc/letsencrypt/live/mydomain.com/pkcs.p12 -srcstoretype PKCS12 -srcstorepass {keystorepass} -alias unifi

Now {keystorepass} and the {pass} in the first command are the same.

That works, no error and unifi restart with no error (before it did remove and regenerate the “broken” keystore.

keytool -list -v -keystore keystore

This is the beginning of the output:

   Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: unifi
Creation date: Oct 16, 2017
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: CN=unifi.cotech.co
Issuer: CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US

See it at https://unifi.cotech.co:8080/
It is stuck on TSL handshake…

Now I am really out of options :\

ok, magic, now works. Maybe I should have just wait for insane unifi webapp startup time…

Of course, this does not seem to fix the Security Exception message people see when accessing the https://portal.cotech.co/

This is another story for another thread. Thanks everybody that helped.

You got it working with JKS, but for the record, all you have to do is replace the JKS file with a PKCS#12 file, and change type="JKS" to type="PKCS12" in your server.xml file if it is explicitly defined. (IIRC the server.xml shipped with the UniFi Controller doesn't require this; I just dropped a PKCS12 file in place of the original JKS store with my LE certificate, chain, and key, encrypted with the password "aircontrolenterprise" and everything Just Worked.)

Looks like you've managed to fix this too. :grinning:

Is not fixed when you are redirected there by the Access point, and that page act as the Captive Portal of a protected network.
Now I know why. The issue is not in the certificate of portal.cotech.co (which was working perfectly since the beginning) or the certificate of the machine where the network controller software workds (the one I imported in the keystore). Both are irrelevant. The issue is that the portal is running on heroku and the Captive Portal pre-authorization whitre-list does NOT work with domain (As stated in webapp and doc) but must also have IPs.
The worst is that heroku have dynamic IPs so in the end the solution will be install the portal webapp on Digital Ocean.

In the end, all this tour on SSL and certbot has been “useless” for the sake of the project, but at least now I a little more knowledgable with SSL :slight_smile:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.