luisgoncalves / xades4j

A Java library for XAdES signature services
GNU Lesser General Public License v3.0
111 stars 66 forks source link

Support explicit security Provider #283

Closed Chlorek closed 8 months ago

Chlorek commented 9 months ago

I am wondering how to handle situation where I have multiple PKCS11 providers. Each of them is responsible for providing its own certificate and private key from different smart-cards. Private keys are instances of sun.security.pkcs11.P11Key$P11PrivateKey therefor they are not accessible in their raw form. They can be only used together with provider that created them, but Java uses the first provider it finds which matches supported crypto algorithm, this leads to invalid provider being used.

This could be fixed by allowing to pass Provider explicitly to the xades4j during signing. The org.apache.xml.security.signature.XMLSignature has a constructor accepting Provider. XadesSigner implementations could be extended to use this constructor.

Did I misunderstood something or am I right and this would be a good feature to have? Thanks for input.

luisgoncalves commented 9 months ago

I believe the provider for crypto operations is selected based on the provider of the PrivateKey. In xades4j, PKCS11KeyStoreKeyingDataProvider (and its builder) allows configuring different native PKCS11 provider (different libs and/or slots), which should cover your scenario. The used Provider is always SunPKCS11, but the actual native provider depends on the configuration passed on the mentioned builder.

FileSystemKeyStoreKeyingDataProvider (and its builder) allows directly passing in the provider.

Isn't this the case?

Chlorek commented 9 months ago

Thank you for quick response. Do you have any source to the selection of the provider taking into account a key? I have read numerous sources and even the Java libraries themselves and cannot find such logic. Sorry for doubting but I want to be absolutely sure I understand how this works.

In my case I have not used PKCS11KeyStoreKeyingDataProvider because I prepare keys and certs myself, but the code inside looks pretty much the same as mine. So instead I am using DirectKeyingDataProvider which does not let me pass Provider. Even if I were using FileSystemKeyStoreKeyingDataProvider the provider would be used to prepare keys, but not during signing.

luisgoncalves commented 9 months ago

I don't have a source, sorry. This was mostly based on observations (and a bit of "what makes sense"). Namely, I have tested xades4j with smart cards, so my reasoning is:

If a signature operation succeeds, I believe it has to happen on the smart card itself (that's the point, right?). A PrivateKey returned from a KeyStore instance backed by the smart card should be a "handle" - since the actual key doesn't leave the device. If that's the case, then the provider for the signature operation needs to be the key's Provider - otherwise it wouldn't be able to use the PrivateKey.

Chlorek commented 9 months ago

I do not have access to multiple card readers right now. I will soon, so I will do more tests and post an update.

Chlorek commented 8 months ago

I had some issues with the new card I have received, but finally I can confirm appropriate provider is chosen when multiple readers are connected. Hope it helps some people wondering about this in the future as Java documentation does not mention the mechanism selecting security provider based on the key.