I developed an applet that I installed on a J2A040 card, then a client program, it works fine, but I wanted to know, in case someone takes this card and uses the command gp -l , he can see the applets AID, is it possible to prohibit this?
the person can also type the command 00 A4 04 00 00? can have forbidden this command?
public void process(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// check SELECT APDU command
buffer[ISO7816.OFFSET_CLA]=(byte)(buffer[ISO7816.OFFSET_CLA]&(byte)0xFC);
if((buffer[ISO7816.OFFSET_CLA]==0)&&
(buffer[ISO7816.OFFSET_INS]==(byte)(0xA4))) return;
/* if (apdu.isISOInterindustryCLA()) {
if (buffer[ISO7816.OFFSET_INS] == (byte)(0xA4)) {
return;
} else {
ISOException.throwIt (ISO7816.SW_CLA_NOT_SUPPORTED);
}
}*/
if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA)
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
switch (buffer[ISO7816.OFFSET_INS]) {
case GET_BALANCE:
getBalance(apdu);
return;
case RESET_BALANCE:
resetBalance(apdu);
return;
case DEBIT:
debit(apdu);
return;
case CREDIT:
credit(apdu);
return;
case VERIFY:
verify(apdu);
return;
case CHANGE:
change(apdu);
return;
case VIEW_DATA:
viewdata(apdu);
case GET_CARD_STATUS:
processGetCardStatus(apdu);
return;
case SET_ATR_HISTORY:
processSetHistoryBytes(apdu);
return;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
} // end of process method
Thanks for your help
There is no official way in the GlobalPlatform specification to hide applets I'm aware of. But only persons in the possession of the keys of the key set of the security domain can execute this command because the GET STATUS command is not accessible outside of a secure channel.
But a general SELECT by AID cannot be protected this way anyway, because this is handled by the card runtime environment and not the applet. I.e. someone can just select this applet by AID and if this succeeds he knows that this applet is installed.
If you want to disallow access to 00 A4 04 00 00 a SELECT you have to enforce some authentication, although I don't know a reason to hide the SELECT command.
What is the use case of hiding the applet?
Related
I've been tinkering with the MFRC-522 (RC-522) RFID module for a project.
I'm testing authentication using an old key to check if the RFID's key A for a sector (in my case, Sector 2) is different from the original, if it was, then I would continue, if not I would like to "register" the card by changing the key.
I was caught at the beginning on checking different keys authentication, if I tested a working key and then an incorrect key, it works as expected, but if I test with the incorrect key first, it doesn't allow even the correct key to authenticate.
If I ran the code below everything in serial is
PCD_Authenticate() failed NEW(read): Timeout in communication.
PCD_Authenticate() failed OLD(read): Timeout in communication.
repeatedly but if I flipped old() and neww() I get
OLD WORKS
PCD_Authenticate() failed NEW(read): Timeout in communication.
Why does it work as such?
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 22 // Configurable, see typical pin layout above
#define SS_PIN 21 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
MFRC522::MIFARE_Key old_key = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
MFRC522::MIFARE_Key new_key = {0x23,0x54,0x64,0x3a,0x32,0x66};
void setup() {
Serial.begin(115200); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
delay(4); // Optional delay. Some board do need more time after init to be ready, see Readme
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
neww();
old();
}
void old(){
//authentication of the desired block for access
byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 15, &old_key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print("PCD_Authenticate() failed OLD(read): ");
Serial.println(mfrc522.GetStatusCodeName((MFRC522::StatusCode)status));
return;
}else {Serial.println("OLD WORKS");}
//delay(1000);
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
void neww() {
//authentication of the desired block for access
byte status_new = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 15, &new_key, &(mfrc522.uid));
if (status_new != MFRC522::STATUS_OK) {
Serial.print("PCD_Authenticate() failed NEW(read): ");
Serial.println(mfrc522.GetStatusCodeName((MFRC522::StatusCode)status_new));
return;
} else {Serial.println("NEW WORKS");}
//delay(1000);
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
}
So, after reading the datasheet extra hard I came to the conclusion that the state of the card was not ready for the next read, so I came with a fire-all-guns solution that helped my case, The Serial prints are for debugging so if using the code feel free to comment them out.
bool reselect_Card() {
//-------------------------------------------------------
// Can also be used to see if card still available,
// true means it is false means card isnt there anymore
//-------------------------------------------------------
byte s;
byte req_buff[2];
byte req_buff_size=2;
mfrc522.PCD_StopCrypto1();
s = mfrc522.PICC_HaltA();
Serial.print("Halt Status: ");
Serial.println(mfrc522.GetStatusCodeName((MFRC522::StatusCode)s));
delay(100);
s = mfrc522.PICC_WakeupA(req_buff,&req_buff_size);
Serial.print("Request: ");
Serial.println(mfrc522.GetStatusCodeName((MFRC522::StatusCode)s));
Serial.print("ATQA : ");
Serial.println(dump_byte_array_to_string(req_buff,req_buff_size));
delay(100);
s = mfrc522.PICC_Select( &(mfrc522.uid),0);
Serial.print("Selected : ");
Serial.println(mfrc522.GetStatusCodeName((MFRC522::StatusCode)s));
if( mfrc522.GetStatusCodeName((MFRC522::StatusCode)s) == F("Timeout in communication.") ) { return false;}
return true;
}
Look at the below code:
private void send_certificate (APDU apdu) {
if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
else{
apdu.setOutgoing();
apdu.setOutgoingLength((short)certificate.length);
apdu.sendBytesLong(certificate,(short)0,(short)certificate.length);
}
}
Certificate is a byte array inside the javacard applet and its length is greater than 256. How can I send this without getting APDUException.BAD_LENGTH?
Also, on sending this byte array, how can I retreive this byte array from the host application ?
I attempt the following from the host application:
CommandAPDU card_cert;
ResponseAPDU resp4;
card_cert = new CommandAPDU(IDENTITY_CARD_CLA, SEND_CERTIFICATE, 0x00, 0x00);
resp4 = c.transmit(card_cert);
if(resp4.getSW()==0x9000) {
byte [] response = resp4.getData();
String certf= DatatypeConverter.printHexBinary(response);
System.out.println("CERTIFICATE:" + certf + "--"+response.length);
System.out.println(" signature to be verivied: " + DatatypeConverter.printHexBinary(card_signature));
CertificateFactory certFac = CertificateFactory.getInstance("X.509");
InputStream is = new ByteArrayInputStream(response);
X509Certificate cert = ( X509Certificate ) certFac .generateCertificate( is ) ;
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(cert.getPublicKey());
signature.update(card_signature);
if(card_signature !=null) {
boolean ok =signature.verify(card_signature);
if(ok==true)System.out.println("verification completed" );
}
}
of course nothing executes after the if(resp4.getSW()==0x9000)since the certificate is not sent successfully to the host application. How can this be achieved?
After making my applet class implement ExtendedLength, I did the following in my send_certificate() method:
private void send_certificate (APDU apdu) {
if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
else{ byte[] buffer = apdu.getBuffer();
short LE = apdu.setOutgoing();
short toSend = (short)certificate.length;
short cert_offset =0;
short len =240;
if (LE != toSend) {
apdu.setOutgoingLength(toSend);
}
while (toSend > 0) {
Util.arrayCopyNonAtomic(certificate, cert_offset, apdu.getBuffer(), (short)0, len);
apdu.sendBytes((short) 0, len);
toSend -= len;
cert_offset += len;
}
}
}
This does not work: Fails with response code 28416.
You should make sure that your Java Card implementation and reader both support extended length. It may be that the implementations have thrown up barriers that will disable the use of full size extended length: the implementations may (incorrectly) limit the size of the APDU's for instance.
The reader may require that the ATR indicates extended length. NFC chips are notorious of not implementing extended length correctly (and Android is notorious for not enabling the functionality if they do). This is probably not your problem as the status word seems to be generated by the card.
The code of Java Card has a mistake, it should always use setOutgoingLength(). It seems that your code already throws the exception when this method is called, so I expect that the size you're trying to send is not supported by the platform. Besides that, your initial code using sendBytesLong looks correct as well. Of course your Applet should implement the ExtendedLength tagging interface.
Note that 6F00 (your status code, always use hex for those, not decimals) may be generated by any unhandled runtime exception generated on the card. So make sure that your issue is not created elsewhere when you try to fix your problem.
Extended length is a mine-field unfortunately. We're now in 2018 and the smart card world still can't seem to send 32/64Ki -1 bytes or over. Time to replace ISO/IEC 7816-4 with something that makes sense I suppose.
He.
The program should constantly check incoming sound from a Bluetooth microphone.
Bluetooth device can be connected/disconnected any time.
How to get event from Pulseaudio that list of sources changed?
I tried to use
pa_context_set_event_callback (pa_ctx, pa_context_event_cb, &mydata);
But no one calls pa_context_event_cb when BT headset is connected/disconnected.
What is the good practice for pulseaudio?
Ok. Figured it out.
1) Subscribe for context state changes:
pa_context_set_state_callback(pa_ctx, pa_state_cb, &mydata);
2) In pa_state_cb:
void pa_state_cb(pa_context *c, void *userdata) {
pa_context_state_t state;
state = pa_context_get_state(c);
switch (state) {
case PA_CONTEXT_READY: {
//set callback
pa_context_set_subscribe_callback(c, pa_context_subscribe_cb, &mydata);
//set events mask and enable event callback.
o = pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE,
NULL, NULL);
if (o)
{
pa_operation_unref(o);
}
}
break;
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_AUTHORIZING:
case PA_CONTEXT_SETTING_NAME:
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
default:
break;
}
3) Then handle mask event (pa_subscription_event_type_t) in the callback pa_context_subscribe_cb.
I found that the keyPress event is never fired until the key is actually released on Linux . This behavior is different on vista. Here is a piece of code from my application.
The difference happens when I do the following sequence:
1) CTRL key down,
2) hold it for a while
3) release it.
On Linux, nothing is printed out till the release.i.e. you'll not see anything till 3), then you'see "notify::KeyPressed" and "notify::KeyReleased".
On Vista, after 1), you'll see "notify::KeyPressed", then in 2), you can detect that the CTRL is down with QApplication::keyboardModifier().testFlag(Qt::ControlModifier). then after 3), you'll see "notify::KeyReleased".
I think what happens on vista is what I expected. How can I fix the problem on Linux and why it happens this way?
Thanks for your help!
MyApplication::QApplication
{
bool notify(Object * receiver, QEvent * event) {
try{
if (event->type() == QEvent::KeyPress) {
std::cout<<"notify::KeyPressed"<<endl;
}
if (event->type() == QEvent::KeyRelease) {
std::cout<<"notify::KeyReleased"<<endl;
}
return QApplication::notify( receiver, event );
}
catch ( ... ) {
std::cerr << "Unknown Exception caught: " << ends;
}
return false;
}
}
Finally found the problem. I'm using a virtual machine running on a blade. When you connect to the blade, the client tool, has an option: "Send First Key", by default, it is disabled, so when connected to the virtual machine, when you pressed CTRL, (remember the first key is disabled), you do not get the "keyPress" event! After I enabled that, it starts to work as expected!
I have a problem that confused me for couple of day.
I want to send out a data with size bigger than 255 bytes from smartcard to host application.
I saw a block of code in some website. this code is like bellow:
private void sendData(APDU apdu) {
// work out how many bytes to send this time and how many will be left
BUF_IN_OFFSET[0] = 0;
short remain = (short) ((short)372 - BUF_IN_OFFSET[0]);
boolean chain = remain > MAX_APDU;
short sendLen = chain ? MAX_APDU : remain;
Util.arrayCopy(data, (short) 0, apdu.getBuffer(), (short) 0, sendLen);
// Get ready to send
apdu.setOutgoing();
apdu.setOutgoingLength((short)sendLen);
apdu.sendBytesLong(apdu.getBuffer(), BUF_IN_OFFSET[0], sendLen);
// Check to see if there are more APDU's to send
if (chain) {
BUF_IN_OFFSET[0] += sendLen; // count the bytes sent
remain -=sendLen;
ISOException.throwIt((short)((ISO7816.SW_BYTES_REMAINING_00) + remain));
} else {
BUF_IN_OFFSET[0] = 0; // no more bytes to send
}
}
When i send apdu to the card in netbeans simulator, it send 6100 correctly. but when i send it to real card (smartcafe 3.2) card. it send for me 9000. it means in simulator it works but by real card it doesn't work.
I guess it related to protocol T=0 or T=1.
I didn't find any code for T=1. above code is for T=0.
thanks in advance.
'6100' sounds like a contradiction in the terms. It tells the reader to fetch some data, with lengh available being naught. I believe the real card will actually turn this into a 9000 which is the proper execution status code when no data is available.