opensc-java
opensc-java copied to clipboard
Certificate chain of length one is not retrieved
When the token has only the leaf certificate but does not carry the entire chain (as most of the cryptographic tokens, such as smart cards do), the code throws an exception or returns null:
. . . . .
Certificate certificate = ks.getCertificate(alias); // this works
System.out.println(" certificate=" + certificate);
// the following either throws an exception on trying to fetch certificate
// of the issuer, or simply returns null
Certificate [] chain = ks.getCertificateChain(alias);
. . . . .
The correct (and expected) result would be Certificate[] chain having one entry - the leaf certificate itself. That's how SunPKCS11 provider behaves.
@CardContact could you please look into addressing this? It it a nasty bug that prevents me from using opens-java as PKCS#11 provider with JDK tools like jarsigner and keytool.
@CardContact I realize you're busy, but could you at least point me at the place/file in your code that would make sense to look to try to address this problem? For it is a show-stopper.
Reading the API specs for KeyStoreSpi.engineGetCertificateChain(), I'm not sure if returning a partial chain is the correct behaviour.
Anyway, you probably only need to replace the throw statement with a break in https://github.com/CardContact/opensc-java/blob/master/java/src/org/opensc/pkcs11/spi/PKCS11KeyStoreSpi.java#L241
Reading the API specs for KeyStoreSpi.engineGetCertificateChain(), I'm not sure if returning a partial chain is the correct behavior.
That is the behavior that SunPKCS11 provider exhibits. I think that OpenSC-Java should match that behavior, regardless of whether it may be considered correct or not. We cannot (and shouldn't) break existing software that works with SunPKCS11.
The main reason this behavior is needed is that most of the PKCS11 tokens (yours possibly excluded) do not carry the entire certificate chain - there's simply no room for that. All they have is:
- (Up to) four private keys
- Corresponding certificates - one per key (from which one can get the public key)
This applies to US government PIV and CAC tokens as well (I've tested it :).
Anyway, you probably only need to replace the throw statement with a break in https://github.com/CardContact/opensc-java/blob/master/java/src/org/opensc/pkcs11/spi/PKCS11KeyStoreSpi.java#L241
Thank you! That worked perfectly. Perhaps you would consider making that change in the master?
@CardContact I'm closing this issue, as after you suggested a simple fix that works it is unfair to keep it open.
In light of the above though, I'd like to urge you to make the change you mentioned above in the master. That change would make your PKCS11 provider compatible with SunPKCS11, which in my opinion would be very good.
@CardContact one thing more: to use your PKCS11 provider in place of SunPKCS11, one needs to be aware that instead of configuration file that SunPKCS11 expects, one should just supply the PKCS#11 library (e.g., /Library/OpenSC/lib/opensc-pkcs11.so in my case).
It was obvious post-factum, but until I figured that out, it took me some hair-pulling attempting to understand why jarsigner works with SunPKCS11, but throws an exception with PKCS11Provider.
Maybe a sentence or two about this in the README file...?
Dear @mouse07410, can you share some command lines that show how you used opensc-java with jarsigner ?
can you share some command lines that show how you used opensc-java with jarsigner?
Certainly! (Needless to say, opensc-java.jar has to be signed with JCE signing key for this to work, and reside on the path where java can find it. On Mac it is /Library/Java/Extensions/ directory.)
This is what my pkcs11jarsigner.sh looks like:
#!/bin/bash
SIGALG="SHA256withRSA"
# For OpenSC-Java PKCS#11 provider
PROVIDERCLASS=org.opensc.pkcs11.PKCS11Provider
PKCS11CONF="/Library/OpenSC/lib/opensc-pkcs11.dylib"
# For OpenSC-Java and YubiKey PIV token
ALIAS="CN=MyName_02"
# For other tokens just use "CN=..._02" (append "_02" (signature key index))
jarsigner -tsa ${TSAURL} -keystore NONE -storetype PKCS11 -providerClass \
${PROVIDERCLASS} -providerArg ${PKCS11CONF} -sigalg ${SIGALG} $1 "${ALIAS}"
Specifying -tsa ${TSAURL} is unnecessary but quite useful. Of course for that you need to know a TSA server that is willing to talk to you and provide you with digitally notarized timestamps.
@CardContact I hope the above helped. Would you like more info? If so, please feel free to ask specific questions.
Tried that myself and it worked after copying the .so files into jre/lib/ext. Unfortunately there doesn't seem to be a way to set java.library.path for keytool or jarsigner.
What I've done for the SmartCard-HSM JCE Provider is to write a simple wrapper around keytool that loads the required provider. That could be done for OpenSC-java as well.
Unfortunately there doesn't seem to be a way to set java.library.path for keytool or jarsigner
I have never tried. I placed the .so (actually .dylib) file also in /Library/Java/Extensions (same place where opensc-java.jar lives).
What I've done for the SmartCard-HSM JCE Provider is to write a simple wrapper around keytool that loads the required provider
Probably similar to my example file above.
That could be done for OpenSC-java as well
That's exactly what I'm doing. You see the actual bash script/wrapper above. Seems to be working fine. One script for keytool, the other (similar) one for jarsigner.
Update I used the same script for jarsigner with SunPKCS11. However SunPKCS11 provider is buggy, and in order for it to even open a PKCS#11 keystore, it has to be started in a debug mode (making nuisance of the screen output). Using OpenSC-Java provider instead (especially now when you suggested a good fix for the only show-stopper bug I encountered) works like charm. Excellent!
Hi, FWIW:
Tried that myself and it worked after copying the .so files into jre/lib/ext. Unfortunately there doesn't seem to be a way to set java.library.path for keytool or jarsigner.
jarsigner '-J-Djava.library.path=/path/to/library' ...
should do the trick.