We have created a new site for our web where we let the users to sign a pdf document using an applet we have designed. The issue is that this applet works fine only in Windows OS and we would like to extend it to linux OS.
When we run the applet in linux we get this error message:
[opensc-pkcs11] reader-pcsc.c:896:pcsc_detect_readers:
SCardListReaders failed: 0x8010002e [opensc-pkcs11]
reader-pcsc.c:1015:pcsc_detect_readers: returning with: No readers
found [opensc-pkcs11] reader-pcsc.c:896:pcsc_detect_readers:
SCardListReaders failed: 0x8010002e [opensc-pkcs11]
reader-pcsc.c:1015:pcsc_detect_readers: returning with: No readers
found java.security.NoSuchProviderException: no such provider:
SunMSCAPI at sun.security.jca.GetInstance.getService(Unknown Source)
at sun.security.jca.GetInstance.getInstance(Unknown Source)
I think the problem comes when we try to read the certificated stored in the Windows OS with this call in our code:
KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keystore.load(null, null);
return keystore;
This is te function we use to obtain the list of certificates.
public KeyStore obtenerCertificados() throws Exception {
String osNombre = System.getProperty("os.name");
String osArquitectura = System.getProperty("os.arch");
String providerConfig = null;
String configuracionPKCS11 = null;
// LINUX
if(osNombre.contains(new StringBuffer("Linux")))
providerConfig = "name = OpenSC\nlibrary = /usr/lib/opensc-pkcs11.so\n";
// WINDOWS
else if(osNombre.contains(new StringBuffer("Windows")))
if(!osArquitectura.toLowerCase().contains("x86")){
System.out.println("Estamos en toLowerCase().contains x86");
providerConfig = "name = NSS"+"\n"+
"nssLibraryDirectory = "+"C:/Archivos de programa/Mozilla Firefox"+"\n"+
"nssSecmodDirectory = "+"C:/Users/SM/AppData/Local/Mozilla/Firefox/Profiles/plmk3eh9.default"+"\n"+
"nssDbMode = readOnly" + "\n" +
"nssModule = keystore" + "\n" +
"\r";
}
else{
System.out.println("Estamos en NO toLowerCase().contains x86");
providerConfig = "name = NSS"+"\n"+
"nssLibraryDirectory = "+"C:/Program Files (x86)/Mozilla Firefox"+"\n"+
"nssLibrary = "+"C:/Program Files (x86)/Mozilla Firefox/softokn3.dll"+"\n"+
"nssSecmodDirectory = "+"C:/Users/SM/AppData/Roaming/Mozilla/Firefox/Profiles/plmk3eh9.default"+"\n"+
"nssDbMode = readOnly" + "\n" +
"nssModule = keystore" + "\n" +
"\r";
}
// MAC OS
else {providerConfig = "name = OpenSC\nlibrary = /Library/OpenSC/lib/opensc-pkcs11.so\n";}
ByteArrayInputStream localByteArrayInputStream = new ByteArrayInputStream(providerConfig.getBytes());
SunPKCS11 _pk11provider = null;
try {
_pk11provider = new SunPKCS11(localByteArrayInputStream);
Security.addProvider(_pk11provider);
// _pk11provider.login(new Subject(), new DialogCallbackHandler());
}catch(Throwable e){
System.out.println(e.getMessage());
}
KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keystore.load(null, null);
return keystore;
}
Any ideas about how to extend this use to linux and MAC???
Thanks a lot for your help!!
You can not use SunMSCAPI provider in Linux or MAC OS X, this provider is Windows specific which deals with Windows keystore. If you want to use a Smart Card or Firefox keystore in Linux or MAC OS X through SunPKCS11 provider you must get an instance of java.security.KeyStore passing SunPKCS11 as provider, like you are doing with SunMSCAPI i.e:
ByteArrayInputStream confStream = ...// your configuration
SunPKCS11 pkcs11 = new SunPKCS11(confStream);
Security.addProvider(pkcs11);
KeyStore ks = KeyStore.getInstance("PKCS11", pkcs11);
ks.load(null, "your_pin".toCharArray());
With this code you load on the Keystore ks the keys from your configured PKCS11.
There is another way to do it if you want that your PKCS11 pin will be introduced by a third party later. To do so you can initialize your keystore with a java.security.KeyStore.CallbackHandlerProtection parameter like follows:
ByteArrayInputStream confStream = ...// your configuration
SunPKCS11 pkcs11 = new SunPKCS11(confStream);
Security.addProvider(pkcs11);
KeyStore.CallbackHandlerProtection cbhp = new KeyStore.CallbackHandlerProtection(new PinInputHandler(msg));
KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", pkcs11, cbhp);
builder.getKeyStore();
Note that PinInputHandler in this second sample must implements: javax.security.auth.callback.CallbackHandler.
Additionally in your code seems that you never loads the PKCS11 keys through SunPKCS11 provider (even in Windows case) because you are not instantiating a keystore with SunPKCS11 you are only adding it as a provider with Security.addProvider method and always you are instantiating only a keystore with SunMSCAPI, however probably in Windows you are getting some of your Smart cards keys because if you install Windows drivers for you smart card you can get their keys through Windows keystore.
Hope this helps,
Related
I'm unable to add a certificate with a 2048 bit key to a Bouncy Castle KeyStore. I've updated my version of JCE, both the JRE and JDK security folders, with UnlimitedJCEPolicyJDK7.zip. The code below indicates the error location. I'm using bcprov-jdk15on-149 but have tried bcprov-jdk15on-157 with the same results. There are a number of posts regarding symmetric encryption problems but fewer on PKE. I'm running Windows 10 Pro, JRE 7, JDK 1.7.0_51. I'd appreciate any suggestions.
char[] testPass = "changeit".toCharArray();
String testAlias = "express";
// -----------------------------------------------------------------
// Open source TrustStore and extract certificate and key
FileInputStream jksFis = new FileInputStream("G:\\testSrc.jks");
KeyStore jksKS = KeyStore.getInstance(KeyStore.getDefaultType());
jksKS.load(jksFis, testPass);
PrivateKey jksPK = (PrivateKey) jksKS.getKey(testAlias,testPass);
RSAKey rsaKey = (RSAKey)jksPK;
int rsaKeyLen = rsaKey.getModulus().bitLength();
System.out.printf("Key length is %d\n",rsaKeyLen); // 2048
X509Certificate[] jksCerts = new X509Certificate[1];
jksCerts[0] = (X509Certificate) jksKS.getCertificate(testAlias);
// -----------------------------------------------------------------
// Create new default type keystore and add certificate and key.
KeyStore jksDest = KeyStore.getInstance(KeyStore.getDefaultType());
jksDest.load(null,null);
jksDest.setKeyEntry(testAlias, jksPK, testPass, jksCerts);
FileOutputStream jfos = new FileOutputStream("G:\\testDest.jks");
jksDest.store(jfos, testPass);
jfos.close();
// -----------------------------------------------------------------
// Create Bouncy Castle KeyStore and add certificate and key
Security.addProvider(new BouncyCastleProvider());
KeyStore bksKS = KeyStore.getInstance("PKCS12","BC");
bksKS.load(null,null);
bksKS.setKeyEntry(testAlias, jksPK, testPass, jksCerts);
FileOutputStream bksFos = new FileOutputStream("G:\\testDest.bks");
// -----------------------------------------------------------------
// Next line gives this error:
// java.io.IOException: exception encrypting data -
// java.security.InvalidKeyException: Illegal key size
bksKS.store(bksFos, testPass); // This is the error line.
// Error on previous line.
The procedure for installing the JCE update seems pretty straightforward so one of my assumptions about the version I'm using may be mistaken. As Omikron pointed out in his helpful comment it shouldn't have mattered anyway. He did get me going in the right direction which led to the solution. I'm posting the revised code below. I'm not sure why the default keystore type worked in the first place and bouncy castle didn't. Maybe someone familiar with bouncycastle will share their thoughts. In the meantime I'm going to see if this works on Android too.
public static void main(String[] args) {
try{
// -----------------------------------------------------------------
// Anonymous recommendation I found here:
// http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html
// This fixed my problem.
try {
Field field = Class.forName("javax.crypto.JceSecurity").
getDeclaredField("isRestricted");
field.setAccessible(true);
field.set(null, java.lang.Boolean.FALSE);
} catch (Exception ex) {
ex.printStackTrace();
}
// -----------------------------------------------------------------
// Check recommended by Omikron, who was correct: I assume I didn't
// install the JCE properly because it prints 128 for the max
// key allowd key length.
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
System.out.printf("max key len: %d\n",maxKeyLen);
// -----------------------------------------------------------------
char[] testPass = "changeit".toCharArray();
String testAlias = "express";
// -----------------------------------------------------------------
// Open source TrustStore and extract certificate and key
FileInputStream jksFis = new FileInputStream("G:\\testSrc.jks");
KeyStore jksKS = KeyStore.getInstance(KeyStore.getDefaultType());
jksKS.load(jksFis, testPass);
PrivateKey jksPK = (PrivateKey) jksKS.getKey(testAlias,testPass);
RSAKey rsaKey = (RSAKey)jksPK;
int rsaKeyLen = rsaKey.getModulus().bitLength();
System.out.printf("JKS key length is %d\n",rsaKeyLen); // 2048
X509Certificate[] jksCerts = new X509Certificate[1];
jksCerts[0] = (X509Certificate) jksKS.getCertificate(testAlias);
// -----------------------------------------------------------------
// Create new default type keystore and add certificate and key.
KeyStore jksDest = KeyStore.getInstance(KeyStore.getDefaultType());
jksDest.load(null,null);
jksDest.setKeyEntry(testAlias, jksPK, testPass, jksCerts);
FileOutputStream jfos = new FileOutputStream("G:\\testDest.jks");
jksDest.store(jfos, testPass);
jfos.close();
// -----------------------------------------------------------------
// Create Bouncy Castle KeyStore and add certificate and key
Security.addProvider(new BouncyCastleProvider());
KeyStore bksKS = KeyStore.getInstance("PKCS12","BC");
bksKS.load(null,null);
bksKS.setKeyEntry(testAlias, jksPK, testPass, jksCerts);
FileOutputStream bksFos = new FileOutputStream("G:\\testDest.bks");
bksKS.store(bksFos, testPass);
bksFos.close();
// -------------------------
// Open file and check key length:
bksKS = KeyStore.getInstance("PKCS12","BC");
FileInputStream bksFis = new FileInputStream("G:\\testDest.bks");
bksKS.load(bksFis, testPass);
PrivateKey bpk = (PrivateKey) bksKS.getKey(testAlias,testPass);
rsaKey = (RSAKey)bpk;
rsaKeyLen = rsaKey.getModulus().bitLength();
System.out.printf("BKS key length is %d\n",rsaKeyLen); // 2048
X509Certificate bkCert = (X509Certificate) bksKS.getCertificate(testAlias);
System.out.printf("Issuer name: %s", bkCert.getIssuerDN().getName());
}catch(Exception e){
e.printStackTrace();
}
}
Please, could someone point me in the right direction to digitally sign an MS-Office document (docx, xlsx, pptx) in Apache POI, or any other open source library?
I have already reviewed the classes under org.apache.poi.openxml4j.opc.signature but I cannot understand how I could add a signature to a document.
Check this sample code .. this sample code uses a file keystore PFX (PKCS12) .. Signs the Document and verify it.
// loading the keystore - pkcs12 is used here, but of course jks & co are also valid
// the keystore needs to contain a private key and it's certificate having a
// 'digitalSignature' key usage
char password[] = "test".toCharArray();
File file = new File("test.pfx");
KeyStore keystore = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream(file);
keystore.load(fis, password);
fis.close();
// extracting private key and certificate
String alias = "xyz"; // alias of the keystore entry
Key key = keystore.getKey(alias, password);
X509Certificate x509 = (X509Certificate)keystore.getCertificate(alias);
// filling the SignatureConfig entries (minimum fields, more options are available ...)
SignatureConfig signatureConfig = new SignatureConfig();
signatureConfig.setKey(keyPair.getPrivate());
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ_WRITE);
signatureConfig.setOpcPackage(pkg);
// adding the signature document to the package
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
si.confirmSignature();
// optionally verify the generated signature
boolean b = si.verifySignature();
assert (b);
// write the changes back to disc
pkg.close();
Here's the sample source : https://poi.apache.org/apidocs/org/apache/poi/poifs/crypt/dsig/SignatureInfo.html
I hope this could help!
I am currently trying to adapt a few scripts we use to sign an encrypt/decrypt xml files using OpenSSL and S/MIME using Java and BouncyCastle.
The command to sign and encrypt our file:
openssl smime -sign -signer Pub1.crt -inkey Priv.key -in foo.xml | openssl smime -encrypt -out foo.xml.smime Pub2.crt Pub1.crt
This generates a signed and encrypted smime-file containing our xml file. Currently this happens using a set of shell scripts under linux using the OpenSSL library. In the future we want to integrate this process into our Java application.
I've found out that this should be possible using the BouncyCastle library (see this post). The answer there provides two Java classes showing how to sign and encrypt an email using BouncyCastle and S/MIME. Comparing this to our OpenSSL command it seems that many of the things needed to sign an encrypt an email is not needed in our approach.
Some more meta information from our generated files:
Signed file
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----709621D94E0377688356FAAE5A2C1321"
Encrypted file
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64
Is it even possible to sign and encrypt a simple file in the way we did it using OpenSSL? My current knowledge of signing and de/encryption is not very high at the moment so forgive me for not providing code samples. I guess what I am looking for is more input into what I need to do and maybe some expertise from people who have already done this. I hope this is the right place to ask this. If not, please correct me.
I had a similar question as you but I managed to solve it. I have to warn you, my knowledge about signing and encryption isn't that high either. But this code seemed to work for me.
In my case I used a personalsign pro 3 certificate from globalsign, Previously I just called openssl from within java. But the I wanted to clean my code and decided to use bouncy castle instead.
public static boolean signAllFiles(List<File> files) {
Boolean signingSucceeded = true;
KeyStore ks = null;
char[] password = null;
Security.addProvider(new BouncyCastleProvider());
try {
ks = KeyStore.getInstance("PKCS12");
password = "yourpass".toCharArray();
ks.load(new FileInputStream("full/path/to/your/original/certificate.pfx"), password);
} catch (Exception e) {
signingSucceeded = false;
}
// Get privatekey and certificate
X509Certificate cert = null;
PrivateKey privatekey = null;
try {
Enumeration<String> en = ks.aliases();
String ALIAS = "";
Vector<Object> vectaliases = new Vector<Object>();
while (en.hasMoreElements())
vectaliases.add(en.nextElement());
String[] aliases = (String[])(vectaliases.toArray(new String[0]));
for (int i = 0; i < aliases.length; i++)
if (ks.isKeyEntry(aliases[i]))
{
ALIAS = aliases[i];
break;
}
privatekey = (PrivateKey)ks.getKey(ALIAS, password);
cert = (X509Certificate)ks.getCertificate(ALIAS);
// publickey = ks.getCertificate(ALIAS).getPublicKey();
} catch (Exception e) {
signingSucceeded = false;
}
for (File source : files) {
String fileName = "the/path/andNameOfYourOutputFile";
try {
// Reading files which need to be signed
File fileToSign = source;
byte[] buffer = new byte[(int)fileToSign.length()];
DataInputStream in = new DataInputStream(new FileInputStream(fileToSign));
in.readFully(buffer);
in.close();
// Generate signature
ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add(cert);
Store<?> certs = new JcaCertStore(certList);
CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
ContentSigner sha1signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(
privatekey);
signGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().build()).build(sha1signer, cert));
signGen.addCertificates(certs);
CMSTypedData content = new CMSProcessableByteArray(buffer);
CMSSignedData signedData = signGen.generate(content, false);
byte[] signeddata = signedData.getEncoded();
// Write signature to Fi File
FileOutputStream envfos = new FileOutputStream(fileName);
byte[] outputString = Base64.encode(signeddata);
int fullLines = (int)Math.floor(outputString.length / 64);
for (int i = 0; i < fullLines; i++) {
envfos.write(outputString, i * 64, 64);
envfos.write("\r\n".getBytes());
}
envfos.write(outputString, fullLines * 64, outputString.length % 64);
envfos.close();
} catch (Exception e) {
signingSucceeded = false;
}
}
return signingSucceeded;
}
This is only the code to sign a file, I hope it helps.
I have a question for sslConnectionin java , I write below code for client side ( this application have to connect to server, I have server that support ssl )but I get this error” javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target”
How can I resolve my problem ?
public static void main(String[] args) {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
PrintStream out = System.out;
SSLSocketFactory f =
(SSLSocketFactory) SSLSocketFactory.getDefault();
try {
SSLSocket c =
(SSLSocket) f.createSocket("192.168.10.38", 7701);
printSocketInfo(c);
System.out.println("End printSocketInfo");
c.startHandshake();
System.out.println("HandShake oK");
BufferedWriter w = new BufferedWriter(
new OutputStreamWriter(c.getOutputStream()));
BufferedReader r = new BufferedReader(
new InputStreamReader(c.getInputStream()));
String m = null;
// String m=
while ((m=r.readLine())!= null) {
System.out.println("11111");
out.println(m);
m = in.readLine();
System.out.println("M is: "+ m);
w.write(m,0,m.length());
w.newLine();
w.flush();
}
w.close();
r.close();
c.close();
} catch (IOException e) {
System.err.println(e.toString());
}
}
private static void printSocketInfo(SSLSocket s) {
System.out.println("Socket class: "+s.getClass());
System.out.println(" Remote address = "
+s.getInetAddress().toString());
System.out.println(" Remote port = "+s.getPort());
System.out.println(" Local socket address = "
+s.getLocalSocketAddress().toString());
System.out.println(" Local address = "
+s.getLocalAddress().toString());
System.out.println(" Local port = "+s.getLocalPort());
System.out.println(" Need client authentication = "
+s.getNeedClientAuth());
SSLSession ss = s.getSession();
System.out.println(" Cipher suite = "+ss.getCipherSuite());
System.out.println(" Protocol = "+ss.getProtocol());
}
I have a certificate file, how have to use this certificate?
Best Regards
Is it Self Signed certificate
If yes then you have two options
First Option :
Import Certificate authority certificate in Global Java Certificate Trust store. This store is located at
%Java Installation%/jre/lib/security/cacerts
To import it you can use Keytool command which comes with java installation
keytool -import -alias keyName -file yourcertificate.crt -keystore cacerts
Advantage:
No code modification needed.
Simple to deploy
Disadvantage:
cacert file will be overwritten in next java update. You have to
import certificate again.
Requires administrative privileges (both on Linux and windows)
Second Option :
If you want to bypass certificate validation follow Java: Overriding function to disable SSL certificate check
Else
create new Trust store for your program
keytool -import -alias keyName -file yourcertificate.crt -keystore yourtruststore
This command will ask for password two times. Enter any password you want and input "yes" for any questions
A file will be created at current directory by name "yourtruststore"
Now you need to use this trust store in your program
SSLSocketFactory sslFactory = null;
InputStream trustStore = null;
KeyStore keyStore = null;
trustStore = new FileInputStream("<your trust store absolute path>");
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(trustStore, "<your trust store password>".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslFactory = ctx.getSocketFactory();
You can use this socket factory to open new sockets
You have to put the HTTPS certificate to your JVM. To get the certificate from the HTTPS, go through a browser, then click on the "lock" logo on the address bar. You should be able to export the certificate.
Solution for Linux: In $JAVA_HOME/jre/lib/security, use this command:
sudo keytool -import -alias keyName -file /[pathForYourKey]/keyName.cert -keystore cacerts
Default password for "cacerts" is changeit.
I want to sign file with the SunMSCAPI provider. As public key and signatures needs to be imported using MS Crypto API.
Generally generating signatures with SHA1withRSA, ends up with big-endian to little-endian (byte order) conversion.
//generate keystore with java keytool
$Keytool -genkey -alias tsign -keystore c:\test\tsignjks.p12 - keyalg rsa -storetype pkcs12
In Java application:
//for signing and getting keystore, assuming windows certificate is installed
..ks = KeyStore.getInstance("Windows-MY","SunMSCAPI");
PrivateKey priv = ks.getKey("tsign",password);
Signature rsa = Signature.getInstance("SHA1withRSA","SunMSCAPI");
rsa.initSign(priv);
..
rsa.update(buffer, 0, len);
..
byte[] realSig = rsa.sign();
//for writing public key for ms crypto api or exporting it from windows certificate store
Certificate cert = ks.getCertificate("tsign");
byte[] encodedCert = cert.getEncoded();
FileOutputStream certfos = new FileOutputStream("tsigncer.cer");
certfos.write(encodedCert);
//for writing signatures for ms crypto api
FileOutputStream sigfos = new FileOutputStream(targetPath + "/"
+ signatureName);
sigfos.write(realSig);
I believe that SunMSCAPI can resolve my problem, but I don't know when i import public key using MS Crypto API, It never import at at first stage (unless i change big endian to little endian byte order) below is my code for crypto API.
LPCSTR file = "tsigncer.cer";
//LPCSTR file = "omsign.p12";
BOOL crypt_res = FALSE;
HCRYPTPROV crypt_prov_hndl = NULL;
crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_RSA_FULL, 0/*CRYPT_NEWKEYSET*/);
//crypt_res = CryptAcquireContext(&crypt_prov_hndl, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT/*CRYPT_NEWKEYSET*/);
if (!crypt_res) {
HRESULT decode_hr = __HRESULT_FROM_WIN32(GetLastError());
return decode_hr;
}
// Load key file
HANDLE fileHandle = CreateFile(file, // name of the write
GENERIC_READ, // open for writing
0, // do not share
NULL, // default security
OPEN_EXISTING, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (fileHandle == INVALID_HANDLE_VALUE)
{
DWORD d = GetLastError();
return -1;
}
BYTE buffer[2056];
DWORD fileSize = 0;
DWORD fileSizeResult = GetFileSize(fileHandle, &fileSize);
DWORD numBytesRead = 0;
BOOL fileLoadResult = ReadFile(fileHandle, (PVOID)buffer, fileSizeResult, &numBytesRead, NULL);
// Import key
BOOL result = ImportKey(crypt_prov_hndl, (LPBYTE)buffer, numBytesRead);
//result is always false..
If you work with MSCAPI, it is assumed that you've added your key to the Microsoft Certificate store. You can check if the key is present by going to "Internet Properties" > "Content" > "Certificates" which gives you a list of certificates that are available. If your certificate isn't there, you can't use it. If it's there, you need this code:
SunMSCAPI providerMSCAPI = new SunMSCAPI();
Security.addProvider(providerMSCAPI);
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
From there on, the code is pretty standard. Please consult my book on digital signatures for more info (the book is free).
IMPORTANT ADDITION: I forgot to mention that SunMSCAPI isn't present in the 64-bit version of Java 6 (I don't know about Java 7). You can fix this by installing the 32-bit version.