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]

Reply via email to