KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > commons > security > cert > CertViewer


1 package com.ca.commons.security.cert;
2
3 import java.awt.*;
4 import java.awt.event.*;
5 import javax.swing.*;
6 import java.util.Properties JavaDoc;
7
8 import java.io.*;
9
10 import java.security.cert.*;
11
12 import com.ca.commons.security.cert.extensions.*;
13 import com.ca.commons.security.asn1.*;
14 import com.ca.commons.security.util.CertUtil;
15
16 import com.ca.commons.cbutil.*;
17
18 import java.util.StringTokenizer JavaDoc;
19
20 /**
21  * <p>A certificate viewer which is similar to the Microsoft's,
22  * written in Java, therefore it can be run in all operating systems
23  * with a Java virtual machine installed.
24  * General tab, Details tab, Certification Path tab, OK button.</p>
25  *
26  * <p>Note that the static 'setProperties()' method must be called
27  * before use if graphics are to be displayed.</p>
28  *
29  * @author vbui, cbetts
30  */

31
32 // XXX this class has gathered a fair bit of lint - there are a bunch of generic security methods
33
// XXX that should be moved into some sort of security util class... - CB
34

35 // TODO: logging, and bubble exception properly from CertUtil
36

37 public class CertViewer extends CBDialog
38 {
39     /**
40      * Utility method for passing around a cert and accompanying
41      * filename
42      */

43
44     public static class CertAndFileName
45     {
46         public X509Certificate cert;
47         public String JavaDoc fileName;
48     }
49
50     /**
51      * The actual cert currently being displayed.
52      */

53
54     private X509Certificate cert = null;
55
56     /**
57      * The file name the cert was loaded from (if any).
58      */

59
60     private String JavaDoc fileName = null;
61
62     // visual elements
63
private JTabbedPane tabs = new JTabbedPane();
64     private CertGeneralViewPanel generalView = null;
65     private CertDetailsViewPanel detailsView = null;
66     private CertPathViewPanel pathView = null;
67     private CBButton okButton, saveButton, loadButton;
68
69
70     /**
71      * When the mode is set to this the cert can only be viewed
72      */

73
74     public static final int VIEW_ONLY = 0;
75
76     /**
77      * When the mode is set to this the cert can be viewed and saved to file
78      */

79
80     public static final int VIEW_SAVE = 1;
81
82     /**
83      * When the mode is set to this the cert can be loaded from file and viewed
84      */

85
86     public static final int VIEW_LOAD = 2;
87
88     /**
89      * When the mode is set to this the cert can be viewed, saved and loaded
90      */

91
92     public static final int VIEW_SAVE_LOAD = 3;
93
94     /**
95      * Synonym for VIEW_SAVE_LOAD
96      */

97
98     public static final int VIEW_LOAD_SAVE = 3;
99
100     protected int mode = VIEW_SAVE;
101
102     //public static String imagePath = null;
103

104     public static ImageIcon certLargeIcon = null;
105     public static ImageIcon certIcon = null;
106     public static ImageIcon attributeIcon = null;
107     public static ImageIcon extensionIcon = null;
108     public static ImageIcon criticalExtensionIcon = null;
109     public static ImageIcon thumbprintIcon = null;
110     public static Image frameIcon = null;
111
112     /**
113      * used to store image directory and default browsing directory properties,
114      * under "dir.images" and "cert.homeDir".
115      */

116
117     public static Properties JavaDoc properties = null;
118
119     public static String JavaDoc helpLink = null; //TE: help link, might not be initialised, if it is a help button should be added.
120

121     /**
122      * sets the graphic icons for the various buttons and cert display screens,
123      * using the image directory set via the setProperties() method.
124      */

125     protected static void setupGraphics()
126     {
127         try
128         {
129             certLargeIcon = getImageIcon("certificate_large.gif");
130             certIcon = getImageIcon("certificate.gif");
131             attributeIcon = getImageIcon("attribute.gif");
132             extensionIcon = getImageIcon("extension.gif");
133             criticalExtensionIcon = getImageIcon("criticalExtension.gif");
134             thumbprintIcon = getImageIcon("thumbprint.gif");
135             frameIcon = getImageIcon("pki_icon.gif").getImage();
136         }
137         catch (Exception JavaDoc ex)
138         {
139             System.out.println(ex.getMessage());
140         }
141     }
142
143     /**
144      * Local copy of standard JXplorer function to allow stand-alone use.
145      */

146
147     public static ImageIcon getImageIcon(String JavaDoc name)
148     {
149         if (properties == null) return null;
150
151         ImageIcon newIcon = new ImageIcon(properties.getProperty("dir.images") + name);
152         return newIcon;
153     }
154
155    /**
156     * Sets up the help link for the help button.
157     */

158
159     public static void setupHelpLink(String JavaDoc link)
160     {
161         helpLink = link;
162     }
163
164     /**
165      * Used to set the global properties used by CertViewer to load images,
166      * and to determine the default browseing directory (which can be
167      * maintained between sessions for added usability).
168      * @param props a properties object containing a "dir.images" property
169      * (setting the image directory path) and a "cert.homeDir" property
170      * describing the directory the browser should start viewing in.
171      */

172
173     public static void setProperties(Properties JavaDoc props) { properties = props; }
174
175     /**
176      * A utility method - this allows just the image directory to be
177      * set. It is usually preferable to use setProperties() instead,
178      * which allows the cert.homeDir property to be maintained between
179      * sessions.
180      */

181
182     public static void setImageDirectory(String JavaDoc imagePath)
183     {
184         if (properties == null)
185             properties = new Properties JavaDoc();
186         properties.put("dir.images", imagePath);
187     }
188
189
190     public static CertAndFileName loadCertificate(Frame owner)
191     {
192         CertViewer viewer = new CertViewer(owner, null, VIEW_SAVE_LOAD);
193
194         // by this stage, the viewer has already prompted the user to
195
// select a certificate - if it is null, it means the user
196
// hit 'cancel' on the file chooser, so bail out...
197

198         if (viewer.getCertificate() == null)
199             return null;
200
201         // show the certificate viewer, and allow the user to decide
202
// whether to use the current cert, or select another.
203

204         viewer.setVisible(true);
205
206         CertAndFileName returnInfo = new CertAndFileName();
207         returnInfo.cert = viewer.getCertificate();
208         returnInfo.fileName = viewer.getFileName();
209
210         return returnInfo;
211     }
212
213     public static CertAndFileName editCertificate(Frame owner, byte[] certData)
214     {
215         if (certData == null) return loadCertificate(owner);
216
217         X509Certificate cert = CertUtil.loadX509Certificate (certData);
218
219         CertViewer viewer = new CertViewer(owner, cert, VIEW_SAVE_LOAD);
220
221         // by this stage, the viewer has already prompted the user to
222
// select a certificate - if it is null, it means the user
223
// hit 'cancel' on the file chooser, so bail out...
224

225         if (viewer.getCertificate() == null)
226             return null;
227
228         // show the certificate viewer, and allow the user to decide
229
// whether to use the current cert, or select another.
230

231         viewer.setVisible(true);
232
233         CertAndFileName returnInfo = new CertAndFileName();
234         returnInfo.cert = viewer.getCertificate();
235         returnInfo.fileName = viewer.getFileName();
236
237         return returnInfo;
238     }
239
240     /**
241      * Frameless Constructor. This should only be used if no
242      * parent frame can be found, and will cause odd behaviour
243      * in some circumstances.
244      * @deprecated
245      * @param cert the X509 certificate to view
246      */

247     public CertViewer(X509Certificate cert)
248     {
249         super(null, CBIntText.get("Certificate"), null);
250         init(cert, VIEW_SAVE);
251     }
252
253     /**
254      * Constructor.
255      * @param owner the parent Frame (used for centering and look and feel propogation)
256      * @param cert the X509 certificate to view
257      */

258
259     public CertViewer(Frame owner, X509Certificate cert)
260     {
261         super(owner, CBIntText.get("Certificate"), helpLink); //TE: if there is no help link supplied helpLink will be null.
262
init(cert, VIEW_SAVE);
263     }
264
265     /**
266      * Constructor.
267      * @param owner the parent Frame (used for centering and look and feel propogation)
268      * @param cert the X509 certificate to view
269      * @param mode one of VIEW, VIEW_SAVE, VIEW_LOAD or VIEW_SAVE_LOAD, describing
270      * what options should be available to the user.
271      */

272
273     public CertViewer(Frame owner, X509Certificate cert, int mode)
274     {
275         super(owner, CBIntText.get("Certificate"), helpLink); //TE: if there is no help link supplied helpLink will be null.
276
init(cert, mode);
277     }
278
279     public void init(X509Certificate cert, int mode)
280     {
281         if (certLargeIcon == null)
282             setupGraphics();
283
284         this.mode = mode;
285
286         displayCert(cert); // setup tab panes.
287

288         saveButton = new CBButton(CBIntText.get("Copy to File"), CBIntText.get("Copy to File."));
289         loadButton = new CBButton(CBIntText.get("Read from File"), CBIntText.get("Read from File."));
290
291         // Since this inherits from CBDialog, it already has 'ok' and
292
// 'cancel'buttons; depending on what mode we're in, we will
293
// add others, and possibly remove the cancel.
294

295         if (mode == VIEW_ONLY || mode == VIEW_SAVE)
296         { // if we can't load, there's no need for cancel
297
buttonPanel.remove(Cancel); // remove default CBDialog cancel button
298
}
299
300         if (mode == VIEW_SAVE || mode == VIEW_SAVE_LOAD)
301         {
302             buttonPanel.add(saveButton, 0);
303         }
304
305         if (mode == VIEW_LOAD || mode == VIEW_SAVE_LOAD)
306         {
307             buttonPanel.add(loadButton, 0);
308             //OK.setText(CBIntText.get("Submit"));
309
}
310
311         buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
312
313         setSize(440, 477);
314         CBUtility.center(this, owner);
315
316         saveButton.addActionListener(new ActionListener()
317         {
318             public void actionPerformed(ActionEvent e) { saveCert(); }
319         });
320
321         loadButton.addActionListener(new ActionListener()
322         {
323             public void actionPerformed(ActionEvent e) { loadCert(); }
324         });
325
326         // if we've started up with a null cert, fire up the load
327
// cert window immediately.
328

329         if (cert == null && (mode & VIEW_LOAD)>0)
330             loadCert();
331     }
332
333     /**
334      * This is a bit heavyhanded - when the cert changes,
335      * tear down everything and recreate all the gui objects
336      * in the tab pane. Better would be to charge off and
337      * update all the individual components, but right now
338      * I'm in a bit of a hurry :-) - CB
339      * @param displayCert the new cert to display.
340      */

341
342     public void displayCert(X509Certificate displayCert)
343     {
344         cert = displayCert;
345
346         tabs.removeAll();
347         generalView = new CertGeneralViewPanel(displayCert);
348         detailsView = new CertDetailsViewPanel(displayCert);
349         pathView = new CertPathViewPanel(displayCert);
350         tabs.add("General", generalView);
351         tabs.add("Details", detailsView);
352         tabs.add("Certification Path", pathView);
353
354         display.removeAll();
355         makeHeavy();
356         display.add(tabs);
357     }
358
359
360     /**
361      * When the user hits 'cancel', the window is shut down,
362      * and the cert is set to null (for the benefit of anyone
363      * using this as a cert loader).
364      */

365
366     public void doCancel()
367     {
368         cert = null;
369         super.doCancel();
370     }
371
372     /**
373      * Returns the certificate currently being viewed by the CertViewer.
374      * @return the current certificate (may be null).
375      */

376
377     public X509Certificate getCertificate() { return cert; }
378
379     /**
380      * Returns the file name (if any) associated with the currently viewed
381      * cert.
382      * @return the full file name
383      */

384
385     public String JavaDoc getFileName() { return fileName; }
386
387     /**
388      * This method prompts the user to select a file name to save the cert to.
389      */

390
391     protected void saveCert()
392     {
393         JFileChooser chooser = new JFileChooser(properties.getProperty("cert.homeDir", System.getProperty("user.dir")));
394
395         chooser.addChoosableFileFilter(new CBFileFilter(new String JavaDoc[] {"der", "pem"}, CBIntText.get("Certificate File") + " (*.der) (*.pem)"));
396
397         int option = chooser.showSaveDialog(this);
398
399         File readFile = chooser.getSelectedFile();
400         if (option != JFileChooser.APPROVE_OPTION || readFile == null) // only do something if user chose 'ok'
401
{
402             return; // user picked 'cancel' or didn't select a file.
403
}
404
405         if (properties != null)
406             properties.setProperty("cert.homeDir", readFile.getParent());
407
408         fileName = readFile.toString();
409
410         try
411         {
412             byte[] derout = cert.getEncoded();
413
414             if (fileName.toLowerCase().endsWith(".pem")) // special handling for PEM files
415
{
416 //System.out.println("saving pem cert!!!");
417
derout = CBSecurity.convertToPEMCertificate(derout);
418             }
419             else if (fileName.toLowerCase().endsWith(".der") == false)
420             {
421                 fileName = fileName + ".der";
422                 readFile = new File(fileName);
423             }
424
425             if (saveFileCheck(readFile) == false) return; // something wrong with the file name
426

427             FileOutputStream fos = new FileOutputStream(readFile);
428 //System.out.println("writeing: " + derout.length + " bytes");
429
fos.write(derout);
430             fos.close();
431         }
432         catch (Exception JavaDoc ex)
433         {
434             CBUtility.error(CBIntText.get("Unable to save Certificate."), ex);
435         }
436     }
437
438     /**
439      * Checks a file before saving it.
440      */

441
442     public boolean saveFileCheck(File checkMe)
443     {
444         if (checkMe.isDirectory())
445         {
446             CBUtility.error(checkMe.toString() + " is a directory.", null);
447             return false;
448         }
449         else if (checkMe.exists())
450         {
451             int saveAnswer = JOptionPane.showConfirmDialog(owner,
452                 (checkMe.toString() + "\n " + CBIntText.get("This file already exists.\nDo you want to overwrite this file?")),
453                 "Question", JOptionPane.OK_CANCEL_OPTION);
454
455             return (saveAnswer == JOptionPane.OK_OPTION);
456         }
457
458         return true;
459     }
460
461
462     protected void loadCert()
463     {
464         String JavaDoc browseDir = System.getProperty("user.dir");
465         if (properties != null)
466         {
467             if (properties.getProperty("cert.homeDir") != null)
468                 browseDir = properties.getProperty("cert.homeDir");
469         }
470         JFileChooser chooser = new JFileChooser(browseDir);
471
472         chooser.addChoosableFileFilter(new CBFileFilter(new String JavaDoc[] {"der", "pem"}, CBIntText.get("Certificate File") + " (*.der), (*.pem)"));
473
474         int option = chooser.showOpenDialog(this);
475
476         File readFile = chooser.getSelectedFile();
477
478         if (option != JFileChooser.APPROVE_OPTION || readFile == null) // only do something if user chose 'ok'
479
{ // user picked 'cancel' or didn't select a file.
480
if (cert == null)
481                 doCancel(); // quit out - we have nothing to display.
482
return;
483         }
484
485         try
486         {
487             if (properties != null)
488                 properties.setProperty("cert.homeDir", readFile.getParent());
489
490 //Obsolete - use Sun code
491
//XXX - don't use Sun code - it doesn't handle plain text prefix in pem file correctly.
492
byte[] data = getDERCertDataFromFile(readFile);
493
494 //Obsolete - use Sun code
495
//XXX - don't use Sun code - it doesn't handle plain text prefix in pem file correctly.
496
X509Certificate newCert = CertUtil.loadX509Certificate(data);
497
498 /* Sun code
499 System.out.println("using new code");
500             X509Certificate newCert = CertUtil.loadX509Certificate(readFile);
501 */

502             displayCert(newCert);
503             fileName = readFile.getName();
504         }
505         catch (Exception JavaDoc ex)
506         {
507             CBUtility.error(CBIntText.get("Unable to load Certificate."), ex);
508         }
509
510     }
511
512
513
514     /**
515      * Attempt to retrieve the most significant name in a distinguish name
516      * ????? (cn = somename)
517      */

518     public static String JavaDoc getMostSignificantName(String JavaDoc dnstring)
519     {
520         String JavaDoc leftmostname = null;
521         StringTokenizer JavaDoc stok = new StringTokenizer JavaDoc(dnstring, ",");
522         if (stok.hasMoreTokens()) leftmostname = stok.nextToken();
523         return leftmostname;
524     }
525
526
527     /**
528      * This takes a file, and converts the certificate data within it into
529      * a byte array. While this is straightforward if it is DER encoded,
530      * some parsing is required if it is PEM to identify the certificate
531      * portion of the text, and convert it into raw DER bytes.
532      *
533      * @param file the file containing an X509 certificate in DER or PEM form
534      * @return the raw (DER) byte data.
535      */

536
537     public static byte[] getDERCertDataFromFile(File file)
538         throws CertificateParsingException, FileNotFoundException, IOException
539     {
540          /* Read the file data into a byte array */
541         FileInputStream in = new FileInputStream(file);
542         byte [] buffer = new byte[(int) (file.length())];
543         in.read(buffer);
544         in.close();
545
546         /* check if this is pem base64 encoded data - if it is, translate it */
547         if (CBSecurity.isPEM(buffer))
548         {
549             //XXX <your code to handle unencrypted private keys here> XXX//
550

551 //System.out.println("\nparsing PEM data!!\n");
552

553             byte[] pemData = CBSecurity.convertFromPEMCertificate(buffer);
554             if (pemData == null)
555                 throw new CertificateParsingException("Unable to parse PEM encoded cert - invalid PEM encoding.");
556
557             buffer = pemData;
558         }
559
560         return buffer;
561     }
562
563
564     /**
565      * Main method, the starting point of this program.
566      */

567     public static void main(String JavaDoc[] args)
568     {
569         JFrame parent = new JFrame();
570         //parent.setIconImage(frameIcon);
571

572         X509Certificate cert = null;
573
574         try
575         {
576             byte[] data = getDERCertDataFromFile(new File(args[0]));
577
578             if ( (cert = CertUtil.loadX509Certificate(data)) == null )
579             {
580                 System.out.println("Problem opening certfile \"" + args[0] + "\"");
581                 System.exit(1);
582             }
583
584
585             String JavaDoc localDir = System.getProperty("user.dir") + File.separator;
586
587             Properties JavaDoc props = new Properties JavaDoc();
588
589             /*
590              * This sets the directory that the file browsers start in.
591              * This can be saved/read from file to allow the user to start
592              * loading/saving from the same place.
593              */

594
595             props.setProperty("cert.homeDir", localDir + "certs" + File.separator);
596
597             /*
598              * This simply sets the directory where the GUI will try to load
599              * its button images from.
600              */

601
602             props.setProperty("dir.images", localDir + "images" + File.separator);
603
604             CertViewer.setProperties(props);
605
606             CertViewer me = new CertViewer(parent, cert);
607
608             me.addWindowListener(new WindowAdapter()
609             {
610                 public void windowClosing(WindowEvent e)
611                 {
612                     System.exit(0);
613                 }
614             });
615
616             me.setVisible(true);
617         }
618         catch (Exception JavaDoc e)
619         {
620             System.err.println("ERROR OCCURRED");
621             e.printStackTrace();
622             System.exit(-1);
623         }
624         // look and feel
625

626     }
627
628 }
Popular Tags