3cx voip / letsencrypt tls

3cx voip / letsencrypt tls

  • Written by
    Walter Doekes
  • Published on

Can you get your 3CX Phone System to connect to your SIP provider Trunk over TLS, when the server uses a Let’s Encrypt certificate?

3CX documentation on this topic is scarce. There are posts like 3CX Forum: SIP TLS:

It’s fairly straightforward: Your provider must give you a TLS Root Certificate (.pem) so you can encrypt the traffic. If they have SRV records the system will automatically know where to connect for TLS mode (Auto Discovery option on General trunk tab), or the provider might just tell you to change your port to the one they are listening to for TLS connections.

It can actually be that straightforward, if you do have the root certificate. But if you try to give the 3CX the certificate itself, or an intermediate — which is a perfectly fine thing to do in the TLS world — it will refuse without any useful info.

Step one: select TLS in the interface.

Step two: upload a root certificate.

\[3CX, transport protocol TLS, PEM fileupload\]

Okay, this is peculiar. Why doesn’t it just use the certificates from the OS? The SIP server uses a perfectly valid Let’s Encrypt certificate. Do I really need to upload anything here?

The server certificate we’re presented with is:

  • a valid and recent Let’s Encrypt certificate;
  • with the common name (CN) matching the FQDN;
  • with a DNS:FQDN subjectAltName (SAN);
  • available over TLSv1.2.

(It doesn’t use fancy new URI:sip:FQDN subject alternative names, but I haven’t come across any of those yet. And I doubt I can get those inserted into my Let’s Encrypt certificates.)

But, as the 3CX needs something uploaded to continue, let’s just upload the certificate itself. Surely that is even more secure than any root certificate…

$ openssl s_client -connect TRUNK:5061 -showcerts </dev/null
...
-----BEGIN CERTIFICATE-----
MIINllCT1NLTkpCRU5IM1NKTFBBRjVSRU9MVTRBTU1VVEVPUjQzSkpBICAtCgcCA
...
-----END CERTIFICATE-----

Put it in a cert.pem, and upload it. Right?

Wrong! The 3CX will refuse to connect with the following error, which has no bearing on the actual problem:

SIP Server / Call Manager ID: 12293
Registration at TRUNK has failed.
Destination (sip: sip.TRUNK.tld: 5061; transport = TLS; lr;
maddr = 1.2.3.4) is not reachable, DNS error resolving FQDN,
or service is not available.

Some tcpdump/wireshark sniffing helps us more:

3CX -> TRUNK.5061: TLSv1.2: Handshake Protocol: Client Hello (len 260)

TRUNK.5061: 3CX -> TLSv1.2: Handshake Protocol: Server Hello (len 58)
TRUNK.5061: 3CX -> TLSv1.2: Handshake Protocol: Certificate (len 2589)
TRUNK.5061: 3CX -> TLSv1.2: Handshake Protocol: Server Hello Done (len 4)

3CX -> TRUNK.5061: TLSv1.2: Alert (Level: Fatal, Description: Unknown CA) (len 2)

Okay, so:

  • there is traffic (no DNS error, and there is a service);
  • they both speak TLS, and the same version at that;
  • the 3CX speaks of an Unknown CA.

Okay. Let’s upload the intermediate certificate then. If we scroll up to the openssl s_client command above, we can find it in the second certificate block. Save it as intermediate.pem and upload it.

Also wrong! Same error, same TLS handshake failure.

Instead, the 3CX really really wants us to get the root certificate. It could be found like this:

$ openssl x509 -in intermediate.pem -noout -subject -hash -issuer -issuer_hash
subject=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
4f06f81d
issuer=O = Digital Signature Trust Co., CN = DST Root CA X3
2e5ac55d

$ ls -l /etc/ssl/certs/2e5ac55d*
lrwxrwxrwx 1 root root 18 mrt 12  2018 /etc/ssl/certs/2e5ac55d.0 -> DST_Root_CA_X3.pem

$ openssl x509 -in /etc/ssl/certs/DST_Root_CA_X3.pem -noout -subject -hash -issuer -issuer_hash
subject=O = Digital Signature Trust Co., CN = DST Root CA X3
2e5ac55d
issuer=O = Digital Signature Trust Co., CN = DST Root CA X3
2e5ac55d

Very well. After uploading DST_Root_CA_X3.pem, things started to work. Now, if only 3CX could work on their error reporting.


Back to overview Newer post: openssl / sign / subject alternative names Older post: recap2019