Yubico/yubico-piv-tool

regression in ykcs11 from 2.0.0-2 to 2.2.0

sborho opened this issue · 15 comments

This is reproduced from Ubuntu/Debian packages with reproduction command line:

pkcs11-tool --module /usr/lib/x86_64-linux-gnu/libykcs11.so --sign --mechanism SHA256-RSA-PKCS-PSS --salt-len 0 --pin XXXXXXXX > sig < to_be_signed.bin

Base Ubuntu 18.04 ykcs11-1.4.2-2ubuntu0.1 did not support the --salt-len argument but the Yubico PPA provided a 2.0.0-2ppa1bionic1 version that did work. This command line generated a signature that could be validated with openssl.

In Ubuntu 20.04 the newer 2.0.0-2 package was shipped within the release and this command line generated a valid signature.

But in Ubuntu 21.04 and later, the package has been updated to 2.2.0 and this command line stops generating a signature that can be validated by openssl. I can prove the regression is in this package by downgrading ykcs11 and libykpiv1 on an Ubuntu 21.04 (or 21.10) and this makes the command successful again.

The stdout output does not change between the success and failure cases; only the signature changes.

Using slot 0 with a present token (0x0)
Using signature algorithm SHA256-RSA-PKCS-PSS
PSS parameters: hashAlg=SHA256, mgf=MGF1-SHA256, salt_len=0 B
Using slot 0 with a present token (0x0)

Note that the output signature in the broken case does not match the output I get when I remove the --salt-len 0 argument, so it is not simply a matter of the salt length getting dropped.

To validate the signature, use:
openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify rsa.pub -signature sig to_be_signed.bin

I am using a YubiKey 5c Nano

$ lsusb | grep Yubi
Bus 003 Device 043: ID 1050:0404 Yubico.com Yubikey 4/5 CCID

Let me know if you need any additional information. Thanks

The unrelated problem I found with libykcs11.so is that it prompts for the PIN twice:

$ pkcs11-tool --module /usr/local/lib/libykcs11.dylib --sign --mechanism SHA256-RSA-PKCS-PSS --salt-len 0 --id 02 -o s.sig -i s
Using slot 0 with a present token (0x0)
Logging in to "YubiKey PIV #xxxx666".
Please enter User PIN: 
Using signature algorithm SHA256-RSA-PKCS-PSS
PSS parameters: hashAlg=SHA256, mgf=MGF1-SHA256, salt_len=0 B
Logging in to "YubiKey PIV #xxxx666".
Please enter context specific PIN: 
$

Coincidentally, on Mac signature verifies OK:

$ openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify s.pub -signature s.sig s 
Verified OK
$ yubico-piv-tool --version
yubico-piv-tool 2.2.1
$ openssl version
OpenSSL 3.0.1 14 Dec 2021 (Library: OpenSSL 3.0.1 14 Dec 2021)
$

Also, from pkcs11-tool man page:

--salt-len bytes
           Specify how many bytes of salt should be used in RSA-PSS signatures. Accepts two special
           values: "-1" means salt length equals to digest length, "-2" means use maximum
           permissible length. Default is digest length (-1).

0 does not seem to be a supported value for --salt-len parameter.

The standard seems to say

A salt length of zero is permitted and will result in a deterministic signature value.

Needless to say, a deterministic value doesn't look too good, but it is allowed, and (at least on Mac) it works.

Is that version built / linked with OpenSSL 3.0 ?

In my case (working example) - with 1.1.1.

Also, when salt len is not zero, signature is randomized - so different values are expected.

I have now tried to reproduce this on Ubuntu Impish (21.10), but it validates OK for me. I used libykcs11 from apt:

ldd /usr/bin/yubico-piv-tool
linux-vdso.so.1 (0x00007ffe0c5be000)
libcrypto.so.1.1 => /lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007efcde997000)
libykpiv.so.2 => /lib/x86_64-linux-gnu/libykpiv.so.2 (0x00007efcde980000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efcde758000)
libpcsclite.so.1 => /lib/x86_64-linux-gnu/libpcsclite.so.1 (0x00007efcde74c000)
/lib64/ld-linux-x86-64.so.2 (0x00007efcdeca7000)

ldd /lib/x86_64-linux-gnu/libykcs11.so
linux-vdso.so.1 (0x00007fff8e19d000)
libcrypto.so.1.1 => /lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f5c11ac2000)
libykpiv.so.2 => /lib/x86_64-linux-gnu/libykpiv.so.2 (0x00007f5c11aab000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5c11aa6000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5c1187e000)
libpcsclite.so.1 => /lib/x86_64-linux-gnu/libpcsclite.so.1 (0x00007f5c11872000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5c11e07000)

pkcs11-tool --module /lib/x86_64-linux-gnu/libykcs11.so --sign --mechanism SHA256-RSA-PKCS-PSS --salt-len 0 --id 02 -o s.sig -i s

Using slot 0 with a present token (0x0)
Logging in to "YubiKey PIV #____".
Please enter User PIN:
Using signature algorithm SHA256-RSA-PKCS-PSS
PSS parameters: hashAlg=SHA256, mgf=MGF1-SHA256, salt_len=0 B
Logging in to "YubiKey PIV #_____".
Please enter context specific PIN:

yubico-piv-tool -aread-certificate -s 9c >cert.pem
openssl x509 -in cert.pem -pubkey -noout >pub

openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify rsa.pub -signature s.sig s
Verified OK

I tried with a couple of different 's' files, one of approx 1000 bytes and one of 200kb. Both succeeded.

I used a YubiKey 5.4.3:

lsusb
Bus 002 Device 011: ID 1050:0407 Yubico.com Yubikey 4/5 OTP+U2F+CCID

I just intstalled the ykcs11 package today, and i have this:
yubico-piv-tool -V
yubico-piv-tool 2.2.0

Maybe run with debug ?
YKCS11_DBG=1 pkcs11-tool --module /lib/x86_64-linux-gnu/libykcs11.so --sign --mechanism SHA256-RSA-PKCS-PSS --salt-len 0 --id 02 -o s.sig -i s

apt info ykcs11
Package: ykcs11
Version: 2.2.0-1

apt info yubico-piv-tool
Package: yubico-piv-tool
Version: 2.2.0-1

openssl version
OpenSSL 1.1.1l 24 Aug 2021

Closing this because of no activity. Please post again if problem persists.

Sorry for the very late response to this.

I tried the same reproduction steps that you did. For the first test my laptop had ykcs11-2.0.0-2.

pkcs11-tool --module=/usr/lib/x86_64-linux-gnu/libykcs11.so -s -m SHA256-RSA-PKCS-PSS --salt-len 0 -i input -o 1.sig

Then I allowed apt to upgrade to the latest ykcs11-2.2.0 xl2tpd-2.2.0

pkcs11-tool --module=/usr/lib/x86_64-linux-gnu/libykcs11.so -s -m SHA256-RSA-PKCS-PSS --salt-len 0 -i input -o 2.sig

(it only asked for the password once, thanks for that). But 1.sig and 2.sig do not match.

openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify pub -signature 1.sig input
Verified OK
openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:0 -verify pub -signature 2.sig input
Verification failure
80EBF1BD477F0000:error:02000086:rsa routines:RSA_verify_PKCS1_PSS_mgf1:last octet invalid:../crypto/rsa/rsa_pss.c:94:
80EBF1BD477F0000:error:1C880004:Provider routines:rsa_verify:RSA lib:../providers/implementations/signature/rsa_sig.c:815:

Could you elablorate a bit how you installed the failing version. Im unsure exactly what this means:
"Then I allowed apt to upgrade to the latest ykcs11-2.2.0 xl2tpd-2.2.0"

I can't reproduce the problem, but I've only tested with code I built myself from the master branch.

In the latest example you are not specifying --id so pkcs11-tool is choosing whatever key it finds first on the YubiKey, likely id 01 which is slot 9a. id 2 is 9c. Slot 9c is by default 'always-auth' which means pkcs11-tool will (also) ask for a context-specific PIN. This is how pkcs11-tool works, libykcs11 simply reports keys to be always-auth or not.

Yes, that was it. When I specify --id 2 the keys do match. Thanks for your patience, this can be closed.

Glad it is fixed! And the issue is already closed :-)