Java Code Examples for javacard.framework.APDU#setOutgoing()

The following examples show how to use javacard.framework.APDU#setOutgoing() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: GaussKeyCard.java    From gauss-key-card with Apache License 2.0 6 votes vote down vote up
private void
processAuthenticate(APDU apdu)
{
	final byte[] buffer = apdu.getBuffer();
	final short incomingLength = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);

	if (incomingLength < (short)0x51) {
		ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
	}

	ecdh.generateSecret(buffer, ISO7816.OFFSET_CDATA, (short)65, buffer, (short)16);

	aes_key.setKey(buffer, (short)16);
	aes_ecb.init(aes_key, Cipher.MODE_ENCRYPT);

	// Generate the random salt.
	rng.generateData(buffer, OFFSET_CHALLENGE, (short)4);

	short len = aes_ecb.doFinal(buffer, OFFSET_CHALLENGE, (short)16, buffer, (short)0);
	final short le = apdu.setOutgoing();

	len = le > 0 ? (le > len ? len : le) : len;
	apdu.setOutgoingLength(len);
	apdu.sendBytes((short)0, len);
}
 
Example 2
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 6 votes vote down vote up
/**
 * \brief Encode a 2048 bit RSAPublicKey according to ISO7816-8 table 3 and send it as a response,
 * using an extended APDU.
 *
 * \see ISO7816-8 table 3.
 *
 * \param apdu The apdu to answer. setOutgoing() must not be called already.
 *
 * \param key The RSAPublicKey to send.
 * 			Can be null for the secound part if there is no support for extended apdus.
 */
private void sendRSAPublicKey(APDU apdu, RSAPublicKey key) {
    short le = apdu.setOutgoing();
    short pos = 0;

    ram_buf[pos++] = (byte) 0x7F; // Interindustry template for nesting one set of public key data objects.
    ram_buf[pos++] = (byte) 0x49; // "
    ram_buf[pos++] = (byte) 0x82; // Length field: 3 Bytes.
    ram_buf[pos++] = (byte) 0x01; // Length : 265 Bytes.
    ram_buf[pos++] = (byte) 0x09; // "

    ram_buf[pos++] = (byte) 0x81; // RSA public key modulus tag.
    ram_buf[pos++] = (byte) 0x82; // Length field: 3 Bytes.
    ram_buf[pos++] = (byte) 0x01; // Length: 256 bytes.
    ram_buf[pos++] = (byte) 0x00; // "
    pos += key.getModulus(ram_buf, pos);
    ram_buf[pos++] = (byte) 0x82; // RSA public key exponent tag.
    ram_buf[pos++] = (byte) 0x03; // Length: 3 Bytes.
    pos += key.getExponent(ram_buf, pos);

    sendLargeData(apdu, (short)0, pos);
}
 
Example 3
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 6 votes vote down vote up
/**
 * \brief Process the GET RESPONSE APDU (INS=C0).
 *
 * If there is content available in ram_buf that could not be sent in the last operation,
 * the host should use this APDU to get the data. The data is cached in ram_buf.
 *
 * \param apdu The GET RESPONSE apdu.
 *
 * \throw ISOException SW_CONDITIONS_NOT_SATISFIED, SW_UNKNOWN, SW_CORRECT_LENGTH.
 */
private void processGetResponse(APDU apdu) {
    byte[] buf = apdu.getBuffer();
    short le = apdu.setOutgoing();

    if( ! pin.isValidated() ) {
        ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
    }

    if(ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING] <= (short) 0) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    short expectedLe = ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING] > 256 ?
                       256 : ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING];
    if(le != expectedLe) {
        ISOException.throwIt( (short)(ISO7816.SW_CORRECT_LENGTH_00 | expectedLe) );
    }

    sendLargeData(apdu, ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS],
                  ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING]);
}
 
Example 4
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 6 votes vote down vote up
/**
 * \brief Process the GET CHALLENGE instruction (INS=0x84).
 *
 * The host may request a random number of length "Le". This random number
 * is currently _not_ used for any cryptographic function (e.g. secure
 * messaging) by the applet.
 *
 * \param apdu The GET CHALLENGE apdu with P1P2=0000.
 *
 * \throw ISOException SW_INCORRECT_P1P2, SW_WRONG_LENGTH, SW_FUNC_NOT_SUPPORTED.
 */
private void processGetChallenge(APDU apdu) {
    byte[] buf = apdu.getBuffer();
    byte p1 = buf[ISO7816.OFFSET_P1];
    byte p2 = buf[ISO7816.OFFSET_P2];

    if(randomData == null) {
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }

    if(p1 != 0x00 || p1 != 0x00) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }
    short le = apdu.setOutgoing();
    if(le <= 0 || le > 256) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }
    randomData.generateData(buf, (short)0, le);
    apdu.setOutgoingLength(le);
    apdu.sendBytes((short)0, le);
}
 
Example 5
Source File: STPayP.java    From CardExamples with The Unlicense 6 votes vote down vote up
private void getMobileKey(APDU apdu) throws ISOException {
    byte[] apduBuffer = apdu.getBuffer();

    // Check if P1=0x00 and P2=0x00.
    if (Util.getShort(apduBuffer, ISO7816.OFFSET_P1) != (short) 0x0000) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    short dataLength = apdu.setOutgoing();
    // Check if Le=0x00.
    if (dataLength != (short) 256) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // Check if Mobile Key is initialized.
    if (!this.dataEncryption.isMobileKeyInit()) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    dataLength = this.dataEncryption.getMobileKey(apduBuffer, (short) 0);
    apdu.setOutgoingLength(dataLength);
    apdu.sendBytes((short) 0, dataLength);
}
 
Example 6
Source File: PayPass.java    From CardExamples with The Unlicense 6 votes vote down vote up
public void get_data(APDU apdu, byte[] buf) {
    // verify that the class for this instruction is correct
    if ((short) (buf[ISO7816.OFFSET_CLA] & 0xFF) != 0x80)
        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    // check state - this command only works in the PERSO state
    if (PROFILE.STATE != PERSO)
        ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    // check that P1 & P2 are correct
    if (buf[ISO7816.OFFSET_P1] != (byte) 0x00 || (byte) buf[ISO7816.OFFSET_P2] != (byte) 0xCF)
        ISOException.throwIt((short) 0x6A88); //referenced data not found
    // build response message
    apdu.setOutgoing();
    apdu.setOutgoingLength((short) 13);

    buf[0] = (byte) 0xCF; //Key Data Tag
    buf[1] = (byte) 11;   //length
    buf[2] = PROFILE.VER_KMC;
    Util.arrayCopyNonAtomic(PROFILE.KMC_ID, (short) 0, buf, (short) 3, (short) 6);
    Util.arrayCopyNonAtomic(PROFILE.CSN, (short) 0, buf, (short) 9, (short) 4);

    apdu.sendBytes((short) 0, (short) 13);
}
 
Example 7
Source File: GaussKeyCard.java    From gauss-key-card with Apache License 2.0 5 votes vote down vote up
private void
processGetCardInfo(APDU apdu)
{
	final byte[] buffer = apdu.getBuffer();
	final short le = apdu.setOutgoing();

	short len = 0;
	buffer[len++] = 0x00;
	buffer[len++] = 0x01;

	len = le > 0 ? (le > len ? len : le) : len;
	apdu.setOutgoingLength(len);
	apdu.sendBytes((short)0, len);
}
 
Example 8
Source File: GaussKeyCard.java    From gauss-key-card with Apache License 2.0 5 votes vote down vote up
private void
processGetPublicKey(APDU apdu)
{
	final byte[] buffer = apdu.getBuffer();

	final short le = apdu.setOutgoing();

	final ECPublicKey epubk = (ECPublicKey)key1.getPublic();

	short len = epubk.getW(buffer, (short)0);

	len = le > 0 ? (le > len ? len : le) : len;
	apdu.setOutgoingLength(len);
	apdu.sendBytes((short)0, len);
}
 
Example 9
Source File: GidsPINManager.java    From GidsApplet with GNU General Public License v3.0 5 votes vote down vote up
/**
 * \brief return information regarding the PIN
 */
public void returnPINStatus(APDU apdu, short id) {
    byte[] buf = apdu.getBuffer();
    GidsPIN pin = null;
    switch(id) {
    default:
        ISOException.throwIt(ErrorCode.SW_REFERENCE_DATA_NOT_FOUND);
        break;
    case (short) 0x7F71:
    case (short) 0x7F72:
        pin = pin_pin;
        break;
    }

    Util.setShort(buf, (short) 0, id);
    buf[2] = (byte) 0x06;
    buf[3] = (byte) 0x97;
    buf[4] = (byte) 0x01;
    buf[5] = pin.getTriesRemaining();
    buf[6] = (byte) 0x93;
    buf[7] = (byte) 0x01;
    buf[8] = pin.getTryLimit();
    apdu.setOutgoing();
    apdu.setOutgoingLength((short)9);
    apdu.sendBytes((short) 0, (short) 9);

}
 
Example 10
Source File: TransmitManager.java    From GidsApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Send the data from ram_buf, using either extended APDUs or GET RESPONSE.
 *
 * \param apdu The APDU object, in STATE_OUTGOING state.
 *
 * \param pos The position in ram_buf at where the data begins
 *
 * \param len The length of the data to be sent. If zero, 9000 will be
 *            returned
 */
private void sendData(APDU apdu) {
    short le;
    short remaininglen = 0;
    byte data[] = null;
    short pos = chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS];

    le = apdu.setOutgoing();
    // le has not been set
    if(le == 0) {
        // we get here when called from the Shared VMWare reader
        byte ins = apdu.getBuffer()[ISO7816.OFFSET_INS];
        if ( ins != GidsApplet.INS_GENERATE_ASYMMETRIC_KEYPAIR) {
            le = 256;
        } else {
            le = 0;
        }
    }

    if (chaining_object[CHAINING_OBJECT] == null) {
        data = ram_buf;
        remaininglen = chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING];
    } else if (chaining_object[CHAINING_OBJECT] instanceof Record) {
        Record record = (Record) (chaining_object[CHAINING_OBJECT]);
        data = record.GetData();
        remaininglen = (short) (((short) data.length) - pos);
    } else if (chaining_object[CHAINING_OBJECT] instanceof Record[]) {
        data = ram_buf;
        remaininglen = copyRecordsToRamBuf(le);
        pos = 0;
    }

    // We have 256 Bytes send-capacity per APDU.
    short sendLen = remaininglen > le ? le : remaininglen;
    apdu.setOutgoingLength(sendLen);
    apdu.sendBytesLong(data, pos, sendLen);
    // the position when using Record[] is maintened by copyRecordsToRamBuf
    if (chaining_object[CHAINING_OBJECT] == null || !(chaining_object[CHAINING_OBJECT] instanceof Record[])) {
        chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS]+= sendLen;
    }

    if (chaining_object[CHAINING_OBJECT] == null) {
        chaining_cache[RAM_CHAINING_CACHE_OFFSET_BYTES_REMAINING] -= sendLen;
    }
    remaininglen -= sendLen;
    if(remaininglen > 0) {
        short nextRespLen = remaininglen > 256 ? 256 : remaininglen;
        ISOException.throwIt( (short)(ISO7816.SW_BYTES_REMAINING_00 | nextRespLen) );
    } else {
        Clear(true);
        return;
    }
}
 
Example 11
Source File: IsoApplet.java    From IsoApplet with GNU General Public License v3.0 4 votes vote down vote up
/**
 * \brief Compute a digital signature of the data from the apdu
 * 			using the private key referenced by	an earlier
 *			MANAGE SECURITY ENVIRONMENT apdu.
 *
 * \attention The apdu should contain a hash, not raw data for RSA keys.
 * 				PKCS1 padding will be applied if neccessary.
 *
 * \param apdu The PERFORM SECURITY OPERATION apdu with P1=9E and P2=9A.
 *
 * \throw ISOException SW_CONDITIONS_NOT_SATISFIED, SW_WRONG_LENGTH
 * 						and SW_UNKNOWN.
 */
private void computeDigitalSignature(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();
    short offset_cdata;
    short lc;
    short sigLen = 0;


    switch(currentAlgorithmRef[0]) {
    case ALG_RSA_PAD_PKCS1:
        // Receive.
        // Bytes received must be Lc.
        lc = apdu.setIncomingAndReceive();
        if(lc != apdu.getIncomingLength()) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        offset_cdata = apdu.getOffsetCdata();

        // RSA signature operation.
        RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) keys[currentPrivateKeyRef[0]];

        if(lc > (short) 247) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        rsaPkcs1Cipher.init(rsaKey, Cipher.MODE_ENCRYPT);
        sigLen = rsaPkcs1Cipher.doFinal(buf, offset_cdata, lc, ram_buf, (short)0);

        if(sigLen != 256) {
            ISOException.throwIt(ISO7816.SW_UNKNOWN);
        }

        // A single short APDU can handle 256 bytes - only one send operation neccessary.
        short le = apdu.setOutgoing();
        if(le < sigLen) {
            ISOException.throwIt(ISO7816.SW_CORRECT_LENGTH_00);
        }
        apdu.setOutgoingLength(sigLen);
        apdu.sendBytesLong(ram_buf, (short) 0, sigLen);
        break;

    case ALG_ECDSA_SHA1:
        // Get the key - it must be a EC private key,
        // checks have been done in MANAGE SECURITY ENVIRONMENT.
        ECPrivateKey ecKey = (ECPrivateKey) keys[currentPrivateKeyRef[0]];

        // Initialisation should be done when:
        // 	- No command chaining is performed at all.
        //	- Command chaining is performed and this is the first apdu in the chain.
        if(ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] == (short) 0) {
            ecdsaSignature.init(ecKey, Signature.MODE_SIGN);
            if(isCommandChainingCLA(apdu)) {
                ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short) 1;
            }
        }

        short recvLen = apdu.setIncomingAndReceive();
        offset_cdata = apdu.getOffsetCdata();

        // Receive data. For extended APDUs, the data is received piecewise
        // and aggregated in the hash. When using short APDUs, command
        // chaining is performed.
        while (recvLen > 0) {
            ecdsaSignature.update(buf, offset_cdata, recvLen);
            recvLen = apdu.receiveBytes(offset_cdata);
        }

        if(!isCommandChainingCLA(apdu)) {
            sigLen = ecdsaSignature.sign(buf, (short)0, (short)0, buf, (short) 0);
            ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS] = (short) 0;
            apdu.setOutgoingAndSend((short) 0, sigLen);
        } else {
            ram_chaining_cache[RAM_CHAINING_CACHE_OFFSET_CURRENT_POS]++;
        }

        break;

    default:
        // Wrong/unknown algorithm.
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }
}
 
Example 12
Source File: CardAgent.java    From CardExamples with The Unlicense 4 votes vote down vote up
/**
 * Handle Read Record command.
 * 
 * @param apdu
 *            the incoming <code>APDU</code> object
 */
private void readRecord(APDU apdu) throws ISOException {
    byte[] apduBuffer = apdu.getBuffer();

    // DEBUG
    Log.v(LOG_TAG, "C-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, 5));

    final byte recordNumber = apduBuffer[ISO7816.OFFSET_P1];

    // Check P1/P2.
    if ((recordNumber == (byte) 0x00) || 
        ((apduBuffer[ISO7816.OFFSET_P2] & (byte) 0x07) != (byte) 0x04)) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    // Check if Lc is not present.
    // Check if Le=0x00.
    if ((apdu.setIncomingAndReceive() != (short) 0) || 
        (apdu.setOutgoing() != (short) 256)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // Check if AFL saved in Get Processing Options or
    //       if Read Records counter is greater than number of records indicated in AFL.
    if ((this.afl == null) || 
        (this.readRecordCounter > this.aflRecords)) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    // Check if SFI and record supported in AFL.
    final byte sfi = (byte) ((apduBuffer[ISO7816.OFFSET_P2] & (byte) 0xF8));
    boolean aflSupported = false;
    this.afl.reset();
    while (this.afl.hasRemaining()) {
        byte aflSfi = this.afl.get();
        byte aflFirstRecord = this.afl.get();
        byte aflLastRecord = this.afl.get();
        if ((aflSfi == sfi) && 
            (aflFirstRecord <= recordNumber) && 
            (aflLastRecord >= recordNumber)) {
            aflSupported = true;
            break;
        }

        // Skip the next byte.
        this.afl.get();
    }
    if (!aflSupported) {
        Log.e(LOG_TAG, "Transaction Failure: SFI and record not supported in AFL.");
        ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }

    // Retrieve record.
    short sfiRecord = (short) ((sfi << 5) | recordNumber);
    byte[] recordData = this.accountParamsStatic.getSfiRecord(sfiRecord);
    if (recordData == null) {
        if (sfiRecord == (short) 0x0204) {
            recordData = this.dynamicSfi2Record4;
        }
        else {
            // Req 7.23
            Log.e(LOG_TAG, "Transaction Failure: SFI and record not found.");
            ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
        }
    }

    // Increment Read Record counter.
    this.readRecordCounter++;

    // Copy record data to APDU response buffer.
    short rdataLength = (short) recordData.length;
    System.arraycopy(recordData, 0, apduBuffer, 0, rdataLength);

    // Determine if this is the last Read Record command.
    if (this.readRecordCounter == this.aflRecords) {
        this.apduState = APDU_SENDING_LAST;
    }
    else {
        this.apduState = APDU_SENDING;
    }

    // DEBUG
    Log.v(LOG_TAG, "R-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, rdataLength) + "9000");

    apdu.setOutgoingLength(rdataLength);
    apdu.sendBytes((short) 0, rdataLength);

    // Determine if this is the last Read Record command.
    if (this.readRecordCounter == this.aflRecords) {
        // Success triggers a successful transaction.
        apdu.setTransactionSuccess();
    }
}
 
Example 13
Source File: Ppse2Pay.java    From CardExamples with The Unlicense 4 votes vote down vote up
@Override
public void process(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();

    if (selectingApplet()) {
        //check that LC is 0x0E
        if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != 0x0E)
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

        //get the rest of the apdu and check length
        if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != apdu.setIncomingAndReceive())
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

        if(FCI_TEMPLATE==null)
        {
            FCI_TEMPLATE = new byte[12 + ADF.length];
            FCI_TEMPLATE[0]=(byte)0xA5; //FCI Proprietary Template
            FCI_TEMPLATE[1]=(byte)(10 + ADF.length);   //length
            FCI_TEMPLATE[2]=(byte)0xBF; //FCI Issuer Discretionary Data
            FCI_TEMPLATE[3]=(byte)0x0C;
            FCI_TEMPLATE[4]=(byte)(7 + ADF.length);   //length

            FCI_TEMPLATE[5]=(byte)0x61; //Directory Entry
            FCI_TEMPLATE[6]=(byte)(ADF.length + 5);   //length
            FCI_TEMPLATE[7]=(byte)0x4F; //ADF Name
            FCI_TEMPLATE[8]=(byte)(ADF.length);    //length
            for(short i=0;i<ADF.length;i++)
                FCI_TEMPLATE[9+i] = ADF[i];
            FCI_TEMPLATE[9 + ADF.length]=(byte)0x87; //Application Priority Indicator
            FCI_TEMPLATE[10 + ADF.length]=(byte)1;    //length
            FCI_TEMPLATE[11 + ADF.length]=(byte)0x01;
        }

        //return FCI upon successful select
        apdu.setOutgoing();

        buf[0]=(byte)0x6F; //FCI Template
        buf[1]=(byte)(2 + DF.length + FCI_TEMPLATE.length);   //length
        buf[2]=(byte)0x84; //DF Name
        buf[3]=(byte)DF.length;   //length
        for(short i=0;i<DF.length;i++)
            buf[4+i] = DF[i];
        for(short i=0;i<FCI_TEMPLATE.length;i++)
            buf[4 + DF.length + i] = FCI_TEMPLATE[i];
        apdu.setOutgoingLength((short)(4 + DF.length + FCI_TEMPLATE.length));
        apdu.sendBytes((short)0,(short)(4 + DF.length + FCI_TEMPLATE.length));
        return;
    }

    switch (buf[ISO7816.OFFSET_INS]) {

        case (byte) 0xA4: //select PPSE
            //check that P1 & P2 are correct
            if(buf[ISO7816.OFFSET_P1] != (byte) 0x04 || buf[ISO7816.OFFSET_P2] != (byte) 0x00)
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);

            //check that LC is 0x0E
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != 0x0E)
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

            //get the rest of the apdu and check length
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != apdu.setIncomingAndReceive())
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
                //otherwise, the file name was wrong for this select
            else ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);

        case (byte) 0xEE: //loopback
            //check that P1 & P2 are correct
            if(buf[ISO7816.OFFSET_P1] != (byte) 0x00 || buf[ISO7816.OFFSET_P2] != (byte) 0x00)
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);

            //check that the length byte is within the spec (1-250)
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) < 1 || (short)(buf[ISO7816.OFFSET_LC] & 0xFF) > 250)
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

            //get the rest of the apdu and check length
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != apdu.setIncomingAndReceive())
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

            short len = buf[ISO7816.OFFSET_LC];
            for(short i=0;i<len;i++)
                buf[i] = buf[i+5];
            apdu.setOutgoingLength(len);
            apdu.sendBytes((short)0,len);
            break;

        default:
            // good practice: If you don't know the INStruction, say so:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }


}
 
Example 14
Source File: Ppse2Pay.java    From CardExamples with The Unlicense 4 votes vote down vote up
@Override
public void process(APDU apdu) throws ISOException {
    byte[] buf = apdu.getBuffer();

    if (selectingApplet()) {
        //check that LC is 0x0E
        if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != 0x0E)
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

        //get the rest of the apdu and check length
        if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != apdu.setIncomingAndReceive())
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

        if(FCI_TEMPLATE==null)
        {
            FCI_TEMPLATE = new byte[12 + ADF.length];
            FCI_TEMPLATE[0]=(byte)0xA5; //FCI Proprietary Template
            FCI_TEMPLATE[1]=(byte)(10 + ADF.length);   //length
            FCI_TEMPLATE[2]=(byte)0xBF; //FCI Issuer Discretionary Data
            FCI_TEMPLATE[3]=(byte)0x0C;
            FCI_TEMPLATE[4]=(byte)(7 + ADF.length);   //length

            FCI_TEMPLATE[5]=(byte)0x61; //Directory Entry
            FCI_TEMPLATE[6]=(byte)(ADF.length + 5);   //length
            FCI_TEMPLATE[7]=(byte)0x4F; //ADF Name
            FCI_TEMPLATE[8]=(byte)(ADF.length);    //length
            for(short i=0;i<ADF.length;i++)
                FCI_TEMPLATE[9+i] = ADF[i];
            FCI_TEMPLATE[9 + ADF.length]=(byte)0x87; //Application Priority Indicator
            FCI_TEMPLATE[10 + ADF.length]=(byte)1;    //length
            FCI_TEMPLATE[11 + ADF.length]=(byte)0x01;
        }

        //return FCI upon successful select
        apdu.setOutgoing();

        buf[0]=(byte)0x6F; //FCI Template
        buf[1]=(byte)(2 + DF.length + FCI_TEMPLATE.length);   //length
        buf[2]=(byte)0x84; //DF Name
        buf[3]=(byte)DF.length;   //length
        for(short i=0;i<DF.length;i++)
            buf[4+i] = DF[i];
        for(short i=0;i<FCI_TEMPLATE.length;i++)
            buf[4 + DF.length + i] = FCI_TEMPLATE[i];
        apdu.setOutgoingLength((short)(4 + DF.length + FCI_TEMPLATE.length));
        apdu.sendBytes((short)0,(short)(4 + DF.length + FCI_TEMPLATE.length));
        return;
    }

    switch (buf[ISO7816.OFFSET_INS]) {

        case (byte) 0xA4: //select PPSE
            //check that P1 & P2 are correct
            if(buf[ISO7816.OFFSET_P1] != (byte) 0x04 || buf[ISO7816.OFFSET_P2] != (byte) 0x00)
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);

            //check that LC is 0x0E
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != 0x0E)
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

            //get the rest of the apdu and check length
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != apdu.setIncomingAndReceive())
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
                //otherwise, the file name was wrong for this select
            else ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);

        case (byte) 0xEE: //loopback
            //check that P1 & P2 are correct
            if(buf[ISO7816.OFFSET_P1] != (byte) 0x00 || buf[ISO7816.OFFSET_P2] != (byte) 0x00)
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);

            //check that the length byte is within the spec (1-250)
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) < 1 || (short)(buf[ISO7816.OFFSET_LC] & 0xFF) > 250)
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

            //get the rest of the apdu and check length
            if((short)(buf[ISO7816.OFFSET_LC] & 0xFF) != apdu.setIncomingAndReceive())
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

            short len = buf[ISO7816.OFFSET_LC];
            for(short i=0;i<len;i++)
                buf[i] = buf[i+5];
            apdu.setOutgoingLength(len);
            apdu.sendBytes((short)0,len);
            break;

        default:
            // good practice: If you don't know the INStruction, say so:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }


}
 
Example 15
Source File: CardAgent.java    From CardExamples with The Unlicense 4 votes vote down vote up
/**
 * Handle Get Processing Options command.
 * 
 * @param apdu
 *            the incoming <code>APDU</code> object
 * @throws ISOException
 */
private void getProcessingOptions(APDU apdu) throws ISOException {
    byte[] apduBuffer = apdu.getBuffer();

    // DEBUG
    Log.v(LOG_TAG, "C-APDU Header: " + DataUtil.byteArrayToHexString(apduBuffer, 0, 5));

    ByteBuffer apduByteBuffer = ByteBuffer.wrap(apduBuffer);

    // Check if P1=0x00 and P2=0x00.
    if (apduByteBuffer.getShort(ISO7816.OFFSET_P1) != (short) 0x0000) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    // Check if Lc=[number of data bytes read].
    // Check if Lc=3.
    // Check if Le=0x00.
    short len = apdu.setIncomingAndReceive();

    // DEBUG
    Log.v(LOG_TAG, "C-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, len + 6));

    if ((len != (short) (apduBuffer[ISO7816.OFFSET_LC] & (short) 0x00FF)) || 
        (len != (short) 3) || 
        (apdu.setOutgoing() != (short) 256)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // Check PDOL data.
    apduByteBuffer.position(ISO7816.OFFSET_CDATA);
    if (apduByteBuffer.getShort() != (short) 0x8301) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    byte terminalType = apduByteBuffer.get();
    // Check if terminal type is offline only.
    if ((terminalType == (byte) 0x13) || 
        (terminalType == (byte) 0x16) || 
        (terminalType == (byte) 0x23) || 
        (terminalType == (byte) 0x26) || 
        (terminalType == (byte) 0x36)) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    this.pdolData = new byte[1];
    this.pdolData[0] = terminalType;

    apduByteBuffer.rewind();
    // Build response.
    apduByteBuffer.put(PayPConstants.TAG_RESPONSE_MESSAGE_TEMPLATE);
    // Skip response message template length.
    apduByteBuffer.put((byte) 0);
    // Skip response message template length.
    // Append data elements in response:
    // '82' [2] Application Interchange Profile
    // '94' [var.] Application File Locator
    apduByteBuffer.put(PayPConstants.TAG_AIP);
    apduByteBuffer.put((byte) this.cardProfile.getAip().length);
    apduByteBuffer.put(this.cardProfile.getAip());
    apduByteBuffer.put(PayPConstants.TAG_AFL);
    apduByteBuffer.put((byte) this.cardProfile.getAfl().length);
    apduByteBuffer.put(this.cardProfile.getAfl());
    int rdataLength = apduByteBuffer.position();
    // Set response template message length.
    apduByteBuffer.put(1, (byte) (rdataLength - 2));

    this.apduState = APDU_SENDING;

    // DEBUG
    Log.v(LOG_TAG, "R-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, rdataLength) + "9000");

    apdu.setOutgoingLength((short) rdataLength);
    apdu.sendBytes((short) 0, (short) rdataLength);
}
 
Example 16
Source File: CardAgent.java    From CardExamples with The Unlicense 4 votes vote down vote up
/**
 * Handle Read Record command.
 * 
 * @param apdu
 *            the incoming <code>APDU</code> object
 */
private void readRecord(APDU apdu) throws ISOException {
    byte[] apduBuffer = apdu.getBuffer();

    // DEBUG
    Log.v(LOG_TAG, "C-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, 5));

    short recordNumber = (short) (apduBuffer[ISO7816.OFFSET_P1] & (short) 0x00FF);
    byte sfi = (byte) ((short) (apduBuffer[ISO7816.OFFSET_P2] & (short) 0x00F8) >> (byte) 3);

    // Check P1/P2.
    if ((recordNumber == (short) 0x0000) || 
        ((apduBuffer[ISO7816.OFFSET_P2] & (byte) 0x07) != (byte) 0x04)) {
        ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    }

    // Check if Lc is not present.
    // Check if Le=0x00.
    if ((apdu.setIncomingAndReceive() != (short) 0) || 
        (apdu.setOutgoing() != (short) 256)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    byte[] recordData = null;
    if (sfi == (byte) 0x01) {
        if (recordNumber == (byte) 0x01) {
            recordData = this.cardProfile.getSfi1Record1();
        }
    }
    else if (sfi == (byte) 0x02) {
        if (recordNumber == (byte) 0x01) {
            recordData = this.cardProfile.getSfi2Record1();
        }
        else if (recordNumber == (byte) 0x02) {
            recordData = this.cardProfile.getSfi2Record2();
        }
        else if (recordNumber == (byte) 0x03) {
            recordData = this.cardProfile.getSfi2Record3();
        }
    }
    else {
        // SFI not found.
        ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }
    if (recordData == null) {
        // SFI found, record number not found.
        ISOException.throwIt(ISO7816.SW_RECORD_NOT_FOUND);
    }

    short rdataLength = (short) recordData.length;
    System.arraycopy(recordData, 0, apduBuffer, 0, rdataLength);

    if (apduBuffer[(byte) 0] == PayPConstants.TAG_READ_RECORD_RESPONSE_MESSAGE_TEMPLATE) {
        // EMV file, check if record is referenced in AFL.

        byte[] afl = this.cardProfile.getAfl();
        short aflDataOffset = 0;
        while (aflDataOffset < afl.length) {
            if ((sfi == (byte) ((short) (afl[aflDataOffset] & (short) 0x00F8) >> (byte) 3)) && 
                (recordNumber >= (short) (afl[(short) (aflDataOffset + (byte) 1)] & (short) 0x00FF)) && 
                (recordNumber <= (short) (afl[(short) (aflDataOffset + (byte) 2)] & (short) 0x00FF))) {
                // Record is referenced in AFL.
                break;
            }

            aflDataOffset += (byte) 4;
        }
        if (aflDataOffset >= afl.length) {
            // Record is not referenced in AFL.
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
        }
    }

    this.apduState = APDU_SENDING;

    // DEBUG
    Log.v(LOG_TAG, "R-APDU: " + DataUtil.byteArrayToHexString(apduBuffer, 0, rdataLength) + "9000");

    apdu.setOutgoingLength(rdataLength);
    apdu.sendBytes((short) 0, rdataLength);
}