Change Private Key Usage retroactivly?

Hey everyone,
am I assuming correctly, that there is no way to change the Usage of a Private-Key after it has been generated? We have a couple of Keys that are missing the Usage ‘derive’ due to the defaults being of when using a python pkcs11-Library.

Is there anyway to fix this or are we out of luck and have to generate new keys and hope that our CA doesn’t charge for the reissuing of the certificates associated with these keys?

Thanks in Advance.
Best Regards,

Jan

Normally you cannot change them.

But you might be lucky if you do a low-level manipulation of files on the card, you might succeed in changing the private key information object, which looks roughly like this:

radziecki> /usr/local/bin/opensc-explorer
OpenSC Explorer version 0.23.0
Using reader with a card: Nitrokey Nitrokey HSM (DENK01045710000         ) 00 00
OpenSC [3F00]> cd aid:E82B0601040181C31F0201
OpenSC [E82B/0601/0401/81C3/1F02/01]> cat C401
00000000: A0 2F 30 04 0C 02 45 31 30 1B 04 14 CD 0A 6B 4D ./0...E10.....kM
00000010: C6 2D 12 D8 FF AD 08 CC E8 D0 5D 00 CC 53 7D C7 .-........]..S}.
00000020: 03 03 07 20 80 A1 0A 30 08 30 02 04 00 02 02 01 ... ...0.0......
00000030: 00                                              .
OpenSC [E82B/0601/0401/81C3/1F02/01]> asn1 C401
A0 Context 0  (47 bytes)
   30 SEQUENCE (4 bytes)
      0C UTF8String (2 bytes): E1
   30 SEQUENCE (27 bytes)
      04 OCTET STRING (20 bytes)
         CD 0A 6B 4D C6 2D 12 D8 FF AD 08 CC E8 D0 5D 00 ..kM.-........].
         CC 53 7D C7                                     .S}.
      03 BIT STRING (3 bytes): 100000100
   A1 Context 1  (10 bytes)
      30 SEQUENCE (8 bytes)
         30 SEQUENCE (2 bytes)
            04 OCTET STRING (0 bytes)
         02 INTEGER (2 bytes): 256

A similar low-level problem has been discussed in the thread linked below, but the solution was a JavaScript code to simplify the update, you might check this out as well:

First of all, thanks for giving me some hope in this stressful situation.

I actually can’t figure out how to translate the fix applied here to my problem though. I found my Private Key and I guess i need to now find the right part of the ASN1-Structure to edit if I am correct. And then how to edit it as well. I saw that my Keys have CKA_MODIFIABLE set to True in the meantime and tried to Update the attribute through C_setAttributeValue, but that failed. Apparently CKA_DERIVE is not Modifiable through those means…

So this is my last straw.

Once again, thanks for giving me some way that might work, even though I haven’t quite figured out how

I wouldn’t use PKCS#11 interfaces at all here. I am not sure if any of the PKCS#11 drivers we can use for SmartCard-HSM/Nitrokey HSM can modify those attributes. From a quick look at the code sc-hsm-embedded driver allows only to set CKA_ID and CKA_LABEL via PKCS#11.

I think there are at least two ways to fix it:

  • Directly modify PKCS#15 file objects (maybe get and put operations from opensc-explorer can do it)
  • Take a backup of the key using SmartCard Shell to the *.wky file and modify the file itself, as it was done in the thread mentioned above. Then just restore the key from a modified backup.
1 Like

We have gotten a step further. Modifying a Backup I was able to add the “derive” usage. Sadly we are now facing the “Private Key not found” issue even though it clearly is there. Sadly I can’t seem to get @sc-hsm script to run correctly it always shows the error

org.mozilla.javascript.EcmaError: ReferenceError: "Dialog" is not defined. (/home/user/scsh-3.18.14/scsh-3.18.14/sc-hsm-sdk-scripts/examples/repair-prkd.js#55)
    at /home/user/scsh-3.18.14/scsh-3.18.14/sc-hsm-sdk-scripts/examples/repair-prkd.js#55

How the key looks like now:

Private EC Key [Derive TEST Key]
        Object Flags   : [0x03], private, modifiable
        Usage          : [0x10C], sign, signRecover, derive
        Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
        Algo_refs      : 0
        FieldLength    : 256
        Key ref        : 11 (0x0B)
        Native         : yes
        Auth ID        : 01
        ID             : cd7484dfe2cb9a20df70e8af099d69d5be2f016c
        MD:guid        : 8523dc1e-9513-0d51-f70e-e3eba31aa3fd

If I can get it to work somehow I will gladly share the code it took to modify the Backup, so that people stumbling over this post with the same “problem” don’t need to do this themselves

EDIT:
For more Information, I will attatch a ls from opensc-explorer. Definetly not quite right…

Using reader with a card: Nitrokey Nitrokey HSM (DENK02008760000         ) 00 00
OpenSC [3F00]> cd aid:E82B0601040181C31F0201
OpenSC [E82B/0601/0401/81C3/1F02/01]> ls
FileID  Type  Size
 2F02    wEF   462
 2F03    wEF    20
 CE01    wEF   490
 C401    wEF    79
 CE02    wEF   490
 C402    wEF    79
 CE03    wEF   490
 C403    wEF    80
 CE04    wEF   490
 C404    wEF    80
 CE05    wEF   490
 C405    wEF    80
 CE06    wEF   490
 C406    wEF    80
 CE07    wEF   490
 C407    wEF    81
 CE08    wEF   490
 C408    wEF    81
 CE09    wEF   490
 CE0A    wEF   416
 C40A    wEF    67
 C40B    wEF    76
 CE0B    wEF   490
 CC00    wEF     0
 CC01    wEF     0
 CC02    wEF     0
 CC03    wEF     0
 CC04    wEF     0
 CC05    wEF     0
 CC06    wEF     0
 CC07    wEF     0
 CC08    wEF     0
 CC0A    wEF     0
 CC0B    wEF     0

EDIT2:
From what I can tell I have the same “Private Key not found” when importing UNMODIFIED Backups of the Key. I guess I now have the same problem as in the linked Thread and just need to figure out how to get the repair-Script working.

EDIT3:
Not exactly the same Issue as we dont have Certificates, its just a key-pair

>load("test.js")
SEQUENCE SIZE( 933 )
  OCTET-STRING SIZE( 363 )
--- Wrapped Key ---
  A0 [ CONTEXT 0 ] IMPLICIT SEQUENCE SIZE( 74 )
    SEQUENCE SIZE( 24 )
      UTF8-STRING SIZE( 15 )
        0000  44 65 72 69 76 65 20 54 45 53 54 20 4B 65 79     Derive TEST Key
      BIT-STRING SIZE( 2 )
        0000  06 C0                                            ..
      OCTET-STRING SIZE( 1 )
        0000  01                                               .
    SEQUENCE SIZE( 34 )
      OCTET-STRING SIZE( 20 )
        0000  CD 74 84 DF E2 CB 9A 20 DF 70 E8 AF 09 9D 69 D5  .t..... .p....i.
        0010  BE 2F 01 6C                                      ./.l
      BIT-STRING SIZE( 3 )
        0000  07 30 80                                         .0.
      BIT-STRING SIZE( 2 )
        0000  03 B8                                            ..
      INTEGER SIZE( 1 )
        0000  09                                               .
    A1 [ CONTEXT 1 ] IMPLICIT SEQUENCE SIZE( 10 )
      SEQUENCE SIZE( 8 )
        SEQUENCE SIZE( 2 )
          OCTET-STRING SIZE( 0 )
        INTEGER SIZE( 2 )
          0000  01 00                                            ..
  67 [ APPLICATION 7 ] IMPLICIT SEQUENCE SIZE( 486 )
    7F21 [ APPLICATION 33 ] IMPLICIT SEQUENCE SIZE( 396 )
      7F4E [ APPLICATION 78 ] IMPLICIT SEQUENCE SIZE( 324 )
        5F29 [ APPLICATION 41 ] SIZE( 1 )
          0000  00                                               .
        42 [ APPLICATION 2 ] SIZE( 9 )
          0000  55 54 43 41 30 30 30 30 31                       UTCA00001
        7F49 [ APPLICATION 73 ] IMPLICIT SEQUENCE SIZE( 285 )
          OBJECT IDENTIFIER = { id-TA-ECDSA-SHA-256 }
          81 [ CONTEXT 1 ] SIZE( 32 )
            --
          82 [ CONTEXT 2 ] SIZE( 32 )
            --
          83 [ CONTEXT 3 ] SIZE( 32 )
            --
          84 [ CONTEXT 4 ] SIZE( 65 )
            --
            0040  97                                               .
          85 [ CONTEXT 5 ] SIZE( 32 )
            --
          86 [ CONTEXT 6 ] SIZE( 65 )
            --                                           <
          87 [ CONTEXT 7 ] SIZE( 1 )
            0000  01                                               .
        5F20 [ APPLICATION 32 ] SIZE( 16 )
          0000  44 45 4E 4B 30 32 30 30 38 37 36 30 30 30 30 31  DENK020087600001
      5F37 [ APPLICATION 55 ] SIZE( 64 )
        --
    42 [ APPLICATION 2 ] SIZE( 16 )
      0000  44 45 4E 4B 30 32 30 30 38 37 36 30 30 30 30 30  DENK020087600000
    5F37 [ APPLICATION 55 ] SIZE( 64 )
      --

Redacted some Data in the “APPLICATION” parts, as i have no idea what they contain. The Backups were made with OpenSC 0.24 and i tried to Recover them with OpenSC 0.24

EDIT4:
It seems that it might be possible that calling pkcs11-tool --id cd7484dfe2cb9a20df70e8af099d69d5be2f016c --derive -i input.raw.txt on an imported (from backup) key results in the “Private Key not found”-thing. The key seems to be usable from our application and from my Python-Library. We actually are testing right now to see if our Application can now derive using our modified test-Key.
Not sure why pkcs11-tool can’t seem to use the key though. It can list it with --list-objects though

1 Like

Where does the Private Key not found message come from?

How do you import the UNMODIFIED Backups of the key?

why? Looks pretty okay to me

The problem seems to only be pkcs11-tool -l --derive in the newest OpenSC-Version. Listing with pkcs11-tool -l --list-objects seems to work just fine. But I might have just realized, why it did say Private Key not found… I forgot the -l. Without a login it`s no wonder it can’t find the key… So needless to say, even this works now.
We also confirmed now that our application can use the Keys just fine and that derive now works. So I would like to thank you for leading us on the right path! Saved us a lot of headache!

The backups where imported with sc-hsm-tool --unwrap-key <filename> --key-reference <new key-ref>

I wouldn’t say it is perfect (but it works just fine), but I will share my script that I use to modify the Backups here, so that anyone stumbling across this can use it (at their own risk). The script relies on the library asn1crypto (available in the ubuntu repositories as python3-asn1crypto btw.) and is written in python.

from asn1crypto.core import *
from pathlib import PosixPath
import argparse

class KeyUsage(BitString):
    _map = {
        0: 'encrypt',
        1: 'decrypt',
        2: 'sign',
        3: 'signRecover',
        4: 'wrap',
        5: 'unwrap',
        6: 'verify',
        7: 'verifyRecover',
        8: 'derive',
        9: 'nonRepudiation',
    }

class ImportantSequence(Sequence):
    _fields = [
        ('octStr', OctetString),
        ('keyUsage', KeyUsage),
        ('bitStr2', BitString),
        ('keyID', Integer),
    ]

class Context1(Sequence):
    _fields = [
        ('sequence1', Sequence),
        ('prkdseq', ImportantSequence),
        ('sequence2', Sequence, {'implicit': 1})
    ]

class KeyWrap(Sequence):
    explicit_class = 1
    _fields = [
        ('oct1', OctetString),
        ('cont1', Context1, {'implicit': 0}),
        ('appls', Sequence, {'explicit': 1}),
    ]

parser = argparse.ArgumentParser(description='Dieses Skript bearbeitet ASN1-Strukturen von NitroKey-Key-Backups um die KeyUsage zu ändern')
parser.add_argument('-f','--file', help='Name/Pfad der Backup-Datei', required=True, type=PosixPath)

args = parser.parse_args()

new_usage = {'signRecover', 'sign', 'derive'}

with open(args.file, 'rb') as file:
    keyWrap = KeyWrap().load(file.read())

keyWrap['cont1']['prkdseq']['keyUsage'] = KeyUsage(new_usage)

with open(str(args.file) + '.fixed', 'wb') as file:
    file.write(keyWrap.dump())

I didn’t know how to model the APPLICATION-Parts of the Sequence in the library, but as we don’t need to modify anything in those parts, it works without touching it just fine.

1 Like

Wow! congratulations! You’ve made it! It was a real pleasure to help!

1 Like