libp11
libp11 copied to clipboard
PIN asked twice, and no way to pass it from outside
Hello,
I've read all the discussion in https://github.com/OpenSC/OpenSC/issues/2039 but this seems to be a different issue, since pin_cache_ignore_user_consent
in opensc.conf has no effect here.
Background
In Italy, we use P7M files (PKCS#7 CAdES signed documents) a lot to communicate with the Public Administration. They're signed using certificates on smart cards provided from authorized manufacturers, who verify your identity before issuing one. I don't know if it's the same in the rest of the world, so I specified it.
For a project, I need to be able to sign documents with a bash script, without user interaction. Of course we're talking about an air-gapped and physically secure environment, where I feel confident to store my PIN on the system. I found OpenSSL to be able to generate P7M files natively since version 3.
My smart card
My smart card is from Aruba, one of the authorized providers. The card itself is from Oberthur or Incard, I'm not sure. However, Aruba provides a PKCS#11 module to interact with it, made by Bit4Id, that works correctly and shows the two certificates, public and private keys (with the OpenSC default module, I only see one of them, the one with id 434e5330, and it's exposed with id 01). The module is provided as a DEB file that sets up the library in /lib/bit4id/libbit4xpki.so
.
This is the output from pkcs11-tool --module /lib/bit4id/libbit4xpki.so -O --login
with some info redacted:
Using slot 0 with a present token (0x0)
Logging in to "CNS".
Please enter User PIN:
Certificate Object; type = X.509 cert
label: CNS User Certificate
subject: DN: CN={redacted}, GN={redacted}, SN={redacted}, O=Progetto CNS Arubapec\/Unical, OU=Universita' della Calabria, C=IT
ID: 434e5330
Data object 1002
label: 'PDATA'
application: 'PDATA'
app_id: 2.0.68.65.84.65
flags: modifiable
Public Key Object; RSA 1024 bits
label: CNS User Public Key
ID: 434e5330
Usage: encrypt, verify
Access: none
Private Key Object; RSA
label: CNS User Private Key
ID: 434e5330
Usage: decrypt, sign
Access: sensitive, always sensitive, never extractable
Certificate Object; type = X.509 cert
label: DS User Certificate3
subject: DN: C=IT, CN={redacted}, GN={redacted}, SN={redacted}
ID: 445333
Private Key Object; RSA
label: DS User Private Key 3
ID: 445333
Usage: sign
Access: always authenticate, sensitive, always sensitive, never extractable, local
Public Key Object; RSA 2048 bits
label: DS User Public Key3
ID: 445333
Usage: encrypt, verify
Access: none
I have 2 certificates, each one with its public and private keys. The first one, with ID 434e5330, is meant to be used for strong HTTPS client-side authentication to the Public Administration services. While it's technically valid also to digitally sign documents, its legal validity is limited. The second one, with ID 445333, is the digital signature certificate, fully legally valid. The digital signature certificate has the always authenticate
attribute, and I think this is where the problem comes from. I don't think I have any control on those attributes, and even if I had, I'd rather not mess up with the smart card itself.
My setup
I compiled libp11 from the master branch, and I'm using it on OpenSSL 3.0.13 from Ubuntu 24.04 repositories, with the PKCS#11 module provided by the smart card manufacturer. This is my openssl.cnf file:
openssl_conf = openssl_conf_section
[openssl_conf_section]
engines = engines_section
[engines_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so
MODULE_PATH = /lib/bit4id/libbit4xpki.so
The problem
I extracted the certificate with ID 445333 using this command:
pkcs11-tool --module /lib/bit4id/libbit4xpki.so -r -y cert -d 445333 -o ds.der --login
and I converted it into PEM with:
openssl x509 -inform der -in ds.der > ds.pem
When I try to digitally sign a file using openssl, I get asked for the PIN twice, one for the token and one for the key:
$ openssl cms -nosmimecap -md sha256 -nodetach -binary -cades -stream -outform DER -sign -signer ds.pem -inkey 'pkcs11:id=%44%53%33' -keyform engine -in test.pdf -out test.pdf.p7m -engine pkcs11
Engine "pkcs11" set.
Enter PKCS#11 token PIN for CNS: [I type my PIN]
Enter PKCS#11 key PIN for DS User Private Key 3: [I type my PIN again]
I found many ways to avoid the first PIN request:
- Setting
PIN = 12345
into the pkcs11_section of the OpenSSL config file - Using 'pkcs11:id=%44%53%33;pin-value=12345' as the
-inkey
value - Passing the additional parameter
-passin pass:12345
However, none of these methods allowed me to skip the second PIN request:
$ openssl cms -nosmimecap -md sha256 -nodetach -binary -cades -stream -outform DER -sign -signer ds.pem -inkey 'pkcs11:id=%44%53%33;pin-value=12345' -keyform engine -in test.pdf -out test.pdf.p7m -engine pkcs11
Engine "pkcs11" set.
Enter PKCS#11 key PIN for DS User Private Key 3:
I don't have this issue if I sign documents with the other certificate, but that's not what I need to do.
I tried editing /etc/opensc/opensc.conf
adding this:
framework pkcs15 {
use_pin_caching = true;
pin_cache_ignore_user_consent = true;
}
but nothing changed. I see this advice pretty much everywhere, but it's always related to OpenSC and never to libp11 so I think libp11 won't look at this setting, maybe?
I could probably use some hack with expect
, but I feel that's really not the way to go.
How I solved it for now
I found this other engine: https://github.com/opensignature/pkcs11engine
It's archived and not mantained anymore, but using this I'm not having the issue: the PIN is always asked only once, and is not asked at all if passed as pin-value in the PKCS#11 URI. This is solving my issue as of now, but I'd really love to be able to do this with a supported, current software like libp11.
I fully understand the rationale behind 'if it's "Always authenticate", then you have to always authenticate' and it makes sense, but I think a tool like OpenSSL is meant to automate things, and having no way to do so seems like a strong limitation to me.