TOC PREV NEXT INDEX




Step 2 - Adding a Certificate Dialog


Sometimes a certificate is invalid because the CA for the certificate is not recognized, the certificate has expired, or other things are wrong with the certificate. In such cases it is sensible to prompt the user to continue the connection or not. To be able to get such a dialog, a certificate handler should be added. A certificate handler must implement the CertificateCallback interface. To add a certificate handler, add the following line before the first SSL connection is done:

ice.ssl.SSLSocket.setCertificateCallback(new CertificateHandler());
 

This installs a new CertificateHandler. The certificate handler is implemented as follows:

class CertificateHandler implements CertificateCallback{

 

     /* The return alteratives */

     final static int CERT_REJECT = 0;

     final static int CERT_SESSIONACCEPT = 1;

     final static int CERT_ALWAYSACCEPT = 2;

 

public synchronized boolean acceptCertificate(X509Certificate[] certs,

             SSLSocket socket){

     String messages = 

      "The certificate from server have the following errors\n\n";

     CertificateErrorInfo[] errinfo = 

         CertificateManager.getCertificateManager().getErrorInfo(certs,socket);

     for(int i = 0; i < errinfo.length ; i++){

         messages += errinfo[i].getMessage();

     }

 

     messages += "\n\nIssuer\n";

     messages += certs[0].getIssuerDN().getName();

     messages += "\n\nSubject\n";

     messages += certs[0].getSubjectDN().getName();

 

     CertificateDialog certdialog = new CertificateDialog(new Frame());

     int acceptance = certdialog.askCert(messages);

     switch(acceptance){

     case CERT_ALWAYSACCEPT:

         //fall through

     case CERT_SESSIONACCEPT:

         CertificateManager.getCertificateManager()

         .getTrustedSites().addCertificate(certs[0]);

         return true;

     case CERT_REJECT:

         return false;
 
    default:

         return false;

     }

}

     

public synchronized X509Certificate[] selectName(X500Name[] names){ 

     return null;

     }

 

     public synchronized PrivateKey supplyPrivateKey(X509Certificate cert){

     return null;

     }

 }


 

The main purpose of this class is to implement the acceptCertificate( ) method, which should return a boolean value that states whether the user accepts the certificate or not. The input to the method is the certificate chain the server sent. The method calls the getErrorInfo( ) in the certificate manager, and composes a string containing the error messages, and the name of the Subject(Owner) and Issuer(Signer) of the certificate.

String messages = "The certificate from server have the following

      errors\n\n";

     CertificateErrorInfo[] errinfo = 

         CertificateManager.getCertificateManager().

          getErrorInfo(certs,socket);

     for(int i = 0; i < errinfo.length ; i++){

         messages += errinfo[i].getMessage();

     }

 

     //Add the subject and issuer to the messages string.

     messages += "\n\nIssuer\n";

     messages += certs[0].getIssuerDN().getName();

     messages += "\n\nSubject\n";

     messages += certs[0].getSubjectDN().getName();
 

The messages are used in a dialog to ask the user to accept the certificate or not. The dialog is implemented in the class CertificateDialog, which is a simple AWT dialog that prints the messages and gives three choices: 'reject', 'accept for this session' and `accept forever'. Both accept alternatives do the same in this example, but 'accept forever' is treated differently in step 4. The following code creates the certificate dialog and pops up the dialog.

CertificateDialog certdialog = new CertificateDialog(new Frame());

int acceptance = certdialog.askCert(messages);
 

Then the user's choice is recorded, and if the user accepts the certificate, `true' is returned.

switch(acceptance){

     case CERT_ALWAYSACCEPT:

         return true;

     case CERT_SESSIONACCEPT:

         return true;

     case CERT_REJECT:

         return false;

     default:

         return false;
 

The certificate dialog is a straightforward AWT dialog, and is implemented as follows:

class CertificateDialog extends Dialog implements ActionListener{

private static final int BUFFER = 7;

     

     java.awt.TextArea textArea = null;

     java.awt.Button okButton = null;

     java.awt.Button rejectButton = null;

     java.awt.Button foreverButton = null;

 

     int choice = CertificateHandler.CERT_REJECT;

 

     CertificateDialog(Frame owner) {

         super(owner);

     this.setModal(true);

     createSelector(owner);

     }

            

     CertificateDialog(Frame owner, boolean modal) {

         super(owner, modal);

     createSelector(owner);

     }

             

     CertificateDialog(Frame owner, String title) {

         super(owner, title);

     this.setModal(true);

     createSelector(owner);

     }

            

     CertificateDialog(Frame owner, String title, boolean modal) {

         super(owner, title, modal);

     createSelector(owner);

}

     

private void createSelector(Frame owner){

     this.setLayout(new GridLayout(2,1));

     //this.add(new Label("The certificate had the following errors:"));

     

     //The certificate list

     textArea = new TextArea(30,40);

     textArea.setEditable(false);

     this.add(textArea);

     

     //the button panel

     Panel buttonPanel = new Panel();

     okButton = new Button("Accept for this session");
 
    buttonPanel.add(okButton);

     foreverButton = new Button("Accept forever");

     buttonPanel.add(foreverButton);

     rejectButton =  new Button("Reject");

     buttonPanel.add(rejectButton);

     this.add(buttonPanel);

     

     okButton.addActionListener(this);

     foreverButton.addActionListener(this);

     rejectButton.addActionListener(this);

}

 

public void actionPerformed(ActionEvent ev){

     if(ev.getSource()==okButton){

         choice = CertificateHandler.CERT_SESSIONACCEPT;

     }

     else if(ev.getSource()==foreverButton){

         choice = CertificateHandler.CERT_ALWAYSACCEPT;

     }

     else if(ev.getSource()==rejectButton){

         choice = CertificateHandler.CERT_REJECT;

     }

     setVisible(false);

}

 

public int askCert(String messages){

     textArea.setText(messages);

     pack();

     setSize(350,400);

     setVisible(true);

     return choice;

}

 

public Insets getInsets() {

         if (super.getInsets().top == 0 && super.getInsets().left == 0) {

             return new Insets(BUFFER, BUFFER, BUFFER, BUFFER);

         } else {

             return super.getInsets();

         }

}

 

public void refreshScreen() {

       pack();

       int x = (this.getParent().getSize().width - this.getSize().width) / 5 

       + this.getParent().getLocationOnScreen().x;

       int y = (this.getParent().getSize().height - this.getSize().height)/ 5 

       + this.getParent().getLocationOnScreen().y;     

       setLocation(x, y);

       invalidate();

}

}
 


Copyright 2005. ICEsoft Technologies, Inc.
http://www.icesoft.com

TOC PREV NEXT INDEX