Marc Wäckerlin
Für eine libertäre Gesellschaft

SuisseID as Code Signing HSM

Juli 11, 2018

Visits: 2720

If you buy a new code signing certificate from SwissSign, you must generate a CSR  using a hardware HSM which stores your private key inaccessibly. Unfortunately, this is a new requirement and pure soft certificates (all secrets in a file) are no more allowed.

Fortunately, the SuisseID is such a valid HSM. It can easily be used in your Ubuntu Linux MinGW cross build environment to sign your executables.

Sign CSR With SuisseID Private Key

You need the engine file, in current Ubuntu, this is /usr/lib/ssl/engines/libpkcs11.so from package libengine-pkcs11-openssl, the PKCS#11 library, which is /usr/lib/libcvP11.so provided by SwissSign in package suisseid-pkcs11. You also need pkcs11-tool from package opensc and openssl from package openssl. For code signing, you need osslsigncode from package osslsigncode. Your SuisseID must be initialized using SuisseID Assistant name swisssign-init from package swisssign-init.

If you haven’t run the SuisseID installer, you can also add the SwissSign repository manually:

sudo apt-add-repository http://update.swisssign.com/repo
sudo apt update

Install the dependencies:

sudo apt install libengine-pkcs11-openssl suisseid-pkcs11 \
                 opensc openssl osslsigncode swisssign-init

If you haven’t initialized your SuisseID, do it now. You should have received a TIN / PUK Sheet from SwissSign with the transport PIN (TIN). Run swisssign-init and follow the instructions. Set a PIN, that you will need below.

SuisseID Assistant

Compile osslsigncode

Unfortunately, as of July 2018, the version of osslsigncode delivered in Ubuntu 16.04 is of the latest version 1.7.1, but still does not support the options -pkcs11engine and -pkcs11module. So I had to compile my own version of osslsigncode:

apt install libcurl4-openssl-dev
git clone https://github.com/Dimrok/osslsigncode
cd osslsigncode
./autogen.sh
./configure
make

Find Key ID

Get a list of all objects in your SuisseID:

pkcs11-tool --module /usr/lib/libcvP11.so -O

This shows all objects found on your SuisseID smart card (which is your HSM), e.g.:

marc@merkur:~$ pkcs11-tool --module /usr/lib/libcvP11.so -O
LOGIN CALLBACK in libCVP11LCB: CK_RV CB_Initialize(CK_CONTEXT_PTR, CK_C_INITIALIZE_ARGS_PTR, CK_ULONG_PTR)
Using slot 0 with a present token (0x1)
Public Key Object; RSA 2048 bits
  label:      SwissSign_nonRep                
  ID:         8b17b91399f4bd9ab62bc6c6ff21c9de4b353133
  Usage:      verify
Public Key Object; RSA 2048 bits
  label:      SwissSign_digSig                
  ID:         00903c80c138a20f4b92625a25550a6503273537
  Usage:      encrypt, verify, wrap
Public Key Object; RSA 2048 bits
  label:      SwissSign_dataEnc               
  ID:         247882b46782e951da176b1170b0031dcf24d932
  Usage:      encrypt, verify, wrap
Certificate Object, type = X.509 cert
  label:      SwissSign Platinum CA - G2
  ID:         7cc3c3b0688964ea3fc31e14687036b91cd566d6
Certificate Object, type = X.509 cert
  label:      SwissSign SuisseID Platinum CA 2010 - G2
  ID:         40788b2001d803248c5815af9e53d5688d4c4cef
Certificate Object, type = X.509 cert
  label:      Tester test (Authentication)
  ID:         00903c80c138a20f4b92625a25550a6503273537
Certificate Object, type = X.509 cert
  label:      SwissSign Qualified Platinum CA 2010 - G2
  ID:         799ab530ff54cfeddc3f8246a0ad8f3371f885bd
Certificate Object, type = X.509 cert
  label:      Tester test (Qualified Signature)
  ID:         8b17b91399f4bd9ab62bc6c6ff21c9de4b353133
Certificate Object, type = X.509 cert
  label:      SwissSign CH Person Platinum CA 2017 - G22 (STAG)
  ID:         d0ca90120c47fb3765f8e86c0a4ea9cc2585eb80
Certificate Object, type = X.509 cert
  label:      SwissSign CH Qualified Platinum CA 2017 - G22 (STAG)
  ID:         0ab4be9d404c9fce373579f22da20e8fe27ce407
LOGIN CALLBACK in libCVP11LCB: CK_RV CB_Finalize(CK_VOID_PTR)

You need the ID of the key with label SwissSign_digSig, here 00903c80c138a20f4b92625a25550a6503273537.

OpenSSL Configuration

You need am openssl configurate file engine.conf:

openssl_conf = openssl_init

[openssl_init]
engines = engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/lib/ssl/engines/libpkcs11.so
MODULE_PATH = /usr/lib/libcvP11.so
init = 0

[req]
distinguished_name = req_dn
string_mask = utf8only
utf8 = yes

[req_dn]
commonName = Common Name (eg, your name)

Generate CSR

Now you have all puzzle pieces to generate the HSM-signed CSR required for getting your SwissSign code signing certificate. Do not forget to plug in your USB SuisseID:

openssl req -nodes -new -sha256 -config engine.conf -engine pkcs11 -keyform engine \
            -key slot_1-id_00903c80c138a20f4b92625a25550a6503273537 \
            -out request.csr

It asks for your PIN and a common name. The comon name will be  overwritten in the SwissSign request form anyway. As you see, in option -key you specify a slot number (1, if you have one reader, just try different numbers), and the key ID that you got in the instructions above.

After running the command, a file request.csr is generated, that contains some lines between -----BEGIN CERTIFICATE REQUEST----- and -----END CERTIFICATE REQUEST-----.

Just copy the content of file request.csr into the CSR field on SuisseSign’s web page, fillout the forms, download the request form, fill it out, sign it and send it to the fullfilment.

Sign Code With SuisseID

After some days, you get a mail containing download link for your certificate from SwissSign. Download it in cer format as certificate.pem.

Something to Sign

You need a windows exe or a dll to test. Simply use my windows cross compilation docker image to generate a windows openssl version in /tmp/test:

docker run -it --rm -u $(id -u) \
           -v /tmp/test:/workdir \
           mwaeckerlin/mingw \
           /build-openssl.sh -d

Now you have an exe that you can sign in the next step:

marc@merkur:~$ ls -l /tmp/test/usr/exeinsgesamt 10876
-rwxr-xr-x 1 marc root    5110 Jul 11 11:34 c_rehash
drwxr-xr-x 1 marc marc     340 Jul 11 11:34 engines
-rw-r--r-- 1 marc root 3700930 Jul 11 11:34 libcrypto.a
-r-xr-xr-x 1 marc root 2348736 Jul 11 11:34 libcrypto.dll.a
-rwxr-xr-x 1 marc root 2760552 Jul 11 11:34 libeay32.dll
-rw-r--r-- 1 marc root  596088 Jul 11 11:34 libssl.a
-r-xr-xr-x 1 marc root  208402 Jul 11 11:34 libssl.dll.a
-rwxr-xr-x 1 marc root  904182 Jul 11 11:34 openssl.exe
drwxr-xr-x 1 marc marc      62 Jul 11 09:28 pkgconfig
-rwxr-xr-x 1 marc root  599307 Jul 11 11:34 ssleay32.dll

Sign a Windows Executable

Use osslsigncode(self-compiled, as explained above) to sign /tmp/test/usr/exe/openssl.exe:

~/git/osslsigncode/osslsigncode sign \
    -pkcs11engine /usr/lib/engines/engine_pkcs11.so \
    -pkcs11module /usr/lib/libcvP11.so \
    -key 00903c80c138a20f4b92625a25550a6503273537 \
    -pass your-suisse-id-pin \
    -certs certificate.pem \
    -ts http://tsa.swisssign.net \
    -h sha2 \
    -in /tmp/test/usr/exe/openssl.exe \
    -out /tmp/test/usr/exe/openssl-signed.exeIf you don't specify the password (which is the SuisseID PIN) on command line, you will be asked on the console.

Sources

comments title