Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X509Certificate in Android permissions #6

Open
jhalbrecht opened this issue Feb 18, 2019 · 11 comments
Open

X509Certificate in Android permissions #6

jhalbrecht opened this issue Feb 18, 2019 · 11 comments
Labels
help wanted Extra attention is needed

Comments

@jhalbrecht
Copy link
Owner

Also see; X509Certificate2 in UWP #5

The UWP app of this sample xamarinforms application is working. The android app not so much.

I'm not sure of what permissions for the Android Manifest. I searched a bit and found this issue on eclipse/paho.mqtt.android Permissions #98 I used these;

<!-- Permissions the Application Requires -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

I'm getting this error at runtime.

uPLibrary.Networking.M2Mqtt.Exceptions.MqttConnectionException: Exception connecting to the broker ---> System.AggregateException: One or more errors occurred. ---> System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
  at /Users/builder/jenkins/workspace/xamarin-android-d15-9/xamarin-android/external/mono/external/boringssl/ssl/handshake_client.c:1132
  at Mono.Btls.MonoBtlsContext.ProcessHandshake () [0x00038] in <fb6d78e506844b3b96d5b35aa047fbbd>:0 
  at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status) [0x0003e] in <fb6d78e506844b3b96d5b35aa047fbbd>:0 
  at (wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake(Mono.Net.Security.AsyncOperationStatus)
  at Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) [0x00006] in <fb6d78e506844b3b96d5b35aa047fbbd>:0 
  at Mono.Net.Security.AsyncProtocolRequest+<ProcessOperation>d__24.MoveNext () [0x000ff] in <fb6d78e506844b3b96d5b35aa047fbbd>:0 
--- End of stack trace from previous location where exception was thrown ---
  at Mono.Net.Security.AsyncProtocolRequest+<StartOperation>d__23.MoveNext () [0x0008b] in <fb6d78e506844b3b96d5b35aa047fbbd>:0 
   --- End of inner exception stack trace ---
  at Mono.Net.Security.MobileAuthenticatedStream+<ProcessAuthentication>d__47.MoveNext () [0x00254] in <fb6d78e506844b3b96d5b35aa047fbbd>:0 
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at System.Threading.Tasks.Task.Wait () [0x00000] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at uPLibrary.Networking.M2Mqtt.MqttNetworkChannel.Connect () [0x000a3] in <e87b8d9e7cd447a9bd7e888c0ab94dbb>:0 
  at uPLibrary.Networking.M2Mqtt.MqttClient.Connect (System.String clientId, System.String username, System.String password, System.Boolean willRetain, System.Byte willQosLevel, System.Boolean willFlag, System.String willTopic, System.String willMessage, System.Boolean cleanSession, System.UInt16 keepAlivePeriod) [0x0001e] in <e87b8d9e7cd447a9bd7e888c0ab94dbb>:0 
   --- End of inner exception stack trace ---
  at uPLibrary.Networking.M2Mqtt.MqttClient.Connect (System.String clientId, System.String username, System.String password, System.Boolean willRetain, System.Byte willQosLevel, System.Boolean willFlag, System.String willTopic, System.String willMessage, System.Boolean cleanSession, System.UInt16 keepAlivePeriod) [0x00037] in <e87b8d9e7cd447a9bd7e888c0ab94dbb>:0 
  at uPLibrary.Networking.M2Mqtt.MqttClient.Connect (System.String clientId) [0x00000] in <e87b8d9e7cd447a9bd7e888c0ab94dbb>:0 
  at MqttDataService.MqttDataService+<Initialize>d__5.MoveNext () [0x00226] in C:\jstuff\MqttSample\MqttDataService\MqttDataService.cs:118 

02-18 09:16:34.026 D/Mono    (28136): Found as 'mono_btls_error_get_error_line'.
02-18 09:16:34.027 D/Mono    (28136): DllImport searching in: 'libmono-btls-shared' ('./libmono-btls-shared.so').
02-18 09:16:34.027 D/Mono    (28136): Searching for 'mono_btls_error_get_error_string_n'.
02-18 09:16:34.027 D/Mono    (28136): Probing 'mono_btls_error_get_error_string_n'.
02-18 09:16:34.027 D/Mono    (28136): Found as 'mono_btls_error_get_error_string_n'.
02-18 09:16:44.466 W/zygote  (28136): Checksum mismatch for dex base.apk
@jhalbrecht jhalbrecht added the help wanted Extra attention is needed label Feb 18, 2019
@jhalbrecht
Copy link
Owner Author

jhalbrecht commented Feb 19, 2019

Me: "My kingdom for a blog post to read on this subject"

I added my ca.crt to the android phone. Add & remove certificates Still getting exception.

Now searching "xamarin conditionally choose file path uwp android"
and
"xamarin android how to access installed certificates"

Hmm wonder why this isn't working for me in vs2017? But let's stay on track.

#if WINDOWS_UWP
            Debug.Writeline("\nIn the WINDOWS_UWP\n");      
#endif
#if __ANDROID__
             Debug.Writeline("\nIn the __ANDROID__\n");
#

This looks interesting Javax.Net.Ssl.IX509KeyManager is it abstracted in XamarinForms?

X509StoreManager Doh! broken link... Reported to; xamarinhq JamesMontemagno CodeMillMatt via a tweet.

To recap. I'm attempting to tls secure mqtt connection currently with M2MqttDotNet This is basically working in UWP I am now attempting to accomplish same on Android phone.

At the same time searching for a real world solution as this is insecure.
How do I access the X509certificates on Android?
Or wider... How do I authenticate or secure an mqtt connection on port 8883?

// in my Settings service
FileData fileData = await Plugin.FilePicker.CrossFilePicker.Current.PickFile();
if (fileData == null)
    return; // user canceled file picking

string fileName = fileData.FileName;
string content = Convert.ToBase64String(fileData.DataArray, 0, fileData.DataArray.Length,
                Base64FormattingOptions.None);

// in my MqttDataServices
string deviceFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), fileName);
File.WriteAllText(deviceFileName, content);
                    string thePfxPathOnDevice = Path.Combine(filesDirectoryBasePath, "xamarinclient.pfx");
                    string theBase64EncodedPfx = File.ReadAllText(thePfxPathOnDevice);
                    byte[] certificate = Convert.FromBase64String(theBase64EncodedPfx);
                    X509Certificate2 clientCert = new X509Certificate2(certificate, "xamarin");

                    _client = new MqttClient(
                        GetHostName(_xpdSetting.MqttBrokerAddress),
                        Int32.Parse(_xpdSetting.MqttBrokerTlsPort),
                        _xpdSetting.UseTls,
                        caCert,
                        clientCert,
                        MqttSslProtocols.TLSv1_2,
                        MyRemoteCertificateValidationCallback);

@baulig
Copy link

baulig commented Feb 20, 2019

In theory, we should check the system certificate store on Android, but I'm not sure whether this is very well tested. The code is in Mono.Btls.MonoBtlsX509LookupAndroid, which calls AndroidPlatform.CertStoreLookup().

I suppose you're trying to use a client certificate from a custom CA and installed that custom CA certificate in the system store on the device? You need to make sure that your PFX file contains both the client certificate and the CA certificate (as well as the private key).

To create the CA file, something like this should work:

openssl pkcs12 -export -passout pass:your-password -out cert.pfx -inkey private-key.key -in certificate.pem -certfile your-ca-cert.pem

If this still doesn't work for you, then you can also try using the Mono-specific APIs in Mono.Security.Interface.

There is MonoTlsSettings.TrustAnchors (https://github.com/mono/mono/blob/master/mcs/class/Mono.Security/Mono.Security.Interface/MonoTlsSettings.cs#L77); you can modify the default by using MonoTlsSettings.DefaultSettings.

Please let me know whether this works for you and don't hesitate to ask if you have any further questions. It is certainly possible that we're having a bug in the certificate validation code that we need to look at.

@jhalbrecht
Copy link
Owner Author

Hi @baulig thank you for taking the time to comment on my issues encountered while learning how to secure my existing mqtt xamarinforms applications.

I suppose you're trying to use a client certificate from a custom CA and installed that custom CA certificate in the system store on the device? You need to make sure that your PFX file contains both the client certificate and the CA certificate (as well as the private key).

I am using a self signed certificate. In the wiki I have a section on the Resources page Self Signed certificates and some additional notes on creating the .pfx

Note that this repository has examples of working applications using the self signed certificate. Goal is to learn how to accomplish this in XamarinForms in a real world manner that is publishable in the mobile stores. Although this file picker method I'm doing works in a UWP app but not in the Android (so far) I don't believe it is secure or would pass certification tests for the mobile stores.

Check out this guide about importing self signed certificates to android. Anyone ever seen / used / confirmed this extra step? (basicConstraints=CA:true)
How to create and import Self Signed Certificate to Android Device

I'm still trying to understand how I can programmatically access the certificates I've installed on the Android device? -- not the ones I saved with the FilePicker. Can someone give me a clear code snippet for that?

@baulig
Copy link

baulig commented Feb 21, 2019

I just looked at the certificate validation code and what it does is essentially

var certStore = KeyStore.GetInstance ("AndroidCAStore");
certStore.Load(null);

This is the entry point: https://github.com/mono/mono/blob/master/mcs/class/System/Mono.Btls/MonoBtlsX509LookupAndroid.cs, it calls this code https://github.com/mono/mono/blob/master/mcs/class/System/System/AndroidPlatform.cs#L101 which then calls into xamarin-android code here:
https://github.com/xamarin/xamarin-android/blob/master/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs

The KeyStore should be this class: https://developer.xamarin.com/api/type/Java.Security.KeyStore/.

So you should be able to do this via Java.Security.KeyStore.

@jhalbrecht
Copy link
Owner Author

Thank you again @baulig

Are you saying that the current mono implementation of var certStore = KeyStore.GetInstance ("AndroidCAStore"); is broken/unfinished/not implemented?

I've been searching for a couple days now, my current knowledge doesn't know how to use Java in XamarinForms apps. Apparently my search skills are failing me too as I can not find a learning resource to teach me about using Java in XamarinForms. Can you point me to some learning resources to study?

Can you elaborate with a more verbose code snippet?

@jhalbrecht
Copy link
Owner Author

Maybe this is what I need Android Callable Wrappers I'm looking for a sample.

@jhalbrecht
Copy link
Owner Author

This Stack Overflow question, Android TLS connection and self signed certificate, points to an answer with a good read from December 28, 2011 Using a Custom Certificate Trust Store on Android

See

KeyStore store = KeyStore.getInstance("BKS");
InputStream truststore = mainActivity.getResources().openRawResource(R.raw.trust);
store.load(truststore, "PASSWORD".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf.init(store);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), new SecureRandom());
Socket socket = context.getSocketFactory().createSocket(ip, port);

@sushihangover
Copy link

sushihangover commented Feb 28, 2019

I added my ca.crt to the android phone. Add & remove certificates Still getting exception.

On newer API levels, Android will not allow apps to automatically trust "user" based certs, the app itself has to elect to use those certs as it is a big security hole that Google patched in the ASOP code.

So, you really want to do that during debugging sessions, you need to add the following inside your application tag

android:networkSecurityConfig="@xml/network_security_config"

Now add a xml/network_security_config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<network-security-config>    
    <debug-overrides> 
        <trust-anchors> 
            <!-- Trust user added CAs while debuggable only -->
            <certificates src="user" /> 
        </trust-anchors>    
    </debug-overrides>  
</network-security-config>

To use .Net/Mono SslStream with a non-trusted CA (thus this includes self-signed certs), use BoringSSL and a RemoteCertificateValidationCallback subclass in your SslStream .ctor and pin your cert within your app (load|cache it into a X509Certificate instance via an Android Asset ( using Xamarin.Essentials to allow only NetStd2.0 coding, no Xamarin.Android native needed). And thus no messing with Android trusted stores and no issues with different API levels.

See my SO answer here for a HOWTO: https://stackoverflow.com/a/54918218/4984832

Of course for production do not use a self-signed cert, use a trusted CA-based cert (i.e. Let’s Encrypt provides them for free)

@jhalbrecht
Copy link
Owner Author

Notes and comments as I begin to attempt to implement your suggested solution.
First; Thank you!

Of course for production do not use a self-signed cert, use a trusted CA-based cert (i.e. Let’s Encrypt provides them for free)

I have successfully secured my cloud vm(s) and my home server with letsencrypt. This push to secure my mobile apps is part of my push to quit ignoring security. The eventual goal is a production app. I'm hoping that this repository will be a resource for others to secure their mqtt apps.

All my research indicates that letsencrypt certificates can not be used to sign client certificates. See; Let's Encrypt and client certificates

Aren't Self Signed Certificates used in Enterprise apps?

I did successfully secure my mosquitto broker with my letsencrypt certificate in a python app. I couldn't figure out how to implement it in M2MqttDotnetCore I may return to that after solving for the self signed client certificate.

@sushihangover
Copy link

sushihangover commented Feb 28, 2019

@jhalbrecht > Aren't Self Signed Certificates used in Enterprise apps?

I can not speak for "all" enterprises and I can not speak for your environment, but the ones that I have worked with do not use self-signed certs (SSC) in production and as a contract DevOps I just refuse to even with really small clients and design houses (too much to lose as a contractor). There are even healthy|heated debates on if developers should even use SSCs...

Normally they either maintain their own CA or use a 3rd-party CA. The basic reasoning is if a self-signed cert is compromised, how do you revoke it?, the answer is the signer cannot. You can black-list it, remove it from use, etc... but you can not revoke it. So with my large enterprise clients, they issue a different cert for "each" end-point grouping, typically using intermediates that were issued to each project|department|... Of course a very few are large enough to use "subordinate" roots (ie. intermediates that are enabled with the CA constraint), but those have dedicated groups and automated systems for issuing certs and I'm not in that league and just become a consumer of their output at that point, I'm just a humble DevOp that needs secure connections ;-)

Sometimes a project is "so small", people say, what the heck, just use a SSC... That decision is up to you and your organization. I've been involved in one project that started that way, and later organically grew to include more users internally and then externally, cloud-based end-points, SQL transports between DCs, mobile apps in the wild via Play/Apple store, etc... One day, an external security audit caused that project to suffer a multi-week outage when a SSC was found compromised and customer data was leaking... fortunately for me, I was not in the line of fire for that issue but was brought back in as a member of an outside team that did not sleep of two weeks as we redid the transport security from scratch. Being involved in a data breach, from customer $ data to just an inconsequential email/chat message, that has to be publicly disclosed, it just not something I wish on anyone.

Personally that wholesale supply ordering app I just finished uses a CA trusted root and it only has a few in-house captive sales/marketing users using it on dedicated Android devices, but thats just me 🍣

@sushihangover
Copy link

@jhalbrecht

All my research indicates that letsencrypt certificates can not be used to sign client certificates. See; Let's Encrypt and client certificates

The fact that he states:

And the apps that are protected this way don’t even need to check for the login data. They don’t even know that there is some form of authentication that protects them

is totally incorrect. I would love to give his apps to my sec. researcher friends as a compromised app has free access to a fully authenticated pipeline to his data...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants