add identify card command to cash applet
This commit is contained in:
parent
a692b6b838
commit
01c46f7009
|
@ -76,6 +76,9 @@ public class CashApplet extends Applet {
|
|||
case KeycardApplet.INS_SIGN:
|
||||
sign(apdu);
|
||||
break;
|
||||
case IdentApplet.INS_IDENTIFY_CARD:
|
||||
IdentApplet.identifyCard(apdu, null, signature);
|
||||
break;
|
||||
default:
|
||||
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
|
||||
break;
|
||||
|
|
|
@ -7,6 +7,11 @@ import javacard.security.*;
|
|||
* The applet's main class. All incoming commands a processed by this class.
|
||||
*/
|
||||
public class IdentApplet extends Applet {
|
||||
static final byte TLV_CERT = (byte) 0x8A;
|
||||
static final byte CERT_VALID = (byte) 0xAA;
|
||||
|
||||
static final byte INS_IDENTIFY_CARD = (byte) 0x14;
|
||||
|
||||
/**
|
||||
* Invoked during applet installation. Creates an instance of this class. The installation parameters are passed in
|
||||
* the given buffer.
|
||||
|
@ -65,7 +70,7 @@ public class IdentApplet extends Applet {
|
|||
byte[] apduBuffer = apdu.getBuffer();
|
||||
apdu.setIncomingAndReceive();
|
||||
|
||||
if (SharedMemory.idCert[0] == SharedMemory.CERT_VALID) {
|
||||
if (SharedMemory.idCert[0] == CERT_VALID) {
|
||||
Util.arrayCopyNonAtomic(SharedMemory.idCert, (short) 1, apduBuffer, (short) 0, SharedMemory.CERT_LEN);
|
||||
apdu.setOutgoingAndSend((short) 0, SharedMemory.CERT_LEN);
|
||||
}
|
||||
|
@ -73,7 +78,7 @@ public class IdentApplet extends Applet {
|
|||
}
|
||||
|
||||
private void processStoreData(APDU apdu) {
|
||||
if (SharedMemory.idCert[0] == SharedMemory.CERT_VALID) {
|
||||
if (SharedMemory.idCert[0] == CERT_VALID) {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
|
@ -86,6 +91,52 @@ public class IdentApplet extends Applet {
|
|||
|
||||
Util.arrayCopyNonAtomic(apduBuffer, ISO7816.OFFSET_CDATA, SharedMemory.idCert, (short) 1, SharedMemory.CERT_LEN);
|
||||
SharedMemory.idPrivate.setS(apduBuffer, (short) (ISO7816.OFFSET_CDATA + SharedMemory.CERT_LEN), Crypto.KEY_SECRET_SIZE);
|
||||
SharedMemory.idCert[0] = SharedMemory.CERT_VALID;
|
||||
SharedMemory.idCert[0] = CERT_VALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the IDENTIFY CARD command according to the application's specifications.
|
||||
*
|
||||
* @param apdu the JCRE-owned APDU object.
|
||||
*/
|
||||
static void identifyCard(APDU apdu, SecureChannel secureChannel, Signature signature) {
|
||||
byte[] apduBuffer = apdu.getBuffer();
|
||||
|
||||
short len;
|
||||
|
||||
if (secureChannel != null && secureChannel.isOpen()) {
|
||||
len = secureChannel.preprocessAPDU(apduBuffer);
|
||||
} else {
|
||||
len = (short) (apduBuffer[ISO7816.OFFSET_LC] & (short) 0xff);
|
||||
}
|
||||
|
||||
if (SharedMemory.idCert[0] != CERT_VALID) {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
if (len != MessageDigest.LENGTH_SHA_256) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||
}
|
||||
|
||||
short off = SecureChannel.SC_OUT_OFFSET;
|
||||
apduBuffer[off++] = KeycardApplet.TLV_SIGNATURE_TEMPLATE;
|
||||
apduBuffer[off++] = (byte) 0x81;
|
||||
off++;
|
||||
apduBuffer[off++] = TLV_CERT;
|
||||
apduBuffer[off++] = (byte) SharedMemory.CERT_LEN;
|
||||
Util.arrayCopyNonAtomic(SharedMemory.idCert, (short) 1, apduBuffer, off, SharedMemory.CERT_LEN);
|
||||
off += SharedMemory.CERT_LEN;
|
||||
|
||||
short outLen = (short)(SharedMemory.CERT_LEN + 5);
|
||||
signature.init(SharedMemory.idPrivate, Signature.MODE_SIGN);
|
||||
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, MessageDigest.LENGTH_SHA_256, apduBuffer, off);
|
||||
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 2)] = (byte)(outLen - 3);
|
||||
|
||||
if (secureChannel != null && secureChannel.isOpen()) {
|
||||
secureChannel.respond(apdu, outLen, ISO7816.SW_NO_ERROR);
|
||||
} else {
|
||||
apdu.setOutgoingAndSend(SecureChannel.SC_OUT_OFFSET, outLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ public class KeycardApplet extends Applet {
|
|||
|
||||
static final byte INS_GET_STATUS = (byte) 0xF2;
|
||||
static final byte INS_INIT = (byte) 0xFE;
|
||||
static final byte INS_IDENTIFY_CARD = (byte) 0x14;
|
||||
static final byte INS_VERIFY_PIN = (byte) 0x20;
|
||||
static final byte INS_CHANGE_PIN = (byte) 0x21;
|
||||
static final byte INS_UNBLOCK_PIN = (byte) 0x22;
|
||||
|
@ -99,7 +98,6 @@ public class KeycardApplet extends Applet {
|
|||
static final byte TLV_UID = (byte) 0x8F;
|
||||
static final byte TLV_KEY_UID = (byte) 0x8E;
|
||||
static final byte TLV_CAPABILITIES = (byte) 0x8D;
|
||||
static final byte TLV_CERT = (byte) 0x8A;
|
||||
|
||||
static final byte CAPABILITY_SECURE_CHANNEL = (byte) 0x01;
|
||||
static final byte CAPABILITY_KEY_MANAGEMENT = (byte) 0x02;
|
||||
|
@ -249,8 +247,8 @@ public class KeycardApplet extends Applet {
|
|||
case SecureChannel.INS_UNPAIR:
|
||||
unpair(apdu);
|
||||
break;
|
||||
case INS_IDENTIFY_CARD:
|
||||
identifyCard(apdu);
|
||||
case IdentApplet.INS_IDENTIFY_CARD:
|
||||
IdentApplet.identifyCard(apdu, secureChannel, signature);
|
||||
break;
|
||||
case INS_GET_STATUS:
|
||||
getStatus(apdu);
|
||||
|
@ -368,8 +366,8 @@ public class KeycardApplet extends Applet {
|
|||
puk.update(apduBuffer, (short)(ISO7816.OFFSET_CDATA + PIN_LENGTH), PUK_LENGTH);
|
||||
|
||||
JCSystem.commitTransaction();
|
||||
} else if (apduBuffer[ISO7816.OFFSET_INS] == INS_IDENTIFY_CARD) {
|
||||
identifyCard(apdu);
|
||||
} else if (apduBuffer[ISO7816.OFFSET_INS] == IdentApplet.INS_IDENTIFY_CARD) {
|
||||
IdentApplet.identifyCard(apdu, null, signature);
|
||||
} else {
|
||||
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
|
||||
}
|
||||
|
@ -479,53 +477,6 @@ public class KeycardApplet extends Applet {
|
|||
secureChannel.respond(apdu, len, ISO7816.SW_NO_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the IDENTIFY CARD command according to the application's specifications.
|
||||
*
|
||||
* @param apdu the JCRE-owned APDU object.
|
||||
*/
|
||||
private void identifyCard(APDU apdu) {
|
||||
byte[] apduBuffer = apdu.getBuffer();
|
||||
|
||||
short len;
|
||||
|
||||
if (secureChannel.isOpen()) {
|
||||
len = secureChannel.preprocessAPDU(apduBuffer);
|
||||
} else {
|
||||
len = (short) (apduBuffer[ISO7816.OFFSET_LC] & (short) 0xff);
|
||||
}
|
||||
|
||||
if (SharedMemory.idCert[0] != SharedMemory.CERT_VALID) {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
if (len != MessageDigest.LENGTH_SHA_256) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||
}
|
||||
|
||||
short off = SecureChannel.SC_OUT_OFFSET;
|
||||
apduBuffer[off++] = TLV_SIGNATURE_TEMPLATE;
|
||||
apduBuffer[off++] = (byte) 0x81;
|
||||
off++;
|
||||
apduBuffer[off++] = TLV_CERT;
|
||||
apduBuffer[off++] = (byte) SharedMemory.CERT_LEN;
|
||||
Util.arrayCopyNonAtomic(SharedMemory.idCert, (short) 1, apduBuffer, off, SharedMemory.CERT_LEN);
|
||||
off += SharedMemory.CERT_LEN;
|
||||
|
||||
short outLen = (short)(SharedMemory.CERT_LEN + 5);
|
||||
signature.init(SharedMemory.idPrivate, Signature.MODE_SIGN);
|
||||
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, MessageDigest.LENGTH_SHA_256, apduBuffer, off);
|
||||
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 2)] = (byte)(outLen - 3);
|
||||
|
||||
if (secureChannel.isOpen()) {
|
||||
secureChannel.respond(apdu, outLen, ISO7816.SW_NO_ERROR);
|
||||
} else {
|
||||
apdu.setOutgoingAndSend(SecureChannel.SC_OUT_OFFSET, outLen);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the Application Status Template to the APDU buffer. Invoked internally by the getStatus method. This
|
||||
* template is useful to understand if the card is blocked, if it has valid keys and if public key derivation is
|
||||
|
|
|
@ -6,7 +6,6 @@ import javacard.security.*;
|
|||
* Keep references to data structures shared across applet instances of this package.
|
||||
*/
|
||||
class SharedMemory {
|
||||
static final byte CERT_VALID = (byte) 0xAA;
|
||||
static final short CERT_LEN = 98;
|
||||
|
||||
/** The NDEF data file. Read through the NDEFApplet. **/
|
||||
|
|
|
@ -298,6 +298,15 @@ public class KeycardTest {
|
|||
assertEquals(0x9000, response.getSw());
|
||||
caPub = Certificate.verifyIdentity(challenge, response.getData());
|
||||
assertArrayEquals(expectedCaPub, caPub);
|
||||
|
||||
random.nextBytes(challenge);
|
||||
CashCommandSet cashCmdSet = new CashCommandSet(sdkChannel);
|
||||
response = cashCmdSet.select();
|
||||
assertEquals(0x9000, response.getSw());
|
||||
response = cashCmdSet.identifyCard(challenge);
|
||||
assertEquals(0x9000, response.getSw());
|
||||
caPub = Certificate.verifyIdentity(challenge, response.getData());
|
||||
assertArrayEquals(expectedCaPub, caPub);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue