package org.eparapher.rcp.dialog;
import java.io.IOException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.NetscapeCertType;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormText;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import org.eparapher.core.crypto.cert.CertificateInfo;
import org.eparapher.core.crypto.cert.CertificateManager;
import org.eparapher.core.crypto.cert.X509Util;
import org.eparapher.core.tools.HexCodec;
import org.eparapher.rcp.tools.GUIIcons;
/** This is a Dialog that parse and display X.509 certificate fields, extentions and properties
*
Based On :
*
* - http://www.eclipse.org/articles/Article-Forms/article.html
* - http://www.eclipse.org/articles/article.php?file=Article-Forms33/index.html
*
*
* @author Arnault MICHEL
*
*/
public class CertificateViewerDialog extends Dialog implements Listener {
private static Logger log = Logger.getLogger(CertificateViewerDialog.class);
private X509Certificate[] certchain;
private String title;
private TabFolder tabFolder = null;
private FormToolkit tab1toolkit;
private Form tab1form;
private FormToolkit tab2toolkit;
private Form tab2form;
private Tree trustchain;
private Table X509FieldsList;
private Text X509FieldValue;
private Section X509FieldValueSection;
public CertificateViewerDialog(X509Certificate[] mcertchain) {
super(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
this.setShellStyle(SWT.DIALOG_TRIM | getDefaultOrientation());
List tmp = null;
try {
tmp = CertificateManager.establishCertChain( mcertchain[0], true);
} catch (Exception e) {
if (log.isDebugEnabled())
log.warn("Building certificate chain failed (subject DN:" + mcertchain[0].getSubjectDN().getName() + ")",e);
else
log.warn("Building certificate chain failed (subject DN:" + mcertchain[0].getSubjectDN().getName() + ")");
}
if (tmp!=null)
this.certchain = tmp.toArray(new X509Certificate[]{});
else this.certchain = mcertchain;
title = CertificateInfo.getSubjectAsShortText( certchain[0] );
}
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
container.setLayout(new FillLayout());
tabFolder = new TabFolder(container,SWT.NONE);
tabFolder.setLayout(new FillLayout());
// Create each tab and set its text, tool tip text, image, and control
TabItem one = new TabItem(tabFolder, SWT.NONE);
one.setText("General");
//one.setToolTipText("Certificate is valid and trusted");
//one.setImage();
one.setControl(getTabOneControl(tabFolder));
TabItem two = new TabItem(tabFolder, SWT.NONE);
two.setText("Details");
two.setToolTipText("Detailed certificate information");
//two.setImage(square);
two.setControl(getTabTwoControl(tabFolder));
// Select the third tab (index is zero-based)
tabFolder.setSelection(0);
return container;
}
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
}
protected Point getInitialSize() {
return new Point(450, 600);
}
/**
* Gets the control for tab one
*
* @param tabFolder the parent tab folder
* @return Control
*/
private Control getTabOneControl(TabFolder tabFolder) {
// Create a composite and add four buttons to it
Composite composite = new Composite(tabFolder, SWT.NONE);
composite.setLayout(new FillLayout());
//title
tab1toolkit = new FormToolkit(composite.getDisplay());
tab1form = tab1toolkit.createForm(composite);
tab1form.getBody().setLayout(new GridLayout());
tab1form.setText("Certificate informations");
tab1toolkit.decorateFormHeading(tab1form);
//tab1form.setImage(GUIIcons.DLG_ICON_VALID_CERT);
//to, from, valid from to
showToFromValidity();
//Certificate Roles
showX509RolesSection();
//Certificate Chain
showX509Chain();
return composite;
}
private void showX509Chain() {
Section section = tab1toolkit.createSection(tab1form.getBody(), Section.TITLE_BAR| Section.TWISTIE|Section.EXPANDED);
section.setLayoutData(new GridData(GridData.FILL_BOTH));
section.addExpansionListener(new ExpAdaptor());
section.setText("Trust Path");
Composite sectionClient = tab1toolkit.createComposite(section);
sectionClient.setLayout(new FillLayout());
sectionClient.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
trustchain = tab1toolkit.createTree(sectionClient, SWT.NONE);
//trustchain.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// Build tree items
TreeItem lastItem = null;
for (int i = 0; i < certchain.length ; i++) {
TreeItem item;
if (i == 0)
item = new TreeItem(trustchain,SWT.NONE);
else {
item = new TreeItem(lastItem,SWT.NONE);
lastItem.setExpanded(true);
}
item.setImage(GUIIcons.CERTIFICATE_ICON_IMAGE);
item.setText(CertificateInfo.getSubjectAsShortText( certchain[i] ));
item.setData(new Integer(i));
lastItem = item;
}
trustchain.addSelectionListener(new TCListner());
section.setClient(sectionClient);
}
private void showX509RolesSection() {
Section section = tab1toolkit.createSection(tab1form.getBody(), Section.TITLE_BAR| Section.TWISTIE|Section.EXPANDED);
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
section.addExpansionListener(new ExpAdaptor());
section.setText("Certificate roles");
Composite sectionClient = tab1toolkit.createComposite(section);
sectionClient.setLayout(new TableWrapLayout());
String eku = CertificateInfo.getExtendedKeyUsageAsText( certchain[0] );
String eu = CertificateInfo.getKeyUsageAsText( certchain[0] );
String text = "";
FormText formText = tab1toolkit.createFormText(sectionClient, true);
formText.setText(text, true, false);
formText.setLayoutData(new TableWrapData(TableWrapData.FILL));
section.setClient(sectionClient);
}
private void showToFromValidity() {
Section section = tab1toolkit.createSection(tab1form.getBody(), Section.TITLE_BAR| Section.TWISTIE|Section.EXPANDED);
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
section.addExpansionListener(new ExpAdaptor());
section.setText("General");
Composite sectionClient = tab1toolkit.createComposite(section);
sectionClient.setLayout(new TableWrapLayout());
String text = "";
FormText formText = tab1toolkit.createFormText(sectionClient, true);
formText.setText(text, true, false);
formText.setLayoutData(new TableWrapData(TableWrapData.FILL));
section.setClient(sectionClient);
}
/**
* Gets the control for tab two
*
* @param tabFolder the parent tab folder
* @return Control
*/
private Control getTabTwoControl(TabFolder tabFolder) {
// Create a composite and add four buttons to it
Composite composite = new Composite(tabFolder, SWT.NONE);
composite.setLayout(new FillLayout());
tab2toolkit = new FormToolkit(composite.getDisplay());
tab2form = tab1toolkit.createForm(composite);
tab2form.setText("Details");
tab2toolkit.decorateFormHeading(tab2form);
GridLayout layout = new GridLayout();
tab2form.getBody().setLayout(layout);
//Table of certificate fields
showX509Fields();
//Fields details
showX509SelectedFieldValue();
return composite;
}
private void showX509Fields() {
Section section = tab2toolkit.createSection(tab2form.getBody(), Section.DESCRIPTION|Section.TITLE_BAR| Section.TWISTIE|Section.EXPANDED);
section.setText("X509 Fields");
section.setDescription("List of all certificate fields :");
section.addExpansionListener(new ExpAdaptor());
section.setLayoutData(new GridData(GridData.FILL_BOTH));
Composite sectionClient = tab2toolkit.createComposite(section);
GridLayout gl = new GridLayout(1,true);
gl.marginLeft = 0;
gl.marginRight= 0;
sectionClient.setLayout(gl);
sectionClient.setLayoutData(new GridData(GridData.FILL_BOTH));
X509FieldsList = tab2toolkit.createTable(sectionClient, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION |SWT.READ_ONLY);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 10;
gd.widthHint = 100;
X509FieldsList.setLayoutData(gd);
X509FieldsList.setLayout(new FillLayout());
X509FieldsList.setHeaderVisible(true);
X509FieldsList.setLinesVisible(true);
tab2toolkit.paintBordersFor(sectionClient);
//Reduce Font size
if (X509FieldsList.getFont()!=null && X509FieldsList.getFont().getFontData()[0].getName() != null) {
Font smallFont = new Font(X509FieldsList.getFont().getDevice(),X509FieldsList.getFont().getFontData()[0].getName(),8,SWT.NORMAL);
X509FieldsList.setFont(smallFont);
}
//x509FieldsTable.set
TableColumn column1 = new TableColumn(X509FieldsList, SWT.CENTER, 0);
column1.setText("Value");
column1.setWidth(260);
column1.setResizable(true);
TableColumn column2 = new TableColumn(X509FieldsList, SWT.CENTER, 0);
column2.setText("Name");
column2.setWidth(120);
column2.setResizable(true);
populateTable(X509FieldsList);
X509FieldsList.addListener(SWT.Selection, this );
section.setClient(sectionClient);
}
private void showX509SelectedFieldValue() {
X509FieldValueSection = tab2toolkit.createSection(tab2form.getBody(), Section.DESCRIPTION|Section.TITLE_BAR| Section.TWISTIE|Section.EXPANDED);
X509FieldValueSection.setText("Field Value");
X509FieldValueSection.setDescription("Value of selected field :");
X509FieldValueSection.addExpansionListener(new ExpAdaptor());
X509FieldValueSection.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout gl = new GridLayout(1,true);
gl.marginLeft = 0;
gl.marginRight = 0;
X509FieldValueSection.setLayout(gl);
Composite sectionClient = tab2toolkit.createComposite(X509FieldValueSection);
sectionClient.setLayout(gl);
sectionClient.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
tab2toolkit.paintBordersFor(sectionClient);
X509FieldValue = tab2toolkit.createText(sectionClient, "", SWT.BORDER|SWT.READ_ONLY|SWT.WRAP|SWT.H_SCROLL);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.heightHint = 70;
X509FieldValue.setLayoutData(gd);
/*X509FieldValue = tab2toolkit.createFormText(sectionClient, true);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.heightHint = 50;
X509FieldValue.setLayoutData(gd);*/
X509FieldValueSection.setClient(sectionClient);
}
public void populateTable(Table table) {
CertificateInfo ci = new CertificateInfo( certchain[0] );
//X509 v1 fields
TableItem version = new TableItem(table,SWT.LEFT);
version.setText(new String[] {"Version", ""+certchain[0].getVersion()});
TableItem serial = new TableItem(table,SWT.LEFT);
serial.setText(new String[] {"Serial number", ""+certchain[0].getSerialNumber().toString(16)});
TableItem sigalg = new TableItem(table,SWT.LEFT);
sigalg.setText(new String[] {"Signature algorithm", certchain[0].getSigAlgName()});
TableItem subject = new TableItem(table,SWT.LEFT);
subject.setText(new String[] {"Subject", certchain[0].getSubjectDN().toString()});
TableItem issuer = new TableItem(table,SWT.LEFT);
issuer.setText(new String[] {"Issuer", certchain[0].getIssuerDN().toString() });
TableItem validfrom = new TableItem(table,SWT.LEFT);
validfrom.setText(new String[] {"Valid from", CertificateInfo.getNotBeforeAsFullText( certchain[0] ) });
TableItem validuntil = new TableItem(table,SWT.LEFT);
validuntil.setText(new String[] {"Valid Until", CertificateInfo.getNotAfterAsFullText( certchain[0] ) });
TableItem pubkey = new TableItem(table,SWT.LEFT);
pubkey.setText(new String[] {"Public key", CertificateInfo.getPublicKeyInfo( certchain[0].getPublicKey() ) });
pubkey.setData(certchain[0].getPublicKey().toString());
//X509 v3 extentions
//Processing Critical Extentions
Set criticalextentions = certchain[0].getCriticalExtensionOIDs();
if (criticalextentions!=null)
for (String oid : criticalextentions) {
insertX509ExtAsTableItem(oid,ci,table,true);
}
//Processing Non Critical Extentions
Set noncriticalextentions = certchain[0].getNonCriticalExtensionOIDs();
if (noncriticalextentions!=null)
for (String oid : noncriticalextentions) {
insertX509ExtAsTableItem(oid,ci,table,false);
}
}
private void insertX509ExtAsTableItem(String oid, CertificateInfo ci, Table table, boolean b) {
//TODO : Manage critical extentions
TableItem certext = new TableItem(table,SWT.LEFT);
if (b) {
certext.setImage(GUIIcons.WARN_ICON_IMAGE);
}
if (oid.equals(X509Extensions.KeyUsage.getId())) {
String value = CertificateInfo.getKeyUsageAsText( certchain[0] );
certext.setText(new String[] { "key usage", value });
}
else if (oid.equals(X509Extensions.ExtendedKeyUsage.getId())) {
certext.setText(new String[] {"Extended key usage", CertificateInfo.getExtendedKeyUsageAsText( certchain[0] ) });
try {
certext.setData(certchain[0].getExtendedKeyUsage());
} catch (CertificateParsingException e) {
log.error("Error while reading X.509 Extended key usage.",e);
}
}
else if (oid.equals(X509Extensions.CRLDistributionPoints.getId())) {
try {
if ( X509Util.getCrlDistributionPoint( certchain[0] ).length != 0 ) {
certext.setText(new String[] {"CRL Distribution Point", ci.getCDPAsText() });
certext.setData( ci.getCDPAsText() );
}
} catch (CertificateParsingException e) {
log.warn("Error while parsing CDP from certificate : " + certchain[0].getSubjectDN());
}
}
else if (oid.equals(X509Extensions.SubjectAlternativeName.getId())) {
certext.setText(new String[] {"Subject alternative names", ci.getSubjectAltName() });
}
else if (oid.equals(X509Extensions.SubjectKeyIdentifier.getId())) {
byte[] ski = certchain[0].getExtensionValue(oid);
certext.setText(new String[] {"Subject key identifier", HexCodec.printHexString(ski) });
}
else if (oid.equals(X509Extensions.AuthorityKeyIdentifier.getId())) {
byte[] aki = certchain[0].getExtensionValue(oid);
certext.setText(new String[] {"Authority key identifier", HexCodec.printHexString(aki) });
}
else if (oid.equals(X509Extensions.PrivateKeyUsagePeriod.getId())) {
//byte[] aki = certchain[0].getExtensionValue(oid);
DERObject obj;
try {
obj = X509Util.getExtensionValue(certchain[0], oid);
certext.setText(new String[] {"Private Key Usage Period", obj.toString() });
} catch (IOException e) {
log.warn("Error while parsing Private Key Usage Period extention from certificate : " + certchain[0].getSubjectDN());
}
}
else if (oid.equals(MiscObjectIdentifiers.netscapeCertType.getId())) {
byte[] nct = certchain[0].getExtensionValue(oid);
NetscapeCertType nst = new NetscapeCertType(nct[5]);
certext.setText(new String[] {"Netscape certificate type", nst.toString() });
}
else if (oid.equals(MiscObjectIdentifiers.entrustVersionExtension.getId())) {
//byte[] ev = certchain[0].getExtensionValue(oid);
DERObject obj;
try {
obj = X509Util.getExtensionValue(certchain[0], oid);
certext.setText(new String[] {"Entrust version info", obj.toString() });
} catch (IOException e) {
log.warn("Error while parsing Entrust version info extention from certificate : " + certchain[0].getSubjectDN());
}
}
else if (oid.equals(X509Extensions.BasicConstraints.getId())) {
int pathlength = certchain[0].getBasicConstraints();
if (pathlength == -1 )
certext.setText(new String[] {"Basic constraints", "This is not a CA Certificate" });
else
certext.setText(new String[] {"Basic constraints", "This certificate is a CA\nAllowed length of the certification path : " + ((pathlength==2147483647)?"unlimited":""+pathlength) });
}
else {
try {
DERObject obj = X509Util.getExtensionValue(certchain[0], oid);
//TODO : try OID online resolver
certext.setText(new String[] {oid, obj.toString() });
} catch (IOException e) {
log.warn("Error while parsing "+oid+" extention from certificate : " + certchain[0].getSubjectDN());
}
}
}
/**
* Disposes the toolkit
*/
public void dispose() {
tab1toolkit.dispose();
tab2toolkit.dispose();
}
/**
* Setting title
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
if (title != null) {
shell.setText(title);
}
shell.setImage(GUIIcons.CERTIFICATE_ICON_IMAGE);
}
/**
*
* @author arnault
*
*/
//TODO : method reflaw from eclipse site not found,
class ExpAdaptor extends ExpansionAdapter {
public void expansionStateChanged(ExpansionEvent e) {
if (tabFolder != null) {
if (tabFolder.getSelectionIndex()==0) {
tabFolder.setSelection(1);
tabFolder.setSelection(0);
}
if (tabFolder.getSelectionIndex()==1) {
tabFolder.setSelection(0);
tabFolder.setSelection(1);
}
}
}
}
class TCListner implements SelectionListener {
public void widgetSelected(SelectionEvent e) { }
public void widgetDefaultSelected(SelectionEvent e) {
int selCertindex = ((Integer) e.item.getData()).intValue();
if (selCertindex!=0) {
X509Certificate[] newcertchaintoview = new X509Certificate[certchain.length-selCertindex];
for (int i = selCertindex; i