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

        //
        // PRE-CONDITIONS
        //

        // PRE-CONDITION 1
        // Only reference data associated with key references '80' and '81' specific to the PIV Card Application (i.e.,
        // local key reference) and the Global PIN with key reference '00' may be changed by the PIV Card
        // Application CHANGE REFERENCE DATA command.
        // Key reference '80' reference data shall be changed by the PIV Card Application CHANGE REFERENCE
        // DATA command. The ability to change reference data associated with key references '81' and '00' using
        // the PIV Card Application CHANGE REFERENCE DATA command is optional.


        // If key reference '81' is specified and the command is submitted over the contactless interface (including
        // SM or VCI), then the card command shall fail. If key reference '00' or '80' is specified and the command
        // is not submitted over either the contact interface or the VCI, then the card command shall fail. In each
        // case, the security status and the retry counter of the key reference shall remain unchanged.

        // NOTE: This is handled in the switch statement and is configurable at compile-time

        OwnerPIN pin = null;
        boolean pinAlways = false;
        byte intermediateLimit = (byte)0;

        switch (id) {

        case ID_KEY_GLOBAL_PIN:
            // Make sure FEATURE_PIN_GLOBAL_ENABLED is enabled (if you can't verify, you can't change either)
            if (!Config.FEATURE_PIN_GLOBAL_ENABLED) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);

            // Make sure FEATURE_PIN_GLOBAL_CHANGE is enabled
            if (!Config.FEATURE_PIN_GLOBAL_CHANGE) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);

            // Check whether we are allowed to operate over contactless if applicable
            if (!Config.FEATURE_PIN_OVER_CONTACTLESS && cspPIV.getIsContactless()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);

            pin = cspPIV.globalPIN;
            intermediateLimit = Config.PIN_RETRIES_INTERMEDIATE;
            break;


        case ID_KEY_PIN:
            // Make sure FEATURE_PIN_CARD_ENABLED is enabled (if you can't verify, you can't change either)
            if (!Config.FEATURE_PIN_CARD_ENABLED) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);

            // Check whether we are allowed to operate over contactless if applicable
            if (!Config.FEATURE_PIN_OVER_CONTACTLESS && cspPIV.getIsContactless()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);

            pin = cspPIV.cardPIN;
            intermediateLimit = Config.PIN_RETRIES_INTERMEDIATE;


            break;

        case ID_KEY_PUK:

            // Make sure FEATURE_PUK_CHANGE is enabled
            if (!Config.FEATURE_PUK_CHANGE) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);

            // Check whether we are allowed to operate over contactless if applicable
            if (!Config.FEATURE_PUK_OVER_CONTACTLESS && cspPIV.getIsContactless()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);

            pin = cspPIV.cardPUK;
            intermediateLimit = Config.PUK_RETRIES_INTERMEDIATE;
            break;

        default:
            ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
        }


        // If the current value of the retry counter associated with the key reference is zero, then the reference data
        // associated with the key reference shall not be changed and the PIV Card Application shall return the
        // status word '69 83'.
        if (pin.getTriesRemaining() == (short)0) ISOException.throwIt(SW_OPERATION_BLOCKED);

        // If the command is submitted over the contactless interface (VCI) and the current value of the retry counter
        // associated with the key reference is at or below the issuer-specified intermediate retry value (see Section 3.2.1),
        // then the reference data associated with the key reference shall not be changed and the PIV Card Application shall
        // return the status word '69 83'.
        if (pin.getTriesRemaining() <= intermediateLimit) ISOException.throwIt(SW_OPERATION_BLOCKED);

        // If the authentication data in the command data field does not match the current value of the reference data
        // or if either the authentication data or the new reference data in the command data field of the command
        // does not satisfy the criteria in Section 2.4.3, the PIV Card Application shall not change the reference data
        // associated with the key reference and shall return either status word '6A 80' or '63 CX', with the following
        // restrictions.
        // SIMPLIFIED: If [Old PIN format is BAD] or [New PIN format is BAD] you can choose 6A80 or 63CX. We choose 6A80

        // If the authentication data in the command data field satisfies the criteria in Section 2.4.3 and
        // matches the current value of the reference data, but the new reference data in the command data field of
        // the command does not satisfy the criteria in Section 2.4.3, the PIV Card Application shall return status
        // word '6A 80'.
        // SIMPLIFIED: If [Old PIN is GOOD] but [New PIN format is BAD], use 6A80.

        // If the authentication data in the command data field does not match the current value of the
        // reference data, but both the authentication data and the new reference data in the command data field of
        // the command satisfy the criteria in Section 2.4.3, the PIV Card Application shall return status word
        // '63 CX'.
        // SIMPLIFIED: If [Old PIN format is GOOD] but [Old PIN is BAD], use 63CX and decrement.

        // If status word '6A 80' is returned, the security status and retry counter associated with the key
        // reference shall remain unchanged.9 If status word '63 CX' is returned, the security status of the key
        // reference shall be set to FALSE and the retry counter associated with the key reference shall be
        // decremented by one.

        // If the new reference data (PIN) in the command data field of the command does not satisfy the
        // criteria in Section 2.4.3, then the PIV Card Application shall return the status word '6A 80'.

        // Verify the authentication reference data (old PIN) format
        if (!verifyPinFormat(id, buffer, offset, Config.PIN_LENGTH_MAX)) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }

        // Verify the authentication reference data (old PIN) value
        if (!pin.check(buffer, offset, Config.PIN_LENGTH_MAX)) {
            // Return the number of retries remaining
            ISOException.throwIt((short)(SW_RETRIES_REMAINING | (short)pin.getTriesRemaining()));
        }

        // Move to the new reference data
        offset += Config.PIN_LENGTH_MAX;

        // Verify the new reference data (new PIN)
        if (!verifyPinFormat(id, buffer, offset, Config.PIN_LENGTH_MAX)) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }

        //
        // EXECUTION STEPS
        //

        // If the card command succeeds, then the security status of the key reference shall be set to TRUE and the
        // retry counter associated with the key reference shall be set to the reset retry value associated with the key
        // reference.

        // STEP 1 - Update the PIN
        pin.update(buffer, offset, Config.PIN_LENGTH_MAX);

        // STEP 2 - Verify the new PIN, which will have the effect of setting it to TRUE and resetting the retry counter
        pin.check(buffer, offset, Config.PIN_LENGTH_MAX);

        // STEP 3 - Set the PIN ALWAYS flag as this is now verified
        if (pinAlways) cspPIV.setPINAlways(true);

        // Done
    }
/**
     * The CHANGE REFERENCE DATA card command initiates the comparison of the authentication data in the command data
     * field with the current value of the reference data and, if this comparison is successful, replaces the reference
     * data with new reference data.
     *
     * @param id The requested PIN reference
     * @param buffer The incoming APDU buffer
     * @param offset The starting offset of the CDATA element
     * @param length The length of the CDATA element
     */
The CHANGE REFERENCE DATA card command initiates the comparison of the authentication data in the command data
field with the current value of the reference data and, if this comparison is successful, replaces the reference
data with new reference data.

@param id The requested PIN reference
@param buffer The incoming APDU buffer
@param offset The starting offset of the CDATA element
@param length The length of the CDATA element
The CHANGE REFERENCE DATA card command initiates the comparison of the authentication data in the command data field with the current value of the reference data and if this comparison is successful replaces the reference data with new reference data . @param id The requested PIN reference @param buffer The incoming APDU buffer @param offset The starting offset of the CDATA element @param length The length of the CDATA element
public void changeReferenceData(byte id, byte[] buffer, short offset, short length) {
         PRE-CONDITIONS
         PRE-CONDITION 1
         Only reference data associated with key references '80' and '81' specific to the PIV Card Application (i.e.,
         local key reference) and the Global PIN with key reference '00' may be changed by the PIV Card
         Application CHANGE REFERENCE DATA command.
         Key reference '80' reference data shall be changed by the PIV Card Application CHANGE REFERENCE
         DATA command. The ability to change reference data associated with key references '81' and '00' using
         the PIV Card Application CHANGE REFERENCE DATA command is optional.
         If key reference '81' is specified and the command is submitted over the contactless interface (including
         SM or VCI), then the card command shall fail. If key reference '00' or '80' is specified and the command
         is not submitted over either the contact interface or the VCI, then the card command shall fail. In each
         case, the security status and the retry counter of the key reference shall remain unchanged.
         NOTE: This is handled in the switch statement and is configurable at compile-time
        OwnerPIN pin = null;
        boolean pinAlways = false;
        byte intermediateLimit = (byte)0;
        switch (id) {
        case ID_KEY_GLOBAL_PIN:
             Make sure FEATURE_PIN_GLOBAL_ENABLED is enabled (if you can't verify, you can't change either)
            if (!Config.FEATURE_PIN_GLOBAL_ENABLED) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
             Make sure FEATURE_PIN_GLOBAL_CHANGE is enabled
            if (!Config.FEATURE_PIN_GLOBAL_CHANGE) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
             Check whether we are allowed to operate over contactless if applicable
            if (!Config.FEATURE_PIN_OVER_CONTACTLESS && cspPIV.getIsContactless()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
            pin = cspPIV.globalPIN;
            intermediateLimit = Config.PIN_RETRIES_INTERMEDIATE;
            break;
        case ID_KEY_PIN:
             Make sure FEATURE_PIN_CARD_ENABLED is enabled (if you can't verify, you can't change either)
            if (!Config.FEATURE_PIN_CARD_ENABLED) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
             Check whether we are allowed to operate over contactless if applicable
            if (!Config.FEATURE_PIN_OVER_CONTACTLESS && cspPIV.getIsContactless()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
            pin = cspPIV.cardPIN;
            intermediateLimit = Config.PIN_RETRIES_INTERMEDIATE;
            break;
        case ID_KEY_PUK:
             Make sure FEATURE_PUK_CHANGE is enabled
            if (!Config.FEATURE_PUK_CHANGE) ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
             Check whether we are allowed to operate over contactless if applicable
            if (!Config.FEATURE_PUK_OVER_CONTACTLESS && cspPIV.getIsContactless()) ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
            pin = cspPIV.cardPUK;
            intermediateLimit = Config.PUK_RETRIES_INTERMEDIATE;
            break;
        default:
            ISOException.throwIt(SW_REFERENCE_NOT_FOUND);
        }
         If the current value of the retry counter associated with the key reference is zero, then the reference data
         associated with the key reference shall not be changed and the PIV Card Application shall return the
         status word '69 83'.
        if (pin.getTriesRemaining() == (short)0) ISOException.throwIt(SW_OPERATION_BLOCKED);
         If the command is submitted over the contactless interface (VCI) and the current value of the retry counter
         associated with the key reference is at or below the issuer-specified intermediate retry value (see Section 3.2.1),
         then the reference data associated with the key reference shall not be changed and the PIV Card Application shall
         return the status word '69 83'.
        if (pin.getTriesRemaining() <= intermediateLimit) ISOException.throwIt(SW_OPERATION_BLOCKED);
         If the authentication data in the command data field does not match the current value of the reference data
         or if either the authentication data or the new reference data in the command data field of the command
         does not satisfy the criteria in Section 2.4.3, the PIV Card Application shall not change the reference data
         associated with the key reference and shall return either status word '6A 80' or '63 CX', with the following
         restrictions.
         SIMPLIFIED: If [Old PIN format is BAD] or [New PIN format is BAD] you can choose 6A80 or 63CX. We choose 6A80
         If the authentication data in the command data field satisfies the criteria in Section 2.4.3 and
         matches the current value of the reference data, but the new reference data in the command data field of
         the command does not satisfy the criteria in Section 2.4.3, the PIV Card Application shall return status
         word '6A 80'.
         SIMPLIFIED: If [Old PIN is GOOD] but [New PIN format is BAD], use 6A80.
         If the authentication data in the command data field does not match the current value of the
         reference data, but both the authentication data and the new reference data in the command data field of
         the command satisfy the criteria in Section 2.4.3, the PIV Card Application shall return status word
         '63 CX'.
         SIMPLIFIED: If [Old PIN format is GOOD] but [Old PIN is BAD], use 63CX and decrement.
         If status word '6A 80' is returned, the security status and retry counter associated with the key
         reference shall remain unchanged.9 If status word '63 CX' is returned, the security status of the key
         reference shall be set to FALSE and the retry counter associated with the key reference shall be
         decremented by one.
         If the new reference data (PIN) in the command data field of the command does not satisfy the
         criteria in Section 2.4.3, then the PIV Card Application shall return the status word '6A 80'.
         Verify the authentication reference data (old PIN) format
        if (!verifyPinFormat(id, buffer, offset, Config.PIN_LENGTH_MAX)) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
         Verify the authentication reference data (old PIN) value
        if (!pin.check(buffer, offset, Config.PIN_LENGTH_MAX)) {
             Return the number of retries remaining
            ISOException.throwIt((short)(SW_RETRIES_REMAINING | (short)pin.getTriesRemaining()));
        }
         Move to the new reference data
        offset += Config.PIN_LENGTH_MAX;
         Verify the new reference data (new PIN)
        if (!verifyPinFormat(id, buffer, offset, Config.PIN_LENGTH_MAX)) {
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
         EXECUTION STEPS
         If the card command succeeds, then the security status of the key reference shall be set to TRUE and the
         retry counter associated with the key reference shall be set to the reset retry value associated with the key
         reference.
         STEP 1 - Update the PIN
        pin.update(buffer, offset, Config.PIN_LENGTH_MAX);
         STEP 2 - Verify the new PIN, which will have the effect of setting it to TRUE and resetting the retry counter
        pin.check(buffer, offset, Config.PIN_LENGTH_MAX);
         STEP 3 - Set the PIN ALWAYS flag as this is now verified
        if (pinAlways) cspPIV.setPINAlways(true);
         Done
    }
public void changeReferenceData ( byte id , byte [ ] buffer , short offset , short length ) { OwnerPIN pin = null ; boolean pinAlways = false ; byte intermediateLimit = ( byte ) 0 ; switch ( id ) { case ID_KEY_GLOBAL_PIN : if ( ! Config . FEATURE_PIN_GLOBAL_ENABLED ) ISOException . throwIt ( SW_REFERENCE_NOT_FOUND ) ; if ( ! Config . FEATURE_PIN_GLOBAL_CHANGE ) ISOException . throwIt ( SW_REFERENCE_NOT_FOUND ) ; if ( ! Config . FEATURE_PIN_OVER_CONTACTLESS && cspPIV . getIsContactless ( ) ) ISOException . throwIt ( ISO7816 . SW_SECURITY_STATUS_NOT_SATISFIED ) ; pin = cspPIV . globalPIN ; intermediateLimit = Config . PIN_RETRIES_INTERMEDIATE ; break ; case ID_KEY_PIN : if ( ! Config . FEATURE_PIN_CARD_ENABLED ) ISOException . throwIt ( SW_REFERENCE_NOT_FOUND ) ; if ( ! Config . FEATURE_PIN_OVER_CONTACTLESS && cspPIV . getIsContactless ( ) ) ISOException . throwIt ( ISO7816 . SW_SECURITY_STATUS_NOT_SATISFIED ) ; pin = cspPIV . cardPIN ; intermediateLimit = Config . PIN_RETRIES_INTERMEDIATE ; break ; case ID_KEY_PUK : if ( ! Config . FEATURE_PUK_CHANGE ) ISOException . throwIt ( SW_REFERENCE_NOT_FOUND ) ; if ( ! Config . FEATURE_PUK_OVER_CONTACTLESS && cspPIV . getIsContactless ( ) ) ISOException . throwIt ( ISO7816 . SW_SECURITY_STATUS_NOT_SATISFIED ) ; pin = cspPIV . cardPUK ; intermediateLimit = Config . PUK_RETRIES_INTERMEDIATE ; break ; default : ISOException . throwIt ( SW_REFERENCE_NOT_FOUND ) ; } if ( pin . getTriesRemaining ( ) == ( short ) 0 ) ISOException . throwIt ( SW_OPERATION_BLOCKED ) ; if ( pin . getTriesRemaining ( ) <= intermediateLimit ) ISOException . throwIt ( SW_OPERATION_BLOCKED ) ; if ( ! verifyPinFormat ( id , buffer , offset , Config . PIN_LENGTH_MAX ) ) { ISOException . throwIt ( ISO7816 . SW_WRONG_DATA ) ; } if ( ! pin . check ( buffer , offset , Config . PIN_LENGTH_MAX ) ) { ISOException . throwIt ( ( short ) ( SW_RETRIES_REMAINING | ( short ) pin . getTriesRemaining ( ) ) ) ; } offset += Config . PIN_LENGTH_MAX ; if ( ! verifyPinFormat ( id , buffer , offset , Config . PIN_LENGTH_MAX ) ) { ISOException . throwIt ( ISO7816 . SW_WRONG_DATA ) ; } pin . update ( buffer , offset , Config . PIN_LENGTH_MAX ) ; pin . check ( buffer , offset , Config . PIN_LENGTH_MAX ) ; if ( pinAlways ) cspPIV . setPINAlways ( true ) ; }
The CHANGE REFERENCE DATA card command initiates the comparison of the authentication data in the command data
 field with the current value of the reference data and, if this comparison is successful, replaces the reference
 data with new reference data.
The CHANGE REFERENCE DATA card command initiates the comparison of the authentication data in the command data field with the current value of the reference data and if this comparison is successful replaces the reference data with new reference data .
// // PRE-CONDITIONS // // PRE-CONDITION 1 // Only reference data associated with key references '80' and '81' specific to the PIV Card Application (i.e., // local key reference) and the Global PIN with key reference '00' may be changed by the PIV Card // Application CHANGE REFERENCE DATA command. // Key reference '80' reference data shall be changed by the PIV Card Application CHANGE REFERENCE // DATA command. The ability to change reference data associated with key references '81' and '00' using // the PIV Card Application CHANGE REFERENCE DATA command is optional. // If key reference '81' is specified and the command is submitted over the contactless interface (including // SM or VCI), then the card command shall fail. If key reference '00' or '80' is specified and the command // is not submitted over either the contact interface or the VCI, then the card command shall fail. In each // case, the security status and the retry counter of the key reference shall remain unchanged. // NOTE: This is handled in the switch statement and is configurable at compile-time // Make sure FEATURE_PIN_GLOBAL_ENABLED is enabled (if you can't verify, you can't change either) // Make sure FEATURE_PIN_GLOBAL_CHANGE is enabled // Check whether we are allowed to operate over contactless if applicable // Make sure FEATURE_PIN_CARD_ENABLED is enabled (if you can't verify, you can't change either) // Check whether we are allowed to operate over contactless if applicable // Make sure FEATURE_PUK_CHANGE is enabled // Check whether we are allowed to operate over contactless if applicable // If the current value of the retry counter associated with the key reference is zero, then the reference data // associated with the key reference shall not be changed and the PIV Card Application shall return the // status word '69 83'. // If the command is submitted over the contactless interface (VCI) and the current value of the retry counter // associated with the key reference is at or below the issuer-specified intermediate retry value (see Section 3.2.1), // then the reference data associated with the key reference shall not be changed and the PIV Card Application shall // return the status word '69 83'. // If the authentication data in the command data field does not match the current value of the reference data // or if either the authentication data or the new reference data in the command data field of the command // does not satisfy the criteria in Section 2.4.3, the PIV Card Application shall not change the reference data // associated with the key reference and shall return either status word '6A 80' or '63 CX', with the following // restrictions. // SIMPLIFIED: If [Old PIN format is BAD] or [New PIN format is BAD] you can choose 6A80 or 63CX. We choose 6A80 // If the authentication data in the command data field satisfies the criteria in Section 2.4.3 and // matches the current value of the reference data, but the new reference data in the command data field of // the command does not satisfy the criteria in Section 2.4.3, the PIV Card Application shall return status // word '6A 80'. // SIMPLIFIED: If [Old PIN is GOOD] but [New PIN format is BAD], use 6A80. // If the authentication data in the command data field does not match the current value of the // reference data, but both the authentication data and the new reference data in the command data field of // the command satisfy the criteria in Section 2.4.3, the PIV Card Application shall return status word // '63 CX'. // SIMPLIFIED: If [Old PIN format is GOOD] but [Old PIN is BAD], use 63CX and decrement. // If status word '6A 80' is returned, the security status and retry counter associated with the key // reference shall remain unchanged.9 If status word '63 CX' is returned, the security status of the key // reference shall be set to FALSE and the retry counter associated with the key reference shall be // decremented by one. // If the new reference data (PIN) in the command data field of the command does not satisfy the // criteria in Section 2.4.3, then the PIV Card Application shall return the status word '6A 80'. // Verify the authentication reference data (old PIN) format // Verify the authentication reference data (old PIN) value // Return the number of retries remaining // Move to the new reference data // Verify the new reference data (new PIN) // // EXECUTION STEPS // // If the card command succeeds, then the security status of the key reference shall be set to TRUE and the // retry counter associated with the key reference shall be set to the reset retry value associated with the key // reference. // STEP 1 - Update the PIN // STEP 2 - Verify the new PIN, which will have the effect of setting it to TRUE and resetting the retry counter // STEP 3 - Set the PIN ALWAYS flag as this is now verified // Done