diff --git a/kse/src/net/sf/keystore_explorer/crypto/x509/X509CertUtil.java b/kse/src/net/sf/keystore_explorer/crypto/x509/X509CertUtil.java index a6aa2f156..a2ffc14c4 100644 --- a/kse/src/net/sf/keystore_explorer/crypto/x509/X509CertUtil.java +++ b/kse/src/net/sf/keystore_explorer/crypto/x509/X509CertUtil.java @@ -68,7 +68,7 @@ /** * Provides utility methods relating to X509 Certificates and CRLs. - * + * */ public final class X509CertUtil extends Object { private static ResourceBundle res = ResourceBundle.getBundle("net/sf/keystore_explorer/crypto/x509/resources"); @@ -83,7 +83,7 @@ private X509CertUtil() { /** * Load one or more certificates from the specified stream. - * + * * @param is * Stream to load certificates from * @return The certificates @@ -216,7 +216,7 @@ private static byte[] attemptSpcBase64Decode(byte[] toTest) { /** * Load certificates from an SSL connection. - * + * * @param host * Connection host * @param port @@ -270,7 +270,7 @@ public boolean verify(String hostname, SSLSession sslSession) { /** * Load a CRL from the specified stream. - * + * * @param is * Stream to load CRL from * @return The CRL @@ -294,7 +294,7 @@ public static X509CRL loadCRL(InputStream is) throws CryptoException { /** * Convert the supplied array of certificate objects into X509Certificate * objects. - * + * * @param certsIn * The Certificate objects * @return The converted X509Certificate objects @@ -302,6 +302,11 @@ public static X509CRL loadCRL(InputStream is) throws CryptoException { * A problem occurred during the conversion */ public static X509Certificate[] convertCertificates(Certificate[] certsIn) throws CryptoException { + + if (certsIn == null) { + return new X509Certificate[0]; + } + X509Certificate[] certsOut = new X509Certificate[certsIn.length]; for (int i = 0; i < certsIn.length; i++) { @@ -313,7 +318,7 @@ public static X509Certificate[] convertCertificates(Certificate[] certsIn) throw /** * Convert the supplied certificate object into an X509Certificate object. - * + * * @param certIn * The Certificate object * @return The converted X509Certificate object @@ -332,30 +337,36 @@ public static X509Certificate convertCertificate(Certificate certIn) throws Cryp /** * Order the supplied array of X.509 certificates in issued to issuer order. - * + * * @param certs * X.509 certificates * @return The ordered X.509 certificates */ public static X509Certificate[] orderX509CertChain(X509Certificate certs[]) { + + if (certs == null) { + return new X509Certificate[0]; + } + + if (certs.length <= 1) { + return certs; + } + // Put together each possible certificate path... ArrayList> paths = new ArrayList>(); // For each possible path... for (int i = 0; i < certs.length; i++) { - // Each possible path assumes a different certificate is the root - // issuer + // Each possible path assumes a different certificate is the root issuer ArrayList path = new ArrayList(); X509Certificate issuerCert = certs[i]; path.add(issuerCert); X509Certificate newIssuer = null; - // Recursively build that path by finding the next issued - // certificate + // Recursively build that path by finding the next issued certificate while ((newIssuer = findIssuedCert(issuerCert, certs)) != null) { - // Found an issued cert, now attempt to find its issued - // certificate + // Found an issued cert, now attempt to find its issued certificate issuerCert = newIssuer; path.add(0, newIssuer); } @@ -399,7 +410,7 @@ private static X509Certificate findIssuedCert(X509Certificate issuerCert, X509Ce /** * X.509 encode a certificate. - * + * * @return The encoding * @param cert * The certificate @@ -416,7 +427,7 @@ public static byte[] getCertEncodedX509(X509Certificate cert) throws CryptoExcep /** * X.509 encode a certificate and PEM the encoding. - * + * * @return The PEM'd encoding * @param cert * The certificate @@ -430,7 +441,7 @@ public static String getCertEncodedX509Pem(X509Certificate cert) throws CryptoEx /** * PKCS #7 encode a certificate. - * + * * @return The encoding * @param cert * The certificate @@ -443,7 +454,7 @@ public static byte[] getCertEncodedPkcs7(X509Certificate cert) throws CryptoExce /** * PKCS #7 encode a number of certificates. - * + * * @return The encoding * @param certs * The certificates @@ -470,7 +481,7 @@ public static byte[] getCertsEncodedPkcs7(X509Certificate[] certs) throws Crypto /** * PKCS #7 encode a certificate and PEM the encoding. - * + * * @param cert * The certificate * @return The PEM'd encoding @@ -483,7 +494,7 @@ public static String getCertEncodedPkcs7Pem(X509Certificate cert) throws CryptoE /** * PKCS #7 encode a number of certificates and PEM the encoding. - * + * * @param certs * The certificates * @return The PEM'd encoding @@ -497,7 +508,7 @@ public static String getCertsEncodedPkcs7Pem(X509Certificate[] certs) throws Cry /** * PKI Path encode a certificate. - * + * * @return The encoding * @param cert * The certificate @@ -510,7 +521,7 @@ public static byte[] getCertEncodedPkiPath(X509Certificate cert) throws CryptoEx /** * PKI Path encode a number of certificates. - * + * * @return The encoding * @param certs * The certificates @@ -538,7 +549,7 @@ public static byte[] getCertsEncodedPkiPath(X509Certificate[] certs) throws Cryp /** * Verify that one X.509 certificate was signed using the private key that * corresponds to the public key of a second certificate. - * + * * @return True if the first certificate was signed by private key * corresponding to the second signature * @param signedCert @@ -576,7 +587,7 @@ public static boolean verifyCertificate(X509Certificate signedCert, X509Certific * certificates contained therein, ie that a chain of trust exists between * the supplied certificate and a self-signed trusted certificate in the * KeyStores. - * + * * @return The trust chain, or null if trust could not be established * @param cert * The certificate @@ -665,7 +676,7 @@ private static List extractCertificates(KeyStore keyStore) thro /** * Check whether or not a trusted certificate in the supplied KeyStore * matches the supplied X.509 certificate. - * + * * @param cert * The certificate * @param keyStore @@ -699,7 +710,7 @@ public static String matchCertificate(KeyStore keyStore, X509Certificate cert) t * name (if any). For a non-self-signed certificate it will be the subject's * common name followed by the issuer's common name in brackets. Aliases * will always be in lower case. - * + * * @param cert * The certificate * @return The alias or a blank string if none could be worked out @@ -737,7 +748,7 @@ private static String extractCommonName(X500Name name) { /** * Get short name for certificate. Common name if available, otherwise use * entire distinguished name. - * + * * @param cert * Certificate * @return Short name @@ -758,7 +769,7 @@ public static String getShortName(X509Certificate cert) { * For a given X.509 certificate get the algorithm of its signature. Useful * as the JCE may return an unfriendly name. This method converts known * "unfriendly names" to friendly names. - * + * * @param cert * The certificate * @return The algorithm @@ -784,7 +795,7 @@ public static final String getCertificateSignatureAlgorithm(X509Certificate cert /** * Is the supplied X.509 certificate self-signed? - * + * * @param cert * The certificate * @return True if it is @@ -793,7 +804,7 @@ public static final boolean isCertificateSelfSigned(X509Certificate cert) { return (cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal())); } - + /** * Implementation of the X509TrustManager. In this implementation we * always trust the server as we are only interested in getting its diff --git a/kse/src/net/sf/keystore_explorer/gui/actions/ExportTrustedCertificateAction.java b/kse/src/net/sf/keystore_explorer/gui/actions/ExportTrustedCertificateAction.java index 999e8865a..ed234b01d 100644 --- a/kse/src/net/sf/keystore_explorer/gui/actions/ExportTrustedCertificateAction.java +++ b/kse/src/net/sf/keystore_explorer/gui/actions/ExportTrustedCertificateAction.java @@ -42,26 +42,43 @@ /** * Action to export the selected trusted certificate entry. - * + * */ public class ExportTrustedCertificateAction extends KeyStoreExplorerAction { - /** - * Construct action. - * - * @param kseFrame - * KeyStore Explorer frame - */ - public ExportTrustedCertificateAction(KseFrame kseFrame) { - super(kseFrame); - - putValue(LONG_DESCRIPTION, res.getString("ExportTrustedCertificateAction.statusbar")); - putValue(NAME, res.getString("ExportTrustedCertificateAction.text")); - putValue(SHORT_DESCRIPTION, res.getString("ExportTrustedCertificateAction.tooltip")); - putValue( - SMALL_ICON, - new ImageIcon(Toolkit.getDefaultToolkit().createImage( - getClass().getResource(res.getString("ExportTrustedCertificateAction.image"))))); - } + + private X509Certificate cert; + + /** + * Construct action. + * + * @param kseFrame + * KeyStore Explorer frame + */ + public ExportTrustedCertificateAction(KseFrame kseFrame) { + this(kseFrame, null); + } + + /** + * Construct action. + * + * @param kseFrame + * KeyStore Explorer frame + * @param cert + * Certificate to be exported. If null, the currently selected keystore entry is used. + */ + public ExportTrustedCertificateAction(KseFrame kseFrame, X509Certificate cert) { + super(kseFrame); + + this.cert = cert; + + putValue(LONG_DESCRIPTION, res.getString("ExportTrustedCertificateAction.statusbar")); + putValue(NAME, res.getString("ExportTrustedCertificateAction.text")); + putValue(SHORT_DESCRIPTION, res.getString("ExportTrustedCertificateAction.tooltip")); + putValue( + SMALL_ICON, + new ImageIcon(Toolkit.getDefaultToolkit().createImage( + getClass().getResource(res.getString("ExportTrustedCertificateAction.image"))))); + } /** * Do action. @@ -70,9 +87,15 @@ protected void doAction() { File exportFile = null; try { - String alias = kseFrame.getSelectedEntryAlias(); + DExportCertificates dExportCertificates = null; + if (cert == null) { + String alias = kseFrame.getSelectedEntryAlias(); + dExportCertificates = new DExportCertificates(frame, alias, false); + cert = getCertificate(alias); + } else { + dExportCertificates = new DExportCertificates(frame, X509CertUtil.getCertificateAlias(cert), false); + } - DExportCertificates dExportCertificates = new DExportCertificates(frame, alias, false); dExportCertificates.setLocationRelativeTo(frame); dExportCertificates.setVisible(true); @@ -84,8 +107,6 @@ protected void doAction() { boolean pemEncode = dExportCertificates.pemEncode(); - X509Certificate cert = getCertificate(alias); - byte[] encoded = null; if (dExportCertificates.exportFormatX509()) { @@ -103,9 +124,7 @@ protected void doAction() { } else if (dExportCertificates.exportFormatPkiPath()) { encoded = X509CertUtil.getCertEncodedPkiPath(cert); } else if (dExportCertificates.exportFormatSpc()) { - encoded = X509CertUtil.getCertEncodedPkcs7(cert); // SPC is just - // DER PKCS - // #7 + encoded = X509CertUtil.getCertEncodedPkcs7(cert); // SPC is just DER PKCS #7 } exportEncodedCertificate(encoded, exportFile); diff --git a/kse/src/net/sf/keystore_explorer/gui/dialogs/DViewCertificate.java b/kse/src/net/sf/keystore_explorer/gui/dialogs/DViewCertificate.java index 623dc9dbf..ea8eb73e4 100644 --- a/kse/src/net/sf/keystore_explorer/gui/dialogs/DViewCertificate.java +++ b/kse/src/net/sf/keystore_explorer/gui/dialogs/DViewCertificate.java @@ -78,7 +78,7 @@ import net.sf.keystore_explorer.gui.JEscDialog; import net.sf.keystore_explorer.gui.KseFrame; import net.sf.keystore_explorer.gui.PlatformUtil; -import net.sf.keystore_explorer.gui.actions.ExportKeyPairCertificateChainAction; +import net.sf.keystore_explorer.gui.actions.ExportTrustedCertificateAction; import net.sf.keystore_explorer.gui.actions.ImportTrustedCertificateAction; import net.sf.keystore_explorer.gui.crypto.JCertificateFingerprint; import net.sf.keystore_explorer.gui.crypto.JDistinguishedName; @@ -90,18 +90,18 @@ * Displays the details of one or more X.509 certificates. The details of one * certificate are displayed at a time with selector buttons allowing the * movement to another of the certificates. - * + * */ public class DViewCertificate extends JEscDialog { private static ResourceBundle res = ResourceBundle.getBundle("net/sf/keystore_explorer/gui/dialogs/resources"); private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MMM/yyyy HH:mm:ss z"); - + public static int NONE = 0; public static int IMPORT = 1; public static int EXPORT = 2; private int importExport = 0; - + private KseFrame kseFrame; private JPanel jpCertificates; @@ -140,7 +140,7 @@ public class DViewCertificate extends JEscDialog { /** * Creates a new DViewCertificate dialog. - * + * * @param parent * Parent frame * @param title @@ -148,13 +148,13 @@ public class DViewCertificate extends JEscDialog { * @param certs * Certificate(s) to display * @param kseFrame - * Reference to main class with currently opened keystores and their contents + * Reference to main class with currently opened keystores and their contents * @param importExport * Show import button/export button/no extra button? * @throws CryptoException * A problem was encountered getting the certificates' details */ - public DViewCertificate(JFrame parent, String title, X509Certificate[] certs, KseFrame kseFrame, int importExport) + public DViewCertificate(JFrame parent, String title, X509Certificate[] certs, KseFrame kseFrame, int importExport) throws CryptoException { super(parent, title, Dialog.ModalityType.APPLICATION_MODAL); this.kseFrame = kseFrame; @@ -164,7 +164,7 @@ public DViewCertificate(JFrame parent, String title, X509Certificate[] certs, Ks /** * Creates new DViewCertificate dialog where the parent is a dialog. - * + * * @param parent * Parent dialog * @param title @@ -174,13 +174,13 @@ public DViewCertificate(JFrame parent, String title, X509Certificate[] certs, Ks * @param certs * Certificate(s) to display * @param kseFrame - * Reference to main class with currently opened keystores and their contents + * Reference to main class with currently opened keystores and their contents * @param importExport * Show import button/export button/no extra button? * @throws CryptoException * A problem was encountered getting the certificates' details */ - public DViewCertificate(JDialog parent, String title, Dialog.ModalityType modality, X509Certificate[] certs, + public DViewCertificate(JDialog parent, String title, Dialog.ModalityType modality, X509Certificate[] certs, KseFrame kseFrame, int importExport) throws CryptoException { super(parent, title, modality); this.kseFrame = kseFrame; @@ -422,7 +422,7 @@ public void actionPerformed(ActionEvent evt) { }); jpButtons = new JPanel(); - if (importExport != NONE) { + if (importExport != NONE) { jpButtons.add(jbImportExport); } jpButtons.add(jbExtensions); @@ -788,7 +788,7 @@ private void importExportPressed() { if (importExport == IMPORT) { new ImportTrustedCertificateAction(kseFrame, cert).actionPerformed(null); } else { - new ExportKeyPairCertificateChainAction(kseFrame).actionPerformed(null); + new ExportTrustedCertificateAction(kseFrame, cert).actionPerformed(null); } } @@ -803,6 +803,8 @@ private void closeDialog() { } private class X509CertificateComparator implements Comparator { + + // TODO public int compare(X509Certificate cert1, X509Certificate cert2) { // Compare certificates for equality. Where all we care about is if diff --git a/kse/src/net/sf/keystore_explorer/gui/dialogs/resources.properties b/kse/src/net/sf/keystore_explorer/gui/dialogs/resources.properties index 71994aa5d..433762025 100644 --- a/kse/src/net/sf/keystore_explorer/gui/dialogs/resources.properties +++ b/kse/src/net/sf/keystore_explorer/gui/dialogs/resources.properties @@ -327,7 +327,7 @@ DViewCertificate.jbExtensions.tooltip=Display the certificate's extensions DViewCertificate.jbPem.tooltip=Display certificate as PEM DViewCertificate.jbAsn1.tooltip=Display ASN.1 dump for certificate DViewCertificate.jbImportExport.import.tooltip=Import certificate into keystore -DViewCertificate.jbImportExport.export.tooltip=Export certificate chain +DViewCertificate.jbImportExport.export.tooltip=Export certificate to file # Icons DViewCertificate.jbViewPublicKeyDetails.image=images/viewpubkey.png