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.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.openslx.dozmod.authentication.FingerprintManager; import org.openslx.dozmod.gui.Gui.GuiCallable; import org.openslx.dozmod.gui.helper.I18n; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.util.ProxyConfigurator; public class GraphicalCertHandler { private static final Logger LOGGER = LogManager.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 { try { if (certs == null || certs.length == 0) { Boolean ret = Gui.syncExec(new GuiCallable() { @Override public Boolean run() { return Gui.showMessageBox(null, I18n.GUI.getString("GraphicalCertHandler.Message.warning.noCertificate"), 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 = I18n.GUI.getString("GraphicalCertHandler.Message.yesNo.fingerprintChanged", address, new BigInteger(expectedFingerprint).toString(16), actualFingerprintReadable); } // 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"); } } catch (Throwable t) { LOGGER.warn("Exception when checking cert of satellite", t); throw t; } } @Override public X509Certificate[] getAcceptedIssuers() { return null; } } private final String address; private final SSLContext sslContext; private GraphicalCertHandler(String address) { SSLContext ctx = null; try { ctx = ProxyConfigurator.getThriftSslContext(); // Make copy ctx = SSLContext.getInstance(ctx.getProtocol(), ctx.getProvider()); } catch (NoSuchAlgorithmException e) { Gui.asyncMessageBox(I18n.GUI.getString("GraphicalCertHandler.Message.error.couldNotGetSSLContext"), MessageType.ERROR, LOGGER, e); } if (ctx != null) { try { ctx.init(null, new TrustManager[] { new GuiTrustManager() }, null); } catch (KeyManagementException e) { Gui.asyncMessageBox( I18n.GUI.getString("GraphicalCertHandler.Message.error.couldNotInitializeSSLContext"), MessageType.ERROR, LOGGER, e); ctx = null; } } this.sslContext = ctx; this.address = address; } public static SSLContext getSslContext(String address) { return new GraphicalCertHandler(address).sslContext; } }