NGINX + SSL certificate securing the connection in some browsers only

httpsnginxreverse-proxysslssl-certificate

I've been strugling with this issue and I seem to be running into a dead end here without knowing what to do next…

I've taken a task left by another worker who left on vacation. He was trying to setup SSL certificates for two diferent websites www.laenergiadelcambio.com and www.theenergyofchange.com. These are thawte certificates for a single domain. Note: we are making these changes in a test enviroment, so the changes to the NGINX URL's vHosts files are not public yet.

The HTTPS conection is made by a NGINX server which after securing the connection, makes a proxy_pass to an Apache machine which serves the website content.

First, he ran into the problem of always receiving the same certificate (laenergiadelcambio.com) for both websites. And after some reading we found that it was because of our OS (Centos 5.5) lacking TLS SNI support (Server Name Indication) due to an old version of openssl (0.9.8e).
We decided to assign a unique IP for listening in each server block as told in the NGINX Documentation.

And here's the things. It works, BUT not in all browsers and versions.

For the following tested browsers:

Opera 31.0.1889.174
Firefox 40.0
Firefox 38.0
Google Chrome 44.0.2403.157
Internet Explorer 11.0.9600.17691
Internet Explorer 9.0.8112.16421

Each one recognizes the certificate and stablishes a secure connection. All fine and no problems.

But for the following ones,

Firefox 39.0.3
Firefox 40.0.3
lynx 2.8.5

I got certificate not trusted errors.

Firefox complains about this: (Error code: sec_error_unknown_issuer)

And I attach the details for the certificate..

Certificate couldn't be verified because of unkown issuer

lynx throws me this…

lynx www.theenergyofchange.com/wp-admin

Making HTTPS connection to www.theenergyofchange.com
Retrying connection without TLS.
Looking up www.theenergyofchange.com
Making HTTPS connection to www.theenergyofchange.com
Secure 256-bit TLSv1/SSLv3 (DHE-RSA-AES256-SHA) HTTP connection
Sending HTTP request.
HTTP request sent; waiting for response.

SSL error:unable to get local issuer certificate-Continue? (y)
SSL error:host(www.theenergyofchange.com)!=cert(theenergyofchange.com)-    Continue? (y) 

Alert!: Unexpected network read error; connection aborted.
Can't Access `https://www.theenergyofchange.com/wp-admin'
Alert!: Unable to access document.

Next, I post two nginx vHosts configuration only for one site www.theenergyofchange.com , the HTTP and HTTPS. The other site is identical except for the server_names

072-blogs_391_ing.conf

    server {
    server_name theenergyofchange.com theenergyofchange.es theenergyofchange.info theenergyofchange.eu www.theenergyofchange.es www.theene
rgyofchange.info www.theenergyofchange.eu;
    rewrite ^ $scheme://www.theenergyofchange.com$request_uri permanent;
}

server {

    listen  80;
    server_name theenergyofchange.com theenergyofchange.es www.theenergyofchange.com pre.theenergyofchange.abg.corp www.theenergyofchange.
es www.theenergyofchange.com www.theenergyofchange.info www.theenergyofchange.eu;

    access_log  /var/log/nginx/blog_391ing.access.log;
    error_log   /var/log/nginx/blog_391ing.error.log error;

    error_page   404 403          /handle404.html;
    # error_page   502 503 504  /handle503.html;
    error_page   500 502 503 504      /handle500.html;

    location = /handle404.html {
         root html/errores-prxy;
    }

    location = /handle503.html {
         root html/errores-prxy;
    }

    location = /handle500.html {
         root html/errores-prxy;
    }

    location = / {
        proxy_pass http://wordpressprepro391.simosa.inet/;
    }

    location  / {
        proxy_pass http://wordpressprepro391.simosa.inet/;
    }


    location ~* /colab/web/system/modules/general/pages/captcha.jsp {
         proxy_pass http://wordpressprepro391.simosa.inet;
    }

    location ~* /colab/web/system/modules/general/resources/js/ {
         proxy_pass http://wordpressprepro391.simosa.inet;
    }

    location ~* /colab/ {
        proxy_pass http://wordpressprepro391.simosa.inet;
    }

    # Redirect wp-admin and wp-login requests to HTTPS.
    location ~ /wp-(?:admin|login|content|includes) {
    return 301 https://$host$request_uri;
    }
}

073-blogs_ing_392-ssl.conf

server {
    listen 80;
    rewrite ^(.*) https://$host$1 permanent;
}


server {
    listen 192.168.14.141:443 ssl;
    server_name www.theenergyofchange.com;

    access_log  /var/log/nginx/blog_392-ING-PRUEBA-SSL.access.log;
    error_log   /var/log/nginx/blog_392-ING-PRUEBA-SSL.error.log error;

    error_page   404 403          /handle404.html;
    # error_page   502 503 504  /handle503.html;
    error_page   500 502 503 504      /handle500.html;

    ssl on;
    ssl_certificate     /etc/nginx/openssl/CA/certs/ssl_certificate_ing.crt;
    ssl_certificate_key /etc/nginx/openssl/CA/private/theenergyofchange.com.key;
    ssl_client_certificate /etc/nginx/openssl/CA/certs/Intermediate_CA.crt;

    location = /handle404.html {
         root html/errores-prxy;
    }

    location = /handle503.html {
         root html/errores-prxy;
    }

    location = /handle500.html {
         root html/errores-prxy;
    }

    location = / {
        proxy_pass http://wordpressprepro391.simosa.inet/;
    }

    location  / {
        proxy_pass http://wordpressprepro391.simosa.inet/;
    }

    proxy_read_timeout       3500;
        proxy_connect_timeout    3250;

        proxy_set_header   X-Real-IP          $remote_addr;
        proxy_set_header   Host               $host;
        proxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto  https;


        proxy_set_header   SSL_PROTOCOL $ssl_protocol;
        proxy_set_header   SSL_CLIENT_CERT $ssl_client_cert;
        proxy_set_header   SSL_CLIENT_VERIFY $ssl_client_verify;
        proxy_set_header   SSL_SERVER_S_DN $ssl_client_s_dn;
}

So.. what am I missing here that makes some browsers secure the connection and others not trust the certificate issuer?

Many.. MANY thanks in advance!!

Best Answer

I suspect that your colleague misunderstood the ssl related directives: the file pointed to by ssl_certificate should contain your server's certificate followed by intermediate certificates, and ssl_client_certificate is only needed for client cert verification and OCSP - I think he copied the intermediate(s) into that file. Now, a browser that already has the proper intermediate certificates in cache will allow the page whereas browsers that don't have them yet will fail as they cannot construct the chain of trust.

Try putting the ssl_client_certificate line in comment and copy the intermediate cert into the ssl_certificate_ing.crt file if it's not there yet, and do so after your server's certificate.

So, ssl_certificate_ing.crt should look like this:

----- BEGIN CERTIFICATE -----
.. your server's certificate
----- END CERTIFICATE -----
----- BEGIN CERTIFICATE -----
.. first intermediate certificate    
----- END CERTIFICATE -----

Also, see the documentation.

Nice tool to check a certificate's content online: https://www.sslshopper.com/certificate-decoder.html