"The certificate for this server is invalid" error in IOS 12.0.1

Hi,

My domain is:
gempost.opensyscon.com.au

My web server is (include version):
Loopback API Server (v3)

The operating system my web server runs on is (include version):
CENTOS 7.0

My hosting provider, if applicable, is:
No hosting provider.

I can login to a root shell on my machine (yes or no, or I don’t know):
Yes

I’m using a control panel to manage my site (no, or provide the name and version of the control panel):
no

Details:

We have a Loopback API server running loopback version 3.0. We have recently implemented https on this server. We used letsencrypt to successfully generate the certificates for our server.We used privkey.pem and the fullchain.pem on the server as shown in the following code:

 var path = require('path'),fs = require("fs");
  exports.privateKey = fs.readFileSync('/etc/letsencrypt/live/gempost.opensyscon.com.au/privkey.pem').toString();
  exports.certificate = fs.readFileSync('/etc/letsencrypt/live/gempost.opensyscon.com.au/fullchain.pem').toString();

The API server is accessible over https without issues in our android app.But, accessing the API Server https://gempost.opensyscon.com.au from our IPhone app gives the following error:

“Failed to load resource: The certificate for this server is invalid. You might be connecting
to a server that is pretending to be “gempost.opensyscon.com.au” which could put your confidential information at risk.”

Our Iphone is running IOS 12.0.1

Any pointers as to where we are going wrong?

Your server doesn’t seem to be accessible over port 443 over the internet - only port 80. So checking it directly is currently not an option.

Can you run this from within your network and show the full output?

openssl s_client -connect gempost.opensyscon.com.au:443 -servername gempost.opensyscon.com.au  -showcerts
Hey,thanks for your quick reply.
Here is the output:
CONNECTED(00000003)
depth=0 C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain
verify error:num=18:self signed certificate
verify return:1
depth=0 C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain
verify error:num=10:certificate has expired
notAfter=Jun  8 07:32:14 2013 GMT
verify return:1
depth=0 C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain
notAfter=Jun  8 07:32:14 2013 GMT
verify return:1
---
Certificate chain
 0 s:C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain
   i:C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain
-----BEGIN CERTIFICATE-----
MIIEDjCCA3egAwIBAgICRnUwDQYJKoZIhvcNAQEFBQAwgbsxCzAJBgNVBAYTAi0t
MRIwEAYDVQQIEwlTb21lU3RhdGUxETAPBgNVBAcTCFNvbWVDaXR5MRkwFwYDVQQK
ExBTb21lT3JnYW5pemF0aW9uMR8wHQYDVQQLExZTb21lT3JnYW5pemF0aW9uYWxV
bml0MR4wHAYDVQQDExVsb2NhbGhvc3QubG9jYWxkb21haW4xKTAnBgkqhkiG9w0B
CQEWGnJvb3RAbG9jYWxob3N0LmxvY2FsZG9tYWluMB4XDTEyMDYwODA3MzIxNFoX
DTEzMDYwODA3MzIxNFowgbsxCzAJBgNVBAYTAi0tMRIwEAYDVQQIEwlTb21lU3Rh
dGUxETAPBgNVBAcTCFNvbWVDaXR5MRkwFwYDVQQKExBTb21lT3JnYW5pemF0aW9u
MR8wHQYDVQQLExZTb21lT3JnYW5pemF0aW9uYWxVbml0MR4wHAYDVQQDExVsb2Nh
bGhvc3QubG9jYWxkb21haW4xKTAnBgkqhkiG9w0BCQEWGnJvb3RAbG9jYWxob3N0
LmxvY2FsZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnSFnKw0Sa
C9qaq1affxp3M3jEAByfn8sPKsLalwiGnatY+hn+fO0yl10aqIjqCGlmq1umnrMR
1jMWCwqFPil94v+CBjdS+fMpPKKChysKMPisv/ExVeSspGIyRf9qrCazzF9ILp5d
LWHkxDYr1WwMrA8kUsVtAa36OKu0NVF8TwIDAQABo4IBHTCCARkwHQYDVR0OBBYE
FGUFQXptETA28hIclpQIwyGCKF01MIHpBgNVHSMEgeEwgd6AFGUFQXptETA28hIc
lpQIwyGCKF01oYHBpIG+MIG7MQswCQYDVQQGEwItLTESMBAGA1UECBMJU29tZVN0
YXRlMREwDwYDVQQHEwhTb21lQ2l0eTEZMBcGA1UEChMQU29tZU9yZ2FuaXphdGlv
bjEfMB0GA1UECxMWU29tZU9yZ2FuaXphdGlvbmFsVW5pdDEeMBwGA1UEAxMVbG9j
YWxob3N0LmxvY2FsZG9tYWluMSkwJwYJKoZIhvcNAQkBFhpyb290QGxvY2FsaG9z
dC5sb2NhbGRvbWFpboICRnUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB
gQB4nAr8uTOuvVPVz6HbX/6hrlSm3F85LwlwzvOpr0CL1/Zq7/zi11UC0fLJkrM7
v0nA8lbJWe5gGq6DhX0U+2AejTTaE51LE7NZtMthIT0q+gCZ6ab/7aoFqkZUAvYt
mw1+na2fELXQ+NDMN7JNN9e3cWj6/5Hf26zZXs1HpzfTDg==
-----END CERTIFICATE-----
---
Server certificate
subject=C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain

issuer=C = --, ST = SomeState, L = SomeCity, O = SomeOrganization, OU = SomeOrganizationalUnit, CN = localhost.localdomain, emailAddress = root@localhost.localdomain

---
No client certificate CA names sent
Peer signing digest: MD5-SHA1
Peer signature type: RSA
Server Temp Key: DH, 1024 bits
---
SSL handshake has read 1613 bytes and written 521 bytes
Verification error: certificate has expired
---
New, SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: 6103F6FC8A58CC9D3134C7F988326182CF2E354EA5411DD2E630F094BF7BBB85
    Session-ID-ctx: 
    Master-Key: 26BD96B0E5E7969AB8DFE72FFD361D43966DDBF0A335A96E8CD911541EF226C320B5FA70A9B97DDD1D113EEC79145386
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1539791903
    Timeout   : 7200 (sec)
    Verify return code: 10 (certificate has expired)
    Extended master secret: no

Are you sure your router isn’t intercepting requests to port 443 or something like that?

What’s the output of these two?

curl -X GET -I http://gempost.opensyscon.com.au
curl -X GET -Ik https://gempost.opensyscon.com.au

Edit:

Wait, I just realized that Apache should not be in the request path if you are configuring HTTPS via your Node application.

If Apache is in the request path on the way to the Node app, then you need to configure Apache with the SSL certificate, rather than your Node app.

1 Like

Yes, we are intercepting requests on port 443. Look at the following outputs:

[root@wpedb client]# curl -X GET -I http://gempost.opensyscon.com.au
HTTP/1.1 403 Forbidden
Date: Wed, 17 Oct 2018 06:04:43 GMT
Server: Apache/2.2.3 (Red Hat)
Accept-Ranges: bytes
Content-Length: 3985
Connection: close
Content-Type: text/html; charset=UTF-8

[root@wpedb client]# curl -X GET -I http://gempost.opensyscon.com.au:3000
HTTP/1.1 302 Found
Vary: Origin, Accept, Accept-Encoding
Access-Control-Allow-Credentials: true
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Strict-Transport-Security: max-age=0; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
Location: https://gempost.opensyscon.com.au:3002/
Content-Type: text/plain; charset=utf-8
Content-Length: 61
Date: Wed, 17 Oct 2018 06:04:55 GMT
Connection: keep-alive

[root@wpedb client]# curl -X GET -I https://gempost.opensyscon.com.au:3002
curl: (60) Peer certificate cannot be authenticated with known CA certificates
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

[root@wpedb client]# curl -X GET -Ik https://gempost.opensyscon.com.au
HTTP/1.1 403 Forbidden
Date: Wed, 17 Oct 2018 06:09:28 GMT
Server: Apache/2.2.3 (Red Hat)
Accept-Ranges: bytes
Content-Length: 3985
Connection: close
Content-Type: text/html; charset=UTF-8

[root@wpedb client]# curl -X GET -Ik https://gempost.opensyscon.com.au:3002
HTTP/1.1 200 OK
Vary: Origin, Accept-Encoding
Access-Control-Allow-Credentials: true
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Strict-Transport-Security: max-age=0; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
Content-Type: application/json; charset=utf-8
Content-Length: 56
ETag: W/"38-ATj62rXtccll7b+OgVVS5QgprhQ"
Date: Wed, 17 Oct 2018 06:09:35 GMT
Connection: keep-alive

So, in the case of your server running on port 3002, it's not sending the issuer certificate.

But looking at your original post:

It should be working fine.

I tried running GitHub - strongloop/loopback-example-ssl: An example to demonstrate how to set up SSL for LoopBack applications with your example ssl-config.js and it properly sends the full chain.

So I'd probably suggest that the problem lies outside of that file (like in server.js), or your fullchain.pem had been modified, or you need to restart the server.

No,my server running on port 3002 is sending the issuer certificate and it works on android but not on IOS.

The following is the code for server.js. I am doing a redirect for any http call to https.

'use strict';

var loopback = require('loopback');
var boot = require('loopback-boot');

var http = require('http');
var https = require('https');
var httpsRedirect = require('./https-redirect');
var sslConfig = require('./ssl-config');

var bunyan = require('bunyan');
var configger = require('./configger');
var config = configger.load();
console.log('config:', config.app.name);

var log = bunyan.createLogger({ name: config.app.name });
var app = module.exports = loopback();

// Load the http redirection code.
app.use(httpsRedirect());

app.start = () => {
  var httpsOptions = {
    key: sslConfig.privateKey,
    cert: sslConfig.certificate,
  };
  // start the HTTP web server so that we can redirect HTTP traffic to HTTPS
  http.createServer(app).listen(app.get('port'), () => {
    var baseUrl = 'http://' + app.get('host') + ':' + app.get('port');
    app.emit('started HTTP web server', baseUrl);
    console.log('LoopBack server listening @ %s%s', baseUrl, '/');
  });
  // start the HTTPS web server
  return https.createServer(httpsOptions, app).listen(app.get('httpsPort'), () => {
    var baseUrl = 'https://' + app.get('host') + ':' + app.get('httpsPort');
    app.emit('started HTTPS web server', baseUrl);
    console.log('LoopBack server listening @ %s%s', baseUrl, '/');
    if (app.get('loopback-component-explorer')) {
      var explorerPath = app.get('loopback-component-explorer').mountPath;
      console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
    }
  });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, (err) => {
  if (err) throw err;

  // start the server if `$ node server.js`
  if (require.main === module)
    app.start();
});
require('./push-osc')(app);

Fullchain.pem has not been modified.
I also restarted the server several times.

Https works fine on the web and android. Its the IOS which is having issues.

Yep, it is now! Wasn't when I checked yesterday.

Looks OK for me in iOS 12 as well: https://screenshotscdn.firefoxusercontent.com/images/e1385f24-a519-4f1b-866b-6ad0166e8c3a.png

Hi _az,
Thanks for your reply.

Yes, the URL is accessible in the safari browser in IOS. But I receive the following error from the app.

Failed to load resource: The certificate for this server is invalid. You might be connecting to a server that is pretending to be “opensyscon.com.au” which could put your confidential information at risk.
https://opensyscon.com.au:3002/api/SiteConfigs

Just to clarify a bit, any requests from outside on https://opensyscon.com.au:3002 are forwarded to https://gempost.opensyscon.com.au:3002/ where gempost is our internal server.

So I generated letsencrypt certificate for gempost and they are working fine with android.
Thanks.

If your apps are connecting to opensyscon.com.au then you need a certificate that’s valid for that name.

Are you sure your Android app is connecting to the same name, and are you sure it’s validating certificates at all?

Solved the issue by pointing the URL in the app to https://gempost.opensyscon.com.au for which I generated the certificates instead of https://opensyscon.com.au

Thanks a lot to @_az and @jmorahan for all the help provided.

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