title: How to set mutual authentication using SSL in Java SE
body: <p>I am playing with SSL in Java for the first time, trying to create an echo server.
  I have managed to get it working when only the server needs to authenticate, with (after setting the properties to point to the appropriate KeyStore and TrustStore):</p>
  
  <p><strong>Server side:</strong></p>
  
  <pre><code>    SSLServerSocketFactory serverSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
      SSLServerSocket serverSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(bancoPort);
      String [] supported = serverSocketFactory.getSupportedCipherSuites();
      serverSocket.setEnabledCipherSuites(supported);
      serverSocket.setEnabledProtocols(new String[]{"TLSv1"});
      SSLSocket s = (SSLSocket) serverSocket.accept();
  </code></pre>
  
  <p><strong>Client side:</strong></p>
  
  <pre><code>SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
  SSLSocket bancoSocket = (SSLSocket) socketFactory.createSocket(bancoIP, bancoPort);
  String[] suites = bancoSocket.getSupportedCipherSuites();
  bancoSocket.setEnabledCipherSuites(suites);
  </code></pre>
  
  <p>Thanks to the debug mode I know the cipher suite used for authentication is TLS_ECDH_anon_WITH_AES_128_CBC_SHA:</p>
  
  <pre><code>main, READ: TLSv1 Handshake, length = 215
  *** ClientHello, TLSv1
  RandomCookie:  GMT: 1399451465 bytes = { 177, 86, 70, 228, 7, 0, 109, 56, 245, 8, 243, 18, 122, 186, 159, 138, 76, 99, 65, 224, 21, 100, 1, 90, 20, 109, 241, 216 }
  Session ID:  {}
  Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_ECDH_anon_WITH_RC4_128_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_anon_WITH_NULL_SHA, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5]
  Compression Methods:  { 0 }
  Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
  Extension ec_point_formats, formats: [uncompressed]
  ***
  %% Initialized:  [Session-1, SSL_NULL_WITH_NULL_NULL]
  %% Negotiating:  [Session-1, TLS_ECDH_anon_WITH_AES_128_CBC_SHA]
  *** ServerHello, TLSv1
  RandomCookie:  GMT: 1399451466 bytes = { 252, 63, 206, 222, 115, 40, 143, 4, 55, 11, 88, 196, 5, 10, 114, 159, 76, 144, 181, 27, 73, 248, 196, 71, 169, 136, 228, 82 }
  Session ID:  {83, 106, 239, 74, 65, 85, 23, 110, 97, 151, 196, 61, 224, 79, 140, 15, 11, 132, 208, 66, 112, 216, 122, 85, 27, 159, 194, 255, 104, 171, 81, 220}
  Cipher Suite: TLS_ECDH_anon_WITH_AES_128_CBC_SHA
  Compression Method: 0
  Extension renegotiation_info, renegotiated_connection: &lt;empty&gt;
  ***
  Cipher suite:  TLS_ECDH_anon_WITH_AES_128_CBC_SHA
  </code></pre>
  
  <p>If I add to the server code the line</p>
  
  <pre><code>serverSocket.setNeedClientAuth(true);
  </code></pre>
  
  <p>everything breaks down. The suite then used is TLS_KRB5_WITH_RC4_128_MD5, but the client is not apparently prepared to use Kerberos, since this is the error that pops up in the client when the first message to be echoed is sent:</p>
  
  <pre><code>may 08, 2014 3:31:30 AM echoclient.EchoClientSSL main
  Grave: null
  java.io.IOException: Invalid service principal name: host/desk-linux
      at sun.security.ssl.krb5.KerberosClientKeyExchangeImpl.getServiceTicket(KerberosClientKeyExchangeImpl.java:307)
      at sun.security.ssl.krb5.KerberosClientKeyExchangeImpl.init(KerberosClientKeyExchangeImpl.java:112)
      at sun.security.ssl.KerberosClientKeyExchange.init(KerberosClientKeyExchange.java:122)
      at sun.security.ssl.KerberosClientKeyExchange.&lt;init&gt;(KerberosClientKeyExchange.java:80)
      at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:873)
      at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:285)
      at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
      at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
      at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
      at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
      at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
      at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
      at java.io.DataOutputStream.write(DataOutputStream.java:107)
      at java.io.DataOutputStream.writeUTF(DataOutputStream.java:401)
      at java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
      at echoclient.EchoClientSSL.main(EchoClientSSL.java:45)
  Caused by: KrbException: Cannot locate default realm
      at sun.security.krb5.PrincipalName.&lt;init&gt;(PrincipalName.java:367)
      at sun.security.ssl.krb5.KerberosClientKeyExchangeImpl.getServiceTicket(KerberosClientKeyExchangeImpl.java:302)
      ... 15 more
  Caused by: KrbException: Cannot locate default realm
      at sun.security.krb5.Config.getDefaultRealm(Config.java:1181)
      at sun.security.krb5.PrincipalName.&lt;init&gt;(PrincipalName.java:365)
      ... 16 more
  Caused by: KrbException: Generic error (description in e-text) (60) - Unable to locate Kerberos realm
      at sun.security.krb5.Config.getRealmFromDNS(Config.java:1277)
      at sun.security.krb5.Config.getDefaultRealm(Config.java:1162)
      ... 17 more
  </code></pre>
  
  <p>I have tried to setEnabledCipherSuites in the client to just the one I know that works (TLS_ECDH_anon_WITH_AES_128_CBC_SHA) instead of the whole allowed cipher suite, but if I do that I get the exception at the server "javax.net.ssl.SSLHandshakeException: no cipher suites in common".
  Log:</p>
  
  <pre><code>main, READ: TLSv1 Handshake, length = 114
  *** ClientHello, TLSv1
  RandomCookie:  GMT: 1399451199 bytes = { 43, 248, 163, 155, 250, 241, 124, 194, 33, 46, 197, 27, 122, 1, 148, 254, 255, 71, 219, 220, 213, 91, 180, 178, 126, 242, 166, 82 }
  Session ID:  {}
  Cipher Suites: [TLS_ECDH_anon_WITH_AES_128_CBC_SHA]
  Compression Methods:  { 0 }
  Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
  Extension ec_point_formats, formats: [uncompressed]
  Extension renegotiation_info, renegotiated_connection: &lt;empty&gt;
  ***
  %% Initialized:  [Session-1, SSL_NULL_WITH_NULL_NULL]
  %% Invalidated:  [Session-1, SSL_NULL_WITH_NULL_NULL]
  main, SEND TLSv1 ALERT:  fatal, description = handshake_failure
  main, WRITE: TLSv1 Alert, length = 2
  main, called closeSocket()
  main, handling exception: javax.net.ssl.SSLHandshakeException: no cipher suites in common
  may 08, 2014 3:38:56 AM echoserver.EchoServerSSL main
  Grave: null
  javax.net.ssl.SSLHandshakeException: no cipher suites in common
  </code></pre>
  
  <p>Both server and client are running on the same machine, so I don't get how a cipher suite that works to authenticate the server fails when trying to authenticate the client.</p>