PKCS#11 pubkey ids order

I’m trying to understand how are ordered the keys generated from the PIV command line.
I have generated every possible key on my Nitrokey 3 using this command (82-95 + 9a, 9c, 9d, 9e):
nitropy nk3 piv --experimental generate-key --key XX --algo rsa2048

Here is my code to list the key ids using python-pkcs11:

from pkcs11 import ObjectClass, Attribute, KeyType, lib

lib = lib("C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll")
token = lib.get_token(token_serial=b"b3164da64aaa4d8e")
with token.open(user_pin="123456") as session:

    pub_keys = session.get_objects(
        {
            Attribute.CLASS: ObjectClass.PUBLIC_KEY,
            Attribute.KEY_TYPE: KeyType.RSA,
        }
    )
    for pub_key in pub_keys:
        print(pub_key[Attribute.LABEL])
        print(pub_key[Attribute.ID])

Here is the output:
PIV AUTH pubkey
b’\x01’
SIGN pubkey
b’\x02’
KEY MAN pubkey
b’\x03’
Retired KEY MAN 1
b’\x05’
Retired KEY MAN 2
b’\x06’
Retired KEY MAN 3
b’\x07’
Retired KEY MAN 4
b’\x08’
Retired KEY MAN 5
b’\t’
Retired KEY MAN 6
b’\x10’
Retired KEY MAN 7
b’\x11’
Retired KEY MAN 8
b’\x12’
Retired KEY MAN 9
b’\x13’
Retired KEY MAN 10
b’\x14’
Retired KEY MAN 11
b’\x15’
Retired KEY MAN 12
b’\x16’
Retired KEY MAN 13
b’\x17’
Retired KEY MAN 14
b’\x18’
Retired KEY MAN 15
b’\x19’
Retired KEY MAN 16
b’ ’
Retired KEY MAN 17
b’!’
Retired KEY MAN 18
b’"’
Retired KEY MAN 19
b’#’
Retired KEY MAN 20
b’$’
CARD AUTH pubkey
b’\x04’

First, when I print their ids, they are different than the argument --key.

Then, why is id 9 = b’\t’ and not b’\x09’ when id 10 is b’\x10’ and not b’\n’
It seems to be hexadecimal until 9 and then turn to decimal written hexadecimal.

Is this an issue with the firmware or with python-pkcs11 ?

It may be another topic but I can decrypt messages with every of those key except b’\x04’. Is this id special ?

The PIV specs can be found here in 3 parts:

pt1 is overall concepts, pt2 is card interface, pt3 is non PKCS11 interfaces.

OpenSC in 2005 introduced a PKCS11 interface to the PIV at the card interface.

The PIV has 4 basic triplets of private key, public key and certificates each with specific keyUsage which is expected to be in the certificates. See sp800 73 pt1: 3.1.3, 3,1.4, 3.2.1 and 3.2.2, and 20 retired keys in pt1: 3.3.4. “Retired X.509 Certificates for Key Management”
which would allow one to decrypt older files when a new card with new certificates was issued.

Also note when a key is generated on a card, is the only time the public key is returned. So during the provisioning process, the public key is save and added to the certificate as the SPKI.
The Nitro key gen process or other software maybe saving a dummy certificate with the SPKI.

Back in 2005, OpenSC introduced a PKCS11 interface to the PIV cards which then were only used by US gov and there was no linux drivers for the PIV card, only the Windows builtin driver. Since then there have been many “PIV like” cards (some approved by NIST, some not) that add extensions and violated some of the requirements as defined in the PIV standards.

PIV is an applet that can be loaded on many different cards. PIV standard does not define a serial number, so OpenSC uses the CHUID objects GUID to make up a serial number. It also reads the History object to determine how many of the retired keys and certificates are present.
You may need to create the CHUID and History Object if Nitro tools have not done so.

For PKCS11 the certificate is read to get the keyUsage and SPKI which also includes type and size of the private key. OpenSC then uses a made up CK_ID which you are seeing: “It seems to be hexadecimal until 9 and then turn to decimal written hexadecimal”. These can be seen in

which also include the default keyUsage. For non US gov cards, the code will use the keyUsage
from the certificates allowing one to use the “Retired X.509 Certificates for Key Management”
for other uses. OpenSC will also use other types ans sizes of keys if the card is known to support them.

The provisioning utilities of “PIV like” cards emphasize the key ref numbers. Users emphasize
the use of the PKCS11 CK_ID as the PKCS11 certificate, public key and private key all use the
same CK_ID.

The OpenSC pkcs11-tool -O --login --pin xxxxxx can be use to see all the objects that maybe on the card and info for the objects which are present.

OpenSC pkcs11-tool -M also shows the PKCS11 mechanisms supported on the card (listed with “hw”) and other mechanisms which are implemented in software and use the on card “hw” mechanisms.

Thank you for the response.
I have yet to finish reading those files but I think you’ve saved me a lot of time.