package eu.geclipse.ui.widgets;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Hashtable;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
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.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
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 eu.geclipse.core.security.X509Util;
public class CertificateInfoPanel extends Composite {
protected Text valueText;
private X509Certificate[] certificateChain;
private ScrolledComposite overviewComp;
private Composite overviewPanel;
private Table chainTable;
private Tree detailsTree;
private Label validText;
private Label notBeforeText;
private Label notAfterText;
private Label sNoText;
private Hashtable< String, Label > subjectLabels
= new Hashtable< String, Label >();
private Hashtable< String, Label > issuerLabels
= new Hashtable< String, Label>();
public CertificateInfoPanel( final Composite parent, final int style ) {
super( parent, style );
setLayout( new GridLayout( 1, false ) );
TabFolder tabFolder = new TabFolder( this, SWT.NONE );
GridData gData = new GridData( GridData.FILL, GridData.FILL, true, true );
gData.widthHint = 300;
gData.heightHint = 400;
tabFolder.setLayoutData( gData );
TabItem overviewItem = new TabItem( tabFolder, SWT.NONE );
overviewItem.setText( "Overview" );
this.overviewComp = new ScrolledComposite( tabFolder, SWT.V_SCROLL );
this.overviewComp.setLayoutData( new GridData( GridData.FILL, GridData.FILL, true, true ) );
this.overviewComp.setExpandHorizontal( true );
this.overviewComp.setExpandVertical( true );
overviewItem.setControl( overviewComp );
this.overviewPanel = new Composite( this.overviewComp, SWT.NONE );
this.overviewPanel.setLayout( new GridLayout( 1, false ) );
this.overviewComp.setContent( this.overviewPanel );
Group generalGroup = new Group( this.overviewPanel, SWT.NONE );
generalGroup.setText( "General" );
generalGroup.setLayoutData( new GridData( GridData.FILL, GridData.BEGINNING, true, false ) );
generalGroup.setLayout( new GridLayout( 2, false ) );
Label validLabel = new Label( generalGroup, SWT.NONE );
validLabel.setText( "Valid:" );
this.validText = new Label( generalGroup, SWT.NONE );
Font font = this.validText.getFont();
FontData[] fontData = font.getFontData();
for ( FontData fData : fontData ) {
int fStyle = fData.getStyle();
fData.setStyle( fStyle | SWT.BOLD );
}
this.validText.setFont( new Font( font.getDevice(), fontData ) );
Label notBeforeLabel = new Label( generalGroup, SWT.NONE );
notBeforeLabel.setText( "Not before:" );
this.notBeforeText = new Label( generalGroup, SWT.NONE );
Label notAfterLabel = new Label( generalGroup, SWT.NONE );
notAfterLabel.setText( "Not after:" );
this.notAfterText = new Label( generalGroup, SWT.NONE );
Label sNoLabel = new Label( generalGroup, SWT.NONE );
sNoLabel.setText( "Serial Number:" );
this.sNoText = new Label( generalGroup, SWT.NONE );
createX500PrincipalGroup( this.overviewPanel, "Issued to", this.subjectLabels );
createX500PrincipalGroup( this.overviewPanel, "Issued from", this.issuerLabels );
TabItem detailsItem = new TabItem( tabFolder, SWT.NONE );
detailsItem.setText( "Details" );
SashForm detailsForm = new SashForm( tabFolder, SWT.VERTICAL );
detailsForm.setLayout( new FillLayout() );
detailsItem.setControl( detailsForm );
Composite tableComp = new Composite( detailsForm, SWT.NONE );
tableComp.setLayout( new GridLayout( 1, false ) );
Label tableLabel = new Label( tableComp, SWT.NONE );
tableLabel.setText( "Certificate chain" );
this.chainTable = new Table( tableComp, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE );
this.chainTable.setLayoutData( new GridData( GridData.FILL, GridData.FILL, true, true ) );
Composite treeComp = new Composite( detailsForm, SWT.NONE );
treeComp.setLayout( new GridLayout( 1, false ) );
Label treeLabel = new Label( treeComp, SWT.NONE );
treeLabel.setText( "Certificate structure" );
this.detailsTree = new Tree( treeComp, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER );
this.detailsTree.setLayoutData( new GridData( GridData.FILL, GridData.FILL, true, true ) );
Composite valueComp = new Composite( detailsForm, SWT.NONE );
valueComp.setLayout( new GridLayout( 1, false ) );
Label valueLabel = new Label( valueComp, SWT.NONE );
valueLabel.setText( "Field value" );
this.valueText = new Text( valueComp, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.READ_ONLY | SWT.MULTI );
this.valueText.setLayoutData( new GridData( GridData.FILL, GridData.FILL, true, true ) );
Display display = Display.getDefault();
FontData[] fData = display.getSystemFont().getFontData();
int fHeight = ( ( fData != null ) && ( fData.length > 0 ) ) ? fData[ 0 ].getHeight() : 10;
this.valueText.setFont( new Font( Display.getDefault(), new FontData( "Courier", fHeight, SWT.NONE ) ) );
detailsForm.setWeights( new int[] { 1, 2, 1 } );
this.chainTable.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( final SelectionEvent e ) {
fillDetailsTree();
}
} );
this.detailsTree.addSelectionListener( new SelectionAdapter() {
@Override
public void widgetSelected( final SelectionEvent e ) {
TreeItem item = ( TreeItem ) e.item;
if ( ( item != null ) && ( item.getData() != null )
&& ! CertificateInfoPanel.this.valueText.isDisposed() ) {
CertificateInfoPanel.this.valueText.setText( item.getData().toString() );
} else {
CertificateInfoPanel.this.valueText.setText( "" );
}
}
} );
updateOverviewPanel();
}
public X509Certificate[] getCertificateChain() {
return this.certificateChain;
}
public X509Certificate getSelectedCertificate() {
X509Certificate result = null;
if ( ( this.chainTable != null ) && ! this.chainTable.isDisposed() ) {
TableItem[] items = this.chainTable.getSelection();
if ( ( items != null ) && ( items.length > 0 ) ) {
result = ( X509Certificate ) items[ 0 ].getData();
}
}
return result;
}
public X509Certificate getSubjectCertificate() {
return ( this.certificateChain != null ) && ( this.certificateChain.length > 0 )
? this.certificateChain[ 0 ]
: null;
}
public void setCertificate( final X509Certificate cert ) {
setCertificateChain( new X509Certificate[] { cert } );
}
public void setCertificateChain( final X509Certificate[] chain ) {
this.certificateChain = chain;
fillOverviewPanel();
fillChainTable();
fillDetailsTree();
}
protected void fillChainTable() {
this.chainTable.removeAll();
X509Certificate[] chain = getCertificateChain();
if ( chain != null ) {
for ( X509Certificate cert : chain ) {
TableItem item = new TableItem( this.chainTable, SWT.NONE );
item.setText( cert.getSubjectDN().getName() );
item.setData( cert );
}
}
this.chainTable.setSelection( 0 );
}
protected void fillDetailsTree() {
this.detailsTree.removeAll();
this.valueText.setText( "" );
X509Certificate certificate = getSelectedCertificate();
if ( certificate != null ) {
TreeItem certItem = new TreeItem( this.detailsTree, SWT.NONE );
certItem.setText( "Certificate" );
TreeItem tbsItem = createTreeItem( certItem, "TBS Certificate", "" );
createTreeItem( tbsItem, "Version", String.valueOf( certificate.getVersion() ) );
createTreeItem( tbsItem, "Serial Number", X509Util.formatSerialNumber( certificate.getSerialNumber() ) );
createTreeItem( tbsItem, "Signature", certificate.getSigAlgName() );
createTreeItem( tbsItem, "Issuer", certificate.getIssuerX500Principal().getName() );
TreeItem validItem = createTreeItem( tbsItem, "Validity", "" );
createTreeItem( validItem, "Not Before", certificate.getNotBefore().toString() );
createTreeItem( validItem, "Not After", certificate.getNotAfter().toString() );
createTreeItem( tbsItem, "Subject", certificate.getSubjectX500Principal().getName() );
TreeItem subPubKeyInfoItem = createTreeItem( tbsItem, "Subject Public Key Info", "" );
createTreeItem( subPubKeyInfoItem, "Subject Public Key Algorithm", certificate.getPublicKey().getAlgorithm() );
createTreeItem( subPubKeyInfoItem, "Subject Public Key", X509Util.formatEncodedData( certificate.getPublicKey().getEncoded() ) );
TreeItem extItem = createTreeItem( tbsItem, "Extensions", "" );
fillExtensions( extItem, certificate );
TreeItem sigAlgItem = createTreeItem( certItem, "Signature Algorithm", certificate.getSigAlgName() );
TreeItem sigItem = createTreeItem( certItem, "Signature", X509Util.formatEncodedData( certificate.getSignature() ) );
certItem.setExpanded( true );
tbsItem.setExpanded( true );
validItem.setExpanded( true );
subPubKeyInfoItem.setExpanded( true );
sigAlgItem.setExpanded( true );
sigItem.setExpanded( true );
}
}
private void fillExtensions( final TreeItem extRoot, final X509Certificate certificate ) {
fillExtensions( extRoot, certificate, true );
fillExtensions( extRoot, certificate, false );
}
private void fillExtensions( final TreeItem extRoot, final X509Certificate certificate, final boolean critical ) {
Set< String > oids
= critical
? certificate.getCriticalExtensionOIDs()
: certificate.getNonCriticalExtensionOIDs();
for ( String oid : oids ) {
TreeItem extItem = createTreeItem( extRoot, "Extensions", "" );
createTreeItem( extItem, "Extension ID", oid );
createTreeItem( extItem, "Critical", Boolean.toString( critical ) );
createTreeItem( extItem, "Extension Value", X509Util.formatEncodedData( certificate.getExtensionValue( oid ) ) );
}
}
protected void fillOverviewPanel() {
boolean valid = false;
X509Certificate certificate = getSubjectCertificate();
try {
certificate.checkValidity();
valid = true;
} catch ( CertificateExpiredException cexpExc ) {
// ignored
} catch ( CertificateNotYetValidException cnvExc ) {
// ignored
}
Display display = Display.getDefault();
this.validText.setText( valid ? "YES" : "NO" );
this.validText.setForeground( valid ? display.getSystemColor( SWT.COLOR_GREEN )
: display.getSystemColor( SWT.COLOR_RED ) );
this.notBeforeText.setText( certificate.getNotBefore().toString() );
this.notAfterText.setText( certificate.getNotAfter().toString() );
this.sNoText.setText( X509Util.formatSerialNumber( certificate.getSerialNumber() ) );
this.notBeforeText.pack();
this.notAfterText.pack();
this.sNoText.pack();
fillX500PrincipalLabels( certificate.getSubjectX500Principal(), this.subjectLabels );
fillX500PrincipalLabels( certificate.getIssuerX500Principal(), this.issuerLabels );
updateOverviewPanel();
}
private void fillX500PrincipalLabels( final X500Principal principal,
final Hashtable< String, Label > table ) {
String name = principal.getName();
String[] parts = name.split( "[,/]" );
for ( String part : parts ) {
int index = part.indexOf( "=" );
if ( index >= 0 ) {
String key = part.substring( 0, index ).trim().toUpperCase();
Label label = table.get( key );
if ( label != null ) {
String value = part.substring( index+1 ).trim();
label.setText( value );
label.pack();
}
}
}
}
private TreeItem createTreeItem( final TreeItem parent,
final String field,
final String value ) {
TreeItem item = new TreeItem( parent, SWT.NONE );
item.setText( field );
item.setData( value );
return item;
}
private void createX500PrincipalGroup( final Composite parent,
final String title,
final Hashtable< String, Label > table ) {
Group group = new Group( parent, SWT.H_SCROLL );
group.setLayout( new GridLayout( 2, false ) );
group.setText( title );
group.setLayoutData( new GridData( GridData.FILL, GridData.BEGINNING, true, false ) );
createX500PrincipalGroupContent( group, table );
}
private void createX500PrincipalGroupContent( final Group group,
final Hashtable< String, Label > table ) {
table.put( "CN", createX500PrincipalField( group, "Common name:" ) );
table.put( "O", createX500PrincipalField( group, "Organization:" ) );
table.put( "OU", createX500PrincipalField( group, "Organizational Unit:" ) );
table.put( "L", createX500PrincipalField( group, "Locality:" ) );
table.put( "ST", createX500PrincipalField( group, "State:" ) );
table.put( "C", createX500PrincipalField( group, "Country:" ) );
}
private Label createX500PrincipalField( final Group group, final String name ) {
Label nameLabel = new Label( group, SWT.NONE );
nameLabel.setText( name );
Label valueLabel = new Label( group, SWT.NONE );
return valueLabel;
}
private void updateOverviewPanel() {
Point size = this.overviewPanel.computeSize( SWT.DEFAULT, SWT.DEFAULT );
this.overviewComp.setMinSize( size );
}
}