Showing posts with label nfc. Show all posts
Emulating a PKI smart card with CyanogenMod 9.1
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
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
<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 Yeager) that 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.
- generating or importing keys
- importing a public key certificate
- user authentication (PIN verification)
- signing and/or encryption with card keys
VERIFY PIN
and SIGN DATA
. The protocol is summarized in the table below:Command | CLA | INS | P1 | P2 | Lc | Data | Response |
---|---|---|---|---|---|---|---|
SELECT | 00 | A4 | 04 | 00 | 06 | AID: A0000000010110 | 9000/6985/6A82/6F00 |
VERIFY PIN | 80 | 01 | XX | XX | PIN length (bytes) | PIN characters (ASCII) | 9000/6982/6985/6F00 |
SIGN DATA | 80 | 02 | XX | XX | Signed data length (bytes) | Signed data | 9000+signature bytes/6982/6985/6F00 |
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);
ListtechList = 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();
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 thesun.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
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.
Exploring Google Wallet using the secure element interface
In the first post of this series we showed how to use the embedded secure element interface Android 4.x offers. Next, we used some GlobalPlatform commands to find out more about the SE execution environment in the Galaxy Nexus. We also showed that there is currently no way for third parties to install applets on the SE. Since installing our own applets is not an option, we will now find some pre-installed applets to explore. Currently the only generally available Android application that is known to install applets on the SE is Google's own Google Wallet. In this last post, we'll say a few words about how it works and then try to find out what publicly available information its applets host.
Google Wallet and the SE
To quote the Google Play description, 'Google Wallet holds your credit and debit cards, offers, and rewards cards'. How does it do this in practice though? The short answer: it's slightly complicated. The longer answer: only Google knows all the details, but we can observe a few things. After you install the Google Wallet app on your phone and select an account to use with it, it will contact the online Google Wallet service (previously known as Google Checkout), create or verify your account and then provision your phone. The provisioning process will, among other things, use First Data's Trusted Service Manager (TSM) infrastructure to download, install and personalize a bunch of applets on your phone. This is all done via the Card Manager and the payload of the commands is, of course, encrypted. However, the GP Secure Channel only encrypts the data part of APDUs, so it is fairly easy to map the install sequence on a device modified to log all SE communication. There are three types of applets installed: a Wallet controller applet, a MIFARE manager applet, and of course payment applets that enable your phone to interact with NFC-enabled PayPass terminals.The controller applet securely stores Google Wallet state and event log data, but most importantly, it enables or disables contactless payment functionality when you unlock the Wallet app by entering your PIN. The latest version seems to have the ability to store and verify a PIN securely (inside the SE), however it does not appear it is actually used by the app yet, since the Wallet Cracker can still recover the PIN on a rooted phone. This implies that the PIN hash is still stored in the app's local database.
The MIFARE manager applet works in conjunction with the offers and reward/loyalty cards features of Wallet. When you save an offer or add a loyalty card, the MIFARE manager applet will write block(s) to the emulated MIFARE 4K Classic card to mirror the offer or card on the SE, letting you redeem it by tapping your phone at a NFC-enabled POS terminal. It also keeps an application directory (similar to the standard MIFARE MAD) in the last sectors, which is updated each time you add or remove a card. The emulated MIFARE card uses custom sector protection keys, which are most probably initialized during the initial provisioning process. Therefore you cannot currently read the contents of the MIFARE card with an external reader. However, the encryption and authentication scheme used by MIFARE Classic has been broken and proven insecure, and the keys can be recovered easily with readily available tools. It would be interesting to see if the emulated card is susceptible to the same attacks.
Finally, there should be one or more EMV-compatible payment applets that enable you to pay with your phone at compatible POS terminals. EMV is an interoperability standard for payments using chip cards, and while each credit card company has their proprietary extensions, the common specifications are publicly available. The EMV standard specifies how to find out what payment applications are installed on a contactless card, and we will use that information to explore Google Wallet further later.
Armed with that basic information we can now extend our program to check if Google Wallet applets are installed. Google Wallet has been around for a while, so by now the controller and MIFARE manager applets' AIDs are widely known. However, we don't need to look further than latest AOSP code, since the system NFC service has those hardcoded. This clearly shows that while SE access code is being gradually made more open, its main purpose for now is to support Google Wallet. The controller AID is
A0000004762010
and the MIFARE manager AID is A0000004763030
. As you can see, they start with the same prefix (A000000476
), which we can assume is the Google RID (there doesn't appear to be a public RID registry). Next step is, of course, trying to select those. The MIFARE manager applet responds with a boring 0x9000
status which only shows that it's indeed there, but selecting the controller applet returns something more interesting:6f 0f -- File Control Information (FCI) Template
84 07 -- Dedicated File (DF) Name
a0 00 00 04 76 20 10 (BINARY)
a5 04 -- File Control Information (FCI) Proprietary Template
80 02 -- Response Message Template Format 1
01 02 (BINARY)
The 'File Control Information' and 'Dedicated File' names are file system-based card legacy terms, but the DF (equivalent to a directory) is the AID of the controller applet (which we already know), and the last piece of data is something new. Two bytes looks very much like a short value, and if we convert this to decimal we get '258', which happens to be the controller applet version displayed in the 'About' screen of the current Wallet app ('v258').
Now that we have an app that can check for wallet applets (see sample code, screenshot above), we can verify if those are indeed managed by the Wallet app. It has a 'Reset Wallet' action on the Settings screen, which claims to delete 'payment information, card data and transaction history', but how does it affect the controller applets? Trying to select them after resetting Wallet shows that the controller applet has been removed, while the MIFARE manager applet is still selectable. We can assume that any payment applets have also been removed, but we still have no way to check. This leads us to the topic of our next section:
Exploring Google Wallet EMV applets
'325041592E5359532E444446303131'
in hex. Upon successful selection it returns a TLV data structure that contains the AIDs, labels and priority indicators of available applications (see Book B, 3.3.1 PPSE Data for Application Selection). To process it, we will use and slightly extend the Java EMV Reader library, which does similar processing for contact cards. The library uses the standard Java Smart Card I/O API to communicate with cards, but as we pointed out in the first article, this API is not available on Android. Card communication interfaces are nicely abstracted, so we only need to implement them using Android's native NfcExecutionEnvironment
. The main classes we need are SETerminal
, which creates a connection to the card, SEConnection
to handle the actual APDU exchange, and SECardResponse
to parse the card response into status word and data bytes. As an added bonus, this takes care of encapsulating our uglish reflected code. We also create a PPSE
class to parse the PPSE selection response into its components. With all those in place all we need to do is follow the EMV specification. Selecting the PPSE with the following command works at first try, but produces a response with 0 applications:--> 00A404000E325041592E5359532E4444463031
<-- 6F10840E325041592E5359532E4444463031 9000
response hex :
6f 10 84 0e 32 50 41 59 2e 53 59 53 2e 44 44 46
30 31
response SW1SW2 : 90 00 (Success)
response ascii : o...2PAY.SYS.DDF01
response parsed :
6f 10 -- File Control Information (FCI) Template
84 0e -- Dedicated File (DF) Name
32 50 41 59 2e 53 59 53 2e 44 44 46 30 31 (BINARY)
We have initialized the $10 prepaid card available when first installing Wallet, so something must be there. We know that the controller applet manages payment state, so after starting up and unlocking Wallet we finally get more interesting results (shown parsed and with some bits masked below). It turns out that locking the Wallet up effectively hides payment applications by deleting them from the PPSE. This, in addition to the fact that card emulation is available only when the phone's screen is on, provides better card security than physical contactless cards, some of which can easily be read by simply using a NFC-equipped mobile phone, as has been demonstrated.
Applications (2 found):
Application
AID: a0 00 00 00 04 10 10 AA XX XX XX XX XX XX XX XX
RID: a0 00 00 00 04 (Mastercard International [US])
PIX: 10 10 AA XX XX XX XX XX XX XX XX
Application Priority Indicator
Application may be selected without confirmation of cardholder
Selection Priority: 1 (1 is highest)
Application
AID: a0 00 00 00 04 10 10
RID: a0 00 00 00 04 (Mastercard International [US])
PIX: 10 10
Application Priority Indicator
Application may be selected without confirmation of cardholder
Selection Priority: 2 (1 is highest)
One of the applications is the well known MasterCard credit or debit application, and there is another MasterCard app with a longer AID and higher priority (1, the highest). The recently announced update to Google Wallet allows you to link practically any card to your Wallet account, but transactions are processed by a single 'virtual' MasterCard and then billed back to your actual credit card(s). It is our guess that the first application in the list above represents this virtual card. The next step in the EMV transaction flow is selecting the preferred payment app, but here we hit a snag: selecting each of the apps always fails with the
0x6999
('Applet selection failed') status. It has been reported that this was possible in previous versions of Google Wallet, but has been blocked to prevent relay attacks and stop Android apps from extracting credit card information from the SE. This leaves us with using the NFC interface if we want to find out more.Most open-source tools for card analysis, such as cardpeek and Java EMV Reader were initially developed for contact cards, and therefore need a connection to a PC/SC-compliant reader to operate. If you have a dual interface reader that provides PC/SC drivers you get this for free, but for a standalone NFC reader we need libnfc, ifdnfc and PCSC lite to complete the PC/SC stack on Linux. Getting those to play nicely together can be a bit tricky, but once it's done card tools work seamlessly. Fortunately, selection via the NFC interface is successful and we can proceed with the next steps in the EMV flow: initiating processing by sending the
GET PROCESSING OPTIONS
and reading relevant application data using the READ RECORD
command. For compatibility reasons, EMV payment applications contain data equivalent to that found on the magnetic stripe of physical cards. This includes account number (PAN), expiry date, service code and card holder name. EMV-compatible POS terminals are required to support transactions based on this data only ('Mag-stripe mode'), so some of it could be available on Google Wallet as well. Executing the needed READ RECORD
commands shows that it is indeed found on the SE, and both MasterCard applications are linked to the same mag-stripe data. The data is as usual in TLV format, and relevant tags and format are defined in EMV Book C-2. When parsed it looks like this for the Google prepaid card (slightly masked):Track 2 Equivalent Data:
Primary Account Number (PAN) - 5430320XXXXXXXX0
Major Industry Identifier = 5 (Banking and financial)
Issuer Identifier Number: 543032 (Mastercard, UNITED STATES OF AMERICA)
Account Number: XXXXXXXX
Check Digit: 0 (Valid)
Expiration Date: Sun Apr 30 00:00:00 GMT+09:00 2017
Service Code - 101:
1 : Interchange Rule - International interchange OK
0 : Authorisation Processing - Normal
1 : Range of Services - No restrictions
Discretionary Data: 0060000000000
As you can see, it does not include the card holder name, but all the other information is available, as per the EMV standard. We even get the 'transaction in progress' animation on screen while our reader is communicating with Google Wallet. We can also get the PIN try counter (set to 0, in this case meaning disabled), and a transaction log in the format shown below. We can't verify if the transaction log is used though, since Google Wallet, like a lot of the newer Google services, happens to be limited to the US .
Transaction Log:
Log Format:
Cryptogram Information Data (1 byte)
Amount, Authorised (Numeric) (6 bytes)
Transaction Currency Code (2 bytes)
Transaction Date (3 bytes)
Application Transaction Counter (ATC) (2 bytes)
This was fun, but it doesn't really show much besides the fact that Google Wallet's virtual card(s) comply with the EMV specifications. What is more interesting is that the controller applet APDU commands that toggle contactless payment and modify the PPSE don't require additional application authentication and can be issued by any app that is whitelisted to use the secure element. The controller applet most probably doesn't store any really sensitive information, but while it allows its state to be modified by third party applications, we are unlikely to see any other app besides Google Wallet whitelsited on production devices. Unless of course more fine-grained SE access control is implemented in Android.
Fine-grained SE access control
This fact that Google Wallet state can be modified by third party apps (granted access to the SE, of course) leads us to another major complication with SE access on mobile devices. While the data on the SE is securely stored and access is controlled by the applets that host it, once an app is allowed access, it can easily perform a denial of service attack against the SE or specific SE applications. Attacks can range from locking the whole SE by repeatedly executing failed authentication attempts until the Card Manager is blocked (a GP-compliant card goes into the TERMINATED state usually after 10 unsuccessful tries), to application-specific attacks such as blocking a cardholder verification PIN or otherwise changing a third party applet state. Another more sophisticated, but harder to achieve and possible only on connected devices, attack is a relay attack. In this attack, the phone's Internet connection is used to receive and execute commands sent by another remote phone, enabling the remote device to emulate the SE of the target device without physical proximity. The way to mitigate those attacks is to exercise finer control on what apps that access the SE can do by mandating that they can only select specific applets or only send a pre-approved list of APDUs. This is supported by JSR-177 Security and Trust Servcies API which only allows connection to one specific applet and only grants those to applications with trusted signature (currently implemented in BlackBerry 7 API). JSR-177 also provides the ability to restrict APDUs by matching them against an APDU mask to determine whether they should be allowed or not. SEEK for Android goes on step further than BlackBerry by supporting fine-grained access control with access policy stored on the SE. The actual format of ACL rules and protocols for managing them are defined in GlobalPlatform Secure Element Access Control standard, which is relatively new (v.1.0 released on May 2012). As we have seen, the current (4.0 and 4.1) stock Android versions do restrict access to the SE to trusted applications by whitlisting their certificates (a hash of those would have probably sufficed) in/etc/nfcee_access.xml
, but once an app is granted access it can select any applet and send any APDU to the SE. If third party apps that use the SE are to be allowed in Android, more fine-grained control needs to be implemented by at least limiting the applets SE-whitelisted Android apps can select.Because for most applications the SE is used in conjunction with NFC, and SE app needs to be notified of relevant NFC events such as RF field detection or applet selection via the NFC interface. Disclosure of such events to malicious applications can also potentially lead to denial of service attacks, that is why access to them needs to be controlled as well. The GP SE access control specification allows rules for controlling access to NFC events to be managed along with applet access rules by saving them on the SE. In Android, global events are implemented by using broadcasts and interested applications can create and register a broadcast receiver component that will receive such broadcasts. Broadcast access can be controlled with standard Android signature-based permissions, but that has the disadvantage that only apps signed with the system certificate would be able to receive NFC events, effectively limiting SE apps to those created by the device manufacturer or MNO. Android 4.x therefore uses the same mechanism employed to control SE access -- whitelisting application certificates. Any application registered in
nfcee_access.xml
can receive the broadcasts listed below. As you can see, besides RF field detection and applet selection, Android offers notifications for higher-level events such as EMV card removal or MIFARE sector access. By adding a broadcast receiver to our test application as shown below, we were able to receive AID_SELECTED
and RF field-related broadcasts. AID_SELECTED
carries an extra with the AID of the selected applet, which allows us to start a related activity when an applet we support is selected. APDU_RECEIVED
is also interesting because it carriers an extra with the received APDU, but that doesn't seem to be sent, at least not in our tests.<receiver android:name="org.myapp.nfc.SEReceiver" >
<intent-filter>
<action android:name="com.android.nfc_extras.action.AID_SELECTED" />
<action android:name="com.android.nfc_extras.action.APDU_RECEIVED" />
<action android:name="com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED" />
<action android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
<action android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
<action android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
<action android:name="com.android.nfc_extras.action.EMV_CARD_REMOVAL" />
<action android:name="com.android.nfc.action.INTERNAL_TARGET_DESELECTED" />
</intent-filter>
</receiver>
Summary
We showed that Google Wallet installs a few applets on the SE when first initialized. Besides the expected EMV payment applets, if makes use of a controller applet for securely storing Wallet state and a MIFARE manager applet for reading/writing emulated card sectors from the app. While we can get some information about the EMV environment by sending commands to the SE from an app, payment applets cannot be selected via the wired SE interface, but only via the contactless NFC interface. Controller applet access is however available to third party apps, as long as they know the relevant APDU commands, which can easily be traced by logging. This might be one of the reasons why third party SE apps are not supported on Android yet. To make third party SE apps possible (besides offering a TSM solution), Android needs to implement more-fined grained access control to the SE, for example by restricting what applets can be selected or limiting the range of allowed APDUs for whitelisted apps.