silkimen / cordova-plugin-advanced-http

Cordova / Phonegap plugin for communicating with HTTP servers. Allows for SSL pinning!
MIT License
392 stars 314 forks source link

There was an error setting up the ssl pinning #74

Closed timofeysie closed 6 years ago

timofeysie commented 6 years ago

Hi,

I am using this plugin ionic-native/http: 3.12.1, with an Ionic app. The app was rejected by Google Play for a vulnerability in the SSL Error Handler (WebView SSL Error Handler alerts). I believe this is due to the plugin no enabling SSL pinning.

I have this in my base provider class:

    constructor(
        public http: Http,
        ...
        private httpPlugin: HTTP
    ) {
        this.httpPlugin.enableSSLPinning(true).then(() => {
            alert('httpPlugin.enableSSLPinning true');
        }).catch((err) => {
            alert('httpPlugin.enableSSLPinning catch: '+err);
        });

The message I get then is httpPlugin.enableSSLPinning catch: There was an error setting up ssl pinning

I have a .cer file in the plugins/android/assts/app.cer directory.

What can cause this function to fail? Is there a problem with the cert in the app, or the cert on the server?

Thanks in advance for all you work on this plugin.

silkimen commented 6 years ago

Hi timofeysie,

if it's failing while configuring SSL pinning it's definetly not related to the cert on the server. It's a problem within the app. The certificate file needs to be either in platforms/android/assets/ or alternatively in www/certificates/. Did you try both?

If you want more detailed information, you can put a breakpoint in CordovaHttpPlugin.java#L95 and see what's going on.

Is your backend a public webservice I can reach and test against? If so can you provide me an example link?

timofeysie commented 6 years ago

I have tried both those locations for the .cer file now (previously I used the platforms/android/assets/ method . Is there any naming convention required? The error message is the same in either case.

I am not sure how to go about setting a breakpoint on a Java source file. Could you explain the method for that or link to an explanation of how to debug Android plugins in Ionic?

[edit] I guess you are talking about using Android Studio to emulate the compiled Android project and use the debugger there?

timofeysie commented 6 years ago

Hi again.

I was able to get the debugging working in Android Studio after some problems with a Gradle updage. Anyhow, the output from the console is:

W/System.err: java.security.cert.CertificateException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: java.lang.RuntimeException: error:09000066:PEM routines:OPENSSL_internal:BAD_END_LINE
W/System.err: at com.android.org.conscrypt.OpenSSLX509CertificateFactory.engineGenerateCertificate(OpenSSLX509CertificateFactory.java:274)
W/System.err: at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:362)
W/System.err: at com.github.kevinsawicki.http.HttpRequest.addCert(HttpRequest.java:488)
W/System.err: at com.synconset.cordovahttp.CordovaHttpPlugin.enableSSLPinning(CordovaHttpPlugin.java:162)
W/System.err: at com.synconset.cordovahttp.CordovaHttpPlugin.execute(CordovaHttpPlugin.java:92)
W/System.err: at org.apache.cordova.CordovaPlugin.execute(CordovaPlugin.java:98)
W/System.err: at org.apache.cordova.PluginManager.exec(PluginManager.java:132)
W/System.err: at org.apache.cordova.CordovaBridge.jsExec(CordovaBridge.java:57)
W/System.err: at org.apache.cordova.engine.SystemExposedJsApi.exec(SystemExposedJsApi.java:41)
W/System.err: at org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
W/System.err: at org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:39)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err: at android.os.Looper.loop(Looper.java:154)
W/System.err: at android.os.HandlerThread.run(HandlerThread.java:61)
W/System.err: Caused by: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: java.lang.RuntimeException: error:09000066:PEM routines:OPENSSL_internal:BAD_END_LINE
W/System.err: at com.android.org.conscrypt.OpenSSLX509CertificateFactory$Parser.generateItem(OpenSSLX509CertificateFactory.java:115)
W/System.err: at com.android.org.conscrypt.OpenSSLX509CertificateFactory.engineGenerateCertificate(OpenSSLX509CertificateFactory.java:272)
W/System.err: ... 13 more
W/System.err: Caused by: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: java.lang.RuntimeException: error:09000066:PEM routines:OPENSSL_internal:BAD_END_LINE
W/System.err: at com.android.org.conscrypt.OpenSSLX509Certificate.fromX509PemInputStream(OpenSSLX509Certificate.java:128)
W/System.err: at com.android.org.conscrypt.OpenSSLX509CertificateFactory$1.fromX509PemInputStream(OpenSSLX509CertificateFactory.java:220)
W/System.err: at com.android.org.conscrypt.OpenSSLX509CertificateFactory$1.fromX509PemInputStream(OpenSSLX509CertificateFactory.java:218)
W/System.err: at com.android.org.conscrypt.OpenSSLX509CertificateFactory$Parser.generateItem(OpenSSLX509CertificateFactory.java:94)
W/System.err: ... 14 more
W/System.err: Caused by: java.lang.RuntimeException: error:09000066:PEM routines:OPENSSL_internal:BAD_END_LINE
W/System.err: at com.android.org.conscrypt.NativeCrypto.PEM_read_bio_X509(Native Method)
W/System.err: at com.android.org.conscrypt.OpenSSLX509Certificate.fromX509PemInputStream(OpenSSLX509Certificate.java:122)
W/System.err: ... 17 more
D/SystemWebChromeClient: http://10.8.30.142:8100/build/vendor.js: Line 1378 : ERROR
I/chromium: [INFO:CONSOLE(1378)] "ERROR", source: http://10.8.30.142:8100/build/vendor.js (1378)
W/art: Attempt to remove non-JNI local reference, dumping thread
D/EGL_emulation: eglMakeCurrent: 0x7b8880d213a0: ver 2 0 (tinfo 0x7b8880cd57c0)
D/EGL_emulation: eglMakeCurrent: 0x7b8880d213a0: ver 2 0 (tinfo 0x7b8880cd57c0)
W/art: Attempt to remove non-JNI local reference, dumping thread
D/EGL_emulation: eglMakeCurrent: 0x7b8880d213a0: ver 2 0 (tinfo 0x7b8880cd57c0)
D/SystemWebChromeClient: http://10.8.30.142:8100/cordova.js: Line 1223 : deviceready has not fired after 5 seconds.
I/chromium: [INFO:CONSOLE(1223)] "deviceready has not fired after 5 seconds.", source: http://10.8.30.142:8100/cordova.js (1223)
D/SystemWebChromeClient: http://10.8.30.142:8100/build/vendor.js: Line 88192 : Native: deviceready did not fire within 5000ms.

So it's saying OPENSSL_internal:BAD_END_LINE, is this a problem with the certificate itself?

silkimen commented 6 years ago

Yes, seems like a problem with the certificate. Can you send me an example URL I can test against?

timofeysie commented 6 years ago

Since finding the the error mentioned above, I have tried the advice from crb on this forum post. However, the apk was still rejected by the Play Store.

I have checked the server with https://www.ssllabs.com/ssltest/ You can try with our public facing domain: sjghcdrapp.emerging.com.au

It returns a B rating with the following info:

Additional Certificates (if supplied)
Certificates provided   1 (1341 bytes)
Chain issues    Incomplete

When researching the OPENSSL_internal:BAD_END_LINE error, this page recommends creating a line break between the two files. However, the certificate I have has only one section between the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----

I have another question about SSL pinning. Is it enough just to enable the pinning say in the constructor with the plugin, and then use the @angular/http lib for API calls after that (if it actually is enabled and passes the cert match)? I mean, will the Google Play store SSL Error Handler requirement be met by doing that, or does the app have to use the plugin for ALL http calls?

silkimen commented 6 years ago

Ah now I see the problem! If your cert contains -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- then it's a PEM encoded certificate, but you need a DER encoded one.

Check this stackoverflow link to see how to convert it.

I have another question about SSL pinning. Is it enough just to enable the pinning say in the constructor with the plugin, and then use the lib for API calls after that (if it actually is enabled and passes the cert match)? I mean, will the Google Play store SSL Error Handler requirement be met by doing that, or does the app have to use the plugin for ALL http calls?

I didn't really understand your question. Do you want to know if you need to do this multiple times? You only need to enable SSL pinning once and after that it's enabled for all subsequent requests sent by this plugin.

timofeysie commented 6 years ago

HI again, Thanks for the feedback there. I used the following command to convert PEM to DER:

openssl x509 -outform der -in certificate.pem -out certificate.der

However, the app is still rejected by the play store, and the plugin is still showing the error (from the title of this issue). The plugin does work to enable ssl pinning on iOS builds.

Any more details on what could be causing the OPENSSL_internal:BAD_END_LINE error?

On my other questions about ssl pinning, I would like to use the Angular HTTP class for API calls and the plugin to check the certificates and set a flag for enabled. If the flag is not set then disallow calls. I was concerned that this approach was the problem with the play store rejection. This method also allows development in the browser using ionic serve which is more convenient than emulation or device development.

timofeysie commented 6 years ago

The plugin appears to be working now for both iOS and Android. I had left the PEN encoded certificate in the www/certificates/ directory, so maybe that was causing the problem.

However, Google Play Store still rejects the apk for the same SSL Error Handler reason.

At least I know it's not a problem with the plugin. Thanks for your help on this.

timofeysie commented 6 years ago

Just in case others have this error and come loooking here, Google Play Developer Support feedback said that the app was rejected due to the following class, which contains a vulnerable version of SslErrorHandler: org.apache.cordova.inappbrowser.InAppBrowser$InAppBrowserClient;

InAppBrowserClient is the Cordova plugin we use for OAuth. src/android/InAppBrowser.java

This is an Apache project which has no issue tracking on it's repo. Issues can be opened with this plugin on the Apache Cordova issue tracker. Searching for SslErrorHandler there turns up this open issue: Add support for interstitial user confirmation of self-signed SSL certs to CordovaWebView and InAppBrowser

There may be a workaround or solution in the comments there. I will report back the solution here when found.

jazzymb7 commented 5 years ago

Did you find any solution?

timofeysie commented 5 years ago

Cordova does not support true certificate pinning. The main barrier to this is a lack of native APIs in Android for intercepting SSL connections to perform the check of the server’s certificate.

That being said, I believe this problem was because of an incomplete certificate on the server side. You can check your domain for this kind of problem on a service like this: https://www.sslshopper.com/ssl-checker.html

It's been a while but in this case I think the network team had to fix the certificate issue to resolve this issue, but I don't have any details about how this was accomplished.

Hope this helps.

jazzymb7 commented 5 years ago

Should I put the same .crt which I used for my server in ionic app? And where should I place it? Is there any naming convention? Any hooks which should tell the ionic to use this certificate?

timofeysie commented 5 years ago

You can read about file locations in the docs if I recall. Check the readme for some info. It says: To use SSL pinning you must include at least one .cer SSL certificate in your app project. You can pin to your server certificate or to one of the issuing CA certificates. Include your certificate in the www/certificates folder. All .cer files found there will be loaded automatically. ⚠️ Your certificate must be DER encoded! If you only have a PEM encoded certificate read this stackoverflow answer. You want to convert it to a DER encoded certificate with a .cer extension.

I think there is a slight difference between iOS and Android locations, but the Ionic docs seem to have lost those details. I believe if you put the file in the www/certificates as well as the root directory they will both work but you will have to confirm this for yourself.

dyabol commented 5 years ago

In my case works this solution:

Android

<platform name="android">
  <resource-file src="src/certificates/RapidSSLTLSRSACAG1.cer" target="app/src/main/assets/www/certificates/RapidSSLTLSRSACAG1.cer" />
  ...
</platform>

iOS

<platform name="ios">
  <resource-file src="src/certificates/RapidSSLTLSRSACAG1.cer" />
  ...
</platform>
grandhisubrahmanyam35 commented 4 years ago

I tried both @dyabol and @timofeysie solution but no luck.

this is how defined cordova plugin looks like below in my config.xml

   <plugin name="cordova-plugin-advanced-http" spec="^2.1.1">
       <variable name="OKHTTP_VERSION" value="3.10.0" />
   </plugin>