@Override public void handleMessage(Message msg) { switch (msg.what) { case VncConstants.DIALOG_X509_CERT: final X509Certificate cert = (X509Certificate) msg.obj; if (connection.getSshHostKey().equals("")) { // Show a dialog with the key signature for approval. DialogInterface.OnClickListener signatureNo = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // We were told not to continue, so stop the activity closeConnection(); ((Activity) getContext()).finish(); } }; DialogInterface.OnClickListener signatureYes = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // We were told to go ahead with the connection, so save the key into the // database. String certificate = null; try { certificate = Base64.encodeToString(cert.getEncoded(), Base64.DEFAULT); } catch (CertificateEncodingException e) { e.printStackTrace(); showFatalMessageAndQuit("Certificate encoding could not be generated."); } connection.setSshHostKey(certificate); connection.save(database.getWritableDatabase()); database.close(); // Indicate the certificate was accepted. certificateAccepted = true; } }; // Generate a sha1 signature of the certificate. MessageDigest sha1; MessageDigest md5; try { sha1 = MessageDigest.getInstance("SHA1"); md5 = MessageDigest.getInstance("MD5"); sha1.update(cert.getEncoded()); Utils.showYesNoPrompt( getContext(), "Continue connecting to " + connection.getAddress() + "?", "The x509 certificate signatures are:" + "\nSHA1: " + Utils.toHexString(sha1.digest()) + "\nMD5: " + Utils.toHexString(md5.digest()) + "\nYou can ensure they are identical to the known signatures of the server certificate to prevent a man-in-the-middle attack.", signatureYes, signatureNo); } catch (NoSuchAlgorithmException e2) { e2.printStackTrace(); showFatalMessageAndQuit( "Could not generate SHA1 or MD5 signature of certificate. No SHA1/MD5 algorithm found."); } catch (CertificateEncodingException e) { e.printStackTrace(); showFatalMessageAndQuit("Certificate encoding could not be generated."); } } else { // Compare saved with obtained certificate and quit if they don't match. try { if (!connection .getSshHostKey() .equals(Base64.encodeToString(cert.getEncoded(), Base64.DEFAULT))) { showFatalMessageAndQuit( "ERROR: The saved x509 certificate does not match the current server certificate! " + "This could be a man-in-the-middle attack. If you are aware of the key change, delete and recreate the connection."); } else { // In case we need to display information about the certificate, we can // reconstruct it like this: // CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); // ByteArrayInputStream in = new // ByteArrayInputStream(Base64.decode(connection.getSshHostKey(), // Base64.DEFAULT)); // X509Certificate c = (X509Certificate)certFactory.generateCertificate(in); // android.util.Log.e(" Subject ", c.getSubjectDN().toString()); // android.util.Log.e(" Issuer ", c.getIssuerDN().toString()); // The certificate matches, so we proceed. certificateAccepted = true; } } catch (CertificateEncodingException e) { e.printStackTrace(); showFatalMessageAndQuit("Certificate encoding could not be generated."); } } break; } }