polhenarejos / pico-hsm

Hardware Security Module (HSM) for Raspberry Pico and ESP32
https://www.picokeys.com
GNU General Public License v3.0
222 stars 30 forks source link

ECDH derived key is missing one byte compared with openssl-pkeyutl #22

Closed rrottmann closed 11 months ago

rrottmann commented 1 year ago

Issue

In a hybrid scenario where one symmetric key is derived on the HSM and the partner derives it in software with openssl pkeyutl, there is a single byte at the beginning missing when comparing both derived keys.

General Info

Using Waveshare RP2040 One with latest stable release.

$ sc-tool -I
Cryptoki version 2.20
Manufacturer     CardContact (www.cardcontact.de)
Library          SmartCard-HSM via PC/SC (ver 2.12)
Using slot 0 with a present token (0x1)

$ sc-tool -M
Using slot 0 with a present token (0x1)
Supported mechanisms:
  RSA-X-509, keySize={1024,4096}, hw, decrypt, sign
  RSA-PKCS, keySize={1024,4096}, hw, decrypt, sign
  RSA-PKCS-PSS, keySize={1024,4096}, hw, sign
  SHA1-RSA-PKCS, keySize={1024,4096}, hw, sign
  SHA256-RSA-PKCS, keySize={1024,4096}, hw, sign
  SHA1-RSA-PKCS-PSS, keySize={1024,4096}, hw, sign
  SHA256-RSA-PKCS-PSS, keySize={1024,4096}, hw, sign
  ECDSA, keySize={192,521}, hw, sign
  ECDSA-SHA1, keySize={192,521}, hw, sign
  AES-CBC, keySize={16,32}, hw, encrypt, decrypt
  AES-CMAC, keySize={16,32}, hw, sign
  ECDSA-KEY-PAIR-GEN, keySize={192,521}, hw, generate_key_pair
  RSA-PKCS-KEY-PAIR-GEN, keySize={1024,4096}, hw, generate_key_pair
  AES-KEY-GEN, keySize={16,32}, hw, generate
  mechtype-0x80000001, keySize={1024,4096}, hw, sign
  mechtype-0x80000003, keySize={1024,4096}, hw, sign
  mechtype-0x80000010, keySize={192,521}, hw, sign
  mechtype-0x80000011, keySize={192,521}, hw, sign

$ sc-tool -O
Using slot 0 with a present token (0x1)
Certificate Object; type = unknown cert type
  label:      C.DevAut
Certificate Object; type = unknown cert type
  label:      C.DICA
Public Key Object; RSA 2048 bits
  label:      RSA2K
  ID:         01
  Usage:      encrypt, verify
  Access:     local
Public Key Object; EC  EC_POINT 192 bits
  EC_POINT:   0431040dcdc12372f719b30294579a6e0117653ea6d3ba7a2881217e7fecc79f76823f3533877607238123d3eda9c4dd48887b
  EC_PARAMS:  06082a8648ce3d030101
  label:      ECDSA
  ID:         11
  Usage:      encrypt, verify
  Access:     local

$ pkcs11-tool -I
Cryptoki version 3.0
Manufacturer     OpenSC Project
Library          OpenSC smartcard framework (ver 0.23)
Using slot 0 with a present token (0x0)

alias sc-tool='/tmp/tmp.uUVSWTVRrA/opensc-compiled/pkcs11-tool --module /tmp/tmp.uUVSWTVRrA/opensc-compiled/libsc-hsm-pkcs11.so'

How to reproduce

openssl ecparam -genkey -name prime192v1 > bob.pem
openssl ec -in bob.pem -pubout -outform DER > bob.der
sc-tool -l --pin 648219 --delete-object --type privkey --id 11
sc-tool -l --pin 648219 --keypairgen --key-type EC:secp192r1 --id 11 --label "ECDSA"
pkcs11-tool --read-object --pin 648219 --id 11 --type pubkey > 11.der
openssl ec -inform DER -outform PEM -in 11.der -pubin > 11.pub
pkcs11-tool --pin 648219 --id 11 --derive -i bob.der -o mine-bob.der
openssl pkeyutl -derive -out bob-mine.der -inkey bob.pem -peerkey 11.pub

xxd bob-mine.der
# 00000000: 1b39 a93c 2948 2b66 6677 5967 02c7 27a1  .9.<)H+ffwYg..'.
# 00000010: ce5a f6b6 197b 42ff                      .Z...{B.
xxd mine-bob.der
# 00000000: 39a9 3c29 482b 6666 7759 6702 c727 a1ce  9.<)H+ffwYg..'..
# 00000010: 5af6 b619 7b42 ff                        Z...{B.

openssl pkeyutil -derive key in this example contains an additional 1b. This is different with every fresh ecdh parameter set but always the first byte is missing in the HSM output of the derived key.

polhenarejos commented 1 year ago

Probably caused by 14c78521

rrottmann commented 1 year ago

Could this be the length of the response data?

Maybe there are two variants of encoding in the response APDU. First: the raw data and the expected returned length only encoded in the response trailer with SW1=0x61,SW2=0x?? until SW1=0x90, SW2=0x00. This is how I would read the spec. All bytes of the body would be considered as data.

Second: prepending the length of the data in the first byte of the response body. Then the first byte needs to be skipped to retrieve the actual data. I would have assumed that only in the command APDU the length is added.

polhenarejos commented 1 year ago

Not at all. SmartCard HSM returns the shared secret with a 04 prepended, as it can be read at OpenSC

https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-sc-hsm.c#L1156

04 usually means the UNCOMPRESSED encoding point. Since the shared secret comes from the mathematical operation shared=aP=abG where P=bG is Bob's public point, I guess what is returned by SC-HSM is the full encoded point trunked to the half+1, since ECDH only requires the x component. I bet that is an implementation aspect of SC-HSM but, since pkcs11-tool relies on sc-hsm driver, it discards the first byte (the 04).

Some days ago I noticed this 0x04 without an aparent reason until you reported this issue, which reminded me that OpenSC expects that rubbish byte.