HSM: is it possible to derive a public key from a RSA private key

If my HSM contains only an RSA private key, is it possible to derive a public key from it?

I tried using OpenSSL but it doesn’t seem to work.

   openssl rsa -engine pkcs11 -in "pkcs11:id=%01;type=private" -inform engine -pubout -text

   engine "pkcs11" set.
    PKCS11_get_private_key returned NULL
    cannot load Private Key from engine
    140701804377920:error:8206F012:PKCS#11 module:pkcs11_getattr_int:Attribute type invalid:p11_attr.c:48:
    140701804377920:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:crypto/engine/eng_pkey.c:78:

I’m not sure what’s happening behind the scenes in OpenSSL, but based on the syntax, it suggests that OpenSSL is trying load the private key from the HSM (which I know it won’t allow). If OpenSSL can’t do it, is there another tool that can?

Hi!

Looking at the raw commands of the Nitrokey HSM’s smart card I do not see such possibility. Please write to support@nitrokey.com if you are interested in the detailed manual.

If you are allowed to use the key, you can request a certificate (for example using OpenSSL PKCS#11 engine https://github.com/OpenSC/OpenSC/wiki/SmartCardHSM#using-openssl-with-engine-pkcs11 ) and the X.509 (or PKCS#10) structure will contain your public key.

1 Like

By the way, the following worked for me:

openssl <<EOF
engine -t dynamic -pre SO_PATH:/usr/local/lib/engines/pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/local/lib/pkcs11/opensc-pkcs11.so
rsa -engine pkcs11 -in "pkcs11:id=%02;type=private" -inform engine -pubout -text
EOF

And the result:

OpenSSL> (dynamic) Dynamic engine loading support
[Success]: SO_PATH:/usr/local/lib/engines/pkcs11.so
[Success]: ID:pkcs11
[Success]: LIST_ADD:1
[Success]: LOAD
[Success]: MODULE_PATH:/usr/local/lib/pkcs11/opensc-pkcs11.so
Loaded: (pkcs11) pkcs11 engine
     [ available ]
OpenSSL> engine "pkcs11" set.
Enter PKCS#11 token PIN for DEV2 (UserPIN):
Public-Key: (4096 bit)
Modulus:
    00:b9:08:58:d6:32:6e:91:44:17:77:7c:d9:1e:bc:
    80:1e:54:78:da:f6:09:0a:91:3e:32:48:c8:58:53:
    5d:a9:21:e1:d8:5d:61:4b:be:a7:11:7e:28:e6:27:
    36:90:78:8d:fa:05:44:26:7f:4c:a2:b7:8d:69:21:
    fb:b6:c4:3c:4a:82:a5:e0:f4:ea:49:9f:5f:f9:13:
    7f:ba:79:c3:6b:bf:a8:79:fc:13:0c:b7:d9:ab:95:
    e4:3f:78:ac:99:eb:25:c1:3f:fa:f4:16:24:38:b5:
    1c:ed:12:e6:18:2f:96:e7:d7:c4:05:95:4b:f6:bf:
    46:f2:07:e0:5a:69:a9:97:85:9f:c2:b9:cf:57:c3:
    f4:50:1e:b4:20:e0:71:db:38:64:df:83:6b:7d:ca:
    5a:81:69:ce:d8:30:81:28:38:6c:37:fd:21:0b:89:
    2f:18:78:f0:6e:5d:a0:3f:81:1d:09:bf:95:92:e6:
    0a:ce:e9:ee:3f:f2:70:bc:c3:08:ca:57:ec:d5:ba:
    12:6d:2e:1a:60:e6:51:5e:63:bb:18:c7:89:a9:f9:
    62:ad:35:3a:27:46:c3:b2:b1:5a:24:9d:00:96:cc:
    1b:7b:5a:81:89:af:54:f3:3f:1b:9d:2d:51:e8:4b:
    e0:71:b3:bf:18:24:1d:5f:f5:41:a0:f0:57:ec:d0:
    08:ce:f4:1c:04:39:03:e4:f8:f0:b5:f6:9f:f5:fc:
    ef:f1:ec:f9:5b:3f:76:66:15:d8:fa:2f:75:e9:4d:
    41:1f:79:e7:25:f7:69:60:d6:bb:ad:23:ec:6d:b1:
    61:3e:dd:d8:73:b8:0b:14:7a:48:51:4f:7a:5b:86:
    16:be:cf:de:bb:e2:02:f4:7a:ee:41:56:4c:95:0d:
    c8:af:1d:68:f0:6d:32:ed:e6:61:ae:f2:72:81:d2:
    c8:a3:dc:ce:a2:db:26:8f:e7:7e:22:97:5c:2f:09:
    f3:c3:d0:90:bf:63:6b:e1:af:e5:4a:08:9d:13:d4:
    3c:d7:0e:bc:9b:59:95:57:36:f7:12:f0:8d:a1:81:
    1c:fa:cf:12:2c:a9:44:df:34:fe:65:28:6e:bb:90:
    b3:9f:fa:7e:43:44:4a:ee:a4:c6:fd:b3:18:ee:cc:
    ad:0c:aa:f1:c5:c7:cb:05:2d:0b:85:c6:6f:c2:1f:
    50:51:d0:f7:6c:7a:78:46:29:de:2e:2c:1e:39:0d:
    8d:5a:90:ab:01:6c:53:a2:25:11:90:c2:cf:9d:71:
    f6:0b:65:a0:9d:b4:20:f3:89:2a:d2:ce:23:b5:89:
    28:fd:8f:45:7c:b2:9d:97:ff:af:68:fd:aa:81:3a:
    d2:eb:06:70:4d:77:32:c5:82:3c:c8:79:e1:8f:88:
    78:76:e1
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuQhY1jJukUQXd3zZHryA
HlR42vYJCpE+MkjIWFNdqSHh2F1hS76nEX4o5ic2kHiN+gVEJn9MoreNaSH7tsQ8
SoKl4PTqSZ9f+RN/unnDa7+oefwTDLfZq5XkP3ismeslwT/69BYkOLUc7RLmGC+W
59fEBZVL9r9G8gfgWmmpl4WfwrnPV8P0UB60IOBx2zhk34NrfcpagWnO2DCBKDhs
N/0hC4kvGHjwbl2gP4EdCb+VkuYKzunuP/JwvMMIylfs1boSbS4aYOZRXmO7GMeJ
qflirTU6J0bDsrFaJJ0Alswbe1qBia9U8z8bnS1R6EvgcbO/GCQdX/VBoPBX7NAI
zvQcBDkD5Pjwtfaf9fzv8ez5Wz92ZhXY+i916U1BH3nnJfdpYNa7rSPsbbFhPt3Y
c7gLFHpIUU96W4YWvs/eu+IC9HruQVZMlQ3Irx1o8G0y7eZhrvJygdLIo9zOotsm
j+d+IpdcLwnzw9CQv2Nr4a/lSgidE9Q81w68m1mVVzb3EvCNoYEc+s8SLKlE3zT+
ZShuu5Czn/p+Q0RK7qTG/bMY7sytDKrxxcfLBS0LhcZvwh9QUdD3bHp4RineLiwe
OQ2NWpCrAWxToiURkMLPnXH2C2WgnbQg84kq0s4jtYko/Y9FfLKdl/+vaP2qgTrS
6wZwTXcyxYI8yHnhj4h4duECAwEAAQ==
-----END PUBLIC KEY-----
1 Like

hmmmm…still can’t get it to work. Maybe it’ll be helpful if I post the steps I’m using…

pkcs11-tool --keypairgen --key-type rsa:2048 --id 01 --login
openssl req -config openssl.cnf -engine pkcs11 -keyform engine -new -x509 -key 01 -sha512 -days 10 -out test.crt
pkcs11-tool --write-object test.crt --type cert --id 01 --login

pkcs11-tool --list-object --login
Using slot 0 with a present token (0x0)
Logging in to "UserPIN (TEST)".
Please enter User PIN: 
Private Key Object; RSA 
  label:      Certificate
  ID:         01
  Usage:      decrypt, sign, unwrap
Certificate Object; type = X.509 cert
  label:      Certificate
  subject:    DN: CN=test
  ID:         01
Public Key Object; RSA 2048 bits
  label:      Certificate
  ID:         01
  Usage:      encrypt, verify

pkcs11-tool --delete-object --id 01 --type cert --login
pkcs11-tool --list-object --login
Using slot 0 with a present token (0x0)
Logging in to "UserPIN (TEST)".
Please enter User PIN: 
Private Key Object; RSA 
  label:      Certificate
  ID:         01
  Usage:      decrypt, sign, unwrap

My engine configuration is in the openssl.cnf but I did try it all on the CLI. Also, I’m using CentOS 8 so my library paths are a little different.

openssl <<EOF
engine -t dynamic -pre SO_PATH:/usr/lib64/engines-1.1/pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/lib64/opensc-pkcs11.so
rsa -engine pkcs11 -in "pkcs11:id=%01;type=private" -inform engine -pubout -text
EOF

PKCS11_get_private_key returned NULL
cannot load Private Key from engine
140154751170368:error:8206F012:PKCS#11 module:pkcs11_getattr_int:Attribute type invalid:p11_attr.c:48:
140154751170368:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:crypto/engine/eng_pkey.c:78:
unable to load Private Key
error in rsa

Curiously, I did discover that if I create a keypair (and don’t bind a cert to it), then I can successfully derive the public key. I’m wondering if the private key attributes are changed during the --write-object step?

With a siging request it worked for me.

Create a certificate with the private key, stored within the Nitrokey at ID 11:

$ openssl req -engine pkcs11 -keyform engine -new -key 11 -nodes -days 35600 -x509 -sha256 -out "id11-cert.pem" -subj "/CN=Test Cert 1" -key "pkcs11:pin-value=648219" engine "pkcs11" set.

The certificate contains the RSA public key (Modulus, Exponent):

$ cat id11-cert.pem |openssl x509 -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            70:fe:41:f8:1f:a1:36:bd:b1:65:15:cf:41:ca:2f:c9:82:b8:0d:68
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = Test Cert 1
        Validity
            Not Before: Nov  6 12:13:33 2020 GMT
            Not After : Apr 27 12:13:33 2118 GMT
        Subject: CN = Test Cert 1
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (1024 bit)
                Modulus:
                    00:b3:88:f1:d6:9d:87:50:94:d3:52:9d:8a:97:e6:
                    3b:35:01:a4:ee:3b:65:4b:e6:14:b7:6d:74:57:ee:
                    29:dc:c8:7f:5d:a7:b5:c8:ea:54:75:97:ea:31:d6:
                    2e:38:07:23:5e:de:04:5a:59:05:03:af:01:67:a6:
                    74:9a:8b:ef:5c:6a:95:13:f9:7a:08:fe:91:5d:f8:
                    95:ca:96:40:14:0f:84:7a:b8:89:e8:a6:4e:3c:a9:
                    e4:24:7b:9e:a3:1a:0b:5f:6b:2a:8e:fe:c5:ac:e4:
                    01:79:00:4a:f9:e0:14:3f:2b:39:31:b2:1b:c5:c7:
                    d8:d9:f7:e9:1d:65:4b:a3:41
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                97:D2:F0:EF:25:44:D2:CE:D6:B8:9D:A5:7C:5C:ED:39:A0:34:C0:61
            X509v3 Authority Key Identifier: 
                keyid:97:D2:F0:EF:25:44:D2:CE:D6:B8:9D:A5:7C:5C:ED:39:A0:34:C0:61

            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
        98:1e:e3:7e:14:f8:b8:4f:0f:4f:b9:57:b3:be:2e:3a:09:d7:
        04:0c:df:bd:53:28:03:39:1c:b1:35:bc:b7:cc:1f:a2:78:e9:
        c9:ac:c3:e9:4b:ef:82:bd:f3:c2:ff:59:d8:37:82:7b:64:be:
        f4:c8:6d:37:43:c6:a3:a6:62:0b:05:89:8d:eb:4a:6b:ac:80:
        fa:8f:5b:4f:59:83:b2:57:15:d8:44:6b:f5:9f:48:11:52:03:
        9f:48:fe:c0:70:a1:71:59:b9:30:50:fe:c5:bf:80:9c:27:06:
        51:40:87:25:04:ea:28:44:cc:19:01:9b:c8:3f:37:b6:52:f5:
        cd:82

Now you can extract the public key from the certificate:

$ openssl x509 -pubkey -noout -in id11-cert.pem  > id11-pubkey.pem

$ cat id11-pubkey.pem 
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCziPHWnYdQlNNSnYqX5js1AaTu
O2VL5hS3bXRX7incyH9dp7XI6lR1l+ox1i44ByNe3gRaWQUDrwFnpnSai+9capUT
+XoI/pFd+JXKlkAUD4R6uInopk48qeQke56jGgtfayqO/sWs5AF5AEr54BQ/Kzkx
shvFx9jZ9+kdZUujQQIDAQAB
-----END PUBLIC KEY-----

I appreciate the help you all have been giving!!

Unfortunately, I still end up with the error “pkcs11_getattr_int:Attribute type invalid:p11_attr.c:48:

This could be inherit to HSM1 so I will test again as soon as my HSM2 arrives.

The easiest way to reproduce the error:

  1. Generate a keypair on the HSM
  2. Generate a certificate from OpenSSL which is signed by the HSM
  3. Copy the certificate to the HSM
  4. Delete the certificate from the HSM (which removes the public key)
  5. Try to generate another certificate with OpenSSL which is signed by the HSM

Well, you didn’t say it is HSM1, I tried HSM2 (I have only access to these).

You can also try building https://github.com/CardContact/sc-hsm-embedded and then make sure you are using --module option to PKCS#11 tools pkcs11-tool --module /usr/local/lib/libsc-hsm-pkcs11.so -L
and change the PKCS#11 module path for OpenSSL