package org.openslx.dozmod.gui; import java.math.BigInteger; import java.security.KeyManagementException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.log4j.Logger; import org.openslx.dozmod.authentication.FingerprintManager; import org.openslx.dozmod.gui.Gui.GuiCallable; import org.openslx.dozmod.gui.helper.MessageType; public class GraphicalCertHandler { private static final Logger LOGGER = Logger.getLogger(GraphicalCertHandler.GuiTrustManager.class); private class GuiTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { if (certs == null || certs.length == 0) { Boolean ret = Gui.syncExec(new GuiCallable() { @Override public Boolean run() { return Gui.showMessageBox(null, "Der Satellit besitzt kein Zertifikat. Verschlüsselte Verbindung nicht möglich.\n\n" + "Möchten Sie trotzdem fortfahren?", MessageType.WARNING, LOGGER, null); } }); if (ret) return; throw new CertificateException("No certificate provided by server"); } byte[] encoded = certs[0].getEncoded(); MessageDigest md; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { LOGGER.warn("Could not get SHA-256 hash of certificate", e); throw new CertificateException("Could not get SHA-256 hash of certificate"); } md.update(encoded); byte[] actualFingerprint = md.digest(); final String actualFingerprintReadable = new BigInteger(actualFingerprint).toString(16); // Now check the finger print byte[] expectedFingerprint = FingerprintManager.getKnownFingerprint(address); if (expectedFingerprint == null) { expectedFingerprint = FingerprintManager.getSuggestedFingerprint(address); } final String question; if (expectedFingerprint == null) { // First time we connect to this server, so remember the finger print FingerprintManager.saveKnownFingerprint(address, actualFingerprint); return; } else if (Arrays.equals(actualFingerprint, expectedFingerprint)) { // Known, matches, everything's fine return; } else { byte[] sf = FingerprintManager.getSuggestedFingerprint(address); if (sf != null && Arrays.equals(actualFingerprint, sf)) { // User stored invalid finger print, but master suggests the finger print we found. // It probably changed, the satellite told the master server, but the user doesn't know yet. FingerprintManager.saveKnownFingerprint(address, actualFingerprint); return; } // Known, mismatch, panic! question = "!!! ALARM !!!! ALARM !!!\n\n" + "Der Fingerabdruck von " + address + " hat sich verändert.\n" + "Erwartet: " + new BigInteger(expectedFingerprint).toString(16) + "\n" + "Vorgefunden: " + actualFingerprintReadable + "\n\n" + "Möchten Sie trotzdem zu diesem Satelliten verbinden?"; } // Some question needs to be asked Boolean userOk = Gui.syncExec(new GuiCallable() { @Override public Boolean run() { return Gui.showMessageBox(null, question, MessageType.QUESTION_YESNO, null, null); } }); if (userOk) { FingerprintManager.saveKnownFingerprint(address, actualFingerprint); } else { throw new CertificateException("Rejected by user"); } } @Override public X509Certificate[] getAcceptedIssuers() { return null; } } private final String address; private final SSLContext sslContext; private GraphicalCertHandler(String address) { SSLContext ctx = null; try { ctx = SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException e) { Gui.asyncMessageBox("Could not get TLSv1.2 SSL context", MessageType.ERROR, LOGGER, e); } if (ctx != null) { try { ctx.init(null, new TrustManager[] { new GuiTrustManager() }, null); } catch (KeyManagementException e) { Gui.asyncMessageBox("Could not initialize TLSv1.2 SSL context", MessageType.ERROR, LOGGER, e); ctx = null; } } this.sslContext = ctx; this.address = address; } public static SSLContext getSslContext(String address) { return new GraphicalCertHandler(address).sslContext; } }