Skip to Main Content

Java Security

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

jarsigner -certchain ?

shoening-OracleMay 13 2014 — edited May 19 2014

Hi,

I am trying to setup signed jar files for Java Webstart. (Using Java 1.8.0_05 on a Linux box)

In a first test - which works - I have created a 'CA Certificate' and a 'Signer Certificate. The 'Signer Certificate' is signed using the private key of the

CA Certificate.

The 'CA Certificate is stored inside a keystore named 'ca_keystore.jks' using alias 'My Personal CA'.

The 'Signer Certificate is stored inside a keystore named 'signer_keystore.jks' using alias 'Signer'

I have added the 'CA Certificate' to the cacerts file (${JRE_HOME}/lib/security/cacerts).

This way I can sign any Jar file via:

jarsign

Hi,

I am trying to setup signed jar files for Java Webstart. (Using Java 1.8.0_05 on a Linux box)

In a first test - which works - I have created a 'CA Certificate' and a 'Signer Certificate. The 'Signer Certificate' is signed using the private key of the

CA Certificate.

The 'CA Certificate is stored inside a keystore named 'ca_keystore.jks' using alias 'My Personal CA'.

The 'Signer Certificate is stored inside a keystore named 'signer_keystore.jks' using alias 'Signer'

I have added the 'CA Certificate' to the cacerts file (${JRE_HOME}/lib/security/cacerts).

This way I can sign any Jar file via:

jarsigner -tsa https://timestamp.geotrust.com/tsa -keystore signer_keystore.jks -storepass XXXXXXX my-app.jar signer

This did not produce any Warnings or Error messages.

But now to my problem:

I created another set of keypairs/certificates - this time with an intermediate CA. So I have now:

'Root CA' -------------> 'Intermediate CA' ---------------> 'Signer'

Again I have added the 'Root CA' to the cacerts file and I have a Keystore 'signer_keystore.jks' which contains the the signers keypair/certificate - but not the intermediate ca certificate and not the root ca certificate.

Additionally I have created a 'cert-chain.der' file containing the concatenated DER Encodings of the 'Signer Certificate', 'Intermediate Certificate', 'Root CA Certificate'

When I try to sign a jar using

jarsigner -tsa https://timestamp.geotrust.com/tsa -keystore signer_keystore.jks -storepass XXXXXXX -certchain cert-chain.der my-app.jar signer

I am getting a warning message 'The signer's certificate chain is not validated.'

Is there any documentation with more details on how to create the file provided as parameter for tho "-certchain" option?

Does anyone has a working Example on how to deal with a case like mine, where the trust-chain from the Leaf-Certificate to the Root Certificate contains intermediate Certificates?

Thanks in advance

Stefan

This post has been answered by shoening-Oracle on May 19 2014
Jump to Answer

Comments

kleopatra-JavaNet
no, there isn't. Some LAFs (like Nimbus f.i.) do - but the way it's done there disrespects render's responsibility

Cheers
Jeanette
802349
thanks for the info! i checked the tree highlighter code of the great Santhosh Kumar from http://jroller.com/santhosh/entry/highlight_a_node_s_descendants
and made my own solution. in case anyone needs it as well, see below. the only annoyance remaining is that i always have to click on the text of a node in order to select it. of course i'd like to click anywhere in a node's row, even on whitespace, in order to select it. does anyone know how to do this properly?

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;

public class TreeExample {

	public static Color selectedColor = new Color(115,164,209);
	public static Color selectedBorderColor = new Color(57,105,138);
	
	public static void main(String args[]) {
		
		JFrame f = new JFrame("JTree Sample");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container content = f.getContentPane();

		
		// custom tree handling
		final JTree tree = new MyTree();
		MyTreeCellRenderer renderer = new MyTreeCellRenderer();
		renderer.setBorderSelectionColor(null); // remove selection border
		renderer.setBackgroundSelectionColor( null); // remove selection background since we paint the selected row ourselves
		tree.setCellRenderer( renderer);

  	// send repaint event when node selection changes; otherwise sometimes the border remained visible although the selected node changed 
		TreeSelectionListener treeSelListener = new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent evt) {
				tree.treeDidChange();
			}
		};
		tree.addTreeSelectionListener(treeSelListener);
		
		
		// add tree to frame and show frame
		JScrollPane scrollPane = new JScrollPane(tree);
		content.add(scrollPane, BorderLayout.CENTER);
		f.setSize(400, 600);
		f.setVisible(true);
	}

	public static class MyTree extends JTree {

		protected void paintComponent(Graphics g) {

			// paint background
			g.setColor(getBackground());
			g.fillRect(0, 0, getWidth(), getHeight());

			// paint selected node's background and border
			int fromRow = getRowForPath( getSelectionPath());
			if (fromRow != -1) {
				int toRow = fromRow + 1;
				Rectangle fromBounds = getRowBounds(fromRow);
				Rectangle toBounds = getRowBounds(toRow - 1);
				if (fromBounds != null && toBounds != null) {
					g.setColor(selectedColor);
					g.fillRect(0, fromBounds.y, getWidth(), toBounds.y - fromBounds.y + toBounds.height);
					g.setColor(selectedBorderColor);
					g.drawRect(0, fromBounds.y, getWidth() - 1, toBounds.y - fromBounds.y + toBounds.height);
				}
			}

			// perform operation of superclass
			setOpaque(false); // trick not to paint background
			super.paintComponent(g);
			setOpaque(false);
		}
	}

	// trick to make renderer transparent for the unselected nodes 
	public static class MyTreeCellRenderer extends DefaultTreeCellRenderer {
		public MyTreeCellRenderer() {
			setBackgroundNonSelectionColor(null);
		}

		public Color getBackground() {
			return null;
		}
	}

}
aterai
Answer
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeExample2 extends JPanel {
  public static Color selectedColor = new Color(115,164,209);
  public static Color selectedBorderColor = new Color(57,105,138);
  private final JTree tree = new JTree() {
    @Override public void paintComponent(Graphics g) {
      g.setColor(getBackground());
      g.fillRect(0,0,getWidth(),getHeight());
      if (tree.getSelectionCount()>0) {
        for(int i: getSelectionRows()) {
          Rectangle r = getRowBounds(i);
          g.setColor(selectedColor);
          g.fillRect(0, r.y, getWidth(), r.height);
        }
      }
      super.paintComponent(g);
      if(getSelectionPath()!=null) {
        Rectangle r = tree.getRowBounds(getRowForPath(getSelectionPath()));
        g.setColor(selectedBorderColor);
        g.drawRect(0, r.y, getWidth()-1, r.height-1);
      }
    }
  };
  public JComponent makeUI() {
    tree.setUI(new javax.swing.plaf.metal.MetalTreeUI() {
      @Override public Rectangle getPathBounds(JTree tree, TreePath path) {
        if(tree != null && treeState != null) {
          return getPathBounds(path, tree.getInsets(), new Rectangle());
        }
        return null;
      }
      private Rectangle getPathBounds( //copied from BasicTreeUI
          TreePath path, Insets insets,  Rectangle bounds) {
        bounds = treeState.getBounds(path, bounds);
        if (bounds != null) {
          bounds.width = tree.getWidth();
          bounds.y += insets.top;
        }
        return bounds;
      }
    });
    tree.setOpaque(false);
    final TreeCellRenderer renderer = tree.getCellRenderer();
    ((JComponent)renderer).setOpaque(true);
    tree.setCellRenderer(new TreeCellRenderer() {
      @Override public Component getTreeCellRendererComponent(
        JTree tree, Object value, boolean selected, boolean expanded,
      boolean leaf, int row, boolean hasFocus) {
        JLabel l = (JLabel)renderer.getTreeCellRendererComponent(
            tree, value, selected, expanded, leaf, row, hasFocus);
        l.setBackground(selected?selectedColor:tree.getBackground());
        return l;
      }
    });
    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(tree));
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() { createAndShowGUI(); }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new TreeExample2().makeUI());
    f.setSize(320,240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
Marked as Answer by 802349 · Sep 27 2020
802349
thank you very much, aterai! your help is very appreciated :) my application has different look and feel, so i can't bind myself to metal look and feel. your solution however is great, i'll see if i can adapt it to be LAF-independent.

in the meantime i also came up with a solution as well. basically i add a mouselistener and use the tree's getClosestRowForLocation method:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;

public class TreeExample2 {

	public static Color selectedColor = new Color(115,164,209);
	public static Color selectedBorderColor = new Color(57,105,138);
	
	public static void main(String args[]) {
		
		JFrame f = new JFrame("JTree Sample");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container content = f.getContentPane();

		
		// custom tree handling
		final JTree tree = new MyTree();
		MyTreeCellRenderer renderer = new MyTreeCellRenderer();
		renderer.setBorderSelectionColor(null); // remove selection border
		renderer.setBackgroundSelectionColor( null); // remove selection background since we paint the selected row ourselves
		tree.setCellRenderer( renderer);

  	// send repaint event when node selection changes; otherwise sometimes the border remained visible although the selected node changed 
		TreeSelectionListener treeSelListener = new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent evt) {
				tree.treeDidChange();
			}
		};
		tree.addTreeSelectionListener(treeSelListener);
		
		// handle mouse clicks outside of the node's label
		// mouse begin ----------------------------------------------------------------
		MouseListener ml = new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				int selRow = tree.getClosestRowForLocation( e.getX(), e.getY());
				if( selRow != -1) {
					Rectangle bounds = tree.getRowBounds( selRow);
					boolean outside = e.getX() < bounds.x || e.getX() > bounds.x + bounds.width || e.getY() < bounds.y || e.getY() >= bounds.y + bounds.height;
					if( outside) {
						
						tree.setSelectionRow(selRow);
						System.out.println( "manual selection: " + selRow);
						
						// handle doubleclick
						if( e.getClickCount() == 2) {
							if( tree.isCollapsed(selRow))
								tree.expandRow( selRow);
							else if( tree.isExpanded( selRow))
								tree.collapseRow( selRow);
						}
						
					} else {
						System.out.println( "auto selection: " + selRow);
					}
				}
			}
		};
		tree.addMouseListener(ml);		
		// mouse end ----------------------------------------------------------------
		
		// add tree to frame and show frame
		JScrollPane scrollPane = new JScrollPane(tree);
		content.add(scrollPane, BorderLayout.CENTER);
		f.setSize(400, 600);
		f.setVisible(true);
	}

	public static class MyTree extends JTree {

		protected void paintComponent(Graphics g) {

			// paint background
			g.setColor(getBackground());
			g.fillRect(0, 0, getWidth(), getHeight());

			// paint selected node's background and border
			int fromRow = getRowForPath( getSelectionPath());
			if (fromRow != -1) {
				int toRow = fromRow + 1;
				Rectangle fromBounds = getRowBounds(fromRow);
				Rectangle toBounds = getRowBounds(toRow - 1);
				if (fromBounds != null && toBounds != null) {
					g.setColor(selectedColor);
					g.fillRect(0, fromBounds.y, getWidth(), toBounds.y - fromBounds.y + toBounds.height);
					g.setColor(selectedBorderColor);
					g.drawRect(0, fromBounds.y, getWidth() - 1, toBounds.y - fromBounds.y + toBounds.height);
				}
			}

			// perform operation of superclass
			setOpaque(false); // trick not to paint background
			super.paintComponent(g);
			setOpaque(false);
		}
	}

	// trick to make renderer transparent for the unselected nodes 
	public static class MyTreeCellRenderer extends DefaultTreeCellRenderer {
		public MyTreeCellRenderer() {
			setBackgroundNonSelectionColor(null);
		}

		public Color getBackground() {
			return null;
		}
	}

}
1 - 4
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Jun 16 2014
Added on May 13 2014
1 comment
2,399 views