fhessel / esp32_https_server

Alternative ESP32 Webserver implementation for the ESP32 Arduino Core, supporting HTTPS and HTTP.
MIT License
334 stars 125 forks source link

Can't get Let's Encrypt certificates to work #88

Closed kaiomatico closed 4 years ago

kaiomatico commented 4 years ago

Describe Your Goal I want to convert my valid let's encrypt certificate to the correct DER format to use it on the HTTPS Async example

What Does Your Project Look Like The example HTTPS Async sketch with only the cert.h and private_key.h replaced. I got the following files from Let's Encrypt:

I have tried the following commands with varying level of success to generate the example.crt.DER which then gets converted to cert.h with xxd:

I test using curl -v which always fails at :

And using the chrome exported certificate from the root level it fails at:

So how do I convert let's encrypt certificated properly? The example.key.DER was produced using the following command: openssl rsa -in privkey.pem -outform DER -out example.key.DER

ESP32 Module ESP32 Dev Module breakout board, no RAM addon or anything fancy

Software (please complete the following information if applicable)

fhessel commented 4 years ago

Sorry for the late reply. If I remember correctly, using the full chain will not work, only the last certificate that is the one you want to use with the server, and for which you have the matching private key.

So this should be the correct syntax if you have a cert.pem file:

# check the certificate, only a single certificate should be shown (not a chain):
openssl x509 -inform pem -in cert.pem -text
# Convert the certificate
openssl x509 -in cert.pem -outform DER -out cert.der
# Check the converted certificate (output should be the same as for the first command)
openssl x509 -inform der -in cert.der -text

For the private key (in .pem format) to the following. Make sure you actually have an RSA key. EC won't work with the server.

openssl rsa -in cert.key -outform der -out cert.key.der

As a last step, you can verify that your private key and certificate in the DER files do match:

# Get modulus of the key
openssl rsa -modulus -noout -in cert.key.der -inform der | openssl sha256
# Get modulus of the cert
openssl x509 -modulus -noout -in cert.der -inform der | openssl sha256

If both commands show the same output, the files should be okay and that should not be the problem.

What might be an issue though is if the intermediate CA used by Let's Encrypt isn't known to your browser (or curl, respectively). In that case, you would have a working certificate presented by the ESP32, but the client isn't able to verify it. These lines from your test with curl look like that could indeed be the problem:

TLSv1.2 (OUT), TLS alert, unknown CA (560):
SSL certificate problem: unable to get local issuer certificate

Does curl --insecure [...] solve the problem? In that case, curl would ignore being not able to validate the certificate, but at least we would see that the certificate as such was deployed correctly. In that case, I'd convert this issue into a feature request to support certificate chains delivered by the server.

kaiomatico commented 4 years ago

Thank you for the answer, I will test it on the weekend :-)

kaiomatico commented 4 years ago

Ok I finally got around to test it today with the commands you gave me. Sadly curl still shows the same error message. When using curl with --insecure it works.

* TCP_NODELAY set
* Connected to [Censored my DNS Name] port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=[Censored my DNS Name]
*  start date: Jun 20 16:17:11 2020 GMT
*  expire date: Sep 18 16:17:11 2020 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET / HTTP/1.1

So thank you very much for your effort :) Sad that this is probably nothing we / you could fix. So I am closing this issue now, have a nice weekend and thank you for the awesome project!

fhessel commented 4 years ago

Thanks for checking that! If curl --insecure works but says SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway., that indeed sounds like a problem with the certificate chain, not the certificate itself. I created #93 to track work on that.