Important!

Blog moved to https://blog.apdu.fr/

I moved my blog from https://ludovicrousseau.blogspot.com/ to https://blog.apdu.fr/ . Why? I wanted to move away from Blogger (owne...

Friday, April 14, 2023

Verify with OpenSSL a signature computed by PyKCS11

With PyKCS11 I provide a sample code signature.py to compute a RSA+SHA256 signature. The Python sample also contains the code to check the signature using PyKCS11.

But what if you want to verify the signature using OpenSSL?

Export the public key

PYKCS11LIB environment variable is used to indicate what PKCS#11 library to use. For the tests I use SoftHSM so I set the variable using:
$ export PYKCS11LIB=/usr/local/lib/softhsm/libsofthsm2.so
#!/bin/bash

set -e

# get the 1st key object ID
ID=$(pkcs11-tool --module $PYKCS11LIB --list-objects --type pubkey \
    | grep ID \
    | cut -d: -f 2)
echo "Object id: $ID"

# export the public key
pkcs11-tool --module $PYKCS11LIB --read-object --type pubkey --id $ID -o rsa_pub.key

# convert the public key to PEM
openssl rsa -pubin -inform DER -in rsa_pub.key -outform PEM -out rsa_pub.pem

The RSA key pair has been generated by the generate.py script and is stored in the PKCS#11 token. We need to export it so that OpenSSL can use it to check the signature.

To export the key I use pkcs11-tool from the OpenSC project. We need to know the object ID of the public key. This ID is configured in generate.py script line 22. We dump the public keys and get the object ID.

$ pkcs11-tool --module $PYKCS11LIB --list-objects --type pubkey
Using slot 0 with a present token (0x27ca3aa)
Public Key Object; RSA 1024 bits
  label:      My Public Key
  ID:         22
  Usage:      encrypt, verify, wrap
  Access:     local

The script will work correctly if only one public key is present in the token. I let you handle more complex cases.

output

$ ./export_key.sh 
Using slot 0 with a present token (0x27ca3aa)
Object id:          22
Using slot 0 with a present token (0x27ca3aa)
writing RSA key

Compute signature

I modified the original signature.py script to also save the clear text message in a file cleartext.txt and the signature in a file sig_sha256.bin so these files can be used later by OpenSSL.

#!/usr/bin/env python3

from PyKCS11 import *
import binascii

pkcs11 = PyKCS11Lib()
pkcs11.load()  # define environment variable PYKCS11LIB=YourPKCS11Lib

# get 1st slot
slot = pkcs11.getSlotList(tokenPresent=True)[0]

session = pkcs11.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login("1234")

# message to sign
toSign = "Hello World!\n"
mechanism = Mechanism(CKM_SHA256_RSA_PKCS, None)

# find first private key and compute signature
privKey = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])[0]
signature = session.sign(privKey, toSign, mechanism)
print("\nsignature: {}".format(binascii.hexlify(bytearray(signature))))

# save the clear text in a file
with open("cleartext.txt", "w") as f:
    f.write(toSign)

# save to a signature in a file
with open("sig_sha256.bin", "bw") as f:
    f.write(bytearray(signature))

# find first public key and verify signature
pubKey = session.findObjects([(CKA_CLASS, CKO_PUBLIC_KEY)])[0]
result = session.verify(pubKey, toSign, signature, mechanism)
print("\nVerified:", result)

# logout
session.logout()
session.closeSession()

Output

$ ./signature.py 

signature: b'322c1591cb9aba1e361264b02464a2bd9d55693bf772b4253da0862616e611dc139005742c511795c27c8f609e4ddbaafceba1c3b3ce278b8e0af564c84de54a639cff67a9a3f97dcc542cd6f0200954ef7fce4a0f87b61636272e21fc1e3ef9f0b683e360cca4231405dd90ae2c4a3638ca7a85e2b62f6ae30975ff3885ab60'

Verified: True

Verify signature

#!/bin/bash

set -e

# verify signature
openssl dgst -sha256 -verify rsa_pub.pem -signature sig_sha256.bin cleartext.txt

Output

$ ./verify.sh 
Verified OK

Conclusion

Thanks to Leon Rman for the initial code and the idea.

I let you write the code to do the symmetrical operations: sign using OpenSSL and verify using PyKCS11.