This is default featured slide 1 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

This is default featured slide 2 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

This is default featured slide 3 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

This is default featured slide 4 title

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. blogger theme by Premiumblogtemplates.com

Wednesday 12 December 2012

A lot has happened in the Android world since our last post, with new devices being announced and going on and off sale.  Most importantly, however, Android 4.2 has been released and made its way to AOSP. It's an evolutionary upgrade, bringing various improvements and some new  user and developer features. This time around, security related enhancements made it into the what's new  list, and there is quite a lot of them. The most widely publicized one has been, as expected, the one users may actually see -- application verification. It recently got an in-depth analysis, so in this post we will look into something less visible, but nevertheless quite important -- certificate pinning

PKI's trust problems and proposed solutions

In the highly unlikely case that you haven't heard about it, the trustworthiness of the existing public CA model has been severely compromised in the recent couple of years. It has been suspect for a while, but recent high profile CA security breaches have brought this problem into the spotlight. Attackers managed to issue certificates for a wide range of sites, including Windows Update servers and Gmail. Not all of those were used (or at least not detected) in real attacks, but the incidents showed just how much of current Internet technology depends on certificates. Fraudulent ones can be used for anything from installing malware to spying to Internet communication, and all that while fooling users that they are using a secure channel or installing a trusted executable. And better security for CA's is not really a solution: major CA's have willingly issued hundreds of certificated for unqualified names such as localhost, webmail and exchange (here is a breakdown, by number of issued certificates). These could enable eavesdropping on internal corporate traffic by using the certificates for a man-in-the-middle (MITM) attack against any internal host accessed using an unqualified name. And of course there is also the matter of compelled certificate creation, where a government agency could compel a CA to issue a false certificate to be used for intercepting secure traffic (and all this may be perfectly legal). 

Clearly the current PKI system, which is largely based on a pre-selected set of trusted CA's (trust anchors), is problematic, but what are some of the actual problems? There are different takes on this one, but for starters, there are too many public CA's. As this map by the EFF's SSL Observatory project shows, there are more than public 650 CA's trusted by major browsers. Recent Android versions ship with over one hundred (140 for 4.2) trusted CA certificates and until ICS the only way to remote a trusted certificate was a vendor-initiated OS OTA. Additionally, there is generally no technical restriction to what certificates CA's can issue: as the Comodo and DigiNotar attack have shown, anyone can issue a certificate for *.google.com (name constraints don't apply to root CA's and don't really work for a public CA). Furthermore, since CA's don't publicize what certificates they have issued, there is no way for site operators (in this case Google) to know when someone issues a new, possibly fraudulent, certificate for one of their sites and take appropriate action (certificate transparency standards aims to address this). In short, with the current system if any of the built-in trust anchors is compromised, an attacker could issue a certificate for any site, and neither users accessing it, nor the owner of the site would notice. So what are some of the proposed solutions? 

Proposed solutions range from radical: scrape the whole PKI idea altogether and replace it with something new and better (DNSSEC is a usual favourite); and moderate: use the current infrastructure  but do not implicitly trust CA's; to evolutionary: maintain compatibility with the current system, but extend it in ways that limit the damage of CA compromise. DNSSEC is still not universally deployed, although the key TLD domains have already been signed. Additionally, it is inherently hierarchical and actually more rigid than PKI, so it doesn't really fit the bill too well. Other even remotely viable solutions have yet to emerge, so we can safely say that the radical path is currently out of the picture. Moving towards the moderate side, some people suggest the SSH model, in which no sites or CA's are initially trusted, and users decide what site to trust on first access. Unlike SSH however, the number of sites that you access directly or indirectly (via CDN's, embedded content, etc.) is virtually unlimited, and user-managed trust is quite unrealistic. Of a similar vein, but much more practical is Moxie Marlinspike's (of sslstrip and CloudCracker fame) Convergence. It is based on the idea of trust agility, a concept he introduced in his SSL And The Future Of Authenticity talk (and related blog post). It both abolishes the browser (or OS) pre-selected trust anchor set, and recognizes that users cannot possibly independently make trust decisions about all the sites they visit. Trust decisions are delegated to a set of notaries, that can vouch for a site by basically confirming that the certificate you receive from a site is one they have seen before. If multiple notaries point out the same certificate as correct, users can be reasonably sure that it is genuine and therefore trustworthy. Convergence is not a formal standard, but was released as actual working code including a Firefox plugin (client) and server-side notary software. While this system is promising, the number of available notaries is currently limited, and Google has publicly stated that it won't add it to Chrome, and it cannot currently be implemented as an extension either (Chrome lacks the necessary API's to let plugins override the default certificate validation module).

That leads us to the current evolutionary solutions, which have been deployed to a fairly large user base, mostly courtesy of the Chrome browser. One is certificate blacklisting, which is more of a band-aid solution: in addition to removing compromised CA certificates from the trust anchor set with a browser update, it also explicitly refuses to trust their public keys in order to cover the case where they are manually added to the trust store again. Chrome added blacklisting around the time Comodo was compromised, and Android has this feature since the original Jelly Bean release (4.1). The next one, certificate pinning (more accurately public key pinning), takes the converse approach: it whitelists the keys that are trusted to sign certificates for a particular site. Let's look at it in a bit more detail.

Certificate pinning

Pinning was introduced in Google Chrome 13 in order to limit the CA's that can issue certificates for Google properties. It actually helped discover the MITM attack against Gmail, which resulted from the DigiNotar breach. It is implemented by maintaining a list of public keys that are trusted to issue certificates for a particular DNS name. The list is consulted when validating the certificate chain for a host, and if the chain doesn't include at least one of the whitelisted keys, validation fails. In practice the browser keeps a list of SHA1 hashes of the SubjectPublicKeyInfo (SPKI) field of trusted certificates. Pinning the public keys instead of the actual certificates allows for updating host certificates without breaking validation and requiring pinning information update. You can find the current Chrome list here.

As you can see, the list now pins non-Google sites as well, such as twitter.com and lookout.com, and is rather large. Including more sites will only make it larger, and it is quite obvious that hard-coding pins doesn't really scale. A couple of new Internet standards have been proposed to help solve this scalability problem: Public Key Pinning Extension for HTTP (PKPE) by Google and Trust Assertions for Certificate Keys (TACK) by Moxie Marlinspike. The first one is simpler and proposes a new HTTP header (Public-Key-Pin, PKP) that holds pinning information including public key hashes, pin lifetime and whether to apply pinning to subdomains of the current host. Pinning information (or simply 'pins') is cached by the browser and used when making trust decisions until it expires. Pins are required to be delivered over a secure (TLS) connection, and the first connection that includes a PKP header is implicitly trusted (or optionally validated against pins built into the client). The protocol also supports an endpoint to report failed validations to via the report-uri directive and allows for a non-enforcing mode (specified with the Public-Key-Pins-Report-Only header), where validation failures are reported, but connections are still allowed. This makes it possible to notify host administrators about possible MITM attacks against their sites, so that they can take appropriate action. The TACK proposal, on the other header, is somewhat more complex and defines a new TLS extension (TACK) that carries pinning information signed with a dedicated 'TACK key'. TLS connections to a pinned hostname require the server to present a 'tack' containing the pinned key and a corresponding signature over the TLS server's public key. Thus both pinning information exchange and validation are carried out at the TLS layer. In contrast, PKPE uses the HTTP layer (over TLS) to send pinning information to clients, but also requires validation to be performed at the TLS layer, dropping the connection if validation against the pins fails. Now that we have an idea how pinning works, let's see how it's implemented on Android.

Certificate pinning in Android

As mentioned at beginning of the post, pinning is one of the many security enhancements introduced in Android 4.2. The OS doesn't come with any built-in pins, but instead reads them from a file in the /data/misc/keychain directory (where user-added certificates and blacklists are stored). The file is called, you guessed it, simply pins and is in the following format: hostname=enforcing|SPKI SHA512 hash, SPKI SHA512 hash,.... Here enforcing is either true or false and is followed by a list of SPKI hashes (SHA512) separated by commas. Note that there is no validity period, so pins are valid until deleted. The file is used not only by the browser, but system-wide by virtue of pinning being integrated in libcore. In practice this means that the default (and only) system X509TrustManager implementation (TrustManagerImpl) consults the pin list when validating certificate chains. However there is a twist: the standard checkServerTrusted() method doesn't consult the pin list. Thus any legacy libraries that do not know about certificate pinning would continue to function exactly as before, regardless of the contents of the pin list. This has probably been done for compatibility reasons, and is something to be aware of: running on 4.2 doesn't necessarily mean that you get the benefit of system-level certificate pins. The pinning functionality is exposed to third party libraries or SDK apps via the new X509TrustManagerExtensions SDK class. It has a single method, List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType, String host) that returns a validated chain on success or throws a CertificateException if validation fails. Note the last parameter, host. This is what the underlying implementation (TrustManagerImpl) uses to search the pin list for matching pins. If one is found, the public keys in the chain being validated will be checked against the hashes in the pin entry for that host. If none of them matches, validation will fail and you will get a CertificateException. So what part of the system uses the new pinning functionality then? The default SSL engine (JSSE provider), namely the client handshake (ClientHandshakeImpl) and SSL socket (OpenSSLSocketImpl) implementations. They would check their underlying X509TrustManager and if it supports pinning, they will perform additional validation against the pin list. If validation fails, the connection won't be established, thus implementing pin validation on the TLS layer as required by the standards discussed in the previous section. We now know what the pin list is and who uses it, so let's find out how it is created and maintained.

First off, at the time of this writing, Google-managed (on Nexus devices) JB 4.2 installations have an empty pin list (i.e., the pins file doesn't exist). Thus certificate pinning on Android has not been widely deployed yet. Eventually it will be, but the current state of affairs makes it easier to play with, because restoring to factory state requires simply deleting the pins file and associated metadata (root access required). As you might expect, the pins file is not written directly by the OS. Updating it is triggered by a broadcast (android.intent.action.UPDATE_PINS) that contains the new pins in it's extras. The extras contain the path to the new pins file, its new version (stored in /data/misc/keychain/metadata/version), a hash of the current pins and a SHA512withRSA signature over all the above. The receiver of the broadcast (CertPinInstallReceiver) will then verify the version, hash and signature, and if valid, atomically replace the current pins file with new content (the same procedure is used for updating the premium SMS numbers list). Signing the new pins ensures that they can only by updated by whoever controls the private signing key. The corresponding public key used for validation is stored as a system secure setting under the "config_update_certificate" key (usually in the secure table of the
/data/data/com.android.providers.settings/databases/settings.db) Just like the pins file, this value currently doesn't exists, so its relatively safe to install your own key in order to test how pinning works. Restoring to factory state requires deleting the corresponding row from the secure table. This basically covers the current pinning implementation in Android, it's now time to actually try it out.

Using certificate pinning

To begin with, if you are considering using pinning in an Android app, you don't need the latest and greatest OS version. If you are connecting to a server that uses a self-signed or a private CA-issued certificate, chances you might already be using pinning. Unlike a browser, your Android app doesn't need to connect to practically every possible host on the Internet, but only to a limited number of servers that you know and have control over (limited control in the case of hosted services). Thus you know in advance who issued your certificates and only need to trust their key(s) in order to establish a secure connection to your server(s). If you are initializing a TrustManagerFactory with your own keystore file that contains the issuing certificate(s) of your server's SSL certificate, you are already using pinning: since you don't trust any of the built-in trust anchors (CA certificates), if any of those got compromised your app won't be affected (unless it also talks to affected public servers as well). If you, for some reason, need to use the default trust anchors as well, you can define pins for your keys and validate them after the default system validation succeeds. For more thoughts on this and some sample code (doesn't support ICS and later, but there is pull request with the required changes), refer to this post by Moxie Marlinspike. Update: Moxie has repackaged his sample pinning code in an easy to use standalone library. Update 2: His version uses a static, app-specific trust tore. Here's a fork that uses the system trust store, both on pre-ICS (cacerts.bks) and post-ICS (AndroidCAStore) devices.

Before we (finally!) start using pinning in 4.2 a word of warning: using the sample code presented below both requires root access and modifies core system files. It does have some limited safety checks, but it might break your system. If you decide to run it, make sure you have a full system backup and proceed with caution.

As we have seen, pins are stored in a simple text file, so we can just write one up and place it in the required location. It will be picked and used by the system TrustManager, but that is not much fun and is not how the system actually works. We will go through the 'proper' channel instead by creating and sending a correctly signed update broadcast. To do this, we first need to create and install a signing key. The sample app has one embedded so you can just use that or generate and load a new one using OpenSSL (convert to PKCS#8 format to include in Java code). To install the key we need the WRITE_SECURE_SETTINGS permission, which is only granted to system apps, so we must either sign our test app with the platform key (on a self-built ROM) or copy it to /system/app (on a rooted phone with stock firmware). Once this is done we can install the key by updating the "config_update_certificate" secure setting:

Settings.Secure.putString(ctx.getContentResolver(), "config_update_certificate", 
"MIICqDCCAZAC...");

If this is successful we then proceed to constructing our update request. This requires reading the current pin list version (from /data/misc/keychain/metadata/version) and the current pins file content. Initially both should be empty, so we can just start off with 0 and an empty string. We can then create our pins file, concatenate it with the above and sign the whole thing before sending the UPDATE_PINS broadcast. For updates, things are a bit more tricky since the metadata/version file's permissions don't allow for reading by a third party app. We work around this by launching a root shell to get the file contents with cat, so don't be alarmed if you get a 'Grant root?' popup by SuperSU or its brethren. Hashing and signing are pretty straightforward, but creating the new pins file merits some explanation.

To make it easier to test, we create (or append to) the pins file by connecting to the URL specified in the app and pinning the public keys in the host's certificate chain (we'll use www.google.com in this example, but any host accessible over HTTPS should do). Note that we don't actually pin the host's SSL certificate: this is to allow for the case where the host key is lost or compromised and a new certificate is issued to the host. This is introduced in the PKPE draft as a necessary security trade-off to allow for host certificate updates. Also note that in the case of one (or more) intermediate CA certificates we pin both the issuing certificate's key(s) and the root certificate's key. This is to allow for testing more variations, but is not something you might want to do in practice: for a connection to be considered valid, only one of the keys in the pin entry needs to be in the host's certificate chain. In the case that this is the root certificate's key, connections to hosts with certificates issued by a compromised intermediary CA will be allowed (think hacked root CA reseller). And above all, getting and creating pins based on certificates you receive from a host on the Internet is obviously pointless if you are already the target of a MITM attack. For the purposes of this test, we assume that this is not the case. Once we have all the data, we fire the update intent, and if it checks out the pins file will be updated (watch the logcat output to confirm). The code for this will look something like this (largely based on pinning unit test code in AOSP). With that, it is time to test if pinning actually works.

URL url = new URL("https://www.google.com");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.connect();

X509Certificate[] chain = (X509Certificate[])conn.getServerCertificates();
X509Certificate cert = chain[1];
String pinEntry = String.format("%s=true|%s", url.getHost(), getFingerprint(cert));
String contentPath = makeTemporaryContentFile(pinEntry);
String version = getNextVersion("/data/misc/keychain/metadata/version");
String currentHash = getHash("/data/misc/keychain/pins");
String signature = createSignature(content, version, currentHash);

Intent i = new Intent();
i.setAction("android.intent.action.UPDATE_PINS");
i.putExtra("CONTENT_PATH", contentPath);
i.putExtra("VERSION", version);
i.putExtra(REQUIRED_HASH", currentHash);
i.putExtra("SIGNATURE", signature);
sendBroadcast(i);

We have now pinned www.google.com, but how to test if the connection will actually fail? There are multiple ways to do this, but to make things a bit more realistic we will launch a MITM attack of sorts by using an SSL proxy. We will use the Burp proxy, which works by generating a new temporary (ephemeral) certificate on the fly for each host you connect to (if you prefer a terminal-based solution, try mitmproxy). If you install Burp's root certificate in Android's trust store and are not using pinning, browsers and other HTTP clients have no way of distinguishing the ephemeral certificate Burp generates from the real one and will happily allow the connection. This allows Burp to decrypt the secure channel on the fly and enables you to view and manipulate traffic as you wish (strictly for research purposes, of course). Refer to the Getting Started page for help with setting up Burp. Once we have Burp all set up, we need to configure Android to use it. While Android does support HTTP proxies, those are generally only used by the built-in browser and it is not guaranteed that HTTP libraries will use the proxy settings as well. Since Android is after all Linux, we can easily take care of this by setting up a 'transparent' proxy that redirects all HTTP traffic to our chosen host by using iptables. If you are not comfortable with iptables syntax or simply prefer an easy to use GUI, there's an app for that as well: Proxy Droid. After setting up Proxy Droid to forward packets to our Burp instance we should have all Android traffic flowing through our proxy. Open a couple of pages in the browser to confirm before proceeding further (make sure Burp's 'Intercept' button is off if traffic seems stuck).

Finally time to connect! The sample app allows you to test connection with both of Android's HTTP libraries (HttpURLConnection and Apache's HttpClient), just press the corresponding 'Check w/ ...' button. Since validation is done at the TLS layer, the connection shouldn't be allowed and you should see something like this (the error message may say 'No peer certificates' for HttpClient; this is due to the way it handles validation errors):



If you instead see a message starting with 'X509TrustManagerExtensions verify result: Error verifying chain...', the connection did go through but our additional validation using the X509TrustManagerExtensions class detected the changed certificate and failed. This shouldn't happen, right? It does though because HTTP clients cache connections (SSLSocket instances, which in turn each hold a X509TrustManager instance, which only reads pins when created). The easiest way to make sure pins are picked up is to reboot the phone after you pin your test host. If you try connecting with the Android browser after rebooting (not Chrome!), you will be greeted with this message:


As you can see the certificate for www.google.com is issued by our Burp CA, but it might as well be from DigiNotar: if the proper public keys are pinned, Android should detected the fraudulent host certificate and show a warning. This works because the Android browser is using the system trust store and pins via the default TrustManager, even though it doesn't use JSSE SSL sockets. Connecting with Chrome on the other hand works fine even though it does have built-in pins for Google sites: Chrome allows manually installed trust anchors to override system pins so that tools such as Burp or Fiddler continue to work (or pinning is not yet enabled on Android, which is somewhat unlikely).


So there you have it: pinning on Android works. If you look at the sample code, you will see that we have created enforcing pins and that is why we get connection errors when connecting through the proxy. If you set the enforcing parameter to false instead, connection will be allowed, but chains that failed validation will still be recorded to the system dropbox (/data/system/dropbox) in cert_pin_failure@timestamp.txt files, one for each validation failure.

Summary

Android adds certificate pinning by keeping a pin list with an entry for each pinned DNS name. Pin entries include a host name, an enforcing parameter and a list of SPKI SHA512 hashes of the of keys that are allowed to sign a certificate for that host. The pin list is updated by sending a broadcast with signed update data. Applications using the default HTTP libraries get the benefit of system-level pinning automatically or can explicitly check a certificate chain against the pin list by using the X509TrustManagerExtensions SDK class. Currently the pin list is empty, but the functionality is available now and once pins for major sites are deployed this will add another layer of defense against MIMT attacks that follow after a CA has been compromised.

Friday 9 November 2012

In the first part of this series, we presented how the standard Android online account management framework works and explored how Google account authentication and authorization modules are implemented on Android. In this article we will see how to use the Google credentials stored on the device to log in to Google Web sites automatically. Note that this is different from using public Google API's, which generally only requires putting an authentication token (and possibly an API key) in a request header, and is quite well supported by the Google APIs Client Library. First, some words on what motivated this whole exercise (may include some ranting, feel free to skip to the next section).

Android developer console API: DIY

If you have ever published an application on the Android Market Google Play Store, you are familiar with the Android developer console. Besides letting you publish and update your apps, it also shows the number of total and active installs (notoriously broken and not too be taken too seriously, though it's been getting better lately), ratings and comments. Depending on how excited about the whole app publishing business you are, you might want to check it quite often to see how your app is doing, or maybe you just like hitting F5. Most people don't however, so pretty much every developer at some point comes up with the heretic idea that there must be a better way: you should be able to check your app's statistics on your Android device (obviously!), you should get notified about changes automatically and maybe even be able to easily see if today's numbers are better than yesterday's at a glance. Writing such a tool should be fairly easy, so you start looking for an API. If your search ends up empty it's not your search engine's fault: there is none! So before you start scraping those pretty Web pages with your favourite P-language, you check if someone has done this before -- you might get a few hits, and if you are lucky even find the Android app.

Originally developed by Timelappse, and now open source, Andlytics does all the things mentioned above, and more (and if you need yet another feature, consider contributing). So how does it manage to do all of this without an API? Through blood, sweat and a lot of protocol reversing guessing. You see, the current developer console is built on GWT which used to be Google's webstack-du-jour a few years back. GWT essentially consists of RPC endpoints at the server, called by a JavaScript client running in the browser. The serialization protocol in between is a custom one, and the specification is purposefully not publicly available (apparently, to allow for easier changes!?!). It has two main features: you need to know exactly how the transferred objects look like to be able to make any sense of it, and it was obviously designed by someone who used to write compilers for a living before they got into Web development ('string table' ring a bell?). Given the above, Andlytics was quite an accomplishment. Additionally, the developer console changing its protocol every other week and adding new features from time to time didn't really make it any easier to maintain. Eventually, the original developer had a bit too much GWT on his plate, and was kind enough to open source it, so others could share the pain.

But there is a bright side to all this: Developer Console v2. It was announced at this year's Google I/O to much applause, but was only made universally available a couple of weeks ago (sound familiar?). It is a work in progress, but is showing promise. And the best part: it uses perfectly readable (if a bit heavy on null's) JSON to transport data! Naturally, there was much rejoicing at the Andlytics Github project. It was unanimously decided that the sooner we obliterate all traces of GWT, the better, and the next version should use the v2 console 'API'. Deciphering the protocol didn't take long, but it turned out that while to log in to the v1 console all you needed was a ClientLogin (see the next section for an explanation) token straight out of Android's AccountManger, the new one was not so forgiving and the login flow was somewhat more complex. Asking the user for their password and using it to login was obviously doable, but no one would like that, so we needed to figure out how to log in using the Google credentials already cached on the device. Android browser and Chrome are able to automatically log you in to the developer console without requiring your password, so it was clearly possible. The process is not really documented though, and that prompted this (maybe a bit too wide-cast) investigation. Which finally leads us to the topic of this post: to show how to use cached Google account credentials for single sign-on. Let's first see what standard ways are available to authenticate to Google's public services and API's.

Google services authentication and authorization

The official place to start when selecting an auth mechanism is the Google Accounts Authentication and Authorization page. It lists quite a few protocols, some open and some proprietary. If you research further you will find that currently all but OAuth 2.0 and Open ID are considered deprecated, and using the proprietary ones is not recommended. However, a lot of services are still using older, proprietary protocols, so we will look into some of those as well. Most protocols also have two variations: one for Web applications and one for the so called, 'installed applications'. Web applications run in a browser, and are expected to be able to take advantage of all standard browser features: rich UI, free-form user interaction, cookie store and ability to follow redirects. Installed applications, on the other hand, don't have a native way to preserve session information, and may not have the full Web capabilities of a browser. Android native applications (mostly) fall in the 'installed applications' category, so let's see what protocols are available for them.

ClientLogin

The oldest and most widely used till now authorization protocol for installed applications is ClientLogin. It assumes the application has access to the user's account name and password and lets you get an authorization token for a particular service, that can be saved and used for accessing that service on behalf of the user. Services are identified by proprietary service names, for example 'cl' for Google Calendar and 'ah' for Google App engine. A (non-exhaustive) list of supported service names can be found in the Google Data API reference. Here are a few Android-specific ones, not listed in the reference: 'ac2dm', 'android', 'androidsecure', 'androiddeveloper', 'androidmarket' and 'youngandroid' (probably for the discontinued App Inventor). The token can be fairly long-lived (up to two weeks), but cannot be refreshed and the application needs to obtain a new token when it expires. Additionally, there is no way to validate the token short of accessing the associated service: if you get an OK HTTP status (200), it is still valid, if 403 is returned you need to consult the additional error code and retry or get a new token. Another limitation is that ClientLogin tokens don't offer fine grained access to a service's resources: access is all or nothing, you cannot specify read-only access or access to a particular resource only. The biggest drawback for use in mobile apps though is that ClientLogin requires access to the actual user password. Therefore, if you don't want to force users to enter it each time a new token is required, it needs to be saved on the device, which poses various problems. As we saw in the previous post, in Android this is handled by GLS and the associated online service by storing an encrypted password or a master token on the device. Getting a token is as simple as calling the appropriate AccountManger method, which either returns a cached token or issues an API request to fetch a fresh one. Despite it's many limitations, the protocol is easy to understand and straightforward to implement, so it has been widely used. It has been officially deprecated since April 2012 though, and apps using it are encouraged to migrate to OAuth 2.0, but this hasn't quite happened yet. 

OAuth 2.0

No one likes OAuth 1.0 (except Twitter) and AuthSub is not quite suited for native applications, so we will only look at the currently recommended OAuth 2.0 protocol. OAuth 2.0 has been in the works for quite some time, but it only recently became an official Internet standard. It defines different authorization 'flows', aimed at different use cases, but we will not try to present all of them here. If you are unfamiliar with the protocol, refer to one of the multiple posts that aim to explain it at a higher level, or just read the RFC if you need the details.  And, of course, you can watch for this for a slightly different point of view. We will only discuss how OAuth 2.0 relates to native mobile applications.

The OAuth 2.0 specification defines 4 basic flows for getting an authorization token for a resource, and the two ones that don't require the client (in our scenario an Android app) to directly handle user credentials (Google account user name and password), namely the authorization code grant flow and the implicit grant flow, both have a common step that needs user interaction. They both require the authorization server (Google's) to authenticate the resource owner (the user of the our Android app) and establish whether they grant or deny the access request for the specified scope (e.g., read-only access to profile information). In a typical Web application that runs in a browser, this is very straightforward to do: the user is redirected to an authentication page, then to a access grant page that basically says 'Do you allow app X to access data Y and Z?', and if they agree, another redirect, which includes an authorization token, takes them back to the original application. The browser simply needs to pass on the token in the next request to gain access to the target resource. Here's an official Google example that uses the implicit flow: follow this link and grant access as requested to let the demo Web app display your Google profile information. With a native app things are not that simple. It can either
  • use the system browser to handle the permission grant step, which would typically involve the following steps:
    • launch the system browser and hope that the user will finish the authentication and permission grant process
    • detect success or failure and extract the authorization token from the browser on success (from the window title, redirect URL or the cookie store)
    • ensure that after granting access, the user ends up back in your app
    • finally, save the token locally and use it to issue the intended Web API request
  • embed a WebView or a similar control in the apps's UI. Getting a token would generally involve these steps:
    • in the app's UI, instruct the user what to do and load the login/authorization page
    • register for a 'page loaded' callback, and check for the final success URL each time it's called
    • when found, extract the token from the redirect URL or the WebView's cookie jar and save it locally
    • finally use the token to send the intended API request
Neither is ideal, both are confusing to the user and to implement the first one on Android you might event have to (temporarily) start a Web server (redirect_uri is set to http://localhost in the API console, so you can't just use a custom scheme). The second one is generally preferable, if not pretty: here's an (somewhat outdated) overview of what needs to be done and a more recent example with full source code. This integration complexity and UI impedance mismatch are the problems that OAuth 2.0 support via the AccountManager initially, and recently Google Play Services aim to solve. When using either of those, user authentication is implemented transparently by passing the saved master token (or encrypted password) to the server side component, and instead of a WebView with a permission grant page, you get the Android native access grant dialog. If you approve, a second request is sent to convey this and the returned access token is directly delivered to the requesting app. This is essentially the same flow as for Web applications, but has the advantages that it doesn't require context switching from native to browser and back, and is much more user friendly. Of course, it only works for Google accounts, so if you wanted to write, say, a Facebook client, you still have to use a WebView to process the access permission grant and get an authorization token.

Now that we have an idea what authentication methods are available, let's see if we can use them to access an online Google service that doesn't have a dedicated API.

Google Web properties single sign-on

Being able to access multiple related, but separate services without needing to authenticate to each one individually is generally referred to as single sign-on (SSO). There are multiple standard ways to accomplish this for different contexts, ranging from Kerberos to SAML-based solutions. We will use the term here in a narrower meaning: being able to use different Google services (Web sites or API's) after having authenticated to only one of them (including the Android login service). If you have a fairly fast Internet connection, you might not even notice it, but after you log in to, say, Gmail, clicking on YouTube links will take you to a completely different domain, and yet you will be able to comment on that neat cat video without having to log in again. If you have a somewhat slower connection and a wide display though, you may notice that there is a lot of redirecting and long parameter passing, with the occasional progress bar going on. What happens behind the scenes is that your current session cookies and authentication tokens are being exchanged for yet other tokens and more cookies, to let you seamlessly log in to that other site. If you are curious, you can observe the flow with Chrome's built-in developer tools (or similar plugins for other browsers), or check out our sample. All of those requests and responses are essentially a proprietary SSO protocol (Google's), which is not really publicly documented anywhere, and, of course, is likely to change fairly often as Google rolls out upgrades to their services. With that said, there is a distinct pattern, and on a higher level you only have two main cases. We are deliberately ignoring the persistent cookie ('Stay signed in')  scenario for simplicity's sake.
  • Case 1: you haven't authenticated to any of the Google properties. If you access, for example, mail.google.com in that state you will get a login screen originating at https://accounts.google.com/ServiceLogin with parameters specifying the service you are trying to access ('mail' for Gmail) and where to send you after you are authenticated. After you enter your credentials, you will generally get redirected a few times around the accounts.google.com, which will set a few session cookies, common (Domain=.google.com) for all services (always SID and LSID, plus a few more). The last redirect will be to the originally requested service and include an authentication token in the redirected location (usually specified with the auth parameter, e.g.: https://mail.google.com/mail/?auth=DQAAA...). The target service will validate the token and set a few more service-specific sessions cookies, restricted by domain and path, and with the Secure and HttpOnly flags set. From there, it might take a couple of more redirects before you finally land at an actual content page.
  • Case 2: you have already authenticated to at least one service (Gmail in our example). In this state, if you open, say, Calendar, you will go through https://accounts.google.com/ServiceLogin again, but this time the login screen won't be shown. The accounts service will modify your SID and LSID cookies, maybe set a few new ones and finally redirect you the original service, adding an authentication token to the redirect location. From there the process is similar: one or more service-specific cookies will be set and you will finally be redirected to the target content.
Those flows obviously work well for browser-based logins, but since we are trying to do this from an Android app, without requiring user credentials or showing WebView's, we have a different scenario. We can easily get a ClientLogin or an OAuth 2.0 token from the AccountManager, but since we are not preforming an actual Web login, we have no cookies to present. The question becomes: is there a way to log in with a standard token alone? Since tokens can be used with the data APIs (where available) of each service, they obviously contain enough information to authenticate us and grant access to the service's resources. What we need is an Web endpoint, that will take our token and give us a set of cookies we could use to access the corresponding Web site in exchange. Clues and traces of such a service are scattered around the Internet, mostly in the code of unofficial Google client libraries and applications. Once we know it is definitely possible, the next problem becomes getting it to work with Android's AccountManger.

Logging in using AccountManager

The only real documentation we could find, besides code comments and READMEs of the unofficial Google client applications mentioned above, is a short Chromium OS design document. It tells us that the standard (at the time) login API for installed applications, ClientLogin, alone is not enough to accomplish Web SSO, and outlines a three step process that lets us exchange ClientLogin tokens for session cookies valid for a particular service:
  1. Get a ClientLogin token (this we can do via the AccountManager)
  2. Pass it to https://www.google.com/accounts/IssueAuthToken, to get a one-time use, short-lived token that will authenticate the user to any service (the so called, 'ubertoken')
  3. Finally, pass the ubertoken to https://www.google.com/accounts/TokenAuth, to exchange it for the full set of browser cookies we need to do SSO
This outlines the process, but is a little light on the details. Fortunately, those can be found in the Chromium OS source code, as well as a few other projects. After a fair bit of digging, here's what we uncovered:
    1. To get the mythical ubertoken, you need to pass the SID and LSID cookies to the IssueAuthToken endpoint like this:
      https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false&SID=sid&LSID=lsid
    2. The response will give you the ubertoken, which you pass to the TokenAuth endpoint along with the URL of the service you want to use:
      https://www.google.com/accounts/TokenAuth?source=myapp&auth=ubertoken&continue=service-URL
    3. If the token check out OK, the response will give you a URL to load. If your HTTP client is set up to follow redirects automatically, once you load it, needed cookies will be set automatically (just as in a browser), and you will finally land on the target site. As long as you keep the same session (which usually means the same HTTP client instance) you will be able to issue multiple requests, without needing to go through the authentication flow again.
    What remains to be seen is, can we implement this on Android. As usual, it turns out that there is more than one way to do it:

    The hard way

    The straightforward way would be to simply implement the flow outlined above using your favourite HTTP client library. We choose to use Apache HttpClient, which supports session cookies and multiple requests using a single instance out of the box. The first step calls for the SID and LSID cookies though, not an authentication token: we need cookies to get a token, in order to get more cookies. Since Android's AccountManager can only give us authentication tokens, and not cookies, this might seem like a hopeless catch-22 situation. However, while browsing the authtokens table of the system's accounts database earlier, we happened to notice that it actually had a bunch of tokens with type SID and LSID. Our next step is, of course, to try to request those tokens via the AccountManager interface, and this happens to work as expected:

    String sid = am.getAuthToken(account, "SID", null, activity, null, null)
    .getResult().getString(AccountManager.KEY_AUTHTOKEN);
    String lsid = am.getAuthToken(account, "LSID", null, activity, null, null)
    .getResult().getString(AccountManager.KEY_AUTHTOKEN);

    Having gotten those, the rest is just a matter of issuing two HTTP requests (error handling omitted for brevity):

    String TARGET_URL = "https://play.google.com/apps/publish/v2/";
    Uri ISSUE_AUTH_TOKEN_URL =
    Uri.parse("https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false");
    Uri TOKEN_AUTH_URL = Uri.parse("https://www.google.com/accounts/TokenAuth");

    String url = ISSUE_AUTH_TOKEN_URL.buildUpon().appendQueryParameter("SID", sid)
    .appendQueryParameter("LSID", lsid)
    .build().toString();
    HttpPost getUberToken = new HttpPost(url);
    HttpResponse response = httpClient.execute(getUberToken);
    String uberToken = EntityUtils.toString(entity, "UTF-8");
    String getCookiesUrl = TOKEN_AUTH_URL.buildUpon()
    .appendQueryParameter("source", "android-browser")
    .appendQueryParameter("auth", authToken)
    .appendQueryParameter("continue", TARGET_URL)
    .build().toString();
    HttpGet getCookies = new HttpGet(getCookiesUrl);
    response = httpClient.execute(getCookies);

    CookieStore cookieStore = httpClient.getCookieStore();
    // check for service-specific session cookie
    String adCookie = findCookie(cookieStore.getCookies(), "AD");
    // fail if not found, otherwise get page content
    String responseStr = EntityUtils.toString(entity, "UTF-8");

    This lets us authenticate to the Android Developer Console (version 2) site without requiring user credentials and we can easily proceed to parse the result and use it in a native app (warning: work in progress!) from here. The downside is that for this to work, the user has to grant access twice, for two cryptically looking token types (SID and LSID).

    Of course, after writing all of this, it turns out that the stock Android browser already has code that does it, which we could have used or at least referenced from the very beginning. Better yet, this find leads us to an yet easier way to accomplish our task. 

    The easy way

    The easy way is found right next to the Browser class referenced above, in the DeviceAccountLogin class, so we can't really take any credit for this. It is hardly anything new, but some Googling suggests that it is neither widely known nor used much. You might have noticed that the Android browser is able to silently log you in to Gmail and friends, when you use the mobile site. The way this is implemented is via the 'magic' token type 'weblogin:'. If you use it along with the service name and URL of the site you want to access, it will do all of the steps listed above automatically and instead of a token will give you a full URL you can load to get automatically logged in to your target service. This magic URL is in the format shown below, and includes both the ubertoken and the URL of the target site, as well as the service name (this example is for the Android Developer Console, line is broken for readability):

    https://accounts.google.com/MergeSession?args=service%3Dandroiddeveloper%26continue
    %3Dhttps://play.google.com/apps/publish/v2/&uberauth=APh...&source=AndroidWebLogin

    Here's how to get the MergeSession URL:

    String tokenType = "weblogin:service=androiddeveloper&"
    + "continue=https://play.google.com/apps/publish/v2/";
    String loginUrl = accountManager.getAuthToken(account,tokenType, false, null, null)
    .getResult().getString(AccountManager.KEY_AUTHTOKEN);

    This is again for the Developer Console, but works for any Google site, including Gmail, Calendar and even the account management page. The only problem you might have is finding the service name, which is hardly obvious in some cases (e.g., 'grandcentral' for Google Voice and 'lh2' for Picasa).

    It takes only a single HTTP request form Android to get the final URL, which tells us that the token issuing flow is implemented on the server side. This means that you can also use the Google Play Services client library to issue a weblogin: 'token' (see screenshot below and note that unlike for OAuth 2.0 scopes, it shows the 'raw' token type). Probably goes without saying, but it also means that if you happen to come across someone's accounts.db file, all it takes to log in into their Google account(s) is two HTTPS requests: one to get the MergeSession URL, and one to log in to their accounts page. If you are thinking 'This doesn't affect me, I use Google two-factor authentication (2FA)!', you should know that in this case 2FA doesn't really help. Why? Because since Android doesn't support 2FA, to register an account with the AccountManager you need to use an application specific password (Update: On ICS and later, GLS will actually show a WebView and let you authenticate using your password and OTP. However, the OTP is not required once you get the master token). And once you have entered one, any tokens issued based on it, will just work (until you revoke it), without requiring entering an additional code. So if you value your account, keep your master tokens close and revoke them as soon as you suspect that your phone might be lost or stolen. Better yet, consider a solution that lets you wipe it remotely (which might not work after your revoke the tokens, so be sure to check how it works before you actually need it).


    As we mentioned above, this is all ClientLogin based, which is officially deprecated, and might be going away soon (EOL scheduled for April 2013). But some of the Android Google data sync feeds still depend on ClientLogin, so if you use it you would probably OK for a while. Additionally, since the weblogin: implementation is server-based, it might be updated to conform with the latest (OAuth 2.0-based?) infrastructure without changing the client-side interface. In any case, watch the Android Browser and Chormium code to keep up to date.

    Summary

    Google offers multiple online services, some with both a traditional browser-based interface and a developer-oriented API. Consequently, there are multiple ways to authenticate to those, ranging from form-based username and password login to authentication API's such as ClientLogin and OAuth 2.0. It is relatively straightforward to get an authentication token for services with a public API on Android, either using Android's native AccountManager interface or the newer Google Play Services extension. Getting the required session cookies to login automatically to the Web sites of services that do not offer an API is however neither obvious, nor documented. Fortunately, it is possible and very easy to do if you combine the special 'weblogin:' token type with the service name and the URL of the site you want to use. The best available documentation about this is the Android Browser source code, which uses the same techniques to automatically log you in to Google sites using the account(s) already registered on your device.

    Moral of the story: interoperability is so much easier when you control all parties involved.

    Monday 5 November 2012

    Our recent posts covered NFC and the secure element as supported in recent Android versions, including community ones. In this two-part series we will take a completely different direction: managing online user accounts and accessing Web services. We will briefly discuss how Android manages user credentials and then show how to use cached authentication details to log in to most Google sites without requiring additional user input. Most of the functionality we shall discuss is hardly new -- it has been available at least since Android 2.0. But while there is ample documentation on how to use it, there doesn't see to be a 'bigger picture' overview of how the pieces are tied together. This somewhat detailed investigation was prompted by trying to develop an app for a widely used Google service that unfortunately doesn't have an official API and struggling to find a way to login to it using cached Google credentials. More on this in the second part, let's first see how Android manages accounts for online services.

    Android account management

    Android 2.0 (API Level 5, largely non-existent, because it was quickly succeeded by 2.0.1, Level 6), introduced the concept of centralized account management with a public API. The central piece in the API is the AccountManager class which, quote: 'provides access to a centralized registry of the user's online accounts. The user enters credentials (user name and password) once per account, granting applications access to online resources with "one-click" approval.' You should definitely read the full documentation of the class, which is quite extensive, for more details. Another major feature of the class is that it lets you get an authentication token for supported accounts, allowing third party applications to authenticate to online services without needing to handle the actual user password (more on this later). It also has a whole of 5 methods that allow you to get an authentication token, all but one with at least 4 parameters, so finding the one you need might take some time, with yet some more to get the parameters right. It might be a good idea to start with the synchronous blockingGetAuthToken() and work your way from there once you have a basic working flow. On some older Android versions, the AccountManager would also monitor your SIM card and wipe cached credentials if you swapped cards, but fortunately this 'feature' has been removed in Android 2.3.4.

    The AccountManager, as most Android system API's, is just a facade for the AccountManagerService which does the actual work. The service doesn't provide an implementation for any particular form of authentication though. It only acts as a coordinator for a number of pluggable authenticator modules for different account types (Google, Twitter, Exchange, etc.). The best part is that any application can register an authentication module by implementing an account authenticator and related classes, if needed. Android Training has a tutorial on the subject that covers the implementation details, so we will not discuss them here. Registering a new account type with the system lets you take advantage of a number of Android infrastructure services:
    • centralized credential storage in a system database
    • ability to issue tokens to third party apps
    • ability to take advantage of Android's automatic background synchronization
    One thing to note is that while credentials (usually user names and passwords) are stored in a central database (/data/system/accounts.db or /data/system/user/0/accounts.db on Jelly Bean and later for the first system user), that is only accessible to system applications, credentials are in no way encrypted -- that is left to the authentication module to implement as necessary. If you have a rooted device (or use the emulator) listing the contents of the accounts table might be quite instructive: some of your passwords, especially for the stock Email application, will show up in clear text. While the AccountManger has a getPassword() method, it can only be used by apps with the same UID as the account's authenticator, i.e., only by classes in the same app (unless you are using sharedUserId, which is not recommended for non-system apps). If you want to allow third party applications to authenticate using your custom accounts, you have to issue some sort of authentication token, accessible via one of the many getAuthToken() methods. Once your account is registered with Android, if you implement an additional sync adapter, you can register to have it called at a specified interval and do background syncing for you app (one- or two-way), without needing to manage scheduling yourself. This is a very powerful feature that you get practically for free, and probably merits its own post. As we now have a basic understanding of authentication modules, let's see how they are used by the system.

    As we mentioned above, account management is coordinated by the AccountManagerService. It is a fairly complex piece of code (about 2500 lines in JB), most of the complexity stemming from the fact that it needs to communicate with services and apps that span multiple processes and threads within each process, and needs to take care of synchronization and delivering results to the right thread. If we abstract out the boilerplate code, what it does on a higher level is actually fairly straightforward:
    • on startup it queries the PackageManager to find out all registered authenticators, and stores references to them in a map, keyed by account type
    • when you add an account of a particular type, it saves its type, username and password to the accounts table
    • if you get, set or reset the password for an account, it accesses or updates the accounts table accordingly
    • if you get or set user data for the account, it is fetched from or saves to the extras table
    • when you request a token for a particular account, things become a bit more interesting:
      • if a token with the specified type has never been issued before, it shows a confirmation activity asking (see screenshot below) the user to approve access for the requesting application. If they accept, the UID of the requesting app and the token type are saved to the grants table.
      • if a grant already exits, it checks the authtoken table for tokens matching the request. If a valid one exists, it is returned.
      • if a matching token is not found, it finds the authenticator for the specified account type in the map and calls its getAuthToken() method to request a token. This usually involves the authenticator fetching the username and password from the accounts table (via the getPassword() method) and calling its respective online service to get a fresh token. When one is returned, it gets cached in the authtokens table and then returned to the requesting app (usually asynchronously via a callback).
    • if you invalidate a token, it gets deleted from the authtokens table

    Now that we know how Android's account management system works, let's see how it is implemented for the most widely used account type.

    Google account management

      Usually the first thing you do when you turn on your brand new (or freshly wiped) 'Google Experience' Android device is to add a Google account. Once you authenticate successfully, you are offered to sync data from associated online services (GMail, Calendar, Docs, etc.) to your device. What happens behinds the scenes is that an account of type 'com.google' is added via the AccountManager, and a bunch of Google apps start getting tokens for the services they represent. Of course, all of this works with the help of an authentication provider for Google accounts. Since it plugs in the standard account management framework, it works by registering an authenticator implementation and using it involves the sequence outlined above. However, it is also a little bit special. Three main things make it different:
      • it is not part of any particular app you can install, but is bundled with the system
      • a lot of the actual functionality is implemented on the server side
      • it does not store passwords in plain text on the device
      If you have ever installed a community ROM built off AOSP code, you know that in order to get GMail and other Google apps to work on your device, you need a few bits not found in AOSP. Two of the required pieces are the Google Services Framework (GSF) and the Google Login Service (GLS). The former provides common services to all Google apps such as centralized settings and feature toggle management, while the latter implements the authentication provider for Google accounts and will be the topic of this section.

      Google provides a multitude of online services (not all of which survive for long), and consequently a bunch of different methods to authenticate to those. Android's Google Login Service, however doesn't call those public authentication API's directly, but via a dedicated online service, which lives at android.clients.google.com. It has endpoints both for authentication and authorization token issuing, as well as data feed (mail, calendar, etc.) synchronization, and more. As we shall see, the supported methods of authentication are somewhat different from those available via other public Google authentication API's. Additionally, it supports a few 'special' token types that greatly simplify some complex authentication flows.

      All of the above is hardly surprising: when you are dealing with online services it is only natural to have as much as possible of the authentication logic on the server side, both for ease of maintenance and to keep it secure. Still, to kick start it you need to store some sort of credentials on the device, especially when you support background syncing for practically everything and you cannot expect people to enter them manually. On-device credential management is one of the services GLS provides, so let's see how it is implemented. As mentioned above, GLS plugs into the system account framework, so cached credentials, tokens and associated extra data are stored in the system's accounts.db database, just as for other account types. Inspecting it reveals that Google accounts have a bunch of Base64-encoded strings associated with them. One of the user data entries (in the extras table) is helpfully labeled sha1hash (but does not exist on all Android versions) and the password (in the accounts table) is a long string that takes different formats on different Android versions. Additionally, the GSF database has a google_login_public_key entry, which when decoded suspiciously resembles a 1024-bit RSA public key. Some more experimentation reveals that credential management works differently on pre-ICS and post-ICS devices. On pre-ICS devices, GLS stores an encrypted version of your password and posts it to the server side endpoints both when authenticating for the first time (when you add the account) and when it needs to have a token for a particular service issued. On post-ICS devices, it only posts the encrypted password the first time, and gets a 'master token' in exchange, which is then stored on the device (in the password column of the accounts database). Each subsequent token request uses that master token instead of a password.

      Let's look into the cached credential strings a bit more. The encrypted password is 133 bytes long, and thus it is a fair bet that it is encrypted with the 1024-bit (128 bytes) RSA public key mentioned above, with some extra data appended. Adding multiple accounts that use the same password produces different password strings (which is a good thing), but the first few bytes are always the same, even on different devices. It turns out those identify the encryption key and are derived by hashing its raw value and taking the leading bytes of the resulting hash. At least from our limited sample of Android devices, it would seem that the RSA public key used is constant both across Android versions and accounts. We can safely assume that its private counterpart lives on the server side and is used to decrypt sent passwords before performing the actual authentication. The padding used is OAEP (with SHA1 and MGF1), which produces random-looking messages and is currently considered secure (at least when used in combination with RSA) against most advanced cryptanalysis techniques. It also has quite a bit of overhead, which in practice means that the GLS encryption scheme can encrypt at most 86 bytes of data. The outlined encryption scheme is not exactly military-grade and there is the issue of millions of devices most probably using the same key, but recovering the original password should be sufficiently hard to discourage most attackers. However, let's not forget that we also have a somewhat friendlier SHA1 hash available. It turns out it can be easily reproduced by 'salting' the Google account password with the account name (typically GMail address) and doing a single round of SHA1. This is considerably easier to do and it wouldn't be too hard to precompute a bunch of hashes based on commonly used or potential passwords if you knew the target account name.

      Fortunately, newer version of Android (4.0 and later) no longer store this hash on the device. Instead of the encrypted password+SHA1 hash combination they store an opaque 'master token' (most probably some form of OAuth token) in the password column and exchange it for authentication tokens for different Google services. It is not clear whether this token ever expires or if it is updated automatically. You can, however, revoke it manually by going to the security settings of your Google account and revoking access for the 'Android Login Service' (and a bunch of other stuff you never use while you are at it). This will force the user to re-authenticate on the device next time it tries to get a Google auth token, so it is also somewhat helpful if you ever lose your device and don't want people accessing your email, etc. if they manage to unlock it. The service authorization token issuing protocol uses some device-specific data in addition to the master token, so obtaining only the master token should not be enough to authenticate and impersonate a device (it can however be used to login into your Google account on the Web, see the second part for details).

      Google Play Services

      Google Play Services (we'll abbreviate it to GPS, although the actual package is com.google.android.gms, guess where the 'M' came from) was announced at this year's Google I/O as an easy to use platform that offers integration with Google products for third-party Android apps. It was actually rolled out only a month ago, so it's probably not very widely used yet. Currently it provides support for OAuth 2.0 authorization to Google API's 'with a good user experience and security', as well some Google+ plus integration (sign-in and +1 button). Getting OAuth 2.0 tokens via the standard AccountManager interface has been supported for quite some time (though support was considered 'experimental') by using the special 'oauth2:scope' token type syntax. However, it didn't work reliably across different Android builds, which have different GLS versions bundled and this results in slightly different behaviour. Additionally, the permission grant dialog shown when requesting a token was not particularly user friendly, because it showed the raw OAuth 2.0 scope in some cases, which probably means little to most users (see screenshot in the first section). While some human-readable aliases for certain scopes where introduced (e.g., 'Manage your taks' for 'oauth2:https://www.googleapis.com/auth/tasks'), that solution was neither ideal, nor universally available. GPS solves this by making token issuing a two-step process (newer GLS versions also use this process):
      1. the first request is much like before: it includes the account name, master token (or encrypted password pre-ICS) and requested service, in the 'oauth2:scope' format. GPS adds two new parameters: requesting app package name and app signing certificate SHA1 hash (more on this later). The response includes some human readable details about the requested scope and requesting application, which GPS shows in a permission grant dialog like the one shown below.
      2. if the users grants the permission, this decision is recorded in the extras table in a proprietary format which includes the requesting app's package name, signing certificate hash, OAuth 2.0 scope and grant time (note that it is not using the grants table). GPS then resends the authorization request setting the has_permission parameter to 1. On success this results in an OAuth 2.0 token and its expiry date in the response. Those are cached in the authtokens table in a similar format.

      To be able to actually use a Google API, you need to register your app's package name and signing key in Google's API console. The registration lets services validating the token query Google what app the token was issued for, and thus identify the calling app. This has one subtle, but important side-effect: you don't have to embed an API key in your app and send it with every request. Of course, for a third party published app you can easily find out both the package name and the signing certificate so it is not particularly hard to get a token issued in the name of some other app (not possible via the official API, of course). We can assume that there are some additional checks on the server side that prevent this, but theoretically, if you used such a token you could, for example, exhaust a third-party app's API request quota by issuing a bunch of requests over a short period of time. 

      The actual GPS implementation seems to reuse much of the original Google Login Service authentication logic, including the password encryption method, which is still used on pre-ICS devices (the protocol is, after all, mostly the same and it needs to be able to use pre-existing accounts). On top of that it adds better OAuth 2.0 support, a version-specific account selection dialog and some prettier and more user friendly permission grant UIs. The GPS app has the Google apps shared UID, so it can directly interact with other proprietary Google services, including GLS and GSF. This allows it, among other things, to directly get and write Google account credentials and tokens to the accounts database. As can be expected, GPS runs in a remote service that the client library you link into your app accesses. The major selling point against the legacy AccountManager API is that while its underlying authenticator modules (GLS and GSF) are part of the system, and as such cannot be updated without an OTA, GPS is an user-installable app that can be easily updated via Google Play. Indeed, it is advertised as auto-updating (much like the Google Play Store client), so app developers presumably won't have to rely on users to update it if they want to use newer features (unless GPS is disabled altogether, of course). This update mechanism is to provide 'agility in rolling out new platform capabilities', but considering how much time the initial roll-out took, it is to be seen how agile the whole thing will turn out to be. Another thing to watch out for is feature bloat: besides OAuth 2.0 support, GPS currently includes G+ and AdMob related features, and while both are indeed Google-provided services, they are totally unrelated. Hopefully, GPS won't turn into a 'everything Google plus the kitchen sink' type of library, delaying releases even more. With all that said, if your app uses OAuth 2.0 tokens to authenticate to Google API's, which is currently the preferred method (ClientLogin, OAuth 1.0 and AuthSub have been officially deprecated), definitely consider using GPS over 'raw' AccountManager access.

      Summary

      Android provides a centralized registry of user online accounts via the AccountManager class. It lets you both get tokens for existing accounts without having to handle the actual credentials and register your own account type, if needed. Registering an account type gives you access to powerful system features, such as authentication token caching and automatic background synchronization. 'Google experience' devices come with built-in support for Google accounts, which lets third party apps access Google online services without needing to directly request authentication information from the user. The latest addition to this infrastructure is the recently released Google Play Services app and companion client library, which aim to make it easy to use OAuth 2.0 from third party applications. 

      We've now presented an overview of how the account management system works, and the next step is to show how to actually use it to access a real online service. That will be the topic of the second article in the series. 

      Tuesday 2 October 2012

      We discussed the embedded secure element available in recent Android devices, it's execution environment and how Google Wallet makes use if it in the last series of articles. We also saw that unless you have a contract with Google and have them (or the TSM they use) distribute your applets to supported devices, there is currently no way to install anything on the embedded secure element. We briefly mentioned that CyanogenMod 9.1 supports software card emulation and it is a more practical way to create your own NFC-enabled applications. We'll now see how software card emulation works and show how you can use it to create a simple PKI 'applet' that can be accessed via NFC from any machine with a contactless card reader.

      Software card emulation

      We already know that if the embedded secure element is put in virtual mode it is visible to external readers as a contactless smartcard. Software card emulation (sometimes referred to as Host Card Emulation or HCE) does something very similar, but instead of routing commands received by the NFC controller to the SE, it delivers them to the application processor, and they can be processed by regular applications. Responses are then sent via NFC to the reader, and thus your app takes the role of a virtual contactless 'smartcard' (refer to this paper for a more thorough discussion).  Software card emulation is currently available on BlackBerry phones, which offer standard APIs for apps to register with the OS and process card commands received over NFC. Besides a BlackBerry device, you can use some contactless  readers in emulation mode to emulate NFC tags or a full-featured smart card. Stock Android doesn't (yet) support software card emulation, even though the NFC controllers in most current phones have this capability. Fortunately, recent version of CyanogenMod integrate a set of patches that unlock this functionality of the PN544 NFC controller found in recent Nexus (and other) devices. Let's see how it works in a bit more detail.

      CyanogenMod implementation

      Android doesn't provide a direct interface to its NFC subsystem to user-level apps. Instead, it leverages the OS's intent and intent filter infrastructure to let apps register for a particular NFC event (ACTION_NDEF_DISCOVERED, ACTION_TAG_DISCOVERED and ACTION_TECH_DISCOVERED) and specify additional filters based on tag type or features. When a matching NFC tag is found, interested applications are notified and one of them is selected to handle the event, either by the user or automatically if it is in the foreground and has registered for foreground dispatch. The app can then access a generic Tag object representing the target NFC device and use it to retrieve a concrete tag technology interface such as MifareClassic or IsoDep that lets it communicate with the device and use its native features. Card emulation support in CyanogenMod doesn't attempt to change or amend Android's NFC architecture, but integrates with it by adding support for two new tag technologies: IsoPcdA and IsoPcdB. 'ISO' here is the International Organization for Standardization, which among other things, is responsible for defining NFC communication standards. 'PCD' stands for Proximity Coupling Device, which is simply ISO-speak for a contactless reader. The two classes cover the two main NFC flavours in use today (outside of Japan, at least) -- Type A (based on NXP technology) and Type B (based on Motorolla technology). As you might have guessed by now, the patch reverses the usual roles in the Android NFC API: the external contactless reader is presented as a 'tag', and 'commands' you send from the phone are actually replies to the reader-initiated communication. If you have Google Wallet installed the embedded secure element is activated as well, so touching the phone to a reader would produce a potential conflict: should it route commands to the embedded SE or to applications than can handle IsoPcdA/B tags? The CyanogenMod patch handles this by using Android's native foreground dispatch mechanism: software card emulation is only enabled for apps that register for foreground dispatch of the relevant tag technologies. So unless you have an emulation app in the foreground, all communication would be routed to Google Wallet (i.e., the embedded SE). In practice though, starting up Google Wallet on ROMs with the current version of the patch might block software card emulation, so it works best if Google Wallet is not installed. A fix is available, but not yet merged in CyanogenMod master (Updated: now merged, should roll out with CM10 nightlies) .

      Both of the newly introduced tag technologies extend BasicTagTechnology and offer methods to open, check and close the connection to the reader. They add a public transceive() method that acts as the main communication interface: it receives reader commands and sends the responses generated by your app to the PCD. Here's a summary of the interface:

      abstract class BasicTagTechnology implements TagTechnology {
      public boolean isConnected() {...}

      public void connect() throws IOException {...}

      public void reconnect() throws IOException {...}

      public void close() throws IOException {...}

      byte[] transceive(byte[] data, boolean raw) throws IOException {...}
      }

      Now that we know (basically) how it works, let's try to use software card emulation in practice.

      Emulating a contactless card

      As discussed in the previous section, to be able to respond to reader commands we need to register our app for one of the PCD tag technologies and enable foreground dispatch. This is no different than handling stock-supported  NFC technologies. We need to add an intent filter and a reference to a technology filter file to the app's manifest:

      <activity android:label="@string/app_name" 
      android:launchmode="singleTop"
      android:name=".MainActivity"
      <intent-filter>
      <action android:name="android.nfc.action.TECH_DISCOVERED" />
      </intent-filter>

      <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
      android:resource="@xml/filter_nfc" />
      </activity>

      We register the IsoPcdA tag technology in filter_nfc.xml:

      <resources>
      <tech-list>
      <tech>android.nfc.tech.IsoPcdA</tech>
      </tech-list>
      </resources>

      And then use the same technology list to register for foreground dispatch in our activity:

      public class MainActivity extends Activity {

      public void onCreate(Bundle savedInstanceState) {
      pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
      getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
      filters = new IntentFilter[] { new IntentFilter(
      NfcAdapter.ACTION_TECH_DISCOVERED) };
      techLists = new String[][] { { "android.nfc.tech.IsoPcdA" } };
      }

      public void onResume() {
      super.onResume();
      if (adapter != null) {
      adapter.enableForegroundDispatch(this, pendingIntent, filters,
      techLists);
      }
      }

      public void onPause() {
      super.onPause();
      if (adapter != null) {
      adapter.disableForegroundDispatch(this);
      }
      }

      }

      With this in place, each time the phone is touched to an active reader, we will get notified via the activity's onNewIntent() method. We can get a reference to the Tag object using the intent's extras as usual. However, since neither IsoPcdA nor its superclass are part of the public SDK, we need to either build the app as part of CyanogenMod's source, or, as usual, resort to reflection. We choose to create a simple wrapper class that calls IsoPcdA methods via reflection, after getting an instance using the static get() method like this:

      Class cls = Class.forName("android.nfc.tech.IsoPcdA");
      Method get = cls.getMethod("get", Tag.class);
      // this returns an IsoPcdA instance
      tagTech = get.invoke(null, tag);

      Now after we connect() we can use the transceive() method to reply to reader commands. Note that since the API is not event-driven, you won't get notified with the reader command automatically. You need to send a dummy payload to retrieve the first reader command APDU. This can be a bit awkward at first, but you just have to keep in mind that each time you call transceive() the next reader command comes in via the return value. Unfortunately this means that after you send your last response, the thread will block on I/O waiting for transceive() to return, which only happens after the reader sends its next command, which might be never. The thread will only stop if an exception is thrown, such as when communication is lost after separating the phone from the reader. Needless to say, this makes writing robust code a bit tricky. Here's how to start off the communication:

      // send dummy data to get first command APDU
      // at least two bytes to keep smartcardio happy
      byte[] cmd = transceive(new byte[] { (byte) 0x90, 0x00 });

      Writing a virtual PKI applet

      Software card emulation in CyanogneMod is limited to ISO 14443-4 (used mostly for APDU-based communication), which means that you cannot emulate cards that operate on a lower-level protocol such as MIFARE Classic. This leaves out opening door locks that rely on the card UID with your phone (the UID of the emulated card is random) or getting a free ride on the subway (you cannot clone a traffic card with software alone), but allows for emulating payment (EMV) cards which use an APDU-based protocol. In fact, the first commercial application (company started by patch author Doug Yeagerthat makes use of Android software card emulation, Tapp, emulates a contactless Visa card and does all necessary processing 'in the cloud', i.e., on a remote server. Payment applications are the ones most likely to be developed using software card emulation because of the potentially higher revenue: at least one other company has announced that it is building a cloud-based NFC secure element. We, however, will look at a different use case: PKI.

      PKI has been getting a lot of bad rep due to major CAs getting compromised every other month, and it has been stated multiple times that it doesn't really work on the Internet. It is however still a valid means of authentication in a corporate environment where personal certificates are used for anything from desktop login to remote VPN access. Certificates and associated private keys are often distributed on smart cards, sometimes contactless or dual-interface. Since Android now has standard credential storage which can be protected by hardware on supported devices, we could use an Android phone with software card emulation in place of a PKI card. Let's try to write a simple PKI 'applet' and an associated host-side client application to see if this is indeed feasible.

      A PKI JavaCard applet can offers various features, but the essential ones are:
      • generating or importing keys
      • importing a public key certificate
      • user authentication (PIN verification)
      • signing and/or encryption with card keys
      Since we will be using Android's credential storage to save keys and certificates, we already have the first two features covered. All we need to implement is PIN verification and signing (which is actually sufficient for most applications, including desktop login and SSL client authentication). If we were building a real solution, we would implement a well known applet protocol, such as one of a major vendor or an open one, such as the MUSCLE card protocol, so that we can take advantage of desktop tools and cryptographic libraries (Windows CSPs and PKCS#11 modules, such as OpenSC). But since this is a proof-of-concept exercise, we can get away by defining our own mini-protocol and only implement the bare minimum. We define the applet AID (quite arbitrary, and may be in already in use by someone else, but there is really no way to check) and two commands: VERIFY PIN and SIGN DATA. The protocol is summarized in the table below:

      Virtual PKI applet protocol
      CommandCLAINSP1P2LcDataResponse
      SELECT00A4040006AID: A00000000101109000/6985/6A82/6F00
      VERIFY PIN8001XXXXPIN length (bytes)PIN characters (ASCII)9000/6982/6985/6F00
      SIGN DATA8002XXXXSigned data length (bytes)Signed data9000+signature bytes/6982/6985/6F00

      The applet behaviour is rather simple: it returns a generic error if you try to send any commands before selecting it, and then requires you to authenticate by verifying the PIN before signing data. To implement the applet, we first handle new connections from a reader in the main activity's onNewIntent() method, where we receive an Intent containing a reference to the IsoPcdA object we use to communicate with the PCD. We verify that the request comes from a card reader, create a wrapper for the Tag object, connect() to the reader and finally pass control to the PkiApplet by calling it's start() method.

      Tag tag = (Tag) intent.getExtras().get(NfcAdapter.EXTRA_TAG);
      List techList = Arrays.asList(tag.getTechList());
      if (!techList.contains("android.nfc.tech.IsoPcdA")) {
      return;
      }

      TagWrapper tw = new TagWrapper(tag, "android.nfc.tech.IsoPcdA");
      if (!tw.isConnected()) {
      tw.connect();
      }

      pkiApplet.start(tw);

      The applet in turn starts a background thread that reads commands until available and exits if communication with the reader is lost. The implementation is not terribly robust, but is works well enough for our POC:

      Runnable r = new Runnable() {
      public void run() {
      try {
      // send dummy data to get first command APDU
      byte[] cmd = transceive(new byte[] { (byte) 0x90, 0x00 });
      do {
      // process commands
      } while (cmd != null && !Thread.interrupted());
      } catch (IOException e) {
      // connection with reader lost
      return;
      }
      }
      };

      appletThread = new Thread(r);
      appletThread.start();


      Before the applet can be used it needs to be 'personalized'. In our case this means importing the private key the applet will use for signing and setting a PIN. To initialize the private key we import a PKCS#12 file using the KeyChain API and store the private key alias in shared preferences. The PIN is protected using 5000 iterations of PBKDF2 with a 64-bit salt. We store the resulting PIN hash and the salt in shared preferences as well and repeat the calculation against the PIN we receive from applet clients to check if it matches. This avoids storing the PIN in clear text, but keep in mind that a short numeric-only PIN can be brute-forced in minutes (the app doesn't restrict PIN size, it can be up to 255 characters (bytes), the maximum size of APDU data). Here's how our 'personalization' UI looks like:


      To make things simple, applet clients send the PIN in clear text, so it could theoretically be sniffed if NFC traffic is intercepted. This can be avoided by using some sort of a challenge-response mechanism, similar to what 'real' (e.g., EMV) cards do. Once the PIN is verified, clients can send the data to be signed and receive the signature bytes in the response. Since the size of APDU data is limited to 255 bytes (due to the single byte length field) and the applet doesn't support any sort of chaining, we are limited to using RSA keys up to 1024 bits long (a 2048-bit key needs 256 bytes). The actual applet implementation is quite straightforward: it does some minimal checks on received APDU commands, gets the PIN or signed data and uses it to execute the corresponding operation. It then selects a status code based on operation success or failure and returns it along with the result data in the response APDU. See the source code for details.

      Writing a host-side applet client

      Now that we have an applet, we need a host-side client to actually make use of it. As we mentioned above, for a real-world implementation this would be a standard PKCS#11 or CSP module for the host operating system that plugs into PKI-enabled applications such as browsers or email and VPN clients. We'll however create our own test Java client using the Smart Card I/O API (JSR 268). This API comes with Sun/Oracle Java SDKs since version 1.6 (Java 6), but is not officially a part of the SDK, because it is apparently not 'of sufficiently wide interest' according to the JSR expert group (committee BS at its best!). Eclipse goes as far as to flag it as a 'forbidden reference API', so you'll need to change error handling preferences to compile in Eclipse. In practice though, JSR 268 is a standard API that works fine on Windows, Solaris, Linux an Mac OS X (you may have to set the sun.security.smartcardio.library system property to point to your system's PC/SC library), so we'll use it for our POC application. The API comes with classes representing card readers, the communication channel and command and response APDUs. After we get a reference to a reader and then a card, we can create a channel and exchange APDUs with the card. Our PKI applet client is a basic command line program that waits for card availability and then simply sends the SELECT, VERIFY PIN and SIGN DATA commands in sequence, bailing out on any error (card response with status different from 0x9000). The PIN is specified in the first command line parameter and if you pass a certificate file path as the second one, it will use it to verify the signature it gets from the applet. See full code for details, but here's how to connect to a card and send a command:

      TerminalFactory factory = TerminalFactory.getDefault();
      CardTerminals terminals = factory.terminals();

      Card card = waitForCard(terminals);
      CardChannel channel = card.getBasicChannel();
      CommandAPDU cmd = new CommandAPDU(CMD);
      ResponseAPDU response = channel.transmit(cmd);

      Card waitForCard(CardTerminals terminals)
      throws CardException {
      while (true) {
      for (CardTerminal ct : terminals
      .list(CardTerminals.State.CARD_INSERTION)) {
      return ct.connect("*");
      }
      terminals.waitForChange();
      }
      }

      And to prove that this all works, here's the output from a test run of the client application:

      $ ./run.sh 1234 mycert.crt 
      Place phone/card on reader to start
      --> 00A4040006A0000000010101
      <-- 9000
      --> 800100000431323334
      <-- 9000
      --> 80020000087369676E206D6521
      <-- 11C44A5448... 9000 (128)

      Got signature from card: 11C44A5448...
      Will use certificate from 'mycert.crt' to verify signature
      Issuer: CN=test-CA, ST=Tokyo, C=JP
      Subject: CN=test, ST=Tokyo, C=JP
      Not Before: Wed Nov 30 00:04:31 JST 2011
      Not After: Thu Nov 29 00:04:31 JST 2012

      Signature is valid: true

      This software implementation comes, of course, with the disadvantage that while the actual private key might be protected by Android's system key store, PIN verification and other operations not directly protected by the OS will be executed in a regular app. An Android app, unlike a dedicated smart card, could be compromised by other (malicious) apps with sufficient privileges. However, since recent Android devices do have (some) support for a Trusted Execution Environment (TEE), the sensitive parts of our virtual applet can be implemented as Trusted Application (TA) running within the TEE. The user-level app would then communicate with the TA using the controlled TEE interface, and the security level of the system could come very close to running an actual applet in a dedicated SE.

      Summary

      Android already supports NFC card emulation using an embedded SE (stock Android) or the UICC (various vendor firmwares). However, both of those are tightly controlled by their owning entities (Google or MNOs), and there is currently no way for third party developers to install applets and create card emulation apps. An alternative to SE-based card emulation is software card emulation, where an user-level app processes reader commands and returns responses via the NFC controller. This is supported by commonly deployed NFC controller chips, but is not implemented in the stock Andorid NFC subsystem. Recent versions of CyanogneMod however do enable it by adding support for two more tag technologies (IsoPcdA and IsoPcdB) that represent contactless readers instead of actual tags. This allows Android applications to emulate pretty much any ISO 14443-4 compliant contactless card application: from EMV payment applications to any custom JavaCard applet. We presented a sample app that emulates a PKI card, allowing you to store PKI credentials on your phone and potentially use it for desktop login or VPN access on any machine equipped with a contacltess reader. Hopefully software card emulation will become a part of stock Android in the future, making this and other card emulation NFC applications mainstream.

      Popular Posts

      Visitors

      Sample Text

      About

      Social Profiles

      Featured Posts Coolbthemes