| Message |
|
|
JCAPI version 1.1.2 has been released today.
This release contains only one bug fix, but it's considered very important.
It turns out that the following methods, after call completion, have reversed the byte order of the passed in signature from big-endian (used in Java) into little-endian (used by MS CAPI):
- Signature.verify(byte[] signature)
- Signature.verify(byte[] signature, int offset, int length)
The error was caused by JCAPI working on an immediate reference to the signature byte array instead of a local copy.
So, if you have persistently saved your signature after calling one of the above methods, then you have to reverse it back into big-endian to make sure that your signature can be successfully verified again.
Here's an example of a Java method that will do the work for you:
static byte[] reverse(byte[] data)
{
int size = data.length;
byte[] reversedData = new byte[size];
for (int i = 0; i < size; i++)
{
reversedData[i] = data[size - i - 1];
}
return reversedData;
}
Our customers can download the commercial (unrestricted) version from the customers download page. Others are welcome to download the evaluation version from our public download page.
Sorry for the inconvenience this may have caused you.
|
 |
|
|
Updated information!
The problem with existing certificate stores that cannot be opened has now been fixed in JCAPI v1.1.1.
Regards,
Tommy
|
 |
|
|
Updated information!
The problem with illegal characters in the name attribute has now been fixed in JCAPI v1.1.1.
Regards,
Tommy
|
 |
|
|
Updated information!
This problem has now been fixed in JCAPI v1.1.1.
Regards,
Tommy
|
 |
|
|
JCAPI version 1.1.1 has been released today.
This is a maintenance release containing bug fixes for reported issues.
The release is binary- & source compatible with earlier releases.
The fixed bugs are:
- Existing system (certificate) stores that could not be opened was considered valid stores in JCAPI.
- The JCAPI DLL threw a JCAPIJNIRuntimeException with message "JCAPIKeyStore_getKey() - Could not get private key blob length." when a private key could not be exported when calling method KeyStore.getKey(). Now it returns a JCAPIRSAPrivateKey instance instead.
- The JCAPI SSL plugin sometimes generated aliases for PKCS#11 tokens that was considered illegal (contained spaces etc) by SUN's PKCS#11 provider. Now, a hexadecimal unique value for the current provider is used instead.
- When a non-existing system (certificate) store was to be opened, the JCAPI DLL automatically created it.
Our customers can download the commercial (unrestricted) version from the customers download page. Others are welcome to download the evaluation version from our public download page.
|
 |
|
|
Sorry about that. The patched DLL was compiled from the development branch which caused the DLL to get another version number.
Use the new DLL below.
Regards,
Tommy
|
 |
|
|
Hi,
I'm a bit confused here. The only way that you can get the error message " JCAPIKeyStore_getKey() - Could not get private key blob length." is if you have forced JCAPI to export your private key (which of course is not possible through your hardware token) by calling the method:
JCAPIProperties.getInstance().setPrivateKeyExportable(true);
So, the exception that is thrown from the JCAPI DLL can only occur if you have forced JCAPI to export the private key and when the MS CAPI function CryptExportKey() doesn't return a NTE_BAD_KEY_STATE (which is the normal case when a private key is not allowed to be exported). In your case NTE_BAD_TYPE was returned and thus causing the exception.
I would like you to try the following two items:
1. What error do you get if you don't force JCAPI to export the private key i.e remove the line: JCAPIProperties.getInstance().setPrivateKeyExportable(true);
2. I have patched the JCAPI DLL to also accept the NTE_BAD_TYPE code as a valid state (see file below) when you force JCAPI to export the key (just in order for you to get a JCAPIRSAPrivateKey for signing). Replace your current JCAPI DLL with this one, run your code again, and please report the result.
Regards,
Tommy
|
 |
|
|
Hello,
If your vendor has only supplied you with an MS CAPI driver, then you can just install the driver and use JCAPI as usual. You don't have to add the CSP explicitly for JCAPI in this case (this is only required for PKCS#11 CSPs).
the private key is not exportable, and suppose i know the alias is:
aaaaaaaaaa
Your given alias is not a valid JCAPI alias. Please see the example code below for an explanation.
can you provide an example that proved how to use jcapi to generate the signature with CallbackforPIN module?
What's a CallbackforPIN module?
If you mean the JCAPIPINCallback interface, then you have to add a PKCS#11 driver for your hardware token into JCAPI. Otherwise the CSP's own native PIN code dialog will be shown instead of the Java Swing based one provided by JCAPI.
I'm a bit surprised that your vendor has not supplied you with a PKCS#11 DLL. If you want to use your own Java based PIN code callback for your hardware key, then you have to use a PKCS#11 DLL for your key with JCAPI. Ask your vendor for such a driver.
Ok, here's an example of how to create a signature with JCAPI:
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import com.pheox.jcapi.*;
public class SignTest
{
static public void main(String[] args)
{
try {
Security.addProvider(new JCAPIProvider());
//Init JCAPI key store.
KeyStore ks = KeyStore.getInstance("msks", "JCAPI");
ks.load(null, null);
//Sign data using JCAPI.
byte[] dataToSign = {1,2,3,4,5};
Signature s = Signature.getInstance("SHA1withRSA", "JCAPI");
//The alias below will not work since a JCAPI alias is built
//from <system store name>|<base 64 encoded hash value of certificate>
//For example: MY|dTrrUZrdV/ULrLFH7iqLdFUKNOA=
String alias = "aaaaaaaaaa";
RSAPrivateKey privateKey = (RSAPrivateKey)ks.getKey(alias, null);
if(privateKey == null)
throw new Exception("No private key found for given alias.");
s.initSign(privateKey);
s.update(dataToSign);
byte[] signature = s.sign();
System.out.println("Signature = " + new String(signature));
} catch(Throwable t) {
t.printStackTrace();
System.err.println("Test prog failed. Exiting...");
}
}
}
Did this answear your questions? If not, please provide some more detailed information about what you want to achieve and I'll try to get you some good answears
Regards,
Tommy
|
 |
|
|
Hmm, ok.
From your given code snippet it should be impossible to get the whole chain since only the certificate associated with your private key is fed into the CertStore instance. The reason that you will still get the whole chain for your single certificate is probably due to:
1. You are using a qualified certificate i.e. your cert was issued by a trusted CA whose root CA cert and intermediate certificate(s) are already present in the JKS trusted key store.
2. You are using classes, not included in your code snippet, that access the JKS trusted key store based on your certificate.
From the above line of reasoning, your program will fail if you are using a certificate chain whose root CA is not trusted i.e not present in your JKS key store.
Anyway, great that you found a solution to overcome your specific problem. However, we (Pheox) must lay our hands on a Rainbow iKey 2032 HW token to find out the original reason for why the JVM is aborted since we couldn't find any anomalies when inspecting the JCAPI source code another round. Yet another challenge I suppose.
Please let us know if you encounter more issues related to JCAPI.
Regards,
Tommy
|
 |
|
|
Hi,
Thank you for the information. You gave us a good starting point.
This problem might be a bit tricky to solve without the actual HW key and certificates, but we'll give it a best try.
Could you please export your certificate chain (base 64 encoded) and post it to us? For each certificate exported, please specify the name of the system store (MY, CA, ROOT etc, you can use their friendly names if desirable) the certificate was exported from.
By importing your certificate chain, we can simulate your operation and hopefully trigger the error.
Regards,
Tommy
|
 |
|
|
Hi,
Nice stack trace
Luckely, we don't see these memory faults too often.
In order to help you, please read chapter 7 in the JCAPI User's Guide and post the requested information (I guess you can skip step 1).
What CSP is your Rainbow iKey using?
Regards,
Tommy
|
 |
|
|
Hi Mattias,
From your logging output, it's obvious that you have not activated client authentication on your server. Client authentication cannot be requested by the client, it's a choice determined by the server that must be fulfilled by all clients.
When client authentication is used, the JCAPI key manager (in your client) will log/print the issuer's distinguished name for each trusted certificate that is sent from the server to your client during the handshake. In your output there's none present.
Regarding your question:
The question is still why it works without giving PIN when running with NetID. I certainly want it to work properly with at least both Personal and NetID as provider (I guess client authentication doesn't work with the latter and the private key isn't used).
You are correct since there's no client authentication requsted by the server. The reason that you have to give a PIN for Personal is that SUN's keystore builder will login on your token when the java.security.KeyStore instance is created which in turn will require a PIN.
Why a PIN is not needed for NetID, I don't know since I have no experience with NetID. Probably its credentials are put on individual objects instead such as the private key, which should make it work anyway in the end. So, in conclusion, you don't give a PIN to access the private key, it's for login on your token.
Hint: you can see when JCAPI is accessing a private key on your token through PKCS#11 (you have to turn on logging). If the key can be successfully referenced, it will print:
JCAPI_SSL_LOG: Good, the private key can be accessed for alias: <alias>
Ok, to lace it up.
To activate client authentication on your server, you have to call method setNeedClientAuth(true) on your SSLServerSocket instance. You also have to define what certificates (trusted issuers) that the server shall send to the clients (use parameter trustStoreAlias in method JCAPISSLFactory.getSSLServerSocketFactory()).
To make a clean start, I've updated the JCAPI SSL client/server example programs to support client authentication with a self-signed certificate. Please study them and the logging output to get a better understanding of JCAPI and the contract between the client and the server. Then update them for your configuration (you have to change the parameters in methods getSSLServerSocketFactory() and getSSLSocketFactory()).
If you stumble into more problems, then try to supply as much information as possible about your configuration such as what kind of server certificate is used? Is is it chained or self-signed? Is it a "soft" certificate stored in MS CAPI or is it stored on a hardware token? Is the client and server running on the same machine etc?
Please let me know if more problems arise.
Regards,
Tommy
|
 |
|
|
Sorry, I should have seen that one coming.
The token labels of both certificates used during the test did not contain the equal sign after encoding.
I've fixed this in version 1.1.1.0 RC-2. Please download it and report your results.
Thanks,
Tommy
|
 |
|
|
Hi again Mattias,
Thank you for starting a new thread to avoid mixing of non-related issues.
There seems to be a problem with SUN's PKCS#11 provider; its parser doesn't like parentheses (neither spaces) very much.
Regarding your question:
Isn't the value of 'name' quite strange? Shouldn't it be the name of the CSP, in this case "SmartTrust Cryptographic Service Provider"? It must be something that is set from JCAPI since the PKCS#11 provider isn't mentioned in the java.security file.
The name attribute is built up from the token label and the selected slot index from your hardware token i.e. the information is fetched from your HW token by JCAPI.
The problem was solved by Base 64 encoding the name attribute.
A new version (1.1.1.0 RC-1) of the JCAPI SSL plugin, containing this patch, has been compiled and can be downloaded below. Could you please verify that your problem is solved as well?
Regards,
Tommy
|
 |
|
|
Hi Mattias,
I'm having problems to reproduce your reported error condition, mainly because our w2k machine is not part of a Windows domain, which excludes the possibility of testing the smart card login through Active Directory.
I think it would be better if I extend JCAPI to not return the name of a certificate store that cannot be successfully opened i.e. JCAPI must test to open each store when the list of available stores is collected.
I'll try to incorporate this functionality during the coming week.
Btw, is there a reason for you to use such an old version of SmartTrust (3.0.2)? I'm using version 3.3.1, even though it should have nothing to do with your problem, you might consider an upgrade.
Regarding your question about client authentication. Yes, you must use Java 5 with the JCAPI SSL plugin to utilise client authentication when a private key is not exportable (such as the case with hardware tokens).
Regards,
Tommy
|
 |
|
|