Issue Description
Connecting using TLS fails, ACME appears to be working fine.
Expected Behavior
Should be able to send and receive mail via TLS ports.
Actual Behavior
40E7EF2F2A7F0000:error:0A00007B:SSL routines:tls_process_cert_verify:bad signature:../ssl/statem/statem_lib.c:545:
Reproduction Steps
Reload and restarting produces the same results.
Stalwart Version
v0.15.x
Installation Method
Built from source
Database Backend
FoundationDB
Blob Storage
FoundationDB
Search Engine
Internal
Directory Backend
Internal
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
on
The OpenSSL error tls_process_cert_verify:bad signature means the public certificate and private key stored on the server do not match – the server is presenting a certificate signed by one key while holding a different private key. ACME appearing to work does not rule this out; it only means the challenge/renewal process completed, but the stored certificate and key pair could have become mismatched (e.g., a new key was generated on renewal but the old certificate – or vice versa – is what got persisted).
Here are the most likely causes and what to check:
-
Certificate/key mismatch after ACME renewal. If ACME renewed the cert but the stored private key in the database is stale (or a different key was stored), the pair will not match. In the WebUI go to Settings › TLS › Certificates and inspect the certificate object. You can verify the match yourself by extracting the public key from both the cert and the private key and comparing them:
openssl x509 -noout -pubkey -in cert.pem | openssl md5
openssl pkey -pubout -in key.pem | openssl md5
Both hashes must be identical.
-
Manually re-upload a matched pair. If you have a working cert/key pair on disk (from the ACME client’s working directory), you can update the Certificate object via the CLI:
stalwart-cli update Certificate <id> \
--field 'certificate={"@type":"Text","value":"<PEM>"}' \
--field 'privateKey={"@type":"Text","secret":"<PEM>"}'
Or do it through the WebUI under Settings › TLS › Certificates.
-
FoundationDB storage issue. Because you are using FoundationDB for blob storage, it is worth checking whether the stored certificate blobs are intact and consistent – a partial write during an ACME renewal could have left a mismatched state.
Note: since this is v0.15.x, the configuration format and management tooling are different from the current release. The above guidance on certificate objects and the CLI applies to the current version; in v0.15 you would manage certificates via the TOML config or the older WebUI. A human contributor familiar with v0.15 will be better placed to advise on the exact recovery path for that version.
Reference: Certificate object docs | TLS/ACME overview
This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong. If you found it useful, mention @helpbot in any reply to ask follow-up questions and the bot will respond again.
“Bad signature” at this point in the handshake means the client cannot verify the leaf against the chain Stalwart sent: either the chain is incomplete (missing intermediate), or the leaf’s signature was made with a private key that doesn’t match the public key being presented (which is what happens when the cert object and the key get out of sync, usually after a half-completed ACME renewal). v0.15.3 is also a few versions back; the cert-loader has been tightened since.
Two things to check:
-
Verify the chain you are actually sending: openssl s_client -starttls smtp -connect <host>:25 -showcerts < /dev/null and look for at least two certificates (leaf + intermediate) and that the leaf’s Issuer matches the intermediate’s Subject. If only the leaf comes back, the chain file in your storage doesn’t include the intermediate.
-
Confirm key/cert are paired: openssl x509 -in leaf.pem -noout -modulus | openssl md5 and openssl rsa -in key.pem -noout -modulus | openssl md5 should print the same hash. If they don’t, ACME rolled the key and the certificate object in the store didn’t get updated.
Ok, the issue seems to be down to this error:
| WARN |
Multiple TLS certificates available |
total = 36 |
| How do I go about flushing the backlog of certificates? |
Stalwart will now automatically update the default certificate id after renewals. That warning you’re seeing is when the client does not provide a hostname during the TLS handshake so Stalwart does not know which certificate to use. This warning can be safely ignored but you might suppress it by setting a default certificate.