title: Android Paho SSL with server sent CA certificate, including Hostname Verification
body: <p><strong>Duplication</strong>: There are a few similar questions (<a href="https://stackoverflow.com/questions/6441158/how-can-i-access-an-ssl-connection-through-android">How Can I Access an SSL Connection Through Android?</a>, <a href="https://stackoverflow.com/questions/26665062/trust-anchor-for-certification-path-not-found-in-android-ssl-socket-client">&quot;Trust anchor for certification path not found&quot; in Android SSL Socket client</a>, <a href="https://stackoverflow.com/questions/19494992/trust-anchor-for-certification-path-not-found-using-ssl">Trust anchor for certification path not found using SSL</a>)
  with no applicable answers to my issue. I try to give a specific context (e.g. paho and specific test sites) and problem.</p>
  
  <p><strong>Main Issue</strong>: I'm using Android Paho, as client, and everything's fine. Now I want to add SSL connection. The broker is the certified entity, and sends its CA-issued certificate during handshake.
  (Please note that I'm a security newbie, I just read a few tutorials on the subject.)</p>
  
  <p>Most Java and Paho examples I can find deal with having a <em>local</em> certificate (self-issued, or less known CA, etc.), while I need instead to manage CA-issued certificates sent to my app by the broker server during handshake.</p>
  
  <p>From Android documentation (<a href="https://developer.android.com/training/articles/security-ssl.html" rel="nofollow noreferrer">https://developer.android.com/training/articles/security-ssl.html</a>), the idea seems to be that you just have to use <code>SSLSocketFactory.getDefault()</code>, since root CA certifications for well-known CAs are included with the system. So, simply:</p>
  
  <pre><code>MqttConnectOptions options;
  
  // ...
  
  options.setSocketFactory(SSLSocketFactory.getDefault());
  </code></pre>
  
  <p>But I tested on both:</p>
  
  <ul>
  <li>ssl://iot.eclipse.org:8883</li>
  <li>ssl://test.mosquitto.org:8883</li>
  </ul>
  
  <p>and I always got the dreaded <code>javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.</code></p>
  
  <p>The possible reasons given by the aforementioned android documentation, and Stack Overflow answers, presumably don't apply to such well-known and used test sites. I presume that both sites have updated certificates, issued by well-known Certification Authorities, with no lesser known CAs in the chain. (While I cannot find clear confirmation, usage examples around the net do seem to imply it.)</p>
  
  <p>Any pointers? I really have no idea where to go from here (and I presume I'm missing something obvious that it's not clearly stated.)</p>
  
  <p><strong>Secondary Issue</strong>: Furthermore, the Android documentation warns that <code>SSLSocket</code> doesn't do any Hostname Verification: <a href="https://developer.android.com/training/articles/security-ssl.html#WarningsSslSocket" rel="nofollow noreferrer">https://developer.android.com/training/articles/security-ssl.html#WarningsSslSocket</a></p>
  
  <p>And hence it suggests:</p>
  
  <pre><code>SocketFactory sf = SSLSocketFactory.getDefault();
  SSLSocket socket = (SSLSocket) sf.createSocket("gmail.com", 443);
  HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
  SSLSession s = socket.getSession();
  
  // Verify that the certicate hostname is for mail.google.com
  // This is due to lack of SNI support in the current SSLSocket.
  if (!hv.verify("mail.google.com", s)) {
      throw new SSLHandshakeException("Expected mail.google.com, "
                                      "found " + s.getPeerPrincipal());
  }
  </code></pre>
  
  <p>Please note that you need a reference to the actual socket to pass to <code>verify()</code> (no overloaded alternative), you cannot just configure the <code>SSLSocketFactory</code>.</p>
  
  <p>Paho doesn't seem to expose access to the socket it's using, not to set a custom verifier. You can only set the <code>SSLSocketFactory</code>.</p>
  
  <p>If I understand correctly, there seem to be a Paho bug reported about it: <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=425195" rel="nofollow noreferrer">https://bugs.eclipse.org/bugs/show_bug.cgi?id=425195</a></p>
  
  <p>Is it actually the same issue?</p>
  
  <p>Finally, if so, is there any way to work around this and actually have Android Paho over SSL with Hostname Verification?</p>
  
  <p><strong>EDIT, Partial answer / findings</strong>: I record here my partial provisional findings.</p>
  
  <p>My assumption about <code>iot.eclipse.org:8883</code> and <code>test.mosquitto.org:8883</code> seems to be wrong: I found doc for both that provide certificates to explicitly be used by the clients (I presume self-signed, it's not specified). Some examples omitting this misled me.</p>
  
  <ul>
  <li>ssl://iot.eclipse.org:8883 :  <a href="http://iot.eclipse.org/iot.eclipse.org.crt" rel="nofollow noreferrer">iot.eclipse.org.crt</a> as indicated by <a href="http://iot.eclipse.org/getting-started" rel="nofollow noreferrer">http://iot.eclipse.org/getting-started</a></li>
  <li>ssl://test.mosquitto.org:8883 : <a href="http://test.mosquitto.org/ssl/mosquitto.org.crt" rel="nofollow noreferrer">mosquitto.org.crt</a> as indicated by <a href="http://test.mosquitto.org/" rel="nofollow noreferrer">http://test.mosquitto.org/</a></li>
  </ul>
  
  <p>Loading the certificates in a custom <code>TrustManager</code>, everything work. Mystery solved on this point. Our own broker with CA certificates isn't ready yet to be tested.</p>