title: How to use MSCAPI provider for client SSL authentication
body: <p>I am writing a program which needs to make HTTPS connections to a web server, where SSL Client authentication needs to be used.</p>
  
  <p>The users of this program will use certificates from the windows environment to authenticate themselves.</p>
  
  <p>I've found plenty of examples showing how to set up client authentication, and it works fine if I first export my certificate to pkcs12 format, but I don't wish to force my users to do that. However when I try to use the MSCAPI it always bombs out with an exception:</p>
  
  <pre><code>javax.net.ssl.SSLHandshakeException: Error signing certificate verify
          at sun.security.ssl.Alerts.getSSLException(Unknown Source)
          at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
          at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
          at sun.security.ssl.ClientHandshaker.serverHelloDone(Unknown Source)
          at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
          at sun.security.ssl.Handshaker.processLoop(Unknown Source)
          at sun.security.ssl.Handshaker.process_record(Unknown Source)
          at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
          at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
          at sun.security.ssl.AppInputStream.read(Unknown Source)
          at java.io.BufferedInputStream.fill(Unknown Source)
          at java.io.BufferedInputStream.read1(Unknown Source)
          at java.io.BufferedInputStream.read(Unknown Source)
          at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
          at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
          at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
          at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
          at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
          at com.example.Win2.main(Win2.java:62)
  Caused by: java.security.SignatureException: Bad Key.
  
          at sun.security.mscapi.RSASignature.signHash(Native Method)
          at sun.security.mscapi.RSASignature.engineSign(RSASignature.java:390)
          at java.security.Signature$Delegate.engineSign(Unknown Source)
          at java.security.Signature.sign(Unknown Source)
          at sun.security.ssl.RSASignature.engineSign(Unknown Source)
          at java.security.Signature$Delegate.engineSign(Unknown Source)
          at java.security.Signature.sign(Unknown Source)
          at sun.security.ssl.HandshakeMessage$CertificateVerify.&lt;init&gt;(Unknown Source)
          ... 16 more
  </code></pre>
  
  <p>I can't really tell what might be wrong with the key from that exception.</p>
  
  <p>I have made a tiny test program to reproduce the problem I am having:</p>
  
  <pre><code>String passwd = .....";
  URL url = new URL("https://.........");
  
  KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  KeyStore keyStore = KeyStore.getInstance("Windows-MY");
  keyStore.load(null, passwd.toCharArray());
  keyManagerFactory.init(keyStore, passwd.toCharArray());
  
  SSLContext context = SSLContext.getInstance("TLS");
  context.init(keyManagerFactory.getKeyManagers(), null, null);
  SSLSocketFactory socketFactory = context.getSocketFactory();
  
  HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
  conn.setSSLSocketFactory(socketFactory);
  </code></pre>
  
  <p>There is clearly something about the APIs I don't understand here. How does it know which of the keys in the keystore I want to use? I was expecting for Windows to prompt me, as it does for other applications which need to authenticate, but I suspect instead it is just choosing the first one it finds.</p>
  
  <p>Do I need to implement my own key manager so it can choose which key will be used?</p>
  
  <p>If I iterate through the keystore, I can see the keys in it and can extract one by calling getKey. To complicate matters, there are multiple keys in the store with the same alias (but differing validity). Other (non-java) applications, eg. Chrome, seem to be able to determine which keys to use somehow.</p>
  
  <p>EDIT: I forgot to mention, I am using Java 1.7.</p>