[PKI/CA] Nitrokey HSM Does Not Support Signing?

Hello,

I just got a Nitrokey HSM 2, and I’m trying to use it to build an internal PKI infrastructure. I have generated a root CA certificate on the HSM, and generated the intermediate CA on the HSM, I also generated a CSR from the intermediate certificate onto my computer. My next objective is to sign the intermediate CA with the root certificate. I’ve tried running variations on the following commands:

openssl ca -config ../ca.ini -engine pkcs11 -keyform engine -key b842f3b4f356373056fc6ec71318404b541498c4 -extensions v3_intermediate_ca -days 1963 -notext -md sha512 -in csr/intermediate.csr -out certs/intermediate.crt
openssl ca -config ../ca.ini -engine pkcs11 -keyform engine -key 'pkcs11:object=root;type=private?pin-source=builtin-dialog' -extensions v3_intermediate_ca -days 1963 -notext -md sha512 -in csr/intermediate.csr -out certs/intermediate.crt

In both cases, and in other variations of the above, I get the following error:

engine "pkcs11" set.
Using configuration from ../ca.ini
Format not recognized!
The key ID is not a valid PKCS#11 URI
The PKCS#11 URI format is defined by RFC7512
The legacy ENGINE_pkcs11 ID format is also still accepted for now
Format not recognized!
The key ID is not a valid PKCS#11 URI
The PKCS#11 URI format is defined by RFC7512
The legacy ENGINE_pkcs11 ID format is also still accepted for now
PKCS11_get_private_key returned NULL
cannot load CA private key from engine
139786102428992:error:80065064:pkcs11 engine:ctx_load_key:invalid id:eng_back.c:659:
139786102428992:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:crypto/engine/eng_pkey.c:77:
unable to load CA private key

I’m not sure why I’m getting that error, except that when I run the following command, I get a message that reading the private key is not supported.

$ pkcs11-tool -l --read-object --type privkey --label rootUsing slot 0 with a present token (0x0)
Logging in to "SmartCard-HSM (UserPIN)".
Please enter User PIN: 
sorry, reading private keys not (yet) supported

Is signing from HSM generated private keys supported on the Nitrokey HSM 2?

Thank you!

Hi!

The cited error says, that OpenSC cannot get the proper key handle to the key.

  1. Have you tried specifying the slot ID, under which the key was stored instead of the URI? E.g. a number from range 1-15? As far as I see you do not use any label for the key to identify in the URI as well - maybe that’s the cause. Something like:
    ca -engine pkcs11 -keyfile "15" -keyform engine -config ./openssl-rootca.conf 
    
    (from micro-ca-tool/micro-ca-tool at master · sektioneins/micro-ca-tool · GitHub)
  2. See examples of the PKCS#11 URIs:
  3. Perhaps any of these tools/guides would help:
1 Like

Have you tried specifying the slot ID?

Yes, you can see the slot ID here:

$ pkcs11-tool -O
Using slot 0 with a present token (0x0)
Public Key Object; EC  EC_POINT 384 bits
  EC_POINT:   04610461695d48f7b6a19059f6929445ad99b5e74b25c2cd8b944827531acbe582bf29531faca7cf92da25fd0d91656e25d87eed940a04d7e4f98006f38e3b09a25ae51423224af1ce599d33fd0d7480a50f0e6e02b3242f9822076104d5483349b6c4
  EC_PARAMS:  06052b81040022
  label:      root
  ID:         b842f3b4f356373056fc6ec71318404b541498c4
  Usage:      verify
  Access:     none

Thus, I try to sign the key using that ID and I get the error as shown above:

openssl ca -config ../ca.ini -engine pkcs11 -keyform engine -key b842f3b4f356373056fc6ec71318404b541498c4 -extensions v3_intermediate_ca -days 1963 -notext -md sha512 -in csr/intermediate.csr -out certs/intermediate.crt

and also:

openssl ca -config ../ca.ini -engine pkcs11 -keyform engine -key 0:b842f3b4f356373056fc6ec71318404b541498c4 -extensions v3_intermediate_ca -days 1963 -notext -md sha512 -in csr/intermediate.csr -out certs/intermediate.crt`

(edit by @szszszsz: difference in the --key switch parameter).
I found this page to have the best description for a PCKS11 URI format. Therefore, I tried several permutations on the PKCS11 URI scheme. Here are some that I’ve tried:

'pkcs11:type=private;object=b842f3b4f356373056fc6ec71318404b541498c4'
'pkcs11:type=private;object=root'
'pkcs11:type=private;token=SmartCard-HSM%20%28UserPIN%29;object=root'
'pkcs11:type=private;token=SmartCard-HSM%20%28UserPIN%29;object=b842f3b4f356373056fc6ec71318404b541498c4'
'pkcs11:object=root;type=private?pin-source=file:///pin'
'pkcs11:object=root;type=private?pin-source=builtin-dialog'
'pkcs11:id=b842f3b4f356373056fc6ec71318404b541498c4;type=private?pin-source=builtin-dialog'

All of those appear to valid URIs according to that page I linked, but I get URI format errors all the same.

I found out that ‘p11tool’ will show you the proper format for the PKCS11 URI, so I copied that, and it’s still not working. I’m still getting the following error message:

PKCS11_get_private_key returned NULL
cannot load CA private key from engine

Is that because I can’t get the private key?

$ pkcs11-tool -l --read-object --type privkey --label root
Using slot 0 with a present token (0x0)
Logging in to "SmartCard-HSM (UserPIN)".
Please enter User PIN: 
sorry, reading private keys not (yet) supported

The message is about reading the private key in a raw format from the device. Nitrokey HSM does not allow to do so, unless in encrypted form using DKEK, hence the error (this is expected).

  1. Could you run signing using OpenSC (e.g. with pkcs11-tool) to confirm the key is correctly written to the device and usable?
  2. I saw in the micro-ca-tool, that they use OpenSSL shell/REPL instead of command switch to set the environment. Could you do the same?
  3. I see you are using -key switch in the OpenSSL call. Should not that be -keyfile (as in micro-ca-tool#L507)?

Figured it out!

My ca.ini file needed to be updated. Instead of using the -key field, I needed to reference the smartcard in the ini file:

private_key       = pkcs11:model=PKCS%2315%20emulated;manufacturer=www.CardContact.de;serial=DENK0104068;token=SmartCard-HSM%20%28UserPIN%29%00%00%00%00%00%00%00%00%00;id=%88%D5%BF%49%14%CD%B1%3C%7B%AD%73%D8%05%77%96%0D%5F%93%41%EC;object=root;type=private
certificate       = root.crt

Remove the -key <key_id> from the command:

openssl ca -config create_root.ini -engine pkcs11 -keyform engine -extensions v3_intermediate_ca -days 1963 -notext -md sha512 -in intermediate.csr -out intermediate.crt

Then, you are correctly prompted to enter your pin and have your certificate signed.

engine "pkcs11" set.
Using configuration from create_root.ini
Enter PKCS#11 token PIN for SmartCard-HSM (UserPIN):
Check that the request matches the signature
Signature ok
Certificate Details:
...

Thanks for your help!

1 Like

Hey,
I have been trying to do this for a while. Could you post a copy of your ca.ini file?

The process looks more intimidating than it actually is. I put it up on Github.

2 Likes

Nice tutorial. Thank you! Can we copy (and modify) your tutorial to our documentation?

I ran through the tutorial again this morning to make sure that I couldn’t find any problems, and everything works exactly as expected. So, feel free to use and change it in any way that you want!

Thank you! I copied and published the document with some minor text modifications.

The -keyfile parameter worked for me.

Originally, I was using openssl ca -config myconfig.cnf -engine pkcs11 -keyform engine -key 00 -gencrl -out crl/mycrl.crl and it was generating the errors:

Format not recognized!
The key ID is not a valid PKCS#11 URI

It strange because specifying -key {id} works perfectly fine when generating an x509 certificate but doesn’t seem to work when you want to sign. However, using -keyfile {id} worked like a charm!

1 Like

Maybe it will help someone in the future: I had identical problem to the one in the original post. In the end I discovered that it wasn’t the problem with private_key value: I was able to sign certificates with private_key=label_root-ca.

The real problem was output from OpenSSL - it kept telling me that it cannot load private key - maybe, but it wasn’t the root of the problem. This was caused by my mistake and it was really simple in the end:

I used this PKI Tutorial to create PKI - it works pretty well. What I did wrong was that I created self-signed certificate WITHOUT SPECIFYING -extensions root_ca_ext - I ended up with root certificate that had CA set to true, but with pathlen: 0 - this means that no subordinate CA can be created using this certificate. After passing -extensions root_ca_ext while creating self-signed certificate I had no problems with signing intermediate CA’s certificate, even with private_key = label_root-ca.

I really miss these few hours that I lost on this…

1 Like

@MagellanTX @Jedrzej_Dudkiewicz
Thank you for sharing!

@jan
Let’s add the last two replies to a separate troubleshooting section in the documentation.