diff options
author | Markus Kilås <markus@markuspage.com> | 2014-04-13 10:36:10 +0200 |
---|---|---|
committer | Markus Kilås <markus@markuspage.com> | 2014-04-13 10:36:10 +0200 |
commit | 8108adbc00c17c595b947ef25b3e6f2f9bb45b03 (patch) | |
tree | 7982138569aa87086d23a0da77c752091c1df64a | |
parent | 183b69c82f558c99e33083fe5b666eba6aa110ad (diff) | |
download | jitsi-8108adbc00c17c595b947ef25b3e6f2f9bb45b03.zip jitsi-8108adbc00c17c595b947ef25b3e6f2f9bb45b03.tar.gz jitsi-8108adbc00c17c595b947ef25b3e6f2f9bb45b03.tar.bz2 |
Logging of TLS protocols and cipher suites available during connection establishment and then the chosen ones.
Add ability to access TLS cipher suite, protocol name and server certificate using an new OperationSet. Only implemented for XMPP so far. Also makes this information available in the call information frame.
6 files changed, 412 insertions, 0 deletions
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index c255cfb..8ae72a7 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -648,6 +648,12 @@ service.gui.callinfo.IS_CONFERENCE_FOCUS=Conference focus service.gui.callinfo.IS_DEFAULT_ENCRYPTED=Encryption enabled service.gui.callinfo.CALL_TRANSPORT=Signalling call transport service.gui.callinfo.CALL_DURATION=Call duration +service.gui.callinfo.TLS_PROTOCOL=TLS protocol +service.gui.callinfo.TLS_CIPHER_SUITE=TLS cipher suite +service.gui.callinfo.TLS_SERVER_CERTIFICATE_CHAIN=TLS server certificate chain +service.gui.callinfo.TLS_CERTIFICATE_CONTENT=The content of the TLS server \ +certificate is displayed below. +service.gui.callinfo.VIEW_CERTIFICATE=View certificate service.gui.callinfo.CODEC=Codec / Frequency service.gui.callinfo.NA=N.A. service.gui.callinfo.VIDEO_SIZE=Video size diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java b/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java index 3094622..b67b336 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java @@ -27,6 +27,8 @@ import org.jitsi.service.resources.*; import org.jitsi.util.*; import com.explodingpixels.macwidgets.*; +import java.security.cert.*; +import javax.swing.event.*; /** * The frame displaying the statistical information for a telephony conference. @@ -70,6 +72,11 @@ public class CallInfoFrame private boolean hasCallInfo; /** + * Dummy URL to indicate that the certificate should be displayed. + */ + private final String CERTIFICATE_URL = "http://viewCertificate"; + + /** * Creates a new frame containing the statistical information for a specific * telephony conference. * @@ -156,6 +163,31 @@ public class CallInfoFrame infoTextPane.setOpaque(false); infoTextPane.setEditable(false); infoTextPane.setContentType("text/html"); + infoTextPane.addHyperlinkListener(new HyperlinkListener() + { + public void hyperlinkUpdate(HyperlinkEvent e) + { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED + && e.getURL() != null + && CERTIFICATE_URL.equals(e.getURL().toString())) + { + List<Call> calls = callConference.getCalls(); + if (!calls.isEmpty()) + { + Call aCall = calls.get(0); + Certificate[] chain = aCall.getProtocolProvider() + .getOperationSet(OperationSetTLS.class) + .getServerCertificates(); + + ViewCertificateFrame certFrame = + new ViewCertificateFrame(chain, null, + resources.getI18NString( + "service.gui.callinfo.TLS_CERTIFICATE_CONTENT")); + certFrame.setVisible(true); + } + } + } + }); return infoTextPane; } @@ -235,6 +267,27 @@ public class CallInfoFrame resources.getI18NString("service.gui.callinfo.CALL_TRANSPORT"), preferredTransport.toString())); + final OperationSetTLS tlsDetails = aCall.getProtocolProvider() + .getOperationSet(OperationSetTLS.class); + if (tlsDetails != null) + { + stringBuffer.append(getLineString( + resources.getI18NString( + "service.gui.callinfo.TLS_PROTOCOL"), + tlsDetails.getProtocol())); + stringBuffer.append(getLineString( + resources.getI18NString( + "service.gui.callinfo.TLS_CIPHER_SUITE"), + tlsDetails.getCipherSuite())); + + stringBuffer.append("<b><a href=\"") + .append(CERTIFICATE_URL) + .append("\">") + .append(resources.getI18NString( + "service.gui.callinfo.VIEW_CERTIFICATE")) + .append("</a></b><br/>"); + } + constructCallPeersInfo(stringBuffer); stringBuffer.append("</font></p></body></html>"); diff --git a/src/net/java/sip/communicator/impl/gui/main/call/ViewCertificateFrame.java b/src/net/java/sip/communicator/impl/gui/main/call/ViewCertificateFrame.java new file mode 100644 index 0000000..529c832 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/ViewCertificateFrame.java @@ -0,0 +1,155 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.security.cert.*; +import javax.swing.*; +import net.java.sip.communicator.plugin.desktoputil.*; +import org.jitsi.service.resources.*; + +/** + * Frame for showing information about a certificate. + */ +public class ViewCertificateFrame extends SIPCommFrame { + + /** + * Serial version UID. + */ + private static final long serialVersionUID = 0L; + + /** + * The resource service. + */ + private final ResourceManagementService R = DesktopUtilActivator.getResources(); + + /** + * The maximum width that we allow message dialogs to have. + */ + private static final int MAX_MSG_PANE_WIDTH = 600; + + /** + * The maximum height that we allow message dialogs to have. + */ + private static final int MAX_MSG_PANE_HEIGHT = 800; + + /** + * The certificate to show. + */ + Certificate cert; + + /** + * A text that describes why the verification failed. + */ + String message; + + /** + * The certificate panel. + */ + TransparentPanel certPanel; + + /** + * This dialog content pane. + */ + TransparentPanel contentPane; + + /** + * Creates the dialog. + * + * @param certs the certificates list + * @param title The title of the dialog; when null the resource + * <tt>service.gui.CERT_DIALOG_TITLE</tt> is loaded. + * @param message A text that describes why the verification failed. + */ + public ViewCertificateFrame(Certificate[] certs, + String title, String message) + { + super(false); + + setTitle(title != null ? title : + R.getI18NString("service.gui.CERT_DIALOG_TITLE")); + + // for now shows only the first certificate from the chain + this.cert = certs[0]; + this.message = message; + + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + + init(); + + setLocationRelativeTo(getParent()); + } + + /** + * Inits the dialog initial display. + */ + private void init() + { + this.getContentPane().setLayout(new BorderLayout()); + + contentPane = + new TransparentPanel(new BorderLayout(5, 5)); + + TransparentPanel northPanel = + new TransparentPanel(new BorderLayout(5, 5)); + northPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5)); + + JLabel imgLabel = new JLabel( + R.getImage("service.gui.icons.CERTIFICATE_WARNING")); + imgLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + northPanel.add(imgLabel, BorderLayout.WEST); + + StyledHTMLEditorPane descriptionPane = new StyledHTMLEditorPane(); + descriptionPane.setOpaque(false); + descriptionPane.setEditable(false); + descriptionPane.setContentType("text/html"); + descriptionPane.setText(message); + descriptionPane.setSize( + new Dimension(MAX_MSG_PANE_WIDTH, MAX_MSG_PANE_HEIGHT)); + int height = descriptionPane.getPreferredSize().height; + descriptionPane.setPreferredSize( + new Dimension(MAX_MSG_PANE_WIDTH, height)); + + northPanel.add(descriptionPane, BorderLayout.CENTER); + contentPane.add(northPanel, BorderLayout.NORTH); + + certPanel = new TransparentPanel(new BorderLayout()); + contentPane.add(certPanel, BorderLayout.CENTER); + + this.getContentPane().add(contentPane, BorderLayout.CENTER); + + Component certInfoPane; + if(cert instanceof X509Certificate) + { + certInfoPane = new X509CertificatePanel((X509Certificate)cert); + } + else + { + JTextArea textArea = new JTextArea(); + textArea.setOpaque(false); + textArea.setEditable(false); + textArea.setText(cert.toString()); + certInfoPane = textArea; + } + + final JScrollPane certScroll = new JScrollPane(certInfoPane); + certScroll.setPreferredSize(new Dimension(300, 600)); + certPanel.add(certScroll, BorderLayout.CENTER); + + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + certScroll.getVerticalScrollBar().setValue(0); + } + }); + setPreferredSize(null); + + pack(); + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTLSJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTLSJabberImpl.java new file mode 100644 index 0000000..0b1e3be --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTLSJabberImpl.java @@ -0,0 +1,75 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.protocol.jabber; + +import java.security.cert.*; +import javax.net.ssl.*; + +import net.java.sip.communicator.service.protocol.*; + +/** + * An implementation of the OperationSetTLS for the Jabber protocol. + * + * @author Markus Kilås + */ +public class OperationSetTLSJabberImpl + implements OperationSetTLS +{ + private final ProtocolProviderServiceJabberImpl jabberService; + + public OperationSetTLSJabberImpl( + ProtocolProviderServiceJabberImpl jabberService) + { + this.jabberService = jabberService; + } + + public String getCipherSuite() { + final String result; + final SSLSocket socket = jabberService.getSSLSocket(); + if (socket == null) + { + result = null; + } + else + { + result = socket.getSession().getCipherSuite(); + } + return result; + } + + public String getProtocol() { + final String result; + final SSLSocket socket = jabberService.getSSLSocket(); + if (socket == null) + { + result = null; + } + else + { + result = socket.getSession().getProtocol(); + } + return result; + } + + public Certificate[] getServerCertificates() { + Certificate[] result = null; + final SSLSocket socket = jabberService.getSSLSocket(); + if (socket != null) + { + try + { + result = socket.getSession().getPeerCertificates(); + } + catch (SSLPeerUnverifiedException ignored) // NOPMD + { + // result will be null + } + } + return result; + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index 4e465c9..f9ca61a 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -1154,6 +1154,32 @@ public class ProtocolProviderServiceJabberImpl {
SSLContext sslContext = loginStrategy.createSslContext(cvs,
getTrustManager(cvs, serviceName));
+
+ // log SSL/TLS algorithms and protocols
+ if (logger.isDebugEnabled())
+ {
+ final StringBuilder buff = new StringBuilder();
+ buff.append("Available TLS protocols and algorithms:\n");
+ buff.append("Default protocols: ");
+ buff.append(Arrays.toString(
+ sslContext.getDefaultSSLParameters().getProtocols()));
+ buff.append("\n");
+ buff.append("Supported protocols: ");
+ buff.append(Arrays.toString(
+ sslContext.getSupportedSSLParameters().getProtocols()));
+ buff.append("\n");
+ buff.append("Default cipher suites: ");
+ buff.append(Arrays.toString(
+ sslContext.getDefaultSSLParameters()
+ .getCipherSuites()));
+ buff.append("\n");
+ buff.append("Supported cipher suites: ");
+ buff.append(Arrays.toString(
+ sslContext.getSupportedSSLParameters()
+ .getCipherSuites()));
+ logger.debug(buff.toString());
+ }
+
connection.setCustomSslContext(sslContext);
}
else if (tlsRequired)
@@ -1220,6 +1246,35 @@ public class ProtocolProviderServiceJabberImpl }
else
{
+ if (connection.getSocket() instanceof SSLSocket)
+ {
+ final SSLSocket sslSocket = (SSLSocket) connection.getSocket();
+ StringBuilder buff = new StringBuilder();
+ buff.append("Chosen TLS protocol and algorithm:\n")
+ .append("Protocol: ").append(sslSocket.getSession()
+ .getProtocol()).append("\n")
+ .append("Cipher suite: ").append(sslSocket.getSession()
+ .getCipherSuite());
+ logger.info(buff.toString());
+
+ if (logger.isDebugEnabled())
+ {
+ buff = new StringBuilder();
+ buff.append("Server TLS certificate chain:\n");
+ try
+ {
+ buff.append(Arrays.toString(
+ sslSocket.getSession().getPeerCertificates()));
+ }
+ catch (SSLPeerUnverifiedException ex)
+ {
+ buff.append("<unavailable: ")
+ .append(ex.getLocalizedMessage()).append(">");
+ }
+ logger.debug(buff.toString());
+ }
+ }
+
connection.addConnectionListener(connectionListener);
}
@@ -1859,6 +1914,11 @@ public class ProtocolProviderServiceJabberImpl new OperationSetUserSearchJabberImpl(this));
}
+ OperationSetTLS opsetTLS
+ = new OperationSetTLSJabberImpl(this);
+ addSupportedOperationSet(OperationSetTLS.class,
+ opsetTLS);
+
isInitialized = true;
}
}
@@ -2867,4 +2927,24 @@ public class ProtocolProviderServiceJabberImpl logger.error("Error loading classes in smack", e);
}
}
+
+ /**
+ * Return the SSL socket (if TLS used).
+ * @return The SSL socket or null if not used
+ */
+ public SSLSocket getSSLSocket()
+ {
+ final SSLSocket result;
+ final Socket socket = connection.getSocket();
+ if (socket instanceof SSLSocket)
+ {
+ result = (SSLSocket) socket;
+ }
+ else
+ {
+ result = null;
+ }
+ return result;
+ }
+
}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetTLS.java b/src/net/java/sip/communicator/service/protocol/OperationSetTLS.java new file mode 100644 index 0000000..2a3e796 --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/OperationSetTLS.java @@ -0,0 +1,43 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.protocol; + +import java.security.cert.*; + +/** + * An <tt>OperationSet</tt> that allows access to information about TLS used by + * the protocol provider. + * + * @author Markus Kilås + */ +public interface OperationSetTLS + extends OperationSet +{ + /** + * Returns the negotiated cipher suite + * + * @return The cipher suite name used for instance + * "TLS_RSA_WITH_AES_256_CBC_SHA" or null if TLS is not used. + */ + String getCipherSuite(); + + /** + * Returns the negotiated SSL/TLS protocol. + * + * @return The protocol name used for instance "TLSv1". + */ + String getProtocol(); + + /** + * Returns the TLS server certificate chain with the end entity certificate + * in the first position and the issuers following (if any returned by the + * server). + * + * @return The TLS server certificate chain. + */ + Certificate[] getServerCertificates(); +} |