I think this is OpenSSL's mailing list and not JSSE :)
Anyway, my quick guess is probably you need to add the "-trustcacert"
option when doing the Java's keytool import.
Cheers
[EMAIL PROTECTED] wrote:
> Hi!
>
> I have the following problem in mutual authentication.
>
> Connection failed: javax.net.ssl.SSLHandshakeException:
> sun.security.validator.V
> alidatorException: No trusted certificate found
>
> At first, I created key and certification as follows.
>
> -------------------------------------
>
> 1. Create CA Authority Key using SSL
> openssl genrsa -out ca.key 1024
>
> 2. Create self-signed CA Certificate
> openssl req -new -x509 -key ca.key -out demoCA/cacert.pem
>
> 3. Create Client Keystore
> keytool -genkey -alias clientapp -keystore clientkeys
>
> 4. Create Server Keystore
> keytool -genkey -alias serverapp -keystore serverkeys
>
> 5. Export public keys from Client and Server keystores
> keytool -keystore clientkeys -certreq -alias clientapp -file clientapp.crs
> keytool -keystore serverkeys -certreq -alias serverapp -file serverapp.crs
>
> 6. Signs both public keys with CA Authority key
> openssl ca -in clientapp.crs -out clientapp.pem -keyfile ca.key
> openssl ca -in serverapp.crs -out serverapp.pem -keyfile ca.key
>
> 7. Convert signed keys to DER format
> openssl x509 -in clientapp.pem -out clientapp.der -outform DER
> openssl x509 -in serverapp.pem -out serverapp.der -outform DER
>
> 8. Import CA certificate to Client and Server keystores
> keytool -keystore clientkeys -alias systemca -import -file demoCA/cacert.pem
> keytool -keystore serverkeys -alias systemca -import -file demoCA/cacert.pem
>
> 9. Import signed key to Client keystore
> keytool -keystore clientkeys -alias clientapp -import -file clientapp.der
>
> 10. Import signed key to Serverkeystore
> keytool -keystore serverkeys -alias serverapp -import -file serverapp.der
>
> ----------------------------------------
> Then, I executed programs.
>
> Server:
>
> $ java -Djavax.net.ssl.keyStore=serverkeys
> -Djavax.net.ssl.keyStorePassword=pas
> sword CASSLServer
> SimpleSSLServer running on port 4915
>
> Client:
>
> $ keytool -import -keystore truststore/cacerts -alias trustca -file
> demoCA/cace
> rt.pem
>
> $ java
> -Djavax.net.ssl.trustStore=/cygdrive/c/eclipse-SDK-2.1.1-win32/eclipse/w
> orkspace/xacml/truststore/cacerts
> -Djavax.net.ssl.trustStorePassword=changeit C
> ACustomKeyStoreClient
> Connection failed: javax.net.ssl.SSLHandshakeException:
> sun.security.validator.V
> alidatorException: No trusted certificate found
>
> Are there something wrong with my setting?
>
>
> ----------------CASSLServer.java--------------------------
>
> import javax.net.ssl.*;
> import java.security.cert.*;
> import java.io.*;
>
> /**
> * A very simple server which accepts SSL connections, and displays
> * text sent through the SSL socket on stdout. The server requires
> * client authentication.
> * Listens on port 49152 by default, configurable with "-port" on the
> * command-line.
> * The server needs to be stopped with Ctrl-C.
> */
> public class CASSLServer extends Thread
> {
> private static final int DEFAULT_PORT=49152;
>
> private SSLServerSocketFactory serverSocketFactory;
> private int port;
>
> /**
> * main() method, called when run from the command-line. Deals with
> * command-line parameters, then starts listening for connections
> */
> public static void main(String args[])
> {
> int port=DEFAULT_PORT;
>
> // Parse command-line arguments
> boolean parseFailed=false;
> try {
> for (int i=0; i<args.length; i++) {
> String arg=args[i].trim().toUpperCase();
>
> // Only the "-port" argument is supported
> if (arg.equals("-PORT")) port=Integer.parseInt(args[++i]);
> else parseFailed=true;
> }
> }
> catch(Exception e) {
> // Something went wrong with the command-line parse.
> // A real application would issue a good error message;
> // we'll just display our usage.
> parseFailed=true;
> }
>
> if (parseFailed) {
> displayUsage();
> }
> else {
> // The command-line parse succeeded.
> // Construct a new instance of SimpleSSLServer based around the
> // default SSLServerSocketFactory and start it up.
> SSLServerSocketFactory ssf=
> (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
> CASSLServer server=new CASSLServer(ssf, port);
> server.start();
> }
> }
>
> /** Displays the command-line usage for SimpleSSLServer */
> private static void displayUsage()
> {
> System.out.println("Options:");
> System.out.println("\t-port\tport of server (default
> "+DEFAULT_PORT+")");
> }
>
>
> /**
> * Constructs a new SimpleSSLServer on the given port, using
> * the given SSLServerSocketFactory
> * @param ssf the SSLServerSocketFactory to use
> * @param port the port to listen on
> */
> public CASSLServer(SSLServerSocketFactory ssf, int port)
> {
> serverSocketFactory=ssf;
> this.port=port;
> }
>
> /**
> * SimpleSSLServer is run as a separate Thread. The run() method
> * provides the main loop for the server. It runs as an infinite
> * loop; stop with Ctrl-C.
> */
> public void run()
> {
> System.out.println("SimpleSSLServer running on port "+port);
>
> try {
> // First, create the server socket on which we'll accept
> // connection requests. We require client authentication.
> SSLServerSocket serverSocket=
> (SSLServerSocket)serverSocketFactory.createServerSocket(port);
>
> serverSocket.setNeedClientAuth(true);
>
> // Each connection is given a numeric identifier, starting at 1.
> int id=1;
>
> // Listen for connection requests. For each request fire off a new
> // thread (the InputDisplayer) which echoes incoming text from the
> // stream to stdout.
> while(true) {
> String ident=String.valueOf(id++);
>
> // Wait for a connection request.
> SSLSocket socket=(SSLSocket)serverSocket.accept();
>
> // We add in a HandshakeCompletedListener, which allows us to
> // peek at the certificate provided by the client.
> HandshakeCompletedListener hcl=new SimpleHandshakeListener(ident);
> socket.addHandshakeCompletedListener(hcl);
>
> InputStream in=socket.getInputStream();
> new InputDisplayer(ident, in);
> }
> }
> catch(IOException ioe) {
> System.out.println("SimpleSSLServer failed with following
> exception:");
> System.out.println(ioe);
> ioe.printStackTrace();
> }
> }
>
> /**
> * Utility HandshakeCompletedListener which simply displays the
> * certificate presented by the connecting peer.
> */
> class SimpleHandshakeListener implements HandshakeCompletedListener
> {
> String ident;
>
> /**
> * Constructs a SimpleHandshakeListener with the given
> * identifier.
> * @param ident Used to identify output from this Listener.
> */
> public SimpleHandshakeListener(String ident)
> {
> this.ident=ident;
> }
>
> /** Invoked upon SSL handshake completion. */
> public void handshakeCompleted(HandshakeCompletedEvent event)
> {
> // Display the peer specified in the certificate.
> try {
> X509Certificate
> cert=(X509Certificate)event.getPeerCertificates()[0];
> String peer=cert.getSubjectDN().getName();
> System.out.println(ident+": Request from "+peer);
> }
> catch (SSLPeerUnverifiedException pue) {
> System.out.println(ident+": Peer unverified");
> }
> }
> }
>
>
> /**
> * Utility thread class which simply forwards any text passed through
> * the supplied InputStream to stdout. An identifier is specified, which
> * preceeds forwarded text in stdout. InputDisplayer also logs its
> * progress to stdout.
> */
> class InputDisplayer extends Thread {
> BufferedReader reader;
> String ident;
>
> /**
> * Constructs an InputDisplayer with the given identifier, around
> * the given InputStream.
> * @param ident Used to identify all output from this InputDisplayer.
> * @param InputStream Stream of bytes, in UTF-8, to echo to stdout.
> */
> InputDisplayer(String ident, InputStream is)
> {
> this.ident=ident;
> log("New connection request");
>
> // Set up a reader to the supplied InputStream. The InputStreamReader
> // converts the raw bytes (from the InputStream) into characters, and
> // the BufferedReader splits the stream into lines for us.
> // We use UTF-8 (matching SimpleSSLClient), which should be supported
> // by the JVM. If it isn't, we'll use the JVM's default codepage which
> // is likely to be good enough.
> try {
> reader=new BufferedReader(new InputStreamReader(is, "UTF-8"));
> }
> catch (UnsupportedEncodingException uee) {
> log("Warning: JVM cannot support UTF-8. Using default instead");
> reader=new BufferedReader(new InputStreamReader(is));
> }
>
> // Mark the thread as a Daemon, and start it.
> setDaemon(true);
> start();
> }
>
> /**
> * Sits in a loop on the reader, echoing each line to the screen.
> */
> public void run()
> {
> boolean done=false;
>
> try {
> while (!done) {
> String line=reader.readLine();
> if (line!=null) display(line);
> else done=true;
> }
> log("Client disconnected");
> }
> catch(IOException ioe) {
> // Something went wrong. Log the exception and close.
> log(ioe.toString());
> log("Closing connection.");
> }
>
> try {
> reader.close();
> }
> catch(IOException ioe) {}
> }
>
> /**
> * Used to log progress.
> * @param text Text to display to stdout, preceeded by the identifier
> */
> private void log(String text)
> {
> System.out.println(ident+": "+text);
> }
>
> /**
> * Used to echo text from the InputStream.
> * @param text Text to display to stdout, preceeded by the identifier
> */
> private void display(String text)
> {
> System.out.println(ident+"> "+text);
> }
> }
> }
>
> -----------------------CASSLClient.java------------------------------
> import javax.net.ssl.*;
> import java.io.*;
>
> /**
> * A very simple client which forges an SSL connection to a remote
> * server. Text entered into stdin is forwarded to the server.
> * By default, uses 'localhost' and port 49152, although these are
> * configurable on the command-line.
> * The client needs to be stopped with Ctrl-C.
> */
> public class CASSLClient
> {
> private static final int DEFAULT_PORT=49152;
> private static final String DEFAULT_HOST="localhost";
>
> private SSLSocket socket;
> private String host=DEFAULT_HOST;
> private int port=DEFAULT_PORT;
>
> /**
> * main() method, called when run from the command-line.
> * Constructs a SimpleSSLClient object and calls runClient on
> * it. Should be overridden by subclasses to construct the
> * correct form of client object.
> */
> public static void main(String args[])
> {
> CASSLClient client=new CASSLClient();
> client.runClient();
> // client.runClient(args);
> client.close();
> }
>
> /**
> *
> */
> public void runClient() {
>
> // The command-line parse succeeded. Now connect
> using the
> // correct SSLSocketFactory.
> SSLSocketFactory ssf=getSSLSocketFactory();
> connect(ssf);
> System.out.println("Connected");
>
> // We connected successfully, now transmit text from
> stdin.
> transmit(System.in);
> }
> catch (IOException ioe) {
> // Connect failed.
> System.out.println("Connection failed: "+ioe);
> }
> catch (java.security.GeneralSecurityException gse) {
> // Connect failed.
> System.out.println("Connection failed: "+gse);
> }
>
> }
>
> /**
> * Intended to be overridden. Deals with one argument. If the
> * argument is unrecognised, can call the super method.
> * @param args Array of strings.
> * @param i array cursor.
> * @return number of successfully handled arguments, zero if an
> * error was encountered.
> */
> protected int handleCommandLineOption(String[] args, int i)
> {
> int out;
> try {
> String arg=args[i].trim().toUpperCase();
>
> // The "-port" and "-host" arguments are supported. There
> // is no super method to call if we encounter a different
> // argument.
> if (arg.equals("-PORT")) {
> port=Integer.parseInt(args[i+1]);
> out=2;
> }
> else if (arg.equals("-HOST")) {
> host=args[i+1];
> out=2;
> }
> else out=0;
> }
> catch(Exception e) {
> // Something went wrong with the command-line parse.
> out=0;
> }
>
> return out;
> }
>
> /**
> * Intended to be overridden. Provides the SSLSocketFactory to
> * be used for this client. The default implementation returns
> * the JVM's default SSLSocketFactory.
> * @return SSLSocketFactory SSLSocketFactory to use
> */
> protected SSLSocketFactory getSSLSocketFactory()
> throws IOException, java.security.GeneralSecurityException
> {
> return (SSLSocketFactory)SSLSocketFactory.getDefault();
> }
>
> /**
> * Displays the command-line usage for this client. Should be
> * overridden if getSSLSocketFactory is.
> */
> protected void displayUsage()
> {
> System.out.println("Options:");
> System.out.println("\t-host\thost of server (default '"+DEFAULT_HOST+"')
> ");
> System.out.println("\t-port\tport of server (default
> "+DEFAULT_PORT+")");
> }
>
>
> /**
> * runClient() deals with command-line parameters, and then runs
> * the client to send text from stdin to the server. Calls
> * handleCommandLineOption() and getSSLSocketFactory() to allow
> * subclasses to customize behaviour.
> * @param args command-line arguments.
> */
> public void runClient(String args[])
> {
> // Parse the command-line
> boolean parseFailed=false;
> int i=0;
> while (i<args.length && !parseFailed) {
> // We pass, to handleCommandLineOption, the entire array
> // of arguments and the position of the cursor.
> // It returns the number of successfully handled arguments,
> // or zero if an error was encountered.
> int handled=handleCommandLineOption(args, i);
> if (handled==0) parseFailed=true;
> else i+=handled;
> }
>
> if (parseFailed) {
> // Something went wrong with the command-line parse.
> // A real application would issue a good error message;
> // we'll just display our usage.
> displayUsage();
> }
> else {
> try {
> // The command-line parse succeeded. Now connect using the
> // correct SSLSocketFactory.
> SSLSocketFactory ssf=getSSLSocketFactory();
> connect(ssf);
> System.out.println("Connected");
>
> // We connected successfully, now transmit text from stdin.
> transmit(System.in);
> }
> catch (IOException ioe) {
> // Connect failed.
> System.out.println("Connection failed: "+ioe);
> }
> catch (java.security.GeneralSecurityException gse) {
> // Connect failed.
> System.out.println("Connection failed: "+gse);
> }
> }
> }
>
> /**
> * Connects to the server, using the supplied SSLSocketFactory.
> * Returns only after the SSL handshake has been completed.
> * @param sf the SocketFactory to use.
> * @exception IOException if the connect failed.
> */
> public void connect(SSLSocketFactory sf) throws IOException
> {
> socket=(SSLSocket)sf.createSocket(host, port);
>
> try {
> socket.startHandshake();
> }
> catch (IOException ioe) {
> // The handshake failed. Close the socket.
> try {
> socket.close();
> }
> catch (IOException ioe2) {
> // Ignore this; throw on the original error.
> }
> socket=null;
> throw ioe;
> }
> }
>
> /**
> * Transmits the supplied InputStream. connect() must have been
> * successfully called before calling transmit. Loops until
> * interrupted (Ctrl-C), end of the stream (Ctrl-D), or until
> * a network error is encountered.
> * @param in the InputStream to transmit. It is converted to UTF-8
> * for transmission to the server.
> */
> public void transmit(InputStream in)
> {
> try {
> // Set up a reader from the InputStream (probably stdin).
> // The InputStreamReader uses the JVM's default codepage to interpret
> // the raw bytes; the BufferedReader splits the input into lines for
> us.
> BufferedReader reader=new BufferedReader(new InputStreamReader(in));
>
> // Set up a writer to the socket. We use UTF-8 to represent text; this
> // matches the server. The JVM really should support UTF-8 - if it
> // doesn't we'll fall back to the JVM's default codepage.
> Writer writer;
> try {
> writer=new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
> }
> catch (UnsupportedEncodingException uee) {
> System.out.println("Warning: JVM cannot support UTF-8. Using default
> instead");
> writer=new OutputStreamWriter(socket.getOutputStream());
> }
>
> // Now read the input line-by-line, and send it to the socket.
> boolean done=false;
> while (!done) {
> String line=reader.readLine();
> if (line!=null) {
> writer.write(line);
> writer.write('\n');
> writer.flush();
> }
> else done=true;
> }
> }
> catch (IOException ioe) {
> // Log the error and exit
> System.out.println("Error: "+ioe);
> }
>
> // Close the socket, ignoring any errors.
> try {
> socket.close();
> }
> catch (IOException ioe) {}
> }
>
> /**
> * Disconnects from the server.
> */
> public void close()
> {
> try {
> if (socket!=null) socket.close();
> }
> catch (IOException ioe) {
> // Ignore this - there's not much we can do.
> }
> socket=null;
> }
> }
>
> ------------------CACustomKeyStoreClient.java----------------
> import javax.net.ssl.*;
> import java.io.*;
> import java.security.*;
>
> /**
> * This class demonstrates constructing and customizing the
> * KeyStore. It loads a keystore called "clientKeys" with
> * password "password" - but allows this to be altered by the
> * command-line.
> */
> class CACustomKeyStoreClient extends CASSLClient
> {
> private final String DEFAULT_KEYSTORE="clientkeys";
> private final String DEFAULT_KEYSTORE_PASSWORD="password";
>
> private String keyStore=DEFAULT_KEYSTORE;
> private String keyStorePassword=DEFAULT_KEYSTORE_PASSWORD;
>
> /**
> * Overrides main() in SimpleSSLClient to use the
> * CustomKeyStoreClient.
> */
> public static void main(String args[])
> {
> CACustomKeyStoreClient client=new CACustomKeyStoreClient();
> client.runClient();
> client.close();
> }
>
> /**
> * Overrides the version in SimpleSSLClient to handle the -ks and
> * -kspass arguments.
> * @param args Array of strings.
> * @param i array cursor.
> * @return number of successfully handled arguments, zero if an
> * error was encountered.
> */
> protected int handleCommandLineOption(String[] args, int i)
> {
> int out;
> try {
> String arg=args[i].trim().toUpperCase();
>
> // We deal with "-ks" and "-kspass" here; other strings
> // are passed up to the superclass.
> if (arg.equals("-KS")) {
> keyStore=args[i+1];
> out=2;
> }
> else if (arg.equals("-KSPASS")) {
> keyStorePassword=args[i+1];
> out=2;
> }
> else out=super.handleCommandLineOption(args,i);
> }
> catch(Exception e) {
> // Something went wrong with the command-line parse.
> out=0;
> }
>
> return out;
> }
>
> /**
> * Displays the command-line usage for this client.
> */
> protected void displayUsage()
> {
> super.displayUsage();
> System.out.println("\t-ks\tkeystore (default '"
> +DEFAULT_KEYSTORE+"', JKS format)");
> System.out.println("\t-kspass\tkeystore password (default '"
> +DEFAULT_KEYSTORE_PASSWORD+"')");
> }
>
> /**
> * Provides a SSLSocketFactory which ignores JSSE's choice of keystore,
> * and instead uses either the hard-coded filename and password, or those
> * passed in on the command-line.
> * This method calls out to getKeyManagers() to do most of the
> * grunt-work. It actally just needs to set up a SSLContext and obtain
> * the SSLSocketFactory from there.
> * @return SSLSocketFactory SSLSocketFactory to use
> */
> protected SSLSocketFactory getSSLSocketFactory()
> throws IOException, GeneralSecurityException
> {
> // Call getKeyManagers to get suitable key managers
> KeyManager[] kms=getKeyManagers();
>
> // Now construct a SSLContext using these KeyManagers. We
> // specify a null TrustManager and SecureRandom, indicating that the
> // defaults should be used.
> SSLContext context=SSLContext.getInstance("SSL");
> context.init(kms, null, null);
>
> // Finally, we get a SocketFactory, and pass it to SimpleSSLClient.
> SSLSocketFactory ssf=context.getSocketFactory();
> return ssf;
> }
>
> /**
> * Returns an array of KeyManagers, set up to use the required
> * keyStore. This is pulled out separately so that later
> * examples can call it.
> * This method does the bulk of the work of setting up the custom
> * trust managers.
> * @param trustStore the KeyStore to use. This should be in JKS format.
> * @param password the password for this KeyStore.
> * @return an array of KeyManagers set up accordingly.
> */
> protected KeyManager[] getKeyManagers()
> throws IOException, GeneralSecurityException
> {
> // First, get the default KeyManagerFactory.
> String alg=KeyManagerFactory.getDefaultAlgorithm();
> KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg);
>
> // Next, set up the KeyStore to use. We need to load the file into
> // a KeyStore instance.
> FileInputStream fis=new FileInputStream(keyStore);
> KeyStore ks=KeyStore.getInstance("jks");
> ks.load(fis, keyStorePassword.toCharArray());
> fis.close();
>
> // Now we initialise the KeyManagerFactory with this KeyStore
> kmFact.init(ks, keyStorePassword.toCharArray());
>
> // And now get the KeyManagers
> KeyManager[] kms=kmFact.getKeyManagers();
> return kms;
> }
> }
>
>
> ______________________________________________________________________
> OpenSSL Project http://www.openssl.org
> User Support Mailing List [EMAIL PROTECTED]
> Automated List Manager [EMAIL PROTECTED]
>
>
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]