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.
fix-message-formatting
Markus Kilås 12 years ago
parent 183b69c82f
commit 8108adbc00

@ -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

@ -27,6 +27,8 @@
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.
@ -69,6 +71,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 @@ private JEditorPane createGeneralInfoPane()
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 @@ private boolean constructCallInfo()
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>");

@ -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();
}
}

@ -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;
}
}

@ -1154,6 +1154,32 @@ private ConnectState connectAndLogin(
{
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 @@ else if (tlsRequired)
}
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 @@ protected void initialize(String screenname,
new OperationSetUserSearchJabberImpl(this));
}
OperationSetTLS opsetTLS
= new OperationSetTLSJabberImpl(this);
addSupportedOperationSet(OperationSetTLS.class,
opsetTLS);
isInitialized = true;
}
}
@ -2867,4 +2927,24 @@ private static void loadJabberServiceClasses()
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;
}
}

@ -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();
}
Loading…
Cancel
Save