I'm building a app that signs some data and is supposed to send the 3-tuple data, signature, certificate-chain to a server. The server then checks the signature against the certificate and checks whether the provided certificate is signed by a fixed CA. I already installed the certificate on my android device and now I want to use it in my app.
My problem is: how can I retrieve the certificate chain (no private key) to send it to the server for verification? I looked at the keychain stuff but I don't see a way.
Thanks for your help
Related
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?
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.
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.
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.
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.
I am trying to implement certificate pinning on my app. As far as I understood there are 3 types of pinning available:
certificate pinning; The certificate should be "hardcoded" in the app and compared with the ones from the server. This is kind of bad because if a certificate needs to be rotated an update of the app is required.
public key pinning; From my research it seems this is deprecated
SubjectPublicKeyInfo(SPKI) pinning; this is a hash of the public key. The advantage with this approach is that if a certificates neeeds to be rotated the public key of the new certificate can remain the same for the new certificate, this way an update is not required.
Based on what I've said, it seems that the recommended way to do this is SPKI pinning.
My app can connect to multiple servers, based on the ip which the user types at login.
This is my idea of implementing but I am not sure it would work.
I would create an Intermediate Certificate signed by a CA. Then create my own public-private keys. Then each server that my app can connect would need to request from me to sign their certificate with my private key.
The hierarchy would be something of RootCertificate(self signed by CA), then my intermediate certificate(signed by CA) and then leafs certificates for every server that my app could connect signed by my private key.
On the app I would store the hash of the public key from my intermediate certificate. Upon first connection to a random server the app will get 3 certificates: the one for the server, my intermediate certificate and the Root Certificate. When checking the hashes will find a match with my public key.
What do you think? Could this be implemented? Did I understand something wrong? Is this approach prone to mitm attack?
Thanks!
My app can connect to multiple servers, based on the ip which the user types at login. This is my idea of implementing but I am not sure it would work.
I would create an Intermediate Certificate signed by a CA. Then create my own public-private keys. Then each server that my app can connect would need to request from me to sign their certificate with my private key. The hierarchy would be something of RootCertificate(self signed by CA), then my intermediate certificate(signed by CA) and then leafs certificates for every server that my app could connect signed by my private key.
On the app I would store the hash of the public key from my intermediate certificate. Upon first connection to a random server the app will get 3 certificates: the one for the server, my intermediate certificate and the Root Certificate. When checking the hashes will find a match with my public key.
I would simplify this approach and just pin against each backend server and the Mobile Certificate Pinning Generator tool can help you with extracting the pins for multiple domains/ips, while generating the proper pinning configurations to use in Android and iOS.
Let's imagine that your mobile app needs to communicate with example.com, httpbin.org and google.com.
Just configure the domains you want to pin against in the Config tab:
After you submit the form you will land in the Results tab, and then if you navigate to the Android tab:
and on the iOS tab:
Below each configuration you have instructions on how to add each configuration into your mobile project and even a link to a step by step tutorial on Github that uses the Pin Test App for Android and iOS.
The advantage of pinning against each backend certificate is that you can now have each one auto generating their certificates with LetsEncrypt that keeps the public key between renewals, thus without the need to change the pins in the mobile app, unless a compromise of the private keys occurs. You can replace LetsEncrypt it whatever allows you to rotate certificates while maintaining the same public key.
I'm trying to understand how the jwt signature validation works.
This is how I'm doing it at the moment:
1) My app calls the attest api
2) My app sends the jwt to my server
3) My server verify the signature (third field of the jwt) using the certificate provided in the header of the jwt.
I understand that the signature is created by hashing the header and the payload of the jwt and then signing it (encrypting it) with Google's private key.
What I do in my step 3 is that I take the header + payload and decrypt it with
certificate's public key and verify that it matches the signature. (when I say 'I' do I mean a lib does it)
My issue is that, what happens if there is a malware on the user device and amend on the fly the JWT that is sent to my server? The malware would add his own certificate (issued by a trusted CA) in the header, modify the payload as it wishes and created the signature.
Me server side... well I'm going to take the public key provided in the cert valid the signature with it which will matches.
Is this correct? Or I'am confused somewhere? Because in that case it would render this all flow a bit useless no? How doe insure myself 100% that the JWT comes from google?
The key point is verify that the signing certificate is issued to attest.android.com by a trusted Certificate Authority
Any trusted CA will issue a fake certificate to attest.android.com. See what happens if they engage in bad practices https://security.googleblog.com/2016/10/distrusting-wosign-and-startcom.html?m=1
See Google's doc
Verify the compatibility check response
You should take steps to make sure that the compatibility check response actually came from the SafetyNet service and includes data that matches your request data.
Caution: You should send the entire JWS response to your own server, using a secure connection, for verification. We don't recommend that you perform the verification directly in your app because, in that case, there is no guarantee that the verification logic itself hasn't been modified.
Follow these steps to verify the origin of the JWS message:
Extract the SSL certificate chain from the JWS message.
Validate the SSL certificate chain and use SSL hostname matching to verify that the leaf certificate was issued to the hostname attest.android.com.
Use the certificate to verify the signature of the JWS message.
Check the data of the JWS message to make sure it matches the data within your original request. In particular, make sure that the nonce, timestamp, package name, and the SHA-256 hashes match.
The second dot requires to validate the certificate chain. It is assumed that it is used a Trust Manager containing the root certificate of the Certificate Authority
I have inspected Google's sample code in OfflineVerify to ensure the existence of a TrustManager because it is not explictly said, and it is effectively used during JWS verification. It uses the default system TrustManager, but you can use a custom one
Note that is used JWS (Json Web Signature), not JWT. A JWT is usually an authentication token signed with JWS
You did grasp the concept correctly. However something that you overlooked is that the lib you use is probably verifying that the certificate from which it extracts the public keys is a valid and a 'trusted' certificate (AKA comes from a trusted CA)
Thanks to this (and like the doc points it out) you need to verify yourself that the certificate has been issued by a "attest.android.com". No one will be able to forge a certificate to make it comes from this CA because.
This is what I understood at least, please correct me if I am wrong.
I have client/server data passing all working correctly. Text, Images, etc. My users create blog-type posts on their android device, and upload to my server.. All is done using HTTP Multipart and Input/Output Streams. My issue is - How do I know the client is actually my app and not some script/other hacker app?
I want to avoid abuse scenarios.
Malicious user A creates a PC script that sends the appropriate form data to my server and is able to spam the server, creating 1000s of malicious posts.
Malicious user B creates a simple Android App that sends the appropriate form data to my server and he is able to spam the server.
Malicious user C signs up to my service, Has a valid account and password, and he spams the server using a PC script or Android App.
One idea I have is to force a wait period server side on frequent posts to prevent spam..
But beyond that, how can I check that the person sending data to my server is
An android device and
Is running my App to send form data and not another.
I want to avoid SSL as I don't want to register with Verisign, TRUST and go through all of that..
If it's only your client and your server, you can (and should) use SSL without purchasing anything. You control the server and the client, so each should only trust one certificate, the one belonging to the other and you don't need CAs for this purpose.
Here's the high-level approach. Create a self-signed server SSL certificate and deploy on your web server. You can use the keytool included with the Android SDK for this purpose. Then create a self-signed client and deploy that within your application in a custom keystore included in your application as a resource (keytool will generate this as well). Configure the server to require client-side SSL authentication and to only accept the client certificate you generated. Configure the client to use that client-side certificate to identify itself and only accept the one server-side certificate you installed on your server for that part of it.
A step-by-step for this is a much longer answer than is warranted here. I would suggest doing this in stages as there are resources on the web about how to deal with self-signed SSL certificate in Android, both server and client side. There is also a complete walk-through in my book, Application Security for the Android Platform, published by O'Reilly.
I finally got it all working, server and client two-way ssl authentication.
I used the instructions here to setup my own cert authority (ca) http://www.garex.net/apache/
I followed the commands there to generate my own ca, server and client files..
The big "GOTCHA" was that in the "create client certificate" section, the garex.net link uses a 1024 size client key. As it turns out, this was throwing the exception java.io.IOException: Wrong version of key store
To get around the above exception, I had to use only 512 sized keys.. This is done by NOT including the "1024" parameter to the openssl genrsa genkey command..
Finally I want to add a link to a tool I ended up using instead of Portecle.. I found the keytool gui program here of great help and easier to use than the portecle one - http://www.lazgosoftware.com/kse/index.html
This issue was a bit of a pain in the butt so I will keep an eye on this thread.. Feel free to reply if you run into any roadblocks..
You can use a captcha to solve this problem.
Before submitting the post, request the server for a captcha.
Server associates a random captcha image with a unique key, and sends the application both the captcha and the key.
Show the captcha image to the user.
Send the post, the letters entered by the user and the unique key in your http request.
Server verifies the captcha letters based on the unique key.
If captcha verification succeeded you add the post, otherwise you don't.
This should solve all the scenarios.
I am developing an Android app which need to consume .Net webservices over SSL which I have no experience in. Now I am looking for some guidance and explanation on SSL handshake and certificates.
Note: the server is using IP address and NOT domain name. It is an intranet application.
So far I have created a certificate(called self-signed?) in web server from IIS 7.
To consume it from Android app, I found two ways of doing it :
1). Embedded the certificate in the app (Which certificate? How do I get it?)
2). Trust all the certificates ( ppl said there is security issue with this approach, could you elaborate more? Does it still do the handshake?)
CERTIFICATES:
How many type of certificates are there in the handshake and what are they?
Does self-signed certificate have root certificate? If yes, how can i get them?
Is it possible to move/copy the self-signed certificate from one server to another?
HANDSHAKE:
First of all, is this process correct?
The SSL handshake process(copied from a website) is described below:
The client initiates the SSL handshake process by sending a URL
starting with the following: https:// to the server.
The client initially sends the Web server a list of each encryption
algorithm which it supports. Algorithms supported by SSL include RC4
and Data Encryption Standard (DES). The client also sends the server
its random challenge string which will be utilized later in the
process.
Will the embedded cert be sent in here?
The Web server next performs the following tasks:
Selects an encryption algorithm from the list of encryption
algorithms supported by, and received from the client.
Sends the client a copy of its server certificate.
Sends the client its random challenge string
The client utilizes the copy of the server certificate received from
the server to authenticate the identity of the server.
The client obtains the public key of the server from the server
certificate.
The client next generates a premaster secret. This is a different
random string which will in turn be utilized to generate the session
key for the SSL session. The client then encrypts a different value
called the premaster secret using the public key of the server, and
returns this encrypted value to the server. This is accompanied with
a keyed hash of the handshake messages, and a master key. The hash
is used to protect the messages exchanged in the handshake process.
The hash is generated from the former two random strings transmitted
between the server and the client.
What is a master key?
The server sends the client a keyed hash of all the handshake
messages exchanged between the two parties so far.
What is this keyed hash made from?
The server and the client then generate the session key from the
different random values and keys, and by applying a mathematical
calculation.
The session key is used as a shared secret key to encrypt and
decrypt data exchanged between the server and the client.
The session key is discarded when the SSL session either times-out or is terminated.
I'll try to answer to the best of my knowledge here
Embedded the certificate in the app (Which certificate? How do I get it?)
This the certificate identifying the client's/app identity. You can either get it through CA or self signed. This certificate will be used by the server to verify the client's/app identity
Trust all the certificates ( ppl said there is security issue with this approach, could you elaborate more? Does it still do the handshake?)
It still does the handshake but it doesn't do the certificate validation which is dangerous unless you are connecting internally (which seems you are). Trusting all certificate means an entity can claim as someone who they are not and thus could obtain confidential information from the users.
How many type of certificates are there in the handshake and what are they? In handshake you have the server's certificate and optionally the client certificate (for two factors authentication)
Does self-signed certificate have root certificate? If yes, how can i get them? Root certificate as far as I know means the ones that identifies by CA itself and thus it has no else to sign it. As your identity can still be verified and needs to be signed by CA, yours would not be classified as root certificate
Is it possible to move/copy the self-signed certificate from one server to another? The short answer is yes though the procedures from one platform to the others are different. Check [this link)(http://www.sslshopper.com/how-to-move-or-copy-an-ssl-certificate-from-one-server-to-another.html), it has instructions to copy certificate for few platforms
Will the embedded cert be sent in here? No, the embedded (client's) certificate is sent after validation of the server's identify is complete
What is a master key? Master key is the key that is used to derived the session key for later communication. It is also used to hash the messages and to verify authenticity of the messages in the next set of stages
What is this keyed hash made from? It's made from the master key sent by the client. In order to verify all messages, the server sent all messages that have been passed and hashed it with the master key. The client will hashed its messages as well with the same key and then compared with the data sent by the server. Only when the hash matches then we could be sure we are still communicating with the same server