Certificate mismatch

My server is serving the wrong certificate for a domain.

content.poppyandbuddy.com is returning the cert for solitaireknights.com. None of the other hosts for poppyandbuddy.com are doing this, just the content.poppyandbuddy.com subdomain.

Here's a config-dump:

poppyandbuddy config:

ssl_certificate /etc/letsencrypt/live/qr.poppyandbuddy.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/qr.poppyandbuddy.com/privkey.pem;

# Audio player websites
server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name qr.poppyandbuddy.com;
        return 301 https://listen.poppyandbuddy.com$request_uri;
}

server {
        listen 80;
        listen [::]:80;
        server_name qr.poppyandbuddy.com listen.poppyandbuddy.com;
        return 301 https://listen.poppyandbuddy.com$request_uri;
}

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name listen.poppyandbuddy.com;
        root /srv/production/poppyandbuddy_qr/public;
        include conf.d/global/php_args.conf;
}

# App content website
server {
        listen 80;
        listen [::]:80;
        server_name content.poppyandbuddy.com;
        return 301 https://content.poppyandbuddy.com$request_uri;
}

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name content.poppyandbuddy.com;
        root /srv/production/poppyandbuddy_content/public;
}

(I've cut a few out that aren't relevant)

Solitaireknights.com config:

ssl_certificate /etc/letsencrypt/live/solitaireknights.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/solitaireknights.com/privkey.pem;

server {
    listen 80;
    listen [::]:80;
    server_name solitaireknights.com www.solitaireknights.com;
    return 301 https://www.solitaireknights.com$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name solitaireknights.com www.solitaireknights.com;
    root /srv/production/solitaireknights;
    index index.html;
}

certbot certificates

Found the following certs:
  Certificate Name: qr.poppyandbuddy.com
    Serial Number: 313f6e21c46e763e88a1072ee8ae679cb99
    Key Type: ECDSA
    Domains: qr.poppyandbuddy.com analytics.poppyandbuddy.com content.poppyandbuddy.com legal.poppyandbuddy.com listen.poppyandbuddy.com trustandsafety.poppyandbuddy.com
    Expiry Date: 2024-09-01 04:52:50+00:00 (VALID: 23 days)
    Certificate Path: /etc/letsencrypt/live/qr.poppyandbuddy.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/qr.poppyandbuddy.com/privkey.pem
  Certificate Name: solitaireknights.com
    Serial Number: 369617e4f7e7e40b94f9a532767c83a6626
    Key Type: ECDSA
    Domains: solitaireknights.com www.solitaireknights.com
    Expiry Date: 2024-11-03 06:00:26+00:00 (VALID: 86 days)
    Certificate Path: /etc/letsencrypt/live/solitaireknights.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/solitaireknights.com/privkey.pem

openssl s_client -showcerts -servername content.poppyandbuddy.com -connect content.poppyandbuddy.com:443 < /dev/null

CONNECTED(00000003)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = E5
verify return:1
depth=0 CN = solitaireknights.com
verify return:1

I've now fixed it by merging all of my certificates into a single cert. Not the biggest fan of this though.

Would still be curious why nginx was failing to serve the correct certificate.

It's kinda weird that it works at all: ssl_certificate* directives should be a part of server blocks.

4 Likes

The server{} block is just scoping. Anything outside of it is in-scope for the block, anything in the block is only in-scope in the block.

I did not deeply study your setup but my guess is that there is only one global HTTP level certificate in effect. This could explain why you weren't getting this cert you expected.

What I mean is I think the entire http level is scanned and just the latest certificate found at that level is retained. Then the server level inherits that latest one, or more commonly the server level sets its own. I am not sure of this but I have seen odd behavior with some versions of nginx in the way it inherits certificate specs from prior server blocks even.

The safest way is to specify the certificate inside the server block. That will be easy then to have a certificate for just the names handled by that server block.

4 Likes

But you probably can only do that once:

Those are both (equally) outside the server{} scope(s).

3 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.