Christopher Meyer

About Christopher Meyer

Chris works as a researcher and is eagerly looking for bugs in SSL/TLS, the Java platform and various applications. In addition, he is primarily interested in secure coding and exploiting coding mistakes.

Browser-based Key Generation and interaction with the Browser’s Key/Certificate Store

Imagine the following scenario:
You need to get a key (in the asymmetric case the user’s public key) from a user visiting your website and want the browser to remember the private part without bothering the user with lengthy import procedures. To be honest, in practice you don’t even want the user to deal with cryptographic details – details that many users are not able to know and do not know anything about it rightly. It should simply work and in the best case the user shouldn’t even notice that crypto is doing it’s magic!
Imagine for example an enterprise-wide Certification Authority where employees can apply for certificates or renew existing ones which are required to log on to the corporate webmail system. This is not part of the employee’s primary tasks, so the process has to be simple, quick and without the need to read any
 
documentation.Thank god – or in this case Netscape – HTML ships, since HTML 5 even browser independent, as part of the official standards, with a tag dedicated to key generation: <KeyGen />. To put it in a nutshell, the tag can force a user’s browser to create an asymmetric key pair, sign the corresponding public key and a server provided challenge and finally send it back to the server (more precisely to the location defined in the form action attribute).  The private key is automatically encrypted and stored in the browser’s key store. The format used for public key, challenge and signature encapsulation is called SPKAC. If the server responds with a X.509 certificate the certificate is directly linked to the private key and stored in the browser’s certificate store.
 
As a result, the browser is now in possession of a server supplied (maybe newly created)  certificate and the corresponding private key. And all of this with a single, simple click on the submit button. (Yeah, maybe the user should also add some details into form fields…)And here is how to do this in Java. For the sake of simplicity we will use a quick and dirty solution on server side, by directly registering as a Servlet.

At first, we will start with the initial website which presents a form where some details of the certificate requester have to be entered. Please note that these form fields are NOT protected by the signature with the newly generated private key! This signature only protects the public key and the challenge which in this case is – for the sake of simplicity – hard coded, but has to be a fresh value chosen by the server in a real world scenario. Hence, it is essential to protect both: the delivery of the website including the form (it contains security critical values, the challenge, the form action, … which must be integrity protected) and the transfer of the data back to the server. Once again, if you fail to protect the communication and ensure at least the security goal integrity, an attacker may break your whole security concept!

<form action="CreateCertificate" method="POST">
<table>
       <tbody>
                <tr>
                    <td>Country name</td>
                    <td>C</td>
                    <td><input name="c" type="text" value="" /></td>
                </tr>
                <tr>
                    <td>Common name</td>
                    <td>CN</td>
                    <td><input name="cn" type="text" value="" /></td>
                </tr>
                <tr>
                    <td>Organizational unit</td>
                    <td>OU</td> 
                    <td><input name="ou" type="text" value="" /></td>
                </tr>
                <tr>
                    <td>Organization</td>
                    <td>O</td>
                    <td><input name="o" type="text" value="" /></td>
                </tr>
                <tr>
                    <td></td>
                    <td><keygen challenge="replaceMe" keyparams="2048" keytype="rsa" 
                      name="newSPKAC"></keygen></td>
                    <td><input type="submit" value="Generate!" /></td>
                </tr>
       </tbody>
</table>
</form>

On server side it is necessary to register a processing class for the form action target. This is done in your web.xml configuration file.

<web-app version="3.0" xmlns:xsi="..." xmlns="..." xsi:schemalocation="...">
    <servlet>
        <servlet-name>CreateCertificate</servlet-name>
        <servlet-class>
            com.blogspot.armoredbarista.examples.certificates.CreateCertificate
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CreateCertificate</servlet-name>
        <url-pattern>/CreateCertificate</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

This causes any call to  the path /CreateCertificate to be handled by the CreateCertificate class. The CreateCertificate class in turn, does what we expect from the name: it creates a certificate including the received public key and the requester’s details. The public key and the challenge are included in the SPKAC structure, created by the KeyGen tag (which in this case is identified by the name newSPKAC).

public class CreateCertificate extends HttpServlet {
    /**
     * Processes requests for both HTTP GET and POST methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(final HttpServletRequest request,
            final HttpServletResponse response)
            throws ServletException, IOException {

        OutputStream out = response.getOutputStream();
        byte[] content = "An error occured".getBytes("UTF-8");
        try {
            String c = request.getParameter("c");
            String cn = request.getParameter("cn");
            String o = request.getParameter("o");
            String ou = request.getParameter("ou");
            String newSPKAC = request.getParameter("newSPKAC");

            X509Certificate cert = createCertificate(c, cn, ou, o, newSPKAC);
            content = cert.getEncoded();

            response.setContentType("application/x-x509-user-cert");
            response.setHeader("Pragma", "No-Cache");
            response.setDateHeader("EXPIRES", -1);
        } catch (...) {
          // error processing
        } finally {
            out.write(content);
            out.flush();
            out.close();
        }
    }

    /**
     * Handles the HTTP
     * GET method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(final HttpServletRequest request,
            final HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * POST method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(final HttpServletRequest request,
            final HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}

The ContentType used for the response is in this case application/x-x509-user-cert.

And that’s all. After the user has entered his details and clicked on the button, he should find a new certificate in the browser’s certificate store:
 

 

 

A final word on the fiddly disassembling of SPKAC: BouncyCastle may help you fighting the ASN.1 and DER beast!
 

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

One Response to "Browser-based Key Generation and interaction with the Browser’s Key/Certificate Store"

  1. rohit says:

    hi
    can you please me how to resolve this line
    createCertificate(c, cn, ou, o, newSPKAC);
    createCertificate method not find.

    thank you.

Leave a Reply


8 + = fourteen



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close