You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Ejabberd is not able to serve the appropriate cert #4102
certfiles:
- abc.com # given by godaddy
- xyz.com # given by lets encrypt for *.xyz.com
Bug description
Ejabberd is not able to serve the appropriate cert if multiple certs. If I am making a request to ejabberd with r0.xyz.com as the SNI, then it serves cert given toabc.com
May be it's related to this issue, so - i have the same problem. Debian (10-12), ejabberd (few versions from Debian repo, latest - 24.02 - official deb; so - at least all 2* is affected); 3 domains (JW is the first domain in hosts). Nothing in logs; usually it's happened after certificates update (permissions are ok) - just after ejabberdctl reload_config SOMETIMES sending wrong certificate for SOME domain and SOME port. Usually i can fix it with one more reload_config.
Just for example (same certs, nothing changed in config file, just launched ejabberdctl reload_config ~10 times):
C2S TLS OK:
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5223 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = linuxoid.in
jabber.name: subject=CN = jabber.name
S2S TLS WRONG:
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5270 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = jabberworld.info
jabber.name: subject=CN = jabberworld.info
First reload_config - same result:
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5223 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = linuxoid.in
jabber.name: subject=CN = jabber.name
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5270 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = jabberworld.info
jabber.name: subject=CN = jabberworld.info
Second - now all ok:
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5223 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = linuxoid.in
jabber.name: subject=CN = jabber.name
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5270 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = linuxoid.in
jabber.name: subject=CN = jabber.name
3-10 reload_config - all ok.
Ok, let's change something. Added a space to /etc/ejabberd/certs/jabber.name.fullchain.pem in between lines:
ls -l /etc/ejabberd/certs/jabber.name.fullchain.pem
-rw-r----- 1 root ejabberd 5852 Mar 24 20:16 /etc/ejabberd/certs/jabber.name.fullchain.pem
Tried reload_config 7 times - all ok.
Ok, let's change something else. Added a "#" to config file (to already commented line at the beginning of file - so now it's just a '##').
1st reload_config - all ok (!)
2nd - got same problem again:
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5223 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = linuxoid.in
jabber.name: subject=CN = jabber.name
rain@walkbook:~$ for i in jabberworld.info linuxoid.in jabber.name ; do echo ${i}: $(openssl s_client -connect $i:5270 </dev/null 2>&1 | grep ^subject=CN) ; done
jabberworld.info: subject=CN = jabberworld.info
linuxoid.in: subject=CN = jabberworld.info
jabber.name: subject=CN = jabberworld.info
3..7 - all ok.
Removed that comment.
1st reload_config - got a problem.
2nd - ok
3rd - ok
...
Maybe having a clear cache ejabberdctl command would be handy ?
It could a hook that module could register to.
It could take a specific parameter to only clear the cache of a single module.
We already do that in reload_config, so probably no need to add separate command just for that (and we call that clear cache function from reload_config). Now the question is why there are sometimes stale results...
The problem being related to fast_tlss caching was just a blind guess of mine. I suggested that test to make sure nothing else is reloaded, just to track things down.
To facilitate the investigation and hopefully finding a solution (or at least an acceptable workaround), it would help to have a reproduction guide, even if it doesn't offer 100% reproducibility.
Following the explanations in the comments, I tried to reproduce the problem... but ejabberd always provides the proper certificate. This is how I setup the test environment, let's hope somebody points how to tweak it to reproduce the problem:
Reproduction steps
Download and install ejabberd 24.07. Run and Deb installers contain exactly the same files, so let's use the Run one which allows a regular user to manage ejabberd:
When asking a domain, if ejabberd offered a certificate with mismatched CN, it would return FAIL.
However, no matter how many times the script runs, it always returns OK. Any clue how to reproduce the problem?
I don't know, so far I wasn't able to reproduce it on a test system either, that's precisely my problem.
no matter how many times the script runs, it always returns OK.
How often did you try? E.g., one of my production servers accepted a few millions of connections since midnight today, and monitoring detected the issue 5 times since then. So it's certainly not trivial to reproduce. And I can't rule out that the issue is only triggered by some condition that is missing when brute-forcing an otherwise idle test system with connection attempts.
let's hope somebody points how to tweak it to reproduce the problem
Your test looks similar to my monitoring script (I'll include that below). My only suggestion would be to not reload ejabberd between your attempts, as reloading hides the problem. (The issue is most certainly related to fast_tls's certs_map, as clearing that fixes the issue.)
Just BTW, I hadn't looked at my script in quite a while and am now surprised that it only detects the problem if ejabberd incorrectly offers the certificate for the 'main' domain, rather than checking whether ejabberd actually offers the correct certificate. This server has a large number of virtual hosts, and from what I remember, the failure case has indeed always been that the certificate for the 'main' domain (the first domain in the hosts list) was offered. Rather than the certificate for another 'secondary' domain.
This server has a large number of virtual hosts, and from what I remember, the failure case has indeed always been that the certificate for the 'main' domain (the first domain in the hosts list) was offered.
Our monitoring detected the issue several times per day until August 18, 2025, and not once since then. On that day, we updated the server from commit 1a9b147 to ff3d33d. However, I haven’t spotted a change in ejabberd or fast_tls that looks related.
On that day, we updated the server from commit 1a9b147 to ff3d33d. However, I haven’t spotted a change in ejabberd or fast_tls that looks related.
Ah, looks like we hadn’t fully restarted ejabberd since June 2025, so we were running an older fast_tls.
I think I got it: The cache key in fast_tls doesn’t include whether a TLS context is used for an incoming or outgoing connection, but the SNI callback is only installed for the former. So if an outgoing s2s connection is the first to create a context (using the default domain's certificate), that context is then reused for incoming connections, and SNI is ignored until the next cache flush.
The changes for accepting s2s client certificates without the client purpose flag (processone/fast_tls@f1e55d6, 72bc9b6) hide the problem for s2s, as the new flag ends up in the cache key, so incoming and outgoing s2s connections no longer share contexts. It could still be triggered for c2s, though, if ciphers, protocol options, DH file, and CA file match the s2s settings.
Activity
licaon-kter commentedon Oct 17, 2023
ejabberd.log has any info?
You made sure ejabberd can access the cert files?
lokesh411 commentedon Oct 17, 2023
EOUpSL93Y commentedon Mar 24, 2024
May be it's related to this issue, so - i have the same problem. Debian (10-12), ejabberd (few versions from Debian repo, latest - 24.02 - official deb; so - at least all 2* is affected); 3 domains (JW is the first domain in hosts). Nothing in logs; usually it's happened after certificates update (permissions are ok) - just after ejabberdctl reload_config SOMETIMES sending wrong certificate for SOME domain and SOME port. Usually i can fix it with one more reload_config.
Just for example (same certs, nothing changed in config file, just launched ejabberdctl reload_config ~10 times):
C2S TLS OK:
S2S TLS WRONG:
Permissions are ok:
Tried reload_config 7 times - all ok.
1st reload_config - all ok (!)
2nd - got same problem again:
3..7 - all ok.
1st reload_config - got a problem.
2nd - ok
3rd - ok
...
licaon-kter commentedon Mar 24, 2024
@EOUpSL93Y are you the admin of
linuxoid.in?EOUpSL93Y commentedon Mar 24, 2024
Yes
weiss commentedon Aug 2, 2024
Next time you run into the issue, could you check whether running the following call in an
ejabberdctl debugshell fixes the issue:(Including the trailing
.. PressCtrl+gand thenqto exit the shell.)As an alternative, you could use a script such as the following (if
escriptis in the path, and assuming the node name isejabberd@localhost):mremond commentedon Aug 5, 2024
Maybe having a clear cache ejabberdctl command would be handy ?
It could a hook that module could register to.
It could take a specific parameter to only clear the cache of a single module.
@weiss Is this a good idea ?
prefiks commentedon Aug 5, 2024
We already do that in
reload_config, so probably no need to add separate command just for that (and we call that clear cache function fromreload_config). Now the question is why there are sometimes stale results...weiss commentedon Aug 6, 2024
The problem being related to
fast_tlss caching was just a blind guess of mine. I suggested that test to make sure nothing else is reloaded, just to track things down.EOUpSL93Y commentedon Aug 11, 2024
Got this problem again just after upgrade to 24.07, then tried
and it fixed the problem!
badlop commentedon May 2, 2025
To facilitate the investigation and hopefully finding a solution (or at least an acceptable workaround), it would help to have a reproduction guide, even if it doesn't offer 100% reproducibility.
Following the explanations in the comments, I tried to reproduce the problem... but ejabberd always provides the proper certificate. This is how I setup the test environment, let's hope somebody points how to tweak it to reproduce the problem:
Reproduction steps
Download and install ejabberd 24.07. Run and Deb installers contain exactly the same files, so let's use the Run one which allows a regular user to manage ejabberd:
Generate self-signed certs and copy them
Configure ejabberd in file $HOME/opt/ejabberd/conf/ejabberd.yml
Start ejabberd:
$HOME/opt/ejabberd-24.07/bin/ejabberdctl liveRun the tests:
When asking a domain, if ejabberd offered a certificate with mismatched CN, it would return FAIL.
However, no matter how many times the script runs, it always returns OK. Any clue how to reproduce the problem?
make-certs.sh
test.sh
weiss commentedon May 3, 2025
I don't know, so far I wasn't able to reproduce it on a test system either, that's precisely my problem.
How often did you try? E.g., one of my production servers accepted a few millions of connections since midnight today, and monitoring detected the issue 5 times since then. So it's certainly not trivial to reproduce. And I can't rule out that the issue is only triggered by some condition that is missing when brute-forcing an otherwise idle test system with connection attempts.
Your test looks similar to my monitoring script (I'll include that below). My only suggestion would be to not reload ejabberd between your attempts, as reloading hides the problem. (The issue is most certainly related to fast_tls's
certs_map, as clearing that fixes the issue.)Just BTW, I hadn't looked at my script in quite a while and am now surprised that it only detects the problem if ejabberd incorrectly offers the certificate for the 'main' domain, rather than checking whether ejabberd actually offers the correct certificate. This server has a large number of virtual hosts, and from what I remember, the failure case has indeed always been that the certificate for the 'main' domain (the first domain in the
hostslist) was offered. Rather than the certificate for another 'secondary' domain.poVoq commentedon May 3, 2025
This is indeed also what happens on my server.
weiss commentedon Oct 18, 2026
Is anyone still running into this?
Our monitoring detected the issue several times per day until August 18, 2025, and not once since then. On that day, we updated the server from commit 1a9b147 to ff3d33d. However, I haven’t spotted a change in ejabberd or fast_tls that looks related.
weiss commentedon Oct 18, 2026
Ah, looks like we hadn’t fully restarted ejabberd since June 2025, so we were running an older fast_tls.
I think I got it: The cache key in fast_tls doesn’t include whether a TLS context is used for an incoming or outgoing connection, but the SNI callback is only installed for the former. So if an outgoing s2s connection is the first to create a context (using the default domain's certificate), that context is then reused for incoming connections, and SNI is ignored until the next cache flush.
The changes for accepting s2s client certificates without the client purpose flag (processone/fast_tls@f1e55d6, 72bc9b6) hide the problem for s2s, as the new flag ends up in the cache key, so incoming and outgoing s2s connections no longer share contexts. It could still be triggered for c2s, though, if ciphers, protocol options, DH file, and CA file match the s2s settings.
processone/fast_tls#68 should fix this.