Skip to content

Conversation

@TSlivede
Copy link

@TSlivede TSlivede commented Oct 26, 2025

This fixes #405.

The change to p11-kit/client.c is exactly as originally suggested by @spfendtner in #405.

The changes in p11-kit/rpc-message.c change the serialization of attributes on systems where size of unsigned long is not 8 bytes. As far as I know, this should only be the case for Windows and some uncommon linux variants (32 bit MIPS?).
With this change the wireprotocol is always identical and allows to connect with a p11-kit-client.dll to a p11-kit server running on Linux.

The length field for ULONG attributes is now always serialized as value 8.
In principle there is no need to serialize the length at all for ULONG attributes,
as the only allowed length value here is sizeof(CK_ULONG) anyway.
But by always serializing as 8 the wire protocoll does only change on the
few platforms where sizeof(CK_ULONG)!=8.
As there never was a p11-kit-client on Windows, I hope this is ok.

As was commented in the issue, LDFLAGS+=" -lintl" was required to build on windows, so I added libintl_deps to the dependencies of the mock_sources in p11-kit/meson.build, as some of those were failing without.

The shared_module('p11-kit-client', call in p11-kit/meson.build is the same as before, just two spaces indentation removed, as I completely removed the if host_system != 'windows' condition.

@TSlivede
Copy link
Author

TSlivede commented Oct 26, 2025

As @ueno asked in #405:

assuming it works: could you confirm?

These were the things I tested (mostly copied from #405):

To test the resulting client, I ran p11-kit server on linux (WSL), (though I had to use the official p11-kit-0.25.10.tar.xz release tarball, using ubuntu's p11-kit server produced errors...):

Click here to show commands to create virtual Smartcard via softhsm, create cert, start p11-kit server ...
sudo apt update
sudo apt install -y softhsm2 opensc openssl gnutls-bin socat

export TMPDIR=/tmp/p11demo
mkdir -p "$TMPDIR/softhsm"
export SOFTHSM2_CONF="$TMPDIR/softhsm2.conf"

cat > "$SOFTHSM2_CONF" <<EOF
directories.tokendir = $TMPDIR/softhsm
objectstore.backend = file
EOF

softhsm2-util --init-token --slot 0 --label "CodeSignToken" --so-pin 1234 --pin 1234

mkdir -p "$TMPDIR/certs"

# CA Key + Self-Signed Cert
openssl genrsa -out $TMPDIR/certs/ca.key.pem 2048
openssl req -x509 -new -nodes -key $TMPDIR/certs/ca.key.pem -sha256 -days 3650 \
  -out $TMPDIR/certs/ca.cert.pem -subj "/CN=My CodeSign CA/O=MyOrg/C=US"

# Code Signing Key
openssl genrsa -out $TMPDIR/certs/codesign.key.pem 2048

# CSR
openssl req -new -key $TMPDIR/certs/codesign.key.pem -out $TMPDIR/certs/codesign.csr.pem \
  -subj "/CN=Code Signing Cert/O=MyOrg/C=US"

# Code Signing Cert signed by CA
openssl x509 -req -in $TMPDIR/certs/codesign.csr.pem \
  -CA $TMPDIR/certs/ca.cert.pem -CAkey $TMPDIR/certs/ca.key.pem -CAcreateserial \
  -out $TMPDIR/certs/codesign.cert.pem -days 365 -sha256
  
# Import Key + Cert to SoftHSM
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \
  --login --pin 1234 --label "CodeSignKey" \
  --write-object $TMPDIR/certs/codesign.key.pem --type privkey

pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so \
  --login --pin 1234 --label "CodeSignCert" \
  --write-object $TMPDIR/certs/codesign.cert.pem --type cert

# Build p11-kit
mkdir p11-kit-linux
cd p11-kit-linux/
wget https://github.com/p11-glue/p11-kit/releases/download/0.25.10/p11-kit-0.25.10.tar.xz
tar xf p11-kit-0.25.10.tar.xz
cd p11-kit-0.25.10/
meson setup _build
meson compile -C _build

# Start server  
cd _build/
P11_SERVER_RESPONSE="$(P11_KIT_PRIVATEDIR=./p11-kit/ ./p11-kit/p11-kit server --provider /usr/lib/softhsm/libsofthsm2.so "pkcs11:token=CodeSignToken")"
eval "$P11_SERVER_RESPONSE"
echo "$P11_SERVER_RESPONSE"

# Check that server is working
GNUTLS_PIN=1234 p11tool --provider /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-client.so  --list-all --login

#Later stop server via
#P11_KIT_PRIVATEDIR=./p11-kit/ ./p11-kit/p11-kit server --kill

In the msys2 mingw64 shell where p11-kit (branch from this PR) was compiled:

pacman -S mingw-w64-x86_64-gnutls mingw-w64-x86_64-osslsigncode
#is there an msys2 package for this dll? I couldn't find one...
wget -O /mingw64/bin/pkcs11.dll https://github.com/mtrojnar/osslsigncode/releases/download/2.8/pkcs11.dll

#adjust path of p11-kit server socket to your actual value
export P11_KIT_SERVER_ADDRESS="|C:\Windows\System32\OpenSSH\ssh.exe [email protected] socat - UNIX-CONNECT:/mnt/wslg/runtime-dir/p11-kit/pkcs11-949"

GNUTLS_PIN=1234 p11tool --provider "$(cygpath -w "$(realpath ./_build/p11-kit/p11-kit-client.dll)")" --list-all --login

osslsigncode.exe sign -pkcs11engine "$(cygpath -w /mingw64/bin/pkcs11.dll)" -pkcs11module "$(cygpath -w "$(realpath ./_build/p11-kit/p11-kit-client.dll)")" -pkcs11cert "pkcs11:object=CodeSignCert" -key "pkcs11:object=CodeSignKey" -n Testname -i "https://example.com" -in ./_build/p11-kit/p11-kit-client.dll -out ./_build/p11-kit/p11-kit-client.signed.dll -pass 1234

/c/Program\ Files/OpenSC\ Project/OpenSC/tools/pkcs11-tool.exe --list-objects --module "$(cygpath -w "$(realpath ./_build/p11-kit/p11-kit-client.dll)")"

All three consumers of p11-kit-client.dll seemed to work as expected with the changes from this PR.

Copy link
Member

@ueno ueno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you; the logic looks correct. I just added minor nit picks which are nice to be fixed before merging it.

{
CK_ATTRIBUTE_PTR attr;
CK_ULONG i;
uint32_t valueLenSerialized;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use snail case instead of camel case: value_len_serialized.

/* And the attribute buffer length */
p11_rpc_buffer_add_uint32 (msg->output, attr->pValue ? attr->ulValueLen : 0);
valueLenSerialized = attr->pValue ? attr->ulValueLen : 0;
/* For ULONG attribures we always serialize the lenght as 8 even if it is not 8 on the current platform */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: lenghtlength

valueLenSerialized = attr->pValue ? attr->ulValueLen : 0;
/* For ULONG attribures we always serialize the lenght as 8 even if it is not 8 on the current platform */
if (sizeof(CK_ULONG) != 8 && valueLenSerialized == sizeof(CK_ULONG) && map_attribute_to_value_type(attr->type) == P11_RPC_VALUE_ULONG)
valueLenSerialized = 8;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe good to have a helper function for this? Something like:

static uint32_t
p11_rpc_buffer_add_value_length (p11_rpc_buffer *buffer, p11_rpc_value_type type, CK_ULONG value_length);

@TSlivede
Copy link
Author

I was trying to use this patched version today at work where I'd actually like to have a working version of p11-kit-client.dll.
Apparently this does not yet work as good as I assumed.

My real use case is with the opencs pkcs11 module. And contrary to softhsm that one seems to use handle values bigger than 32bit. But as CK_ULONG and therfore CK_OBJECT_HANDLE is only 32 bit on Windows the handle values get truncated and all further calls using the truncated handle values return invalid handle errors (I think it was CKR_OBJECT_HANDLE_INVALID ?).

I guess to properly connect from a p11-kit-client on platform with 32bit long to a p11-kit server on a 64bit long platform we'd need to have some kind of dictionary, that gets filled when a 64bit object handle gets deserialized into a 32bit CK_OBJECT_HANDLE and translated back to the correct 64bit value when serializing the value again for another api function call...

As a workaround I tried to run a 32 bit version of the p11-kit server on the linux side (as the object handle just looked like pointer values in pkcs11-spy), so my hope was that this would lead to all object handles being small enough. This was the case but lead me to find out that apparently on 32 bit linux they type long is also just 32 bit, so the impact of changing the wireprotocoll for those platforms is bigger then I expected.
Should this serialization change be configurable via environment variable so clients can still connect to servers not yet changed to always serialize as 8 ?

(When connecting with the windows p11-kit-client (with the patch from this pull request to normalize ULONG attribute serialized size to 8) to the 32bit p11-kit server, no pkcs11 function actually errored out but I guess some values somewhere were overwritten because several api function calls later strange things started to happen in the opencs pkcs11 module...)

I built another p11-kit-client.dll version without the ULONG attribute size normalization (basically state of the master branch) and got further with that one. p11tool --list-all [...] works, but osslsigncode fails. This was connected to the p11-kit server version of the debian packaged p11-kit version in i386 architecture. With osslsigncode I got the same error message (at the same place) I got yesterday with the ubuntu packaged p11-kit server (x86_64) version, though I did not setup debugging tools to actually confirm that it was the same cause (advancing parsed by 8 instead of 4 in this line IN_MECHANISM (mechanism); as mentioned in #405).

Instead I tried to build a 32 bit version of p11-kit for linux myself using
CFLAGS=-m32 CXXFLAGS=-m32 PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig meson --prefix=/opt/p11-kit/ --libdir=lib/i386-linux-gnu setup _build32. However this version crashes (the subprocess) with SIGSEGV when a connected client calls C_Initialize (Any idea why? Is this not how to build an i386 version?), so I could not yet confirm any p11-kit-client.dll version as working in production environment.

@TSlivede TSlivede force-pushed the feature_p11kit_client_on_windows branch from 8f1706c to b575e49 Compare October 28, 2025 19:52
@TSlivede
Copy link
Author

TSlivede commented Oct 29, 2025

Ok, I do have it working now in my "production" environment with an physical smartcard usbstick. The 32bit p11-kit server version I compiled myself does actually work, it just somehow does not work together with a pkcs11-spy in between it and the opensc pkcs11 module.

To recap:

64bit p11-kit-client.dll with normalization of ULONG attribute length to 8 works when connecting to a x86_64 p11-kit server (without the normalization) on linux if the pkcs11 module generates CK_OBJECT_HANDLE values that are below 0xffffffff (e.g. softhsm).

64bit p11-kit-client.dll with normalization of ULONG attribute length to 8 does not work when connecting to a i386 p11-kit server (without the normalization) on linux.

64bit p11-kit-client.dll without normalization of ULONG attribute length to 8 does not work when connecting to a x86_64 p11-kit server (without the normalization) on linux.

64bit p11-kit-client.dll without normalization of ULONG attribute length to 8 works when connecting to a i386 p11-kit server (without the normalization) on linux.

And not tested but based on my understanding: If the normalization of ULONG attribute length to 8 from this PR were to be added, then a p11-kit-client.so on linux i386 does not work when connecting to a i386 p11-kit server (without the normalization) on linux.

Also (for now) not tested and just based on my understanding: All "does not work" would be fixed, if the server side did already include the normalization to 8 from this PR.


This is obviously not a great result, especially as this change could break existing workflows, if someone updates either client or server but not the other.

My suggestion: We do not normalize the ULONG attribute length when serializing but instead always ignore the sent length when deserializing ULONG attributes (on server and client side, on all platforms, not just where sizeof ULONG is 4). This would mean that no existing workflow breaks when only one side (server or client) is updated to the version with the change.

But as soon as both sides are updated this would still allow communication between systems with ULONG size 8 and 4. While client with ULONG size 4 (Windows (x64 or x32) or linux x32) can only connect to a server with ULONG size 8 if it does not use big CK_OBJECT_HANDLE values, connecting from client with ULONG size 8 to a server with ULONG size 4 should in theory always work then.

TsLiveDe added 2 commits November 2, 2025 20:39
In principle there is no need to serialize the length at all in this case,
as the only allowed length value here is sizeof(CK_ULONG) anyway.
But by not changing the serialization the wire protocoll does not change
so no existing useages can break. But as soon as both client and server
use a version with this patch, communication between platforms with
different sizes of ULONG is possible (e.g. Windows to Linux x64).
@TSlivede TSlivede marked this pull request as draft November 2, 2025 20:45
@TSlivede TSlivede force-pushed the feature_p11kit_client_on_windows branch from b575e49 to 3df81c6 Compare November 2, 2025 20:45
@TSlivede
Copy link
Author

TSlivede commented Nov 2, 2025

Short update:
I changed this PR such that only on receiving the ULONG attribute length is deserialized as the correct value of the platform. In my test this did not yet work, though I did not yet debug why. Will post update in a few days.

Though at least this version does (as intended) seem to not break any existing working configuration based on my short tests.

I kept the previous version of this PR in this branch for reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

p11-kit-client.dll for Windows

2 participants