Changing an OpenPGP PIN

When changing the User or Admin PIN on the OpenPGP function of a YubiKey, there is an important quirk to the GPG card-edit behavior which may lead to locking a user out.

When changing either the User or Admin PIN in OpenPGP, a user is requested to supply both their current PIN value, as well as the value the user wishes to change the PIN to. If a user enters their current PIN such that the full correct value has extra characters appended to it, the PIN will be accepted as valid, but the new PIN value set will not match the value supplied by the user.

Example:

For example, consider the case where a user has their YubiKey’s OpenPGP functionality to use PIN with the current value of 123456, and they wish to change this to abcdef.

  1. User connects to their GPG tool and runs the command gpg --card-edit

  2. User enters the command passwd to initate a user PIN change

  3. When prompted for the current PIN, the user enters an incorrect PIN of 123456**7**

  4. When prompted for the new value for the PIN, the user enters abcdef

In this case, the current value for the PIN will be accepted, even though it has an extra character 7 appended to it. The PIN will appear to be changed to the new value abcdef. However, attempting to use this new value for the PIN will fail with an incorrect PIN warning. In actuallity, the new value for the PIN will be 7abcdef, with the extra characters provided for the current PIN being prefixed to the supplied value for the new PIN.

Underlying Causes

This behavior arises from the OpenPGP Card specification, which has an unfortunate ambiguity around the change PIN functionality.

The latest version of the specification mentions the following:

7.2.3 CHANGE REFERENCE DATA

With this command the passwords of the application can be changed. In compliance with EN 419212 only one P1 variation from ISO 7816-4 is defined for signature cards. The command can be accessed without restrictions, the actual PW is part of the command data and will be verified first by the card. The length of the existing password is known in the card, so that neither a delimiter nor padding for filling up fixed formats is necessary for UTF-8 or derived passwords. The length of the new UTF-8/derived password therefore computes L new = Lc – L old. PIN block format 2 passwords have a fixed length of 8 bytes.

Command:

CLA 00 / 0C

INS 24

P1 00

P2 81 (PW1) or 83 (PW3)

Lc xx

Data Actual PW + New PW

Field Length of new UTF-8 or derived PW: min. 06 for PW1, min. 08 for PW3

For max. length see DO ´C4´

For PIN block format 2 two blocks (8 bytes each) for old and new PIN are concatenated

Le Empty (means not present in command)

What this section states is that in order to change a PIN, one single command is sent to the card. This command consists of the current PIN and the new PIN, concatenated and without a separator in between.

In other words, if changing from the current PIN OOOOOO to the new PIN NNNNNN, the data part of the command will look like OOOOOONNNNNN. It is then up to the card to know where the first ends and the second begins based off the expected length of the current PIN. This works most of the time, except when the correct PIN has additional characters accidentially added to the end of it.

In the case where a user accidentially adds additional characters to a valid PIN, an OpenPGP card (including the OpenPGP function on the YubiKey) will receive a single command with both the current PIN, extra characters and new PIN values. For example, if the current PIN is OOOOOO, the new PIN is NNNNNN and the user accidentially enters OOOOOO**AA**, the command will look like OOOOOOAANNNNNN.

The OpenPGP card will know the PIN is 6 characters in size (in this instance), and look at the first 6 characters for validation from the string - **OOOOOO**AANNNNNN. Since OOOOOO is valid for the current PIN, the OpenPGP card will accept the change command as valid. However, the card will then assume the rest of the string, AANNNNNN is the value of the new PIN, and set it to such.

Note that since the length of the PIN is known and checked at validation, adding additional characters when using the PIN for OpenPGP operations will cause it to be rejected.

Since the PIN behavior is part of the specification, changes to this behavior will require modification to the specification itself.