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!

Tomcat, servlet, cacerts, client authentication and Thawte...

843811Aug 14 2001 — edited Dec 19 2001

Hello all,

the steps and code samples below (well known to you) work fine for a VeriSign Personal Digital Id trial and a GlobalSign PersonalSign demo certificate. However:

1) how can I make Tomcat or JSSE use both my default keystore and the cacerts file?

The VeriSign class 1 root is in this cacerts file, but still I need to import the very same root into my own keystore to accept the client certificate. Also, importing the GlobalSign root into cacerts does not help me; instead I am required to import it into my default keystore.

I know I can set the keystore parameter in the Tomcat server.xml -- but that does not feel right... When I import a cert using "keytool -trustcacerts" then I get "Certificate already exists in system-wide CA keystore under alias <verisignclass1ca> Do you still want to add it to your own keystore?" This gives me the feeling that the system knows where to find the cacerts file, but Tomcat somehow does not use it...

2) anyone used Thawte Personal Freemail with Tomcat?

Even when I import the Thawte root certificate into my own keystore, a Thawte Personal Freemail cert is never accepted. In Internet Explorer, although having three certificates installed, the popup dialog that prompts me to choose one only shows the VeriSign and GlobalSign things. When using "TOMCAT_OPTS=-Djavax.net.debug=all" I see that Tomcat "proposes" all three roots to the client browser:
  *** CertificateRequest
  Cert Types: DSS, RSA,
  Cert Authorities:
  <CN=GlobalSign Root CA, OU=Root CA,
     O=GlobalSign nv-sa, C=BE>
  <OU=Class 1 Public Primary Certification Authority,
     O="VeriSign, Inc.", C=US>
  <EmailAddress=personal-freemail@thawte.com,
     CN=Thawte Personal Freemail CA,
     OU=Certification Services Division,
     O=Thawte Consulting, L=Cape Town,
     ST=Western Cape, C=ZA>
  *** ServerHelloDone
All details below.
Thanks,
Arjan.

- JDK 1.4 beta. I also have 1.3 installed; I did not try 1.3 with the JSSE extension available at http://java.sun.com/products/jsse/index-102.html
- JAVA_HOME and PATH are set allright.
- Tomcat 3.2.1

Steps taken:

VeriSign
- free trial at http://www.verisign.com/client/enrollment
- export the VeriSign root certificate from the global CA certificates. The password defaults to changeit
- import the exported root into the default key store
  cd /jdk1.4/jre/lib/security
  keytool -export -keystore cacerts -alias verisignclass1ca -file myverisignroot.cer
  keytool -import -alias myverisignroot -trustcacerts -file myverisignroot.cer
Above, the -trustcacerts is only added to show you the warning I mentioned above...

GlobalSign
- free trial at http://www.globalsign.com/secure_demo.cfm
- get the root certificate at http://secure.globalsign.net/en/trust
- import the root certificate into the default keystore
  keytool -import -alias myglobalsignroot -file root.cacert
Thawte
- free certificate at http://thawte.com/getinfo/products/personal
- the Personal Freemail root certificate at http://www.thawte.com/certs/trustmap.html
- import the Personal Freemail root certificate into the default keystore
  keytool -import -alias mythawteroot -file persfree.crt
Tomcat
- uncomment the SSL Connector section in server.xml, except for keystore and keypass (the password is still the default, being changeit)
- to the very same Connector section, add
  <Parameter name="clientAuth" value="true"/>
- create a security certificate, as mentioned in server.xml as well. When using JDK 1.4, one does not need to set the classpath or change java.security. So:
  keytool -genkey -alias tomcat -validity 180 -keyalg RSA
- to see debug info:
  set TOMCAT_OPTS=-Djavax.net.debug=all
- make sure the VeriSign etc. roots are imported
- restart Tomcat
- connect to the servlet at port 8443, using https. You will see security warnings because your browser does not know the Tomcat certificate.

Servlet
Finally the code, as you may know it:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

// For Tomcat: javax.security, not java.security
import javax.security.cert.X509Certificate;
import javax.security.cert.Certificate;
import java.security.Principal;

// JSSE classes
import javax.net.*;
import javax.net.ssl.*;

public class sslTest extends HttpServlet
{
  private static final String CONTENT_TYPE = "text/html";

  public void init(ServletConfig config) throws ServletException
  {
    super.init(config);
  }

  private void printCert(PrintWriter pw, Object obj)
  {
    if(obj instanceof Certificate)
    {
      pw.println("<>---------------------------------------<>");
      if(obj instanceof X509Certificate)
      {
        X509Certificate cert = (X509Certificate)obj;
        Principal principal = cert.getIssuerDN();
        pw.println("  Principal Name : " + principal.getName());
        pw.println("  Version        : " + cert.getVersion());
        pw.println("  Serial Number  : " + cert.getSerialNumber());
        pw.println("  Issue DN       : " + cert.getIssuerDN());
        pw.println("  Subject DN     : " + cert.getSubjectDN());
        pw.println("  Not Before     : " + cert.getNotBefore());
        pw.println("  Not After      : " + cert.getNotAfter());
        pw.println("<>---------------------------------------<>");
        pw.println(cert.toString());
      }
      else
      {
        Certificate cert = (Certificate)obj;
        pw.println(cert.toString());
      }
    }
  }

  private void printCertificateDetails(String attributeName,
    HttpServletRequest req, PrintWriter pw)
  {
    Object obj=req.getAttribute(attributeName);
    if(obj instanceof Certificate[])
    {
      if(obj instanceof X509Certificate[])
        pw.println("<h1>Client X509Certificate Chain</h1>");
      else
        pw.println("<h1>Client Certificate Chain</h1>");
      Certificate[] array = (Certificate[])obj;
      for (int x=0; x < array.length; x++)
        printCert(pw, array[x]);

    }
    else if(obj instanceof Certificate)
    {
      if(obj instanceof X509Certificate)
        pw.println("<h1>Client X509Certificate</h1>");
      else
        pw.println("<h1>Client Certificate</h1>");
      printCert(pw, obj);
    }
    else
    {
      if (obj != null)
      {
        pw.println("Client Certificate Attribute "
          + attributeName
          + ", type \""
          + obj.getClass().getName()
          + "\":\n" + obj);
      }
      else
        pw.println (attributeName + " attribute not set");
    }
  }

  /**Process the HTTP Get request*/
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    PrintWriter pw = resp.getWriter();
    pw.println("<html><head><title>SSL Details</title></head><body><pre>");

    if (req.isSecure())
      pw.println("Got a secure connection.");
    else
      pw.println("This connection is not secure.");

    pw.println("IP address: " + req.getRemoteAddr());
    pw.println("User: " + req.getRemoteUser());
    pw.println("Subject: " + req.getHeader("CERT_SUBJECT")); // null for Tomcat
    pw.println("Issuer: " + req.getHeader("CERT_ISSUER"));   // null for Tomcat

    pw.println("\nAvailable attributes:");
    Enumeration attributeNames = req.getAttributeNames();
    while(attributeNames.hasMoreElements())
      pw.println("  " + attributeNames.nextElement().toString());
    pw.println("\n");

    Object obj;
    obj = req.getAttribute("javax.net.ssl.cipher_suite");
    if(obj instanceof String)
      pw.println("Cipher Suite: " + obj);
    else
    {
      if(obj instanceof String[])
      {
        pw.print("Cipher Suite: { ");
        String[] otherArray= (String[])obj;
        for (int x=0; x<otherArray.length; x++)
          pw.print(otherArray[x].toString() + " ");
        pw.println("}");
      }
      else
      {
        if (obj != null)
        {
          pw.println("SSL Session Attribute javax.net.ssl.cipher_suite, type \""
            + obj.getClass().getName() + "\":\n" + obj.toString() );
        }
        else
          pw.println ("javax.net.ssl.cipher_suite attribute not set");
      }
    }

    obj = req.getAttribute("javax.net.ssl.session");
    if(obj instanceof SSLSession)
    {
      pw.println("SSL session:");
      SSLSession session = (SSLSession)obj;
      pw.println("Cipher Suite: " + session.getCipherSuite());
      pw.println("Peer Host: " + session.getPeerHost());
      pw.println("ID: " + new String(session.getId()));
    }
    else
    {
      if (obj != null)
        pw.println("SSL Session Attribute javax.net.ssl.session, type \""
          + obj.getClass().getName() + "\":\n" + obj);
      else
        pw.println ("javax.net.ssl.session attribute not set");
    }

    // JSSE recommends �javax.net.ssl.peer_certificates� as the attribute name.
    // However, some web servers do not support these generic names. Like the
    // "javax.net.ssl.peer_certificates" is said to work for WebSphere 3.5 but
    // not for Tomcat 3.2.1.
    // "The javax.security.cert.X509Certificate class is similar to the newer
    // java.security.cert.X509Certificate. New applications should use the newer
    // java.security version". However, Tomcat does not support that:

    printCertificateDetails("javax.net.ssl.peer_certificates", req, pw);
    printCertificateDetails("javax.servlet.request.X509Certificate", req, pw);
    printCertificateDetails("tomcat.request.X509CertificateChain", req, pw);

    pw.println("</pre></body></html>");
  }

  /**Clean up resources*/
  public void destroy()
  {
  }
}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jan 16 2002
Added on Aug 14 2001
6 comments
628 views