src/com/makina/security/OpenFIPS201/PIV.java
public void changeReferenceDataAdmin(byte id, byte[] buffer, short offset, short length) {

        final byte CONST_TAG_SEQUENCE			= (byte)0x30;
        final byte CONST_TAG_KEY				= (byte)0x80;
        final byte CONST_TAG_RSA_N				= (byte)0x81; // RSA Modulus
        final byte CONST_TAG_RSA_E				= (byte)0x82; // RSA Public Exponent
        final byte CONST_TAG_RSA_D				= (byte)0x83; // RSA Private Exponent

        // NOTE: Currently RSA CRT keys are not used, this is a placeholder
        //final short CONST_TAG_RSA_P				= (short)0x0084; // RSA Prime Exponent P
        //final short CONST_TAG_RSA_Q				= (short)0x0085; // RSA Prime Exponent Q
        //final short CONST_TAG_RSA_DP			= (short)0x0086; // RSA D mod P - 1
        //final short CONST_TAG_RSA_DQ			= (short)0x0087; // RSA D mod Q - 1
        //final short CONST_TAG_RSA_PQ			= (short)0x0088; // RSA Inverse Q

        // The PIV Card Application may allow the reference data associated with other key references
        // to be changed by the PIV Card Application CHANGE REFERENCE DATA, if PIV Card Application will
        // only perform the command with other key references if the requirements specified in Section
        // 2.9.2 of FIPS 201-2 are satisfied.

        //
        // SECURITY PRE-CONDITION
        //

        // The command must have been sent over SCP with CEnc+CMac
        if (!cspPIV.checkAccessModeAdmin(true)) {
            ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
        }

        //
        // COMMAND CHAIN HANDLING
        //

        // Pass the APDU to the chainBuffer instance first. It will return zero if there is store more
        // to of the chain to process, otherwise it will return the length of the large CDATA buffer
        length = chainBuffer.processIncomingAPDU(buffer, offset, length, scratch, (short)0);

        // If the length is zero, just return so the caller can keep sending
        if (length == 0) return;

        // If we got this far, the scratch buffer now contains the incoming DATA. Keep in mind that the original buffer
        // still contains the APDU header.


        //
        // PIN cases
        //

        if (buffer[ISO7816.OFFSET_P2] == ID_KEY_PIN) {
            if (!verifyPinFormat(ID_KEY_PIN, scratch, (short)0, length)) {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }

            // Update the PIN
            cspPIV.cardPIN.update(scratch, (short)0, (byte)length);

            // Done
            return;
        }

        if (buffer[ISO7816.OFFSET_P2] == ID_KEY_PUK) {
            if (!verifyPinFormat(ID_KEY_PUK, scratch, (short)0, length)) {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }

            // Update the PUK
            cspPIV.cardPUK.update(scratch, (short)0, (byte)length);

            // Done
            return;
        }



        // PRE-CONDITION 1 - The key reference and mechanism must point to an existing key
        PIVKeyObject key = cspPIV.selectKey(buffer[ISO7816.OFFSET_P2], buffer[ISO7816.OFFSET_P1]);
        if (key == null) {
            // If any key reference value is specified that is not supported by the card, the PIV Card Application
            // shall return the status word '6A 88'.
            ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
        }

        // Set up our TLV reader
        tlvReader.init(scratch, (short)0, length);

        // PRE-CONDITION 2 - The sequence tag must be present in the data
        if (!tlvReader.find(CONST_TAG_SEQUENCE)) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }

        // Move to the child tag
        tlvReader.moveInto();

        //
        // EXECUTION STEPS
        //
        
        key.updateElement(tlvReader.getTag(), scratch, tlvReader.getDataOffset(), tlvReader.getLength());
    }
/**
     * This method is the equivalent of the CHANGE REFERENCE DATA command, however it is intended to
     * operate on key references that are NOT listed in SP800-37-4. This is the primary method
     * by which administrative key references are updated and is intended to fill in the gap in PIV
     * that does not cover how pre-personalisation is implemented.
     *
     * @param id The target key / pin reference being changed
     * @param buffer The incoming APDU buffer
     * @param offset The starting offset of the CDATA section
     * @param length The length of the CDATA section
	 *
     * The main differences to CHANGE REFERENCE DATA are:
     * - It supports updating any key reference that is not covered by CHANGE REFERENCE DATA already
     * - It requires a global platform secure channel to be operating with the CEncDec attribute (encrypted)
     * - It does NOT require the old value to be supplied in order to change a key
     * - It also supports updating the PIN/PUK values, without requiring knowledge of the old value
     *
     */
This method is the equivalent of the CHANGE REFERENCE DATA command, however it is intended to
operate on key references that are NOT listed in SP800-37-4. This is the primary method
by which administrative key references are updated and is intended to fill in the gap in PIV
that does not cover how pre-personalisation is implemented.

@param id The target key / pin reference being changed
@param buffer The incoming APDU buffer
@param offset The starting offset of the CDATA section
@param length The length of the CDATA section

The main differences to CHANGE REFERENCE DATA are:
- It supports updating any key reference that is not covered by CHANGE REFERENCE DATA already
- It requires a global platform secure channel to be operating with the CEncDec attribute (encrypted)
- It does NOT require the old value to be supplied in order to change a key
- It also supports updating the PIN/PUK values, without requiring knowledge of the old value
This method is the equivalent of the CHANGE REFERENCE DATA command however it is intended to operate on key references that are NOT listed in SP800 - 37 - 4 . This is the primary method by which administrative key references are updated and is intended to fill in the gap in PIV that does not cover how pre - personalisation is implemented . @param id The target key / pin reference being changed @param buffer The incoming APDU buffer @param offset The starting offset of the CDATA section @param length The length of the CDATA section The main differences to CHANGE REFERENCE DATA are : - It supports updating any key reference that is not covered by CHANGE REFERENCE DATA already - It requires a global platform secure channel to be operating with the CEncDec attribute ( encrypted ) - It does NOT require the old value to be supplied in order to change a key - It also supports updating the PIN / PUK values without requiring knowledge of the old value
public void changeReferenceDataAdmin(byte id, byte[] buffer, short offset, short length) {
        final byte CONST_TAG_SEQUENCE			= (byte)0x30;
        final byte CONST_TAG_KEY				= (byte)0x80;
        final byte CONST_TAG_RSA_N				= (byte)0x81; 
        final byte CONST_TAG_RSA_E				= (byte)0x82; 
        final byte CONST_TAG_RSA_D				= (byte)0x83; 
         SECURITY PRE-CONDITION
         The command must have been sent over SCP with CEnc+CMac
        if (!cspPIV.checkAccessModeAdmin(true)) {
            ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
        }
         COMMAND CHAIN HANDLING
         Pass the APDU to the chainBuffer instance first. It will return zero if there is store more
         to of the chain to process, otherwise it will return the length of the large CDATA buffer
        length = chainBuffer.processIncomingAPDU(buffer, offset, length, scratch, (short)0);
         If the length is zero, just return so the caller can keep sending
        if (length == 0) return;
         If we got this far, the scratch buffer now contains the incoming DATA. Keep in mind that the original buffer
         still contains the APDU header.
         PIN cases
        if (buffer[ISO7816.OFFSET_P2] == ID_KEY_PIN) {
            if (!verifyPinFormat(ID_KEY_PIN, scratch, (short)0, length)) {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
             Update the PIN
            cspPIV.cardPIN.update(scratch, (short)0, (byte)length);
             Done
            return;
        }
        if (buffer[ISO7816.OFFSET_P2] == ID_KEY_PUK) {
            if (!verifyPinFormat(ID_KEY_PUK, scratch, (short)0, length)) {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
             Update the PUK
            cspPIV.cardPUK.update(scratch, (short)0, (byte)length);
             Done
            return;
        }
         PRE-CONDITION 1 - The key reference and mechanism must point to an existing key
        PIVKeyObject key = cspPIV.selectKey(buffer[ISO7816.OFFSET_P2], buffer[ISO7816.OFFSET_P1]);
        if (key == null) {
             If any key reference value is specified that is not supported by the card, the PIV Card Application
             shall return the status word '6A 88'.
            ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
        }
         Set up our TLV reader
        tlvReader.init(scratch, (short)0, length);
         PRE-CONDITION 2 - The sequence tag must be present in the data
        if (!tlvReader.find(CONST_TAG_SEQUENCE)) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
         Move to the child tag
        tlvReader.moveInto();
         EXECUTION STEPS
        key.updateElement(tlvReader.getTag(), scratch, tlvReader.getDataOffset(), tlvReader.getLength());
    }
public void changeReferenceDataAdmin ( byte id , byte [ ] buffer , short offset , short length ) { final byte CONST_TAG_SEQUENCE = ( byte ) 0x30 ; final byte CONST_TAG_KEY = ( byte ) 0x80 ; final byte CONST_TAG_RSA_N = ( byte ) 0x81 ; final byte CONST_TAG_RSA_E = ( byte ) 0x82 ; final byte CONST_TAG_RSA_D = ( byte ) 0x83 ; if ( ! cspPIV . checkAccessModeAdmin ( true ) ) { ISOException . throwIt ( ISO7816 . SW_SECURITY_STATUS_NOT_SATISFIED ) ; } length = chainBuffer . processIncomingAPDU ( buffer , offset , length , scratch , ( short ) 0 ) ; if ( length == 0 ) return ; if ( buffer [ ISO7816 . OFFSET_P2 ] == ID_KEY_PIN ) { if ( ! verifyPinFormat ( ID_KEY_PIN , scratch , ( short ) 0 , length ) ) { ISOException . throwIt ( ISO7816 . SW_WRONG_DATA ) ; } cspPIV . cardPIN . update ( scratch , ( short ) 0 , ( byte ) length ) ; return ; } if ( buffer [ ISO7816 . OFFSET_P2 ] == ID_KEY_PUK ) { if ( ! verifyPinFormat ( ID_KEY_PUK , scratch , ( short ) 0 , length ) ) { ISOException . throwIt ( ISO7816 . SW_WRONG_DATA ) ; } cspPIV . cardPUK . update ( scratch , ( short ) 0 , ( byte ) length ) ; return ; } PIVKeyObject key = cspPIV . selectKey ( buffer [ ISO7816 . OFFSET_P2 ] , buffer [ ISO7816 . OFFSET_P1 ] ) ; if ( key == null ) { ISOException . throwIt ( SW_REFERENCE_NOT_FOUND ) ; } tlvReader . init ( scratch , ( short ) 0 , length ) ; if ( ! tlvReader . find ( CONST_TAG_SEQUENCE ) ) { ISOException . throwIt ( ISO7816 . SW_WRONG_DATA ) ; } tlvReader . moveInto ( ) ; key . updateElement ( tlvReader . getTag ( ) , scratch , tlvReader . getDataOffset ( ) , tlvReader . getLength ( ) ) ; }
This method is the equivalent of the CHANGE REFERENCE DATA command, however it is intended to
 operate on key references that are NOT listed in SP800-37-4.
This method is the equivalent of the CHANGE REFERENCE DATA command however it is intended to operate on key references that are NOT listed in SP800 - 37 - 4 .
// RSA Modulus // RSA Public Exponent // RSA Private Exponent // NOTE: Currently RSA CRT keys are not used, this is a placeholder //final short CONST_TAG_RSA_P				= (short)0x0084; // RSA Prime Exponent P //final short CONST_TAG_RSA_Q				= (short)0x0085; // RSA Prime Exponent Q //final short CONST_TAG_RSA_DP			= (short)0x0086; // RSA D mod P - 1 //final short CONST_TAG_RSA_DQ			= (short)0x0087; // RSA D mod Q - 1 //final short CONST_TAG_RSA_PQ			= (short)0x0088; // RSA Inverse Q // The PIV Card Application may allow the reference data associated with other key references // to be changed by the PIV Card Application CHANGE REFERENCE DATA, if PIV Card Application will // only perform the command with other key references if the requirements specified in Section // 2.9.2 of FIPS 201-2 are satisfied. // // SECURITY PRE-CONDITION // // The command must have been sent over SCP with CEnc+CMac // // COMMAND CHAIN HANDLING // // Pass the APDU to the chainBuffer instance first. It will return zero if there is store more // to of the chain to process, otherwise it will return the length of the large CDATA buffer // If the length is zero, just return so the caller can keep sending // If we got this far, the scratch buffer now contains the incoming DATA. Keep in mind that the original buffer // still contains the APDU header. // // PIN cases // // Update the PIN // Done // Update the PUK // Done // PRE-CONDITION 1 - The key reference and mechanism must point to an existing key // If any key reference value is specified that is not supported by the card, the PIV Card Application // shall return the status word '6A 88'. // Set up our TLV reader // PRE-CONDITION 2 - The sequence tag must be present in the data // Move to the child tag // // EXECUTION STEPS //