diff --git a/src/java/davmail/http/DavGatewayX509TrustManager.java b/src/java/davmail/http/DavGatewayX509TrustManager.java index 1bd38df8..fa301054 100644 --- a/src/java/davmail/http/DavGatewayX509TrustManager.java +++ b/src/java/davmail/http/DavGatewayX509TrustManager.java @@ -8,13 +8,14 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import java.awt.*; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; +import java.security.*; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.InputStreamReader; /** * Custom Trust Manager, let user accept or deny. @@ -56,31 +57,90 @@ public class DavGatewayX509TrustManager implements X509TrustManager { } protected void userCheckServerTrusted(final X509Certificate[] x509Certificates) throws CertificateException { - try { - String acceptedCertificateHash = Settings.getProperty("davmail.server.certificate.hash"); - String certificateHash = getFormattedHash(x509Certificates[0]); - // if user already accepted a certificate, - if (acceptedCertificateHash != null && acceptedCertificateHash.length() > 0 - && acceptedCertificateHash.equals(certificateHash)) { - DavGatewayTray.debug("Found permanently accepted certificate, hash " + acceptedCertificateHash); + String acceptedCertificateHash = Settings.getProperty("davmail.server.certificate.hash"); + String certificateHash = getFormattedHash(x509Certificates[0]); + // if user already accepted a certificate, + if (acceptedCertificateHash != null && acceptedCertificateHash.length() > 0 + && acceptedCertificateHash.equals(certificateHash)) { + DavGatewayTray.debug("Found permanently accepted certificate, hash " + acceptedCertificateHash); + } else { + boolean isCertificateTrusted; + if (Settings.getBooleanProperty("davmail.server")) { + // headless mode + isCertificateTrusted = isCertificateTrusted(x509Certificates[0]); } else { - - if (!AcceptCertificateDialog.isCertificateTrusted(x509Certificates[0])) { - throw new CertificateException("User rejected certificate"); - } - // certificate accepted, store in settings - Settings.saveProperty("davmail.server.certificate.hash", certificateHash); + isCertificateTrusted = AcceptCertificateDialog.isCertificateTrusted(x509Certificates[0]); } - } catch (NoSuchAlgorithmException nsa) { - throw new CertificateException(nsa); + if (!isCertificateTrusted) { + throw new CertificateException("User rejected certificate"); + } + // certificate accepted, store in settings + Settings.saveProperty("davmail.server.certificate.hash", certificateHash); } } - public static String getFormattedHash(X509Certificate certificate) throws NoSuchAlgorithmException, CertificateEncodingException { + protected boolean isCertificateTrusted(X509Certificate certificate) { + BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in)); + String answer = null; + while (!"y".equals(answer) && !"Y".equals(answer) && !"n".equals(answer) && !"N".equals(answer) ) { + System.out.println("Server Certificate:"); + System.out.println("Issued to: " + DavGatewayX509TrustManager.getRDN(certificate.getSubjectDN())); + System.out.println("Issued by: " + getRDN(certificate.getIssuerDN())); + SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); + String notBefore = formatter.format(certificate.getNotBefore()); + System.out.println("Valid from: " + notBefore); + String notAfter = formatter.format(certificate.getNotAfter()); + System.out.println("Valid until: " + notAfter); + System.out.println("Serial: " + getFormattedSerial(certificate)); + String sha1Hash = DavGatewayX509TrustManager.getFormattedHash(certificate); + System.out.println("FingerPrint: " + sha1Hash); + System.out.println(); + System.out.println("Server provided an untrusted certificate,"); + System.out.println("you can choose to accept or deny access."); + System.out.println("Accept certificate (y/n)?"); + try { + answer = inReader.readLine(); + } catch (IOException e) { + System.err.println(e); + } + } + return "y".equals(answer) || "Y".equals(answer); + } + + public static String getRDN(Principal principal) { + String dn = principal.getName(); + int start = dn.indexOf('='); + int end = dn.indexOf(','); + if (start >= 0 && end >= 0) { + return dn.substring(start + 1, end); + } else { + return dn; + } + } + + public static String getFormattedSerial(X509Certificate certificate) { + StringBuilder builder = new StringBuilder(); + String serial = certificate.getSerialNumber().toString(16); + for (int i = 0; i < serial.length(); i++) { + if (i > 0 && i % 2 == 0) { + builder.append(' '); + } + builder.append(serial.charAt(i)); + } + return builder.toString().toUpperCase(); + } + + public static String getFormattedHash(X509Certificate certificate) { String sha1Hash; - MessageDigest md = MessageDigest.getInstance("SHA1"); - byte[] digest = md.digest(certificate.getEncoded()); - sha1Hash = formatHash(digest); + try { + MessageDigest md = MessageDigest.getInstance("SHA1"); + byte[] digest = md.digest(certificate.getEncoded()); + sha1Hash = formatHash(digest); + } catch (NoSuchAlgorithmException nsa) { + sha1Hash = nsa.getMessage(); + } catch (CertificateEncodingException cee) { + sha1Hash = cee.getMessage(); + } return sha1Hash; } diff --git a/src/java/davmail/ui/AcceptCertificateDialog.java b/src/java/davmail/ui/AcceptCertificateDialog.java index 8517ca85..813ca42a 100644 --- a/src/java/davmail/ui/AcceptCertificateDialog.java +++ b/src/java/davmail/ui/AcceptCertificateDialog.java @@ -36,39 +36,9 @@ public class AcceptCertificateDialog extends JDialog { panel.add(fieldPanel); } - protected String getRDN(Principal principal) { - String dn = principal.getName(); - int start = dn.indexOf('='); - int end = dn.indexOf(','); - if (start >= 0 && end >= 0) { - return dn.substring(start + 1, end); - } else { - return dn; - } - } - - public String getFormattedSerial(X509Certificate certificate) { - StringBuilder builder = new StringBuilder(); - String serial = certificate.getSerialNumber().toString(16); - for (int i = 0; i < serial.length(); i++) { - if (i > 0 && i % 2 == 0) { - builder.append(' '); - } - builder.append(serial.charAt(i)); - } - return builder.toString().toUpperCase(); - } - public AcceptCertificateDialog(X509Certificate certificate) { setAlwaysOnTop(true); - String sha1Hash; - try { - sha1Hash = DavGatewayX509TrustManager.getFormattedHash(certificate); - } catch (NoSuchAlgorithmException nsa) { - sha1Hash = nsa.getMessage(); - } catch (CertificateEncodingException cee) { - sha1Hash = cee.getMessage(); - } + String sha1Hash = DavGatewayX509TrustManager.getFormattedHash(certificate); SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); setTitle("DavMail: Accept certificate ?"); @@ -81,8 +51,8 @@ public class AcceptCertificateDialog extends JDialog { JPanel subjectPanel = new JPanel(); subjectPanel.setLayout(new BoxLayout(subjectPanel, BoxLayout.Y_AXIS)); subjectPanel.setBorder(BorderFactory.createTitledBorder("Server Certificate")); - addFieldValue(subjectPanel, "Issued to", getRDN(certificate.getSubjectDN())); - addFieldValue(subjectPanel, "Issued by", getRDN(certificate.getIssuerDN())); + addFieldValue(subjectPanel, "Issued to", DavGatewayX509TrustManager.getRDN(certificate.getSubjectDN())); + addFieldValue(subjectPanel, "Issued by", DavGatewayX509TrustManager.getRDN(certificate.getIssuerDN())); Date now = new Date(); String notBefore = formatter.format(certificate.getNotBefore()); if (now.before(certificate.getNotBefore())) { @@ -94,7 +64,7 @@ public class AcceptCertificateDialog extends JDialog { notAfter = ""+notAfter+""; } addFieldValue(subjectPanel, "Valid until", notAfter); - addFieldValue(subjectPanel, "Serial", getFormattedSerial(certificate)); + addFieldValue(subjectPanel, "Serial", DavGatewayX509TrustManager.getFormattedSerial(certificate)); addFieldValue(subjectPanel, "FingerPrint", sha1Hash); JPanel warningPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));