Improved X509CertificatePanel with support for displaying multiple certificates.

fix-message-formatting
Markus Kilås 11 years ago
parent e51decb08d
commit 4bea72d481

@ -720,23 +720,23 @@ identity cannot<br> be automatically verified. \
Do you want to continue connecting?<br><br> \
For more information, click "Show Certificate".</html>
service.gui.CONTINUE_ANYWAY=Continue anyway
service.gui.CERT_INFO_ISSUED_TO=<html><b>Issued To</b></html>
service.gui.CERT_INFO_ISSUED_TO=Issued To
service.gui.CERT_INFO_CN=Common Name:
service.gui.CERT_INFO_O=Organization:
service.gui.CERT_INFO_C=Country Name:
service.gui.CERT_INFO_ST=State or Province Name:
service.gui.CERT_INFO_L=Locality Name:
service.gui.CERT_INFO_ISSUED_BY=<html><b>Issued By</b></html>
service.gui.CERT_INFO_ISSUED_BY=Issued By
service.gui.CERT_INFO_OU=Organizational Unit:
service.gui.CERT_INFO_VALIDITY=<html><b>Validity</b></html>
service.gui.CERT_INFO_VALIDITY=Validity
service.gui.CERT_INFO_ISSUED_ON=Issued On:
service.gui.CERT_INFO_EXPIRES_ON=Expires On:
service.gui.CERT_INFO_FINGERPRINTS=<html><b>Fingerprints</b></html>
service.gui.CERT_INFO_CERT_DETAILS=<html><b>Certificate Info</b></html>
service.gui.CERT_INFO_FINGERPRINTS=Fingerprints
service.gui.CERT_INFO_CERT_DETAILS=Certificate Info
service.gui.CERT_INFO_SER_NUM=Serial Number:
service.gui.CERT_INFO_VER=Version:
service.gui.CERT_INFO_SIGN_ALG=Signature Algorithm:
service.gui.CERT_INFO_PUB_KEY_INFO=<html><b>Public Key Info</b></html>
service.gui.CERT_INFO_PUB_KEY_INFO=Public Key Info
service.gui.CERT_INFO_ALG=Algorithm:
service.gui.CERT_INFO_PUB_KEY=Public Key:
service.gui.CERT_INFO_KEY_BYTES_PRINT={0} bytes: {1}

@ -10,13 +10,16 @@
import java.security.*;
import java.security.cert.*;
import java.security.interfaces.*;
import java.text.*;
import java.util.*;
import javax.naming.*;
import javax.naming.ldap.*;
import javax.security.auth.x500.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.tree.*;
import org.jitsi.service.resources.*;
@ -28,6 +31,8 @@ public class X509CertificatePanel
{
private static final long serialVersionUID = -8368302061995971947L;
private final JEditorPane infoTextPane = new JEditorPane();
/**
* Constructs a X509 certificate panel from a single certificate.
* If a chain is available instead use the second constructor.
@ -48,36 +53,100 @@ public X509CertificatePanel(X509Certificate certificate)
*/
public X509CertificatePanel(java.util.List<X509Certificate> certificates)
{
ResourceManagementService R = DesktopUtilActivator.getResources();
DateFormat dateFormatter
= DateFormat.getDateInstance(DateFormat.MEDIUM);
setLayout(new BorderLayout(5, 5));
// Certificate chain list
TransparentPanel topPanel = new TransparentPanel(new BorderLayout());
topPanel.add(new JLabel(
"<html><body><b>Certificate chain:</b></body></html>"),
BorderLayout.NORTH);
DefaultMutableTreeNode top = new DefaultMutableTreeNode();
DefaultMutableTreeNode previous = top;
ListIterator<X509Certificate> it = certificates.listIterator(
certificates.size());
while (it.hasPrevious()) {
X509Certificate cert = it.previous();
DefaultMutableTreeNode next = new DefaultMutableTreeNode(cert);
previous.add(next);
previous = next;
}
JTree tree = new JTree(top);
tree.setBorder(new BevelBorder(BevelBorder.LOWERED));
tree.setRootVisible(false);
tree.setExpandsSelectedPaths(true);
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setCellRenderer(new DefaultTreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree,
Object value, boolean sel, boolean expanded, boolean leaf,
int row, boolean hasFocus) {
JLabel component = (JLabel) super.getTreeCellRendererComponent(
tree, value, sel, expanded, leaf, row, hasFocus);
if (value instanceof DefaultMutableTreeNode) {
Object o = ((DefaultMutableTreeNode) value).getUserObject();
if (o instanceof X509Certificate) {
component.setText(
getSimplifiedName((X509Certificate) o));
}
}
return component;
}
Insets valueInsets = new Insets(2,10,0,0);
Insets titleInsets = new Insets(10,5,0,0);
});
tree.getSelectionModel().addTreeSelectionListener(
new TreeSelectionListener()
{
setLayout(new GridBagLayout());
@Override
public void valueChanged(TreeSelectionEvent e) {
valueChangedPerformed(e);
}
});
tree.setSelectionPath(new TreePath(((
(DefaultTreeModel)tree.getModel()).getPathToRoot(previous))));
topPanel.add(tree, BorderLayout.CENTER);
int currentRow = 0;
add(topPanel, BorderLayout.NORTH);
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.WEST;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.insets = new Insets(2,5,0,0);
constraints.gridx = 0;
constraints.weightx = 0;
constraints.weighty = 0;
constraints.gridy = currentRow++;
// Certificate details pane
Caret caret = infoTextPane.getCaret();
if (caret instanceof DefaultCaret)
{
((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
}
X509Certificate certificate = certificates.get(0);
/*
* Make JEditorPane respect our default font because we will be using it
* to just display text.
*/
infoTextPane.putClientProperty(
JEditorPane.HONOR_DISPLAY_PROPERTIES,
true);
infoTextPane.setOpaque(false);
infoTextPane.setEditable(false);
infoTextPane.setContentType("text/html");
infoTextPane.setText(toString(certificates.get(0)));
final JScrollPane certScroll = new JScrollPane(infoTextPane);
certScroll.setPreferredSize(new Dimension(300, 500));
add(certScroll, BorderLayout.CENTER);
}
private String toString(X509Certificate certificate)
{
final StringBuilder sb = new StringBuilder();
ResourceManagementService R = DesktopUtilActivator.getResources();
X500Principal issuer = certificate.getIssuerX500Principal();
X500Principal subject = certificate.getSubjectX500Principal();
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ISSUED_TO")),
constraints);
sb.append("<html><body><table cellspacing='1' cellpadding='1'>\n");
// subject
constraints.insets = valueInsets;
addTitle(sb, R.getI18NString("service.gui.CERT_INFO_ISSUED_TO"));
try
{
for(Rdn name : new LdapName(subject.getName()).getRdns())
@ -89,47 +158,31 @@ public X509CertificatePanel(java.util.List<X509Certificate> certificates)
if ((lbl == null) || ("!" + lblKey + "!").equals(lbl))
lbl = nameType;
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(lbl), constraints);
final String value;
Object nameValue = name.getValue();
if (nameValue instanceof byte[])
{
byte[] nameValueAsByteArray = (byte[]) nameValue;
lbl
value
= getHex(nameValueAsByteArray) + " ("
+ new String(nameValueAsByteArray) + ")";
}
else
lbl = nameValue.toString();
value = nameValue.toString();
constraints.gridx = 1;
add(new JLabel(lbl), constraints);
addField(sb, lbl, value);
}
}
catch (InvalidNameException ine)
{
constraints.gridy = currentRow++;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_CN")),
constraints);
constraints.gridx = 1;
add(
new JLabel(subject.getName()),
constraints);
addField(sb, R.getI18NString("service.gui.CERT_INFO_CN"),
subject.getName());
}
// issuer
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ISSUED_BY")),
constraints);
constraints.insets = valueInsets;
addTitle(sb, R.getI18NString("service.gui.CERT_INFO_ISSUED_BY"));
try
{
for(Rdn name : new LdapName(issuer.getName()).getRdns())
@ -141,268 +194,135 @@ public X509CertificatePanel(java.util.List<X509Certificate> certificates)
if ((lbl == null) || ("!" + lblKey + "!").equals(lbl))
lbl = nameType;
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.gridx = 0;
add(new JLabel(lbl), constraints);
final String value;
Object nameValue = name.getValue();
if (nameValue instanceof byte[])
{
byte[] nameValueAsByteArray = (byte[]) nameValue;
lbl
value
= getHex(nameValueAsByteArray) + " ("
+ new String(nameValueAsByteArray) + ")";
}
else
lbl = nameValue.toString();
value = nameValue.toString();
constraints.gridx = 1;
add(new JLabel(lbl), constraints);
addField(sb, lbl, value);
}
}
catch (InvalidNameException ine)
{
constraints.gridy = currentRow++;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_CN")),
constraints);
constraints.gridx = 1;
add(
new JLabel(issuer.getName()),
constraints);
addField(sb, R.getI18NString("service.gui.CERT_INFO_CN"),
issuer.getName());
}
// validity
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_VALIDITY")),
constraints);
constraints.insets = valueInsets;
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ISSUED_ON")),
constraints);
constraints.gridx = 1;
add(
new JLabel(dateFormatter.format(certificate.getNotBefore())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_EXPIRES_ON")),
constraints);
constraints.gridx = 1;
add(
new JLabel(dateFormatter.format(certificate.getNotAfter())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_FINGERPRINTS")),
constraints);
constraints.insets = valueInsets;
addTitle(sb, R.getI18NString("service.gui.CERT_INFO_VALIDITY"));
addField(sb, R.getI18NString("service.gui.CERT_INFO_ISSUED_ON"),
certificate.getNotBefore().toString());
addField(sb, R.getI18NString("service.gui.CERT_INFO_EXPIRES_ON"),
certificate.getNotAfter().toString());
addTitle(sb, R.getI18NString("service.gui.CERT_INFO_FINGERPRINTS"));
try
{
String sha1String = getThumbprint(certificate, "SHA1");
String md5String = getThumbprint(certificate, "MD5");
JTextArea sha1Area = new JTextArea(sha1String);
sha1Area.setLineWrap(false);
sha1Area.setOpaque(false);
sha1Area.setWrapStyleWord(true);
sha1Area.setEditable(false);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel("SHA1:"),
constraints);
constraints.gridx = 1;
add(
sha1Area,
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel("MD5:"),
constraints);
JTextArea md5Area = new JTextArea(md5String);
md5Area.setLineWrap(false);
md5Area.setOpaque(false);
md5Area.setWrapStyleWord(true);
md5Area.setEditable(false);
constraints.gridx = 1;
add(
md5Area,
constraints);
addField(sb, "SHA1:", sha1String);
addField(sb, "MD5:", md5String);
}
catch (Exception e)
catch (CertificateException e)
{
// do nothing as we cannot show this value
}
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_CERT_DETAILS")),
constraints);
constraints.insets = valueInsets;
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_SER_NUM")),
constraints);
constraints.gridx = 1;
add(
new JLabel(certificate.getSerialNumber().toString()),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_VER")),
constraints);
constraints.gridx = 1;
add(
new JLabel(String.valueOf(certificate.getVersion())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_SIGN_ALG")),
constraints);
constraints.gridx = 1;
add(
new JLabel(String.valueOf(certificate.getSigAlgName())),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
constraints.insets = titleInsets;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_PUB_KEY_INFO")),
constraints);
constraints.insets = valueInsets;
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_ALG")),
constraints);
constraints.gridx = 1;
add(
new JLabel(certificate.getPublicKey().getAlgorithm()),
constraints);
addTitle(sb, R.getI18NString("service.gui.CERT_INFO_CERT_DETAILS"));
addField(sb, R.getI18NString("service.gui.CERT_INFO_SER_NUM"),
certificate.getSerialNumber().toString());
addField(sb, R.getI18NString("service.gui.CERT_INFO_VER"),
String.valueOf(certificate.getVersion()));
addField(sb, R.getI18NString("service.gui.CERT_INFO_SIGN_ALG"),
String.valueOf(certificate.getSigAlgName()));
addTitle(sb, R.getI18NString("service.gui.CERT_INFO_PUB_KEY_INFO"));
addField(sb, R.getI18NString("service.gui.CERT_INFO_ALG"),
certificate.getPublicKey().getAlgorithm());
if(certificate.getPublicKey().getAlgorithm().equals("RSA"))
{
RSAPublicKey key = (RSAPublicKey)certificate.getPublicKey();
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_PUB_KEY")),
constraints);
JTextArea pubkeyArea = new JTextArea(
addField(sb, R.getI18NString("service.gui.CERT_INFO_PUB_KEY"),
R.getI18NString(
"service.gui.CERT_INFO_KEY_BYTES_PRINT",
new String[]{
String.valueOf(key.getModulus().toByteArray().length-1),
key.getModulus().toString(16)
}));
pubkeyArea.setLineWrap(false);
pubkeyArea.setOpaque(false);
pubkeyArea.setWrapStyleWord(true);
pubkeyArea.setEditable(false);
constraints.gridx = 1;
add(
pubkeyArea,
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_EXP")),
constraints);
constraints.gridx = 1;
add(
new JLabel(key.getPublicExponent().toString()),
constraints);
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_KEY_SIZE")),
constraints);
constraints.gridx = 1;
add(
new JLabel(R.getI18NString(
addField(sb, R.getI18NString("service.gui.CERT_INFO_EXP"),
key.getPublicExponent().toString());
addField(sb, R.getI18NString("service.gui.CERT_INFO_KEY_SIZE"),
R.getI18NString(
"service.gui.CERT_INFO_KEY_BITS_PRINT",
new String[]{
String.valueOf(key.getModulus().bitLength())})),
constraints);
String.valueOf(key.getModulus().bitLength())}));
}
else if(certificate.getPublicKey().getAlgorithm().equals("DSA"))
{
DSAPublicKey key =
(DSAPublicKey)certificate.getPublicKey();
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel("Y:"), constraints);
JTextArea yArea = new JTextArea(key.getY().toString(16));
yArea.setLineWrap(false);
yArea.setOpaque(false);
yArea.setWrapStyleWord(true);
yArea.setEditable(false);
constraints.gridx = 1;
add(
yArea,
constraints);
addField(sb, "Y:", key.getY().toString(16));
}
constraints.gridy = currentRow++;
constraints.gridx = 0;
add(new JLabel(
R.getI18NString("service.gui.CERT_INFO_SIGN")),
constraints);
JTextArea signArea = new JTextArea(
addField(sb, R.getI18NString("service.gui.CERT_INFO_SIGN"),
R.getI18NString(
"service.gui.CERT_INFO_KEY_BYTES_PRINT",
new String[]{
String.valueOf(certificate.getSignature().length),
getHex(certificate.getSignature())
}));
signArea.setLineWrap(false);
signArea.setOpaque(false);
signArea.setWrapStyleWord(true);
signArea.setEditable(false);
constraints.gridx = 1;
add(
signArea,
constraints);
sb.append("</table></body></html>");
return sb.toString();
}
/**
* Add a title.
*
* @param sb StringBuilder to append to
* @param title to print
*/
private void addTitle(StringBuilder sb, String title)
{
sb.append("<tr><td colspan='2'")
.append(" style='margin-top: 5pt; white-space: nowrap'><p><b>")
.append(title).append("</b></p></td></tr>\n");
}
/**
* Add a field.
* @param sb StringBuilder to append to
* @param field name of the certificate field
* @param value to print
*/
private void addField(StringBuilder sb, String field, String value)
{
sb.append("<tr>")
.append("<td style='margin-left: 5pt; margin-right: 25pt;")
.append(" white-space: nowrap'>")
.append(field).append("</td>")
.append("<td>").append(value).append("</td>")
.append("</tr>\n");
}
/**
@ -464,4 +384,62 @@ private static String getThumbprint(X509Certificate cert, String algorithm)
}
return sb.toString();
}
/**
* Construct a "simplified name" based on the subject DN from the
* certificate. The purpose is to have something shorter to display in the
* list. The name used is one of the following DN parts, if
* available, otherwise the complete DN:
* 'CN', 'OU' or else 'O'.
* @param cert to read subject DN from
* @return the simplified name
*/
private static String getSimplifiedName(X509Certificate cert) {
final HashMap<String, String> parts = new HashMap<String, String>();
try
{
for (Rdn name : new LdapName(
cert.getSubjectX500Principal().getName()).getRdns())
{
if (name.getType() != null && name.getValue() != null)
{
parts.put(name.getType(), name.getValue().toString());
}
}
}
catch (InvalidNameException ignored) {} // NOPMD
String result = parts.get("CN");
if (result == null)
{
result = parts.get("OU");
}
if (result == null) {
result = parts.get("O");
}
if (result == null)
{
result = cert.getSubjectX500Principal().getName();
}
return result;
}
/**
* Called when the selection changed in the tree.
* Loads the selected certificate.
* @param e the event
*/
private void valueChangedPerformed(TreeSelectionEvent e)
{
Object o = e.getNewLeadSelectionPath().getLastPathComponent();
if (o instanceof DefaultMutableTreeNode)
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode) o;
if (node.getUserObject() instanceof X509Certificate)
{
infoTextPane.setText(
toString((X509Certificate) node.getUserObject()));
}
}
}
}

Loading…
Cancel
Save