/** * Process the MANAGE SECURITY ENVIRONMENT instruction (0x22). ISO7816-4, Section 7.5.11 * * <p>This command can be also used to prepare key generation. In this case the algorithm * indication is not required, in fact, should not be present. Note that the key identifiers * should be already set up with put data before that. */ private void processManageSecurityEnvironment(APDU apdu) { boolean forKeyGeneration = false; if (state == STATE_INITIAL) { forKeyGeneration = true; } else if (state == STATE_PREPERSONALISED) { ISOException.throwIt(SW_INS_NOT_SUPPORTED); } pin.reset(); byte[] buf = apdu.getBuffer(); byte p1 = buf[OFFSET_P1]; byte p2 = buf[OFFSET_P2]; // P1 should be: // (a) 0x40: computation, decipherment, internal authentication, ... // (b) 0x01: set if (p1 != (byte) 0x41) { ISOException.throwIt(SW_INCORRECT_P1P2); } byte[] expectedKeyId = null; // P2 should be one of the following, see ISO7816-4 Table 79 if (p2 == (byte) 0xa4) { expectedKeyId = authKeyId; } else if (p2 == (byte) 0xb6) { expectedKeyId = signKeyId; } else if (p2 == (byte) 0xB8) { expectedKeyId = decKeyId; } else { ISOException.throwIt(SW_INCORRECT_P1P2); } short lc = unsigned(buf[OFFSET_LC]); if (lc == 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); short offset = OFFSET_CDATA; lc += OFFSET_CDATA; // Tag for the private key: short len = checkDataObject(buf, offset, lc, (byte) 0x84); offset += 2; if (len != expectedKeyId[0]) { ISOException.throwIt(SW_WRONG_LENGTH); } if (Util.arrayCompare(buf, offset, expectedKeyId, (short) 1, len) != 0) { ISOException.throwIt(SW_KEY_NOT_FOUND); } offset += len; // Algorithm identfier tag if (!forKeyGeneration) { if (offset >= lc) { ISOException.throwIt(SW_WRONG_DATA); } len = checkDataObject(buf, offset, lc, (byte) 0x80); offset += 2; if (len != 1) { ISOException.throwIt(SW_WRONG_LENGTH); } byte sAlg = buf[offset++]; if (offset != lc) { ISOException.throwIt(SW_WRONG_LENGTH); } if (sAlg < ALG_AUTH_DEC_RSA || sAlg > ALG_SIGN_RSA_PKCS1_SHA1MD5) { ISOException.throwIt(SW_WRONG_DATA); } tmp[TMP_SIGNALG_OFFSET] = sAlg; } else { if (offset != lc) { ISOException.throwIt(SW_WRONG_LENGTH); } } if (expectedKeyId == authKeyId) { currentPrivateKey[0] = authKeyPrivate; } else if (expectedKeyId == signKeyId) { currentPrivateKey[0] = signKeyPrivate; } else if (expectedKeyId == decKeyId) { currentPrivateKey[0] = decKeyPrivate; } }
/** Process the SELECT (file) instruction (0xA4) ISO7816-4 Section 7.1.1 */ private void processSelectFile(APDU apdu) { byte[] buf = apdu.getBuffer(); byte p1 = buf[OFFSET_P1]; // byte p2 = buf[OFFSET_P2]; short lc = unsigned(buf[OFFSET_LC]); if (p1 == 0x04) { // Select the AID of the applet // do heavy verification, just for the fun of it ;) if (lc != (short) 0x0C) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); if (Util.arrayCompare(buf, OFFSET_CDATA, myAID, (short) 0, lc) != 0) { ISOException.throwIt(SW_WRONG_DATA); } return; } short id = 0; switch (p1) { case (byte) 0x00: // Direct selection of MF, DF, or EF: if (lc != 0 && lc != 2) { ISOException.throwIt(SW_WRONG_LENGTH); } if (lc > 0) { apdu.setIncomingAndReceive(); id = Util.makeShort(buf[OFFSET_CDATA], buf[(short) (OFFSET_CDATA + 1)]); } else { id = FileSystem.MASTER_FILE_ID; } if (!fileSystem.selectEntryAbsolute(id)) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; case (byte) 0x01: case (byte) 0x02: // Select the child under the current DF, // p1 0x01 DF identifier in data field // p1 0x02 EF identifier in data field if (lc != 2) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); id = Util.makeShort(buf[OFFSET_CDATA], buf[(short) (OFFSET_CDATA + 1)]); if (!fileSystem.selectEntryUnderCurrent(id, p1 == (byte) 0x02)) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; case (byte) 0x03: // Select the parent of the current DF // no command data if (lc != 0) { ISOException.throwIt(SW_WRONG_LENGTH); } if (!fileSystem.selectEntryParent()) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; case (byte) 0x08: case (byte) 0x09: // Select by path // p1 0x08 from MF // p1 0x09 from current DF // data field: the path without the head if (lc == 0 || (short) (lc % 2) != 0) { ISOException.throwIt(SW_WRONG_LENGTH); } apdu.setIncomingAndReceive(); if (!fileSystem.selectEntryByPath(buf, OFFSET_CDATA, lc, p1 == (byte) 0x08)) { ISOException.throwIt(SW_FILE_NOT_FOUND); } break; default: ISOException.throwIt(SW_INCORRECT_P1P2); } }