owncloud / android

:phone: The ownCloud Android App
GNU General Public License v2.0
3.82k stars 3.05k forks source link

Use a client side SSL certificate to authenticate the client through https #163

Open akirasan opened 11 years ago

akirasan commented 11 years ago

Hi,

I've an owncloud 5.0 server with https connection. I open by NAT the web connection from internet and protect the access with a certificate (on Apache 2). Therefore, to access to my owncloud I use https and a certifcate generate from my server. All work fine from web navigator (IE, Chrome, Firefox,...) when I configure the certificate (pfx, for example).

If I try to configure the android client to my server, not setting the certificate is available and the error appear: "Failed the inicialization SSL" (sorry I translate from Spanish message).

Is possible use a own certificate (.pfx or .crt) to use in the https connection?? (from the android client).

Regards, Akirasan

davivel commented 11 years ago

In the login view, you should see a modal dialog with the option to see details about the certificate and trust it. Doesn't it appear?

Does your server use SNI ? The Android app does not support HTTPS with SNI.

akirasan commented 11 years ago

I don't see a modal dialog. When I try to configure my https, this is the error I see (the port at the end is omitted, but the entered url is "https://akirasan.dyndns-home.com:/owncloud":

1368519707006 1368519709925

I need to check if Apache is configured with SNI, but I think that the problem is: where I define my own SSL-Certificate in the client?, this certificate is require by Apache server.

davivel commented 11 years ago

In the modal dialog that is not appearing. Seems there is some kind of problem in the SSL initialization before the client can reach your SSL certificate. I see you use dyndns, I assume it uses HTTP redirections. Well, we know there is a bug with some types of redirections in the client that we need to fix. Probably that is you real problem, and not the certificate.

akirasan commented 11 years ago

Thanks David, I've tried to connect with my the public IP (not DynDNS service), and the result is the same. :(

akirasan commented 11 years ago

I've force to no use SNI on the Apache server with the directive "SSLStrictSNIVHostCheck off", but the result is the same (failed). I've tried both url's: with dyndns and static ip public.

This is the directive that I use in Apache for request the certificate to the clients: SSLVerifyClient require

If I comment the SSLVerifyClient in the configuration the connection from the android is established and I don't have any problem to use the client.

davivel commented 11 years ago

Oh, sorry, I didn't understand you before.

The app supports the existance of server certificates to ensure the server identity. But we have no support by now for granting the client identity with a client-side certificate. That is what the SSLVerifyClient directive enables.

I am not sure if the client-side certification is what you really wanted, or just were trying to get a "regular" HTTPS connection.

beddari commented 11 years ago

Was just referenced here from https://github.com/bartoszprzybylski/owncloud-android/issues/23

It would be nice to be able to use/provide/configure client-side certs like the OP suggests. This would provide another security layer in that ONLY client apps that you have given a cert (through whatever mechanism you have, some other channel) would ever be able to connect to the server.

asd-er commented 11 years ago

I agree, i've just setup ownCloud to require a client certificate to be able to connect. Unfortunately i can't use the Android app until support for this is added.

davivel commented 10 years ago

Let me update the title so it's a bit clearer.

tommys-place commented 10 years ago

Hi all,

I'm using ownCloud personaly on my own private server to sync mobile data with home server (nginx). I wanted to make connection more secure by using client side ssl certificate verification and have noticed SSL issues with Android app.

I've found solution and it is very simple.

Problems are in class com.owncloud.android.lib.common.network.NetworkUtils:

  1. location of ssl certificate store is wrong (not available on locked mobile) file knownServers.p12 should be in external cache dir /sdcard/Android/data/com.owncloud.android/cache/
  2. type of certificate store. For pkcs, file format should not be BKS, but PKCS12 file knownServers.p12 should be in pkcs12 format
  3. file knownServers.p12 should be protected with "password"

Solution is to replace two methods in mentioned class, here is the code. (it's not perfect but it works)

public static AdvancedSslSocketFactory getAdvancedSslSocketFactory(Context context) throws GeneralSecurityException, IOException {
    if (mAdvancedSslSocketFactory  == null) {           
        KeyStore trustStore = getKnownServersStore(context);
        AdvancedX509TrustManager trustMgr = new AdvancedX509TrustManager(trustStore);
        TrustManager[] tms = new TrustManager[] { trustMgr };

        SSLContext sslContext = SSLContext.getInstance("TLS");

        if("PKCS12".equals(KeyStore.getDefaultType())){
            String alg = KeyManagerFactory.getDefaultAlgorithm();
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
            kmf.init(trustStore, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
            sslContext.init(kmf.getKeyManagers(), tms, null);
        } else {
            sslContext.init(null, tms, null);   
        }
        SSLContext.setDefault(sslContext);

        mHostnameVerifier = new BrowserCompatHostnameVerifier();
        mAdvancedSslSocketFactory = new AdvancedSslSocketFactory(sslContext, trustMgr, mHostnameVerifier);
    }
    return mAdvancedSslSocketFactory;
}

private static KeyStore getKnownServersStore(Context context) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
    if (mKnownServersStore == null) {                                   
        String defaultType = KeyStore.getDefaultType();
        Log.d(TAG, "Default store type :"  + defaultType);
        Security.setProperty("keystore.type", "PKCS12");
        File localTrustStoreFile = new File(context.getExternalCacheDir(), LOCAL_TRUSTSTORE_FILENAME.replace("bks", "p12"));
        Log.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
        if (!localTrustStoreFile.exists()) {
            Security.setProperty("keystore.type", defaultType);            
            localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME);
            Log.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
        }

        //mKnownServersStore = KeyStore.getInstance("BKS");
        mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());            
        if (localTrustStoreFile.exists()) {
            InputStream in = new FileInputStream(localTrustStoreFile);
            try {
                mKnownServersStore.load(in, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
            } finally {
                in.close();
            }
        } else {
            mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray()); // necessary to initialize an empty KeyStore instance
        }
    }
    return mKnownServersStore;
}
davivel commented 10 years ago

@tommys-place,

tommys-place commented 10 years ago

@davivel,

Sorry I was not clear enough.

As I understand, this thread is about client side SSL authetication issue? I have the same problem with SSL client certificate authentication so I've found solution that works for me. And this is what I posted here. This is the answer to your first question. Please read my second sentence once more....

I wanted to make connection more secure by using client side ssl certificate verification and have noticed SSL issues with Android app. Meaning , "I could not use client side SSL certificate authentication also"

I have modified original code to check for the private keys store in the first place and if not found, fallback to functionality of original version of the code. So, if someone needs client side SSL authentication, this code will search for p12 format keystore and try to load private keychain for authetication with the server. P12 keystore is the same one used in browsers but with different extension (pfx)

Java SSL engine should be configured differently when working with client side SSL authetication.

As mentioned, It's not perfect, but it works. Real solution would be possibility to import private ssl certificate into keystore stored in the private space of the app. This will require a lot more work than adding a quick fix. So my solution is a quick fix because I'm not Android developer and I needed SSL client side authtication.

Maybe there is an other way to put private SSL certificate in protected store but as i'm not android developer, I don't know how to do it. I didn't want to bother too much with changing a lot of code and I've used standard Java functionality... see method getKnownServersStore.

   -- keep original default store type (bks)
   String defaultType = KeyStore.getDefaultType();

    -- switch ssl engine to p12 
    Security.setProperty("keystore.type", "PKCS12");

Later, try to load p12 keystore and if not found , return engine to bks format and original functionality.

I hope it is more clear now.

cheers.

beddari commented 10 years ago

Thank you very much for showing this is indeed possible to support :+1:

flavio-pessoa commented 9 years ago

I need this fix, the last post was 29 Aug 2014, will be fix???

davivel commented 9 years ago

We don't have an estimated time of arrival for this feature. Being honest, right now this is not a high priority for us.

beddari commented 9 years ago

@davivel Thanks for replying. I'd just add that I'm very glad @tommys-place stepped up to explain in detail how this could be implemented. At this point any larger organization with the resources needed could pick this up easily :+1: So far that has not happened but so is the nature of open source ... it doesn't mean it won't EVER happen.

sakishrist commented 9 years ago

+1 for this. An additional layer of security through client certification would be a Very nice thing to have.

BentHaase commented 8 years ago

Is there still development or any work around for this bug? I cannot use my OwnCloud weather with official certificates or self signed ones I always get the "SSL initialization failed" error. I don't want an ETA I just wan't to know if this get fixed anyway because for me and many others this makes the app unusable.

luckyhacky commented 8 years ago

+1

wlp7s0 commented 8 years ago

This thread was created in 2013 and this feature wasn't implemented yet. Is there any chance it can be added? I can't use android mobile app because of this error. Thanks for answer.

tobiasKaminsky commented 8 years ago

@wip7s0 there is just not enough man power to do all wishes. The best would be a contribution. That would speed it up...

@ET-Bent "with official certificates or self signed". This issue is about client certificates. I think you are talking about server certificates? If so, please open a new issue and we can try to help you.

agroeschl commented 8 years ago

Okay I'm the next one with the same problem.

@tommys-place run your quick fix without problems?

Is there any work around this bug?

BentHaase commented 8 years ago

@tobiasKaminsky @agroeschl I fixed the issue by using this https://www.ssllabs.com/ssltest/ to see all issues with my ssl setup. It turned out that I had some issues with my keychain. After resolving all issues that SSLLabs selftest showed all works fine on any phone and pc.

agroeschl commented 8 years ago

@et-bent sorry but how can this fix the bug in the owncloud Android APP?

I have the same Problem as akirasan and tommys-place: I wanted to make connection more secure by using client side ssl certificate verification and have noticed SSL issues with Android app. Meaning , "I could not use client side SSL certificate authentication"

BentHaase commented 8 years ago

@agroeschl Sorry I misunderstood you then, so you are referring to the fact that the OwnCloud App does not allow to use SSL Certificates as authentication method right?

agroeschl commented 8 years ago

@ET-BENT I'm using SSLVerifyClient require in Apache to increase the owncloud security. And I have no problems with Firefox, IE or chrome.

But the owncloud APP doesn't work. I get the same error message as described in this thread.

michaelstingl commented 7 years ago

Has been implemented in the ownCloud desktop sync client: https://github.com/owncloud/client/issues/69#issuecomment-264898683

fjf2002 commented 7 years ago

Hello everybody,

I'm also interested in client certificate authentication.

As far as I understand, the suggestion of tommys-place of 26 Aug 2014 was kindof roasted by davivel - and it looks like since then, no more efforts have been made on this topic?

I didn't want to wait any longer and tried to implement client-cert auth myself. Seems to work.

The user experience is just like in the web browser: A dialog will pop up that lists all installed client certificates, so that the user can choose one.

Changes in code in short:

  1. I have borrowed the class KeyChainKeyManager from https://android.googlesource.com/platform/packages/apps/KeyChain/+/aa14e89b1194c4d4054fcd8dbd0af9d08dd5715c/tests/src/com/android/keychain/tests/KeyChainTestActivity.java
  2. ... and used in com.owncloud.android.lib.common.network.NetworkUtils.getAdvancedSslSocketFactory(...) .

Problems:

  1. Since I'm new to owncloud development, what are the next steps? a. Sigining https://owncloud.org/wp-content/themes/owncloudorgnew/assets/files/owncloud-copyright-assignment-common.pdf ? and b. issuing a pull request? c. Or just posting the code here?
  2. I have questions left concerning the architecture, i. e. a. The android.security.KeyChain.choosePrivateKeyAlias method which I used needs a reference to the parent Activity. Am I really supposed to pass that reference through the whole call hierarchy into the utility class NetworkUtils? - My current version uses a global variable. That's very dirty, of course. b. I am not using application private storage for the client certificate. I load them from android system-wide certificate storage (Settings->Security->User credentials ("Nutzeranmeldedaten")). This is not consistent with the current functionality concerining the server-side certificates, which I consider as quite strange: Server-Side certs for which I have installed system-wide Root Certs (Settings->Security->Trusted credentials ("Vertrauenswürdige Anmeldedaten") are shown as untrusted(!) and I have to trust them manually by clicking yes in a dialog. Then, they seem to get copied in app private storage!?

Thanks in advance for any hints concerning functionality or integration into owncloud-android .

smalltoe commented 6 years ago

Great project an thanks to contributors. I would be happy to see this functionality.

davigonz commented 5 years ago

@tommys-place @fjf2002 have you touched the server to make your code explained in comments above works? Thanks

ghost commented 4 years ago

+1 for this feature. This is the missing link for us for a almost perfect file-sharing solution across all devices in our company.

bsodcc commented 11 months ago

Any news? It still is not supported, would be great to have it, and as others say, its the only reason why I cannot use the android app

jesmrec commented 11 months ago

no news

bestrocker221 commented 8 months ago

Nextcloud just added this feature. Might be interesting for speeding up further development of the owncloud android project

https://github.com/nextcloud/android/issues/603#event-11598079119 MR: https://github.com/nextcloud/android/pull/12408