From wireshark trace the tls handshake initiated by letsencrypt to retrieve the challenge response certificate runs through and serves the certificate.
The certificate looks fine. What you are missing is the negotiation of the acme-tls/1. ALPN
Let's Encrypt connects to your TLS server and requests the protocol in an ALPN extension. Your TLS server needs to respond during the handshake with the same ALPN. That way, both peers agree that they are "speaking acme-tls/1".
...
The ACME server initiates a TLS connection to the chosen IP
address. This connection MUST use TCP port 443. The ACME server
MUST provide an ALPN extension with the single protocol name
"acme-tls/1" and an SNI extension containing only the domain name
being validated during the TLS handshake.
The ACME server verifies that during the TLS handshake the
application-layer protocol "acme-tls/1" was successfully
negotiated (and that the ALPN extension contained only the value
"acme-tls/1") and that the certificate returned contains:
...
How to do this varies by what server you are using to terminate TLS. It will require a different kind of configuration in nginx, haproxy, netty etc.
Thank you for your help.
Yes, I followed https://shredzone.org/maven/acme4j/challenge/tls-alpn-01.html when implementing the process that initiates the challenge procedure.
Yes, there is an nginx running on the tls-server. It redirects http to https. It does not terminate TLS but streams to two java based processes in the background, one serving the challenge requests, one serving normal traffic.
If you see an option to get rid off the java based challenge reply process and to move it to nginx it would be great. However, it is no option for me (requirement by my customer) to replace the java process by a python process or the like.
nginx can process the validation requests via http.
[and redirect all else to https]
Here is sample nginx code:
location ^/(?!\.well-known) { # skip challenge requests
return 301 https://$host$request_uri; # send all requests to HTTPS
}# location
All you need is a root statement for the challenge requests to base their path.
Then you can use almost any Linux ACME client quite easily.
Like: certbot certonly --webroot -w /root/path/from/nginx/config -d example.com -d www.example.com
The final production environment of my customer (not enpasos.com) is only accessible via port 443 from the internet - not even nginx can be reached by port 80.
OK I understand now better your situation.
I think you might be able to get the nginx to work with TLS-ALPN faster then the Java.
If so, you could use the nginx as a TLS reverse proxy to the Java [which could be http or https].
If I could understand, what the remaining problem with my response to the challenge request is, I think I could simply change the behaviour of the responding java process.
Thinking out loud - does your TLS server implementation allow for multiple clients to fetch the TLS-ALPN certificate? Or will it stop working after a single client has requested it?
I noticed in your screenshot that there's one ALPN handshake that succeeds, but then there's 3 more ClientHello messages from other IPs which do not appear to have responses.
Is it possible you're only allowing a single client to fetch the ALPN certificate and then you delete it?
Here is sample nginx alpn code:
[simply add to the main nginx.conf]
stream {
map $ssl_preread_alpn_protocols $tls_port { # define tls_ports
~\bacme-tls/1\b 5443; # when alpn
default 443; # otherwise
}#map
server {
listen localhost:6443; # this is where the firewall/router nats inbound port 443
proxy_pass localhost:$tls_port; # this local system proxies to itself on the defined tls_port
ssl_preread on; #####
}#server
}#stream
# Notes:
# initial connections come in on 6443
# all the alpn connections go to 5443
# all other tls connections go to 443
Then using acme.sh as follows: /root/.acme.sh/acme.sh --issue -d do.main,www.do.main --alpn --tlsport 5443