1

My app needs to consume webservice, and I would like to authenticate app against server with certificate.

However, embedding keystore with signed key into package is considered bad practice (and explicitly warned against: https://developer.android.com/google/play/asi) as it can be extracted an decrypted.

I can generate private key with android provided keystore, and use it - but I still need it to be signed in order to verify it on server side.

In ideal case there shall be certificate chain, with trusted root authority and containing metadata of signed app package I could verify on server side.

Or is it somehow possible to use package signature in certificate generation process to prove that self signed certificate originated form untampered package?

Konstantin Pribluda
  • 12,329
  • 1
  • 30
  • 35
  • 1
    are you trying to do certificate pinning ? or is this something different ? – a_local_nobody Feb 03 '21 at 11:37
  • No - I try to provide app with private key and certificate I can use for authentication without storing keystore in apk archive. – Konstantin Pribluda Feb 03 '21 at 11:40
  • ok, was just making sure this isn't the same thing, i don't have a ton of experience with certificate pinning but it sounded quite familiar so just wanted to make sure it's not related – a_local_nobody Feb 03 '21 at 11:42
  • sorry if I sound noob, but why use certificate? I mean, aren't certificates (aditionally pinning ) are meant for client to verify that they are making requests to real server and not MIM, not other way around. Why can't you use some kind of authorization technique like secret key, bearer and refresh tokens? Again sorry for noob comment) – Rinat Diushenov Feb 06 '21 at 12:54
  • 1
    Usually client uses server certificate to validate that the server is genuine ( it is signed with proper authority chain, and client trusts this authority). Most common use case. And also sever may use the same technique other way around - client presents public key secured with proper authorities to authenticate itself against server. In my use case server has explicit knowledge about client key (self signed certificate placed in truststore on server side ) - so both sides can set up proper TLS connection and trust it. – Konstantin Pribluda Feb 06 '21 at 13:02

4 Answers4

1

A bad actor ("Trudy") can flash any custom Android ROM, including a ROM that removes package certificate validation during APK installation. Thus, any query that your app makes to its Android host OS is essentially a request to Trudy.

So, it might be possible to uncover the installation of a hacked APK with an unadulterated OS. But with an adulterated OS, all bets are off.

I think any solution for the client to self-validate would necessitate an authoritative validation of the host OS. Not easy.

Is it somehow possible to use package signature in certificate generation process to prove that self signed certificate originated form untampered package?

(1) Do you mean that each client generates a different self-signed certificate after installation and somehow cross-references this against the apk package signature in order to authenticate? Then no, this will not stop Trudy. (And it would not be useful in authentication, either.)

(2) Do you mean that the client has a universal private key embedded in the APK and that metadata on the package certificate can be used to verify against the private key? I do not know offhand if there are any available fields in the package certificate metadata in which to add this information. This is an interesting approach that you suggest. However, since Trudy might be the OS, theoretically Trudy could mock any result it wishes. I do not see this stopping Trudy.

This (SO) post by a developer for Proguard offers 5 options for handling secrets in your Android app. He notes:

Intrinsically, nothing on the client-side is unbreakable, but you can certainly raise the bar.

Razzle Shazl
  • 1,287
  • 1
  • 8
  • 20
  • 1
    I looked into signature returned from package manager but most fields like CN were bogus ( I assume on a real device there would be something more meaningful) - but since it can be extracted form APK this is not a good secret. Hovever I have another idea where to hide keystore password - assemble it somewhere else in code and use reflection to provide it in specific place in memory at some random time. This will definitely raise the bar. – Konstantin Pribluda Feb 06 '21 at 09:16
  • @KonstantinPribluda that's interesting idea to use reflection, Would that method be covered by one of the methods that I linked to? – Razzle Shazl Feb 07 '21 at 01:32
0

I understand that you want user authentication of Webservice (API) using user's private key, and signed token would be verified at the server with user's certificate or public key already registered there at the time of user registration.

Are you looking to use external USB Token to store private key securely or you want to store the private key to be stored in Android device memory?

We have worked on such requirements on desktop (sample at https://web.signer.digital/Home) but not on Android. I know we can connect USB Cryptographic Token (like ePass2003 or others) to Android device with OTG USB and drivers for Android for some devices are available to access from Android but didn't worked on it actually. But this can be direction for you to look into.

Bharat Vasant
  • 850
  • 3
  • 12
  • 46
  • Not quite. I want to authenticate my application without any user interaction. And made it reasonably tamper proof. External (to the app) tokens are beyond the scope - I am looking for self contained solution. – Konstantin Pribluda Feb 06 '21 at 09:05
0

A mobile application is public app, because an end user could possibly view and modify the app code. So, your application can't keep secrets from malicious users. That includes client certificates, which are required for mutual TLS (mTLS).

It is not safe to store any client certificate on the Android device for machine to machine (don't mix machine to machine with user to machine) mTLS authentication. It can be exported and then used on other devices by any user.

Operation systems (Android as well, some browsers, e.g. Firefox may have own) provides certificate storage, where CA certificates are stored and where client certificates can be stored.

It is a good idea to store user (issued for the user, not for the app/machine) client certificates there. Then mobile app should get an option to select which user client certs should be used for mTLS. But I want to authenticate my application without any user interaction. won't be possible. There must be at least initial user interaction: user client cert import to client storage, mTLS app configuration. That's IMHO the best and secure mTLS implementation. Real world example: Rocket Chat app.

Jan Garaj
  • 25,598
  • 3
  • 38
  • 59
0

You are asking for reverse TLS based verification ? Usually, clients verify web services because client's host OS trusts a particular CA certificate that is also used to generate the web-service TLS certificates.

The difference is:

web servers are protected and controlled by authors. Client devices are not. So, having a private key in app to sign the data sent to server is futile.

Still, You can explore Google's Licensing implementation with server side verification to enforce that a legitimately installed and licensed app can contact the server.

S.D.
  • 29,290
  • 3
  • 79
  • 130