Setting up SSL for development in Nativescript


#1

Generating self-signed certificates is common for development.

Our development server uses certificates signed using the following technique:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -reqexts v3_req -extensions v3_ca

Certificate was installed on Android emulator and shows up in Settings > Security & Location > Trusted Credentials > User

AndroidManifest.xml was modified to include android:debuggable="true" flag.

However, when accessing REST API on https://10.0.0.2, in Android we see the following error:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

FWIW, installing the certificate on iOS and pointing REST API for iOS Simulator to https://localhost works fine.


#2

Solved it.

Here is a quick how to I ended up writing for setting up SSL and using it with NatveScript.
Connecting mobile apps to backends for development with SSL


#3

Wow, this is great @noumaan! Thanks for the awesomely thorough writeup.


#5

Hi, I am new to android development, I have followed the solution steps, but I get this error, my android version is 4.4.2 KitKat, did I miss anything? Thanks.

System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:409)
System.err:     at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
System.err:     at com.android.okhttp.Connection.connect(Connection.java:107)
System.err:     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
System.err:     at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
System.err:     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:89)
System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
System.err:     at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:254)
System.err:     at org.nativescript.widgets.Async$Http$RequestOptions.writeContent(Async.java:313)
System.err:     at org.nativescript.widgets.Async$Http$HttpRequestTask.doInBackground(Async.java:536)
System.err:     at org.nativescript.widgets.Async$Http$1.run(Async.java:482)
System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
System.err:     at org.nativescript.widgets.Async$PriorityThreadFactory$1.run(Async.java:52)
System.err:     at java.lang.Thread.run(Thread.java:841)
System.err: Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
System.err:     at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:282)
System.err:     at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:611)
System.err:     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
System.err:     ... 16 more
System.err: Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
System.err:     ... 21 more
JS: error in login method
JS: login error
JS: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

#6

Are you able to access your backend server endpoint on Chrome in Android KitKat emulator?
https://10.0.2.2:8443

It looks like your Certificate is not installed properly.


#7

Hi @noumaan, sorry for late reply, I’m installing my app onto my device, not emulator, I can access my backend https://192.168.1.184:2225 through chrome browser on my device with a “Your connection is not private” warning though:

I followed your guide completely except for the server code which I use expressjs, here is the code:

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('server:server');
var http = require('http');
var https = require('https');
var fs = require('fs');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
app.set('secPort', port+443);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

// var options = {
//   key: fs.readFileSync(__dirname+ '/private.key'),
//   cert: fs.readFileSync(__dirname+ '/certificate.pem')
// };
var options = {
  key: fs.readFileSync(__dirname+ '/server_dev.key'),
  cert: fs.readFileSync(__dirname+ '/server_dev.crt')
};

var secureServer = https.createServer(options, app);

secureServer.listen(app.get('secPort'), ()=>{
  console.log('Secure Server listening on port ', app.get('secPort'));
});

secureServer.on('error', onError);
secureServer.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

I still get the same error. Please advise.

Thanks
Lanette


#8

Hi @lanette,

Really quickly, can you please check what happens on Android Emulator (please follow the same process, you just need to copy the same certificate you copied to device, and make sure you’ve PIN lock setup )?

Just want to isolate whether the issue is related to device itself or not.

Thanks


#9

Hi @noumaan, unfortunately, I do not have emulator set up on my pc, I tried to set up one but it gave me error: Your CPU does not support required features (VT-x or SVM). I’m using a linux VM and I haven’t found a way to set it up. Any idea?

Edit: I want to show you my certificate installation: