title: Java TLS client can't find certificate when accessing soap service
body: <p>I have a java app that runs inside Tomcat.  It is trying to access a TLS client certificate authenticated SOAP service.  All certificates being used are self-signed.  I specify the trustStore and keyStore via the Java Options in Tomcat and I have also tried doing it in code for all the needed properties before creating my service.  Both keyStore and trustStore are JKS with RSA certificates.  I have verified the certificates exist in the server's trustStore and that the self client certificate exists in the client keyStore and that the hashes are the same.</p>
  
  <p>Client side:</p>
  
  <pre><code>c:\Program Files\Java\jre7\bin&gt;keytool -list -keystore c:\tomcat\certs\tomcat.keystore
  Enter keystore password:
  
  Keystore type: JKS
  Keystore provider: SUN
  
  Your keystore contains 1 entry
  
  tomcat, Jan 20, 2014, PrivateKeyEntry,
  Certificate fingerprint (SHA1): 78:F3:30:A0:40:B0:CC:8D:86:1F:99:FF:7C:3B:85:7C:6D:C7:F2:D2
  </code></pre>
  
  <p>Server side:</p>
  
  <pre><code>C:\Program Files (x86)\Java\jre7\bin&gt;keytool -list -keystore c:\tomcat\certs\tomcat.truststore
  Enter keystore password:
  
  Keystore type: JKS
  Keystore provider: SUN
  
  Your keystore contains 1 entry
  
  clientcert, Jan 23, 2014, trustedCertEntry,
  Certificate fingerprint (SHA1): 78:F3:30:A0:40:B0:CC:8D:86:1F:99:FF:7C:3B:85:7C:6D:C7:F2:D2
  </code></pre>
  
  <p>When I start Tomcat I see the loading of the keystore like this:</p>
  
  <pre><code>keyStore is : c:\tomcat\certs\tomcat.keystore
  keyStore type is : JKS
  keyStore provider is : 
  init keystore
  init keymanager of type SunX509
  ***
  found key for : tomcat
  chain [0] = [
  [
    Version: V3
    Subject: CN=Name, OU=Engineering, O=MyOrg, ST=NJ, C=US
  </code></pre>
  
  <p>...</p>
  
  <p>At the end of server hello I see the certificate DN that I expect and was loaded from the keystore above:</p>
  
  <pre><code>*** CertificateRequest
  Cert Types: RSA, DSS, ECDSA
  Cert Authorities:
  &lt;CN=Name, OU=Engineering, O=MyOrg, ST=NJ, C=US&gt;
  [read] MD5 and SHA1 hashes:  len = 115
  </code></pre>
  
  <p>...</p>
  
  <p>Then immediately after the ServerHelloDone I see an empty Certificate chain with no "matching alias: mycert" logging like I would expect to see.</p>
  
  <pre><code>*** ServerHelloDone
  [read] MD5 and SHA1 hashes:  len = 4
  0000: 0E 00 00 00                                        ....
  *** Certificate chain
  ***
  </code></pre>
  
  <p>Server side I get this:</p>
  
  <pre><code>http-nio-8443-exec-2, READ: TLSv1 Handshake, length = 269
  *** Certificate chain
  ***
  http-nio-8443-exec-2, fatal error: 42: null cert chain
  javax.net.ssl.SSLHandshakeException: null cert chain
  %% Invalidated:  [Session-1, TLS_RSA_WITH_AES_128_CBC_SHA]
  http-nio-8443-exec-2, SEND TLSv1 ALERT:  fatal, description = bad_certificate
  http-nio-8443-exec-2, WRITE: TLSv1 Alert, length = 2
  http-nio-8443-exec-2, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLHandshakeException: null cert chain
  http-nio-8443-exec-2, called closeOutbound()
  http-nio-8443-exec-2, closeOutboundInternal()
  </code></pre>
  
  <p>When I take the client's certificate and I load it into my browser and navigate to the site, I am prompted to choose the certificate and able to see the wsdl and such.  So I believe the certificate is fine.</p>
  
  <p>The Java client uses it's trustStore specified in the Java options just fine to validate the server which makes me believe the trustStore is loaded and used just fine.  Finally, here's the client piece of code I think is responsible for creating the service:</p>
  
  <pre><code>System.setProperty("javax.net.ssl.keyStore","C:\\tomcat\\certs\\tomcat.keystore");
  System.setProperty("javax.net.ssl.keyStorePassword", "password");
  System.setProperty("javax.net.ssl.keyStoreType", "JKS");
  System.setProperty("javax.net.ssl.trustStore","C:\\tomcat\\certs\tomcat.truststore");
  System.setProperty("javax.net.ssl.trustStorePassword", "password");
  System.setProperty("javax.net.ssl.trustStoreType", "JKS");
  URL url = DocumentRepositoryProxy.class.getClassLoader().getResource("XDS.b_DocumentRepositoryWSDLSynchMTOM.wsdl");
  
  QName qname = new QName("urn:ihe:iti:xds-b:2007", "DocumentRepository_Service");
  DocumentRepositoryService service = new DocumentRepositoryService(url, qname);
  
  if (handlerResolver != null)
      service.setHandlerResolver(handlerResolver);
  
  proxy = service.getDocumentRepositoryPortSoap12(new MTOMFeature(true, 1));
  
  BindingProvider bp = (BindingProvider) proxy;
  SOAPBinding binding = (SOAPBinding) bp.getBinding();
  binding.setMTOMEnabled(true);
  
  bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);
  </code></pre>
  
  <p>I've spent the majority of a week going down this rabbit hole and if anyone can help it'll save me some hairs.</p>