I want to route APDUs I get from an NFC Reader to the SIM Card. According to the HCE documentation I thought it would be possible simply by creating an OffHostApduService with the according routing-entries (which I did).
Sadly, the SIM does not seem to get any APDUs. SELECT-Commands that work when the SIM is directly attached to my workstation by a SIM-Reader return with 6a82 (File not found).
In LogCat I found two interesting bits of information:
Every time I shoot a select command which should be routed to the SIM, I get these entries:
01-14 10:44:18.501: D/BrcmNfcJni(1009): RoutingManager::stackCallback: event=0x17
01-14 10:44:18.501: D/BrcmNfcJni(1009): RoutingManager::stackCallback: NFA_CE_DATA_EVT; h=0x302; data len=12
01-14 10:44:18.501: D/HostEmulationManager(1009): notifyHostEmulationData
I think that this is a clue that the routing is not set correctly, since I think the Android OS should not be aware when the routing to the SIM is active, and a select or another command is sent to the SIM.
Every time I remove the phone from the NFC field of the reader, I receive the following error:
01-14 10:46:48.791: E/BrcmNfcNfa(1009): UICC[0x0] is not activated
I tried to track the cause of this error down and found the file external/libnfc-nci/src/nfa/ce/nfa_ce_act.chere which seems to belong to the Broadcom NFC Driver.
I think that the mistake is that the application cannot set the correct routing for the APDUs since the driver thinks that the SIM is not activated. In the moment I send the commands, the SIM is unlocked (PIN-Entry), but I doubt that this has anything to do with it since I don't have to unlock the SIM before using it in the card reader.
I use a Nexus 5 for testing. Does anybody have experience and / or a working example where the APDUs can be routed to the SIM instead of the CPU?
A quick check (analyzing the signals on the SWP pin of a UICC inserted into the device) revealed that the Nexus 5 is not activating the SIM as an NFC secure element (neither at boot nor when putting the phone on a smartcard reader).
However, I found two interesting files on the device's system partition:
/system/etc/libnfc-brcm-20791b05.conf and
/system/etc/libnfc-brcm.conf.
These two files seem to provide the configuration for the NFC controller (the first one a chip-sepecific configuration and the second one a chip-family specific one?).
After unlocking the bootloader, I was able to modify those files through adb by booting a clockworkmod recovery image, so I did some experimenting with the configuration parameters.
The result is that I managed to let the device activate the UICC (UICC was activated and registered its CE gates through SWP?), the device sometimes even notified the UICC about field status changes. However, with none of my modified configurations, I was able to get the reader to smoothly discover card emulation (this was working before, when only HCE was available on the device) nor to communicate with the UICC.
The interesting parameters in /system/etc/libnfc-brcm.conf seem to be:
NFA_MAX_EE_SUPPORTED: This is currently set to 0. I tried a value of 3, which seems to be the default.
ACTIVE_SE: This is currently set to 0 (no active SE). I tried to uncomment that line to let the device use the first SE detected.
NFA_HCI_STATIC_PIPE_ID_??: Should not be necessary but on out GS4 this is set to 0x71 for ?? = F3 and F4.
UICC_LISTEN_TECH_MASK: This is set to 0x00 on our GS4.
REGISTER_VIRTUAL_SE: I left this as it was (== commented out).
SCREEN_OFF_POWER_STATE: I did not experiment with this, but on our GS4 this is set to 3 (screen-off CE).
The interesting parameters in /system/etc/libnfc-brcm-20791b05.conf seem to be:
NFA_DM_START_UP_CFG: I've tried the commented-out parameters for UICC and I tried to use the configuration from our GS4. The value starts with a length byte and is structured in TLV format (one tag byte, one length byte, parameter data). The relevant tag for UICC activation seems to be C2, where the upper two bits in the second parameter byte disable the SWP interfaces of the NFC controller if set.
NFA_DM_PRE_DISCOVERY_CFG: The comments suggest that this need to be uncommented for UICC support.
It's been a while since I last played with card emulation on Android but AFAIK (I could be wrong), secure element access (internal or inside SIM) has not yet been opened to all developers (without some hacking). There are many non-technical issues regarding SE control which seem not yet solved (who keeps the biggest slice of the cake the Telcos or service providers?).
The news is that Google has taken a different approach with KitKat and its HCE, which basically consists on implementing a NFC card emulation mode without hardware secure element. IMHO this basically breaks the security required for the interesting card emulation mode applications: e-payment, ticketing, authentication, etc. Nexus 5 lacks such secure element and I doubt Google will pander to carriers by easing the access to secure element inside SIM, so I guess it still will not be possible to send APDUs to the SIM with stock firmware.
If you add the following to /etc/libnfc-brcm.conf
DEFAULT_ISODEP_ROUTE=0xF3
the UICC will receive APDUs
You also need all modifications above in libnfc-brcm.conf and libnfc-brcm-20791b05.conf
Up to Jelly Bean 4.3, normal way is to use nfc_extras and its method CardEmulationRoute (<route>, <nfcEe>) to route the UICC to the RF.
But on KITKAT, this brutal modification through DEFAULT_ISODEP_ROUTE is enough to have UICC Card Emulation enabled.
Related
I'm working on an Android application to interface between a mobile phone and a specific chip that supports NFC, which is called the NF4 chip and is manufactured by EM Microelectronic. Here is a link to the datasheet of this chip: http://www.emmicroelectronic.com/sites/default/files/public/products/datasheets/nf4-fs.pdf
In page 3 of the datasheet, the memory system of the chip is summarized. Part of what I need to do is to create a file in the memory and write to it. I was working on this and testing it using a phone and the NFC tag.
To achieve what I need, the app sends the following APDUs to the chip:
select an EF in the memory system (Select File APDU)
write to this file (Update Binary APDU)
The chip comes with other NFC tags/cards that are basically the same as this chip, only without the serial interface.
One time I was testing my app with one of the extra tags (cards). The tag stopped functioning as it used to. An application made by EM Microelectronic (who make the tag) used to be able to read and write to the tag, but after this incident the EM app stopped being able to do this.
When I looked into the matter further, I found that the technologies of the tag went from being (IsoDep, NfcA and Ndef) in the beginning to only (IsoDep and NfcA) after that one testing session with my app. Therefore, it is basically not an NFC-Forum supported tag anymore.
I'm not sure what happened and need to solve this problem and return the tag to its previous state. I also need to understand what my app did to the tag to cause it to become like this so that I can stop it from happening when I test again.
One theory that I thought of is that maybe when my app selected an EF that isn't a child of the DF that stores the NFC data in the tag, this is what caused the problem. That is, the NFC Dedicated File is still in memory but is not selected as the current file... I'm not sure if this could actually cause the problem that I described.
Does this make sense, or could it be something else?
I am working on an app that scans just the UID of MIFARE Classic cards to facilitate attendance registration. I have got it working. However, every time I scan a card on my Galaxy S4, I get a toast stating "NFC tag type not supported".
I want to either block or hide that message while the app is open.
I noticed there was one other question asking for the same thing on a Galaxy S6 but it was down-voted once and then ignored.
I found this conversation on the Samsung Developers forum, however, I could not extract an answer from what is written there:
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {
myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
tagID = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
alertDialog.dismiss();
It looks like the alertDialog.dismiss() section is what I need but there is no explanation for where they got the alertDialog object from.
Before Android 4.4
What you are trying to do is simply not possible from an app (at least not on a non-rooted/non-modified device). The message "NFC tag type not supported" is displayed by the Android system (or more specifically the NFC system service) before and instead of dispatching the tag to your app. This means that the NFC system service filters MIFARE Classic tags and never notifies any app about them. Consequently, your app can't detect MIFARE Classic tags or circumvent that popup message.
On a rooted device, you may be able to bypass the message using either
Xposed to modify the behavior of the NFC service, or
the CSC (Consumer Software Customization) feature configuration files on the system partition (see /system/csc/. The NFC system service disables the popup and dispatches MIFARE Classic tags to apps if the CSC feature <CscFeature_NFC_EnableSecurityPromptPopup> is set to any value but "mifareclassic" or "all". For instance, you could use:
<CscFeature_NFC_EnableSecurityPromptPopup>NONE</CscFeature_NFC_EnableSecurityPromptPopup>
You could add this entry to, for instance, the file "/system/csc/others.xml" (within the section <FeatureSet> ... </FeatureSet> that already exists in that file).
Since, you asked for the Galaxy S6 (the question that you linked) as well: I have tested this method on the S4 when it came out. I have not verified if this still works in the latest firmware or on other devices (e.g. the S6).
Since Android 4.4
This is pure guessing, but according to this (link no longer available), it seems that some apps (e.g. NXP TagInfo) are capable of detecting MIFARE Classic tags on affected Samsung devices since Android 4.4. This might mean that foreground apps are capable of bypassing that popup using the reader-mode API (see NfcAdapter.enableReaderMode) possibly in combination with NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK.
I want to exchange (or only read) the NFC tag ID from one Android device to another but I don't know if I should use peer-to-peer mode or emulate an NFC tag with HCE.
If I use HCE, is the emulated tag ID unique?
What is the better option or is there a simpler one?
Neither P2P nor HCE will provide you a unique ID, least not on any phone I'm aware of. With P2P it's required that the ID exchanged in ATR is random. With HCE the emulated tag ID is usually set to 08h plus a random number. There may be API call to set but I'm not aware of such. But it makes a lot of sense that a phone can not be uniquely identified by just anyone reading.
How can I read the NFC ID of another Android device?
I assume you are talking about the anti-collision identifier/UID here. On the reading Android device, you can use the reader-mode API to access devices in HCE mode:
nfcAdapter.enableReaderMode(this, new NfcAdapter.ReaderCallback() {
public void onTagDiscovered (Tag tag) {
byte[] uid = tag.getId();
// TODO: do something with the UID ...
}
}, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
Is the emulated tag ID unique?
See Stephen's answer. Typically, neither P2P mode nor HCE should provide a unique and stable ID. However, there are some exceptions to this and the point of time when a non-stable ID changes may vary (also see this answer). It could be that:
The device has a secure element and uses the static UID of that secure element.
The device generates a new random UID whenever it is turned on, but continues to use the same UID until it is powered off.
The device generates a new random UID on every activation by an external reader device. I.e. whenever an external HF field is applied to the NFC antenna of the Android device.
Also note that some NFC devices will use randomly generated UIDs that do not start with the random-prefix 0x08.
Can I force a device to use a fixed/stable UID?
Android does not provide an API to influence the UID/anti-collision identifier, so the short answer is no. However, if rooting or creating a custom ROM is an option, there are some possibilities to change the UID and other protocol parameters:
Editing Functionality of Host Card Emulation in Android
Host-based Card Emulation with Fixed Card ID
Should you use the UID to identify (or even authenticate) a device?
No, you should definitely not do this. While you sometimes do not have much choice when you try to integrate a HCE device into some legacy system, you should definitely think about a different design.
First of all, as Stephen already wrote, if an NFC device exposes a fixed/stable identifier, this could possibly introduce a privacy issue as anyone could read and track the ID.
Second, while many systems still use these IDs to authenticate(!) cards, UIDs are not necessarily unique (particularly there are less 4-byte UIDs than cards out there) and UIDs can easily be cloned. See this answer for further details.
Using a Nexus 4 and the latest Android API level 18 to communicate with a Mifare DESFire EV1 AES tag is giving me a headache. Following the NXP native protocol in order to write and read this type of tag, these steps must be followed:
Select application
Authenticate
Write or Read
To do it so, I use Android's IsoDep class which provides access to ISO 14443-4 properties and I/O operations. The very weird thing about it is that once I send the select application native command I get an unexpected response. Imagine I have the AID F4013D so I send:
-> 5AF4013D
<- 6E00
All possible responses must be one byte length (success 0x00 or error_code) and never two or more. Thus, the 0x6E before the success response is absolutely unexpected. It does not happen always, and when it does not and works fine, the select application and authentication processes work fine. However once authenticated the write command does not have a correct behavior, all write commands finishes with a 0xAF from the PICC instead of a success 0x00. It seems like the PICC expect some extra data when it should not (I send the correct length payload). If I send any other command I get a 0xCA (Command Aborted) error code.
-> 5AF4013D
<- 00 /*Success*/
-> AA01
<- AFA8394ED57A5E83106B4EE72FD2BB0CC4
-> AF148F525E1DDE0AD6AB60B4B615552475C91F2E8D89B8523E4465113DD5BD19C6
<- 0066D255C93F2F492AFE3715C88964F1BD /*Authentication success*/
-> 3D02000000030000222222 /*Write 3 bytes to file nÂș2*/
<- AF /*Unexpected, 0x00 was expected*/
As it is normal, if I send these type of commands with a personal reader (non Android NFC) it always works fine. It seems that something in the Android NFC API is going strange, when it should just be a raw data transporter which never interprets or modifies data.
I have also tried with ISO 7816-4 APDU structure with the same result. As a curiosity, with a Galaxy Nexus does not happen the select application strange response, but yes the write command one always.
(1) For the first part concerning the status code 6E00:
6E 00 is not a "strange byte 0x6E + success status code 0x00". Instead it is a response APDU status word 6E 00 ("Class not supported"). This indicates that there was previous communication with the card using APDU-based access (e.g. Android itself tried to read the card as Type 4 tag and did not reset the connection afterwards). Thus, the card will expect all further communication to be in ISO 7816-4 APDUs. In that case (i.e. if you receive an ISO 7816-4 status code like 6E 00), you could continue using DESFire APDU wrapped commands by simply wrapping your native commands.
EDIT: In fact, this is somewhat expected behavior on an NFC device. The idea is that an NFC device will automatically scan detected tags for NDEF messages. In the case of a DESFire card, the NFC device will detect the card as potential Type 4 tag. Thus the NFC device will send ISO 7816-4 APDUs as it would send to any other Type 4 tag. Hence, if the NFC device doesn't reset the communication with the tag before handing the detected tag to the app, the app can only communicate using ISO 7816-4 APDUs. Note, however, that I would consider it a bug that this happens only for some activations on the same device. In my opinion, the behavior on one specific device model should be consistent.
EDIT: While I would not consider this behavior a bug, it is actually caused by a known bug (#58773) in Android's NFC stack for devices with Broadcom NFC controller. On affected devices, the automatic presence check sends ISO 7816-4 APDUs at timed intervals that cause DESFire cards to switch into ISO 7816-4 APDU mode.
(2) For the second part concerning the (unexpected) response code 0xAF:
Could it be that your file's communication settings are setup for either "plain communication secured by MACing" or "fully enciphered communication"? In that case, simply sending the three data bytes would not be enough. Instead you would need to send either the plain data plus MAC or the padded, CRCed and encyrypted data. Hence the 0xAF indicating that the card expects further data.
EDIT: So to summarize the comments below. After sending further bytes (one byte at a time for each received 0xAF status code: AF FF) it turned out that exactly 8 more bytes were expected by the card. 8 bytes is exactly the size of the CMAC for AES authentication. Thus, the communication settings were set to "plain communication secured by MACing".
I am working on an application for Android reading a contactless smart card but I have some problems with my Galaxy S3.
Before to describe problems, I need to precise that on a PC, I can communicate perfectly with the card using the smartcardio API in Java and NFC readers from different manufacturers.
This card is detected as supporting technologies "IsoDep" and "NfcB" by the NFC stack.
However, when I send my apdu command with "transceive", I get an exception "Transceive failed". I have tried to increase timeout but no better result.
iso = IsoDep.get(tag);
if (iso!=null) {
try {
iso.connect();
// txMessage is a TextView object used for debugging purpose
txMessage.setText("Max:"+iso.getMaxTransceiveLength()+" timeout:"+iso.getTimeout()+" connected:"+iso.isConnected());
iso.setTimeout(2000);
txMessage.setText("Max:"+iso.getMaxTransceiveLength()+" timeout:"+iso.getTimeout()+" connected:"+iso.isConnected());
byte[] command = new byte[] {(byte) 0x00, (byte) 0xA4, (byte) 0x04,(byte) 0x00, (byte) 0x06,(byte) 0xA0,(byte) 0x00,(byte) 0x00, (byte) 0x00,(byte) 0x12,(byte) 0x00};
byte[] response = iso.transceive(command);
} catch (IOException e) {
txMessage.setText(txMessage.getText()+"\n"+e.getMessage());
}
}
When running this code, I get:
Max:261 timeout:309 connected: true
Max:261 timeout:2474 connected: true
Transceive failed
I have noticed that this card requires to be very close of the NFC antenna to work. I need to remove the additional plastic protection case (not the back cover) of my phone in order the card would be detected (I guess powered).
Before to post, I have read NFC typeb card not getting detected by any NFC application (like:nfctaginfo) and Android isodep.isConnected() returns false and maximum Transceive length:0 byte ,for type B card.? and several other posts elsewhere (http://forum.xda-developers.com/showthread.php?t=1705970 , http://code.google.com/p/android/issues/detail?id=35960 ) but I did not find a solution.
A possible solution would be to try to communicate with an external antenna but I am not sure where to connect it? On battery connector where there is no "+" and "-"?
Another solution would be to try to communicate with the card with NfcB (NfcB nfcb = NfcB.get(tag);), but I do not know the ISO14443-3B protocol (I only know quite well APDU, T0-TPDU but not other TPDU protocols).
Just to be sure, I have updated my phone to Android 4.1.2 (instead of 4.1.1) but no better result.
I have a Samsung Galaxy S3 too and I noticed that the connection performance for TypeB contactless cards is worse than for TypeA. Raising the timeout value seems to be a quick fix for problems of this kind, but as it didn't work for you, the problem might be with the strength of the RF-field. Have you tested if the call of transceive() fails because of the timeout or because of a connection loss? Maybe you could try raising the timeout even further, some operations might take a long time on a smart card.
Another suggestion to your problem is to remove the backcover of your S3 and place the smart card directly on the battery (the NFC antenna is integrated in there). In my experience it makes a slight difference where the chip is located on the smart card, so you could experiment with the orientation of the card. You might test this by sliding the card onto the battery from the bottom of the device to the top.
In my work with the Galaxy S3 (Android 4.1.1) I was able to connect to and transceive data to TypeA and TypeB contactless smart cards (German eID cards). I noticed that the TypeB card was lost sometimes without any reason while being idle. But I can send and receive data with it anyway. Even when the Chip on the card has to perform some computation and hence needs slightly more power from the RF field, the field of the NFC antenna seems sufficiently strong to keep the connection in my case. Maybe your card is not properly designed to work with lower power RF fields? Unfortunately to my knowledge there is no possibility to raise the power output of the NFC antenna on Android devices.
Communicating via the NfcB (NfcB nfcb = NfcB.get(tag);) does not seem to make any difference to me. I am able to comunicate via the IsoDep Object and transceive data perfectly.
Using an external or additional antenna would be worth a try. In this YouTube video it is shown how one can put an additional NFC antenna into the Galaxy S4. In the video you will notice the external antenna pins on the back of the S4. When watching the third picture here (Galaxy SIII teardown) - the one with the battery taken out - you will notice that there are additional antenna pins on the back of the SIII as well. The two golden contact pins on the left side. Googling a bit showed that these pins are named 'ANT500' and 'ANT501', so they are probably external NFC antenna contacts. If you search for "Samsung Galaxy Note2 external NFC antenna" or something similar on eBay (or any search engine), you will get the antenna used in the YouTube video. There are no official external NFC antennas for the SIII nor for the S4, but probably it will work. The antenna is not very expensive (currently around $5), so you might give it a try.
It is definitely a timeout thing, and a compatibility thing with NXP NFC chips (like the one in the S3)
I have worked with Type B tags on an antenna with a higher Q factor than that of a typical mobile phone antenna, and when doing ISO-DEP I need to still change the default timeouts of the NFC chip that I'm using (NXP PN532). Type A modulation was developed by Phillps, now NXP. Type B modulation was developed by Motorolla, and is under license to NXP for its reader chips, so only a basic implementation is included relative the the Type A implementation.
I am not doing this on an Android, but an embedded platform, so I have full access to the NFC chip's features. Thus, only by using a more basic transeiving method that requires the application to handle the 14443-4 protocol and extending the timeout tolerance of the reader was I able to talk to a Type B tag using ISO-DEP
Android 4.4 has something called reader mode, that may have a feature that enables you to extend this timeout.