http://demo.webpki.org/mozkeygen

The 230 line on-line CA service is as follows:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.security.SecureRandom;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.cert.X509Certificate;
import java.security.KeyStore;
import java.security.Signature;

import java.security.interfaces.RSAPublicKey;

import java.security.spec.RSAPublicKeySpec;

import java.util.GregorianCalendar;
import java.util.Date;

import java.math.BigInteger;

import org.webpki.util.Base64;

import org.webpki.asn1.BaseASN1Object;
import org.webpki.asn1.ASN1Sequence;
import org.webpki.asn1.ASN1BitString;
import org.webpki.asn1.DerDecoder;
import org.webpki.asn1.ParseUtil;

import org.webpki.asn1.cert.DistinguishedName;

import org.webpki.crypto.AsymEncryptionAlgorithms;
import org.webpki.crypto.SignatureAlgorithms;
import org.webpki.crypto.AsymKeySignerInterface;
import org.webpki.crypto.CertificateExtensions;
import org.webpki.crypto.KeyUsageBits;

import org.webpki.crypto.test.DemoKeyStore;

import org.webpki.ca.CertSpec;
import org.webpki.ca.CA;


@SuppressWarnings("serial")
public class mozkeygen extends HttpServlet
  {
    static final String SUBJECT_DN = "CN=Just Me,C=US";

    class CASignature implements AsymKeySignerInterface
      {
        KeyStore ks;

        CASignature () throws IOException
          {
            ks = DemoKeyStore.getSubCAKeyStore ();
          }

        public byte[] signData (byte[] data, SignatureAlgorithms sign_alg) 
throws IOException, GeneralSecurityException
          {
            Signature s = Signature.getInstance (sign_alg.getJCEName ());
            s.initSign ((PrivateKey)ks.getKey ("mykey", 
DemoKeyStore.getSignerPassword ().toCharArray ()));
            s.update (data);
            return s.sign ();
          }

        public PublicKey getPublicKey () throws IOException, 
GeneralSecurityException
          {
            return ks.getCertificate ("mykey").getPublicKey ();
          }
      }

    void print (HttpServletRequest request, HttpServletResponse response, 
boolean error) throws IOException, ServletException
      {
        StringBuffer s = new StringBuffer ();
        s.append ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">" +
                  "<html><head><title>Mozilla Firefox key generation 
demo</title>" +
                  "<style type=\"text/css\">html, body 
{margin:0px;padding:0px;height:100%}" +
                  "body 
{font-size:8pt;color:#000000;font-family:verdana,arial;background-color:white}" 
+
                  "h2 
{font-weight:bold;font-size:12pt;color:#000000;font-family:arial,verdana,helvetica}"
 +
                  "h3 
{font-weight:bold;font-size:11pt;color:#000000;font-family:arial,verdana,helvetica}"
 +
                  "a:link 
{font-weight:bold;font-size:8pt;color:blue;font-family:arial,verdana;text-decoration:none}"
 +
                  "a:visited 
{font-weight:bold;font-size:8pt;color:blue;font-family:arial,verdana;text-decoration:none}"
 +
                  "a:active 
{font-weight:bold;font-size:8pt;color:blue;font-family:arial,verdana}" +
                  "input {font-weight:normal; 
font-size:8pt;font-family:verdana,arial}" +
                  "td {font-size:8pt;font-family:verdana,arial}" +
                  ".smalltext {font-size:6pt;font-family:verdana,arial}" +
                  "button 
{font-weight:normal;font-size:8pt;font-family:verdana,arial;padding-top:2px;padding-bottom:2px}"
 +
                  ".headline 
{font-weight:bolder;font-size:11pt;font-family:arial,verdana}" +
                  "</style><script language=\"javascript\">\n" +
                  "function doit ()\n" +
                  "  {\n" +
                  "    if (window.crypto == null || 
window.crypto.generateCRMFRequest == null)\n" +
                  "      {\n" +
                  "        alert ('This doesn\\'t appear to be a Mozilla 
Firefox browser...');\n" +
                  "      }\n" +
                  "    else\n" +
                  "      {\n" +
                  "        var crmfObject = window.crypto.generateCRMFRequest 
('CN=Just me', 'anythinggoes', 'somethingelse', " +
                  "null, '', 1024, null, 'rsa-dual-use');\n" +
                  "        document.shoot.request.value = 
crmfObject.request;\n" +
                  "        document.shoot.submit ();\n" +
                  "      }\n" +
                  "  }\n" +
                  "</script></head><body><table cellpadding=\"0\" 
cellspacing=\"0\" width=\"100%\" height=\"100%\">" +
                  "<tr><td align=\"center\" valign=\"middle\"><table 
width=\"450\"><form method=\"POST\" name=\"shoot\" action=\"").
          append (request.getRequestURL ().toString ()).
          append ("\"><input type=\"hidden\" name=\"request\" value=\"hu\">" +
                  "<tr><td class=\"headline\" align=\"center\">Mozilla Firefox 
Key-Generation Demo</td></tr>" +
                  "<tr><td>&nbsp;</td></tr>");
        if (error)
          {
            s.append ("<tr><td align=\"center\"><font color=\"red\"><b>There 
was some kind of
error...<br>&nbsp;</b></font></td></tr>");
          }
        s.append ("<tr><td align=\"left\">This web-application holds a 
minimalistic demo "+
                  "showing how you with one click on button can create a 
key-pair as well as " +
                  "getting the public key certified by a CA and then installed 
in the browser key-store.&nbsp; " +
                  "The demo uses Mozilla's proprietary 
<code>generateCRMFRequest()</code> JavaScript function.&nbsp; "+
                  "Other browsers have similar (but different) methods for 
performing such tasks.</td></tr>" +
                  "<tr><td height=\"4\"></td></tr>" +
                  "<tr><td align=\"left\">The subject DN of the issued 
certificate will be &quot;" + SUBJECT_DN +
"&quot;.</td></tr>" +
                  "<tr><td height=\"4\"></td></tr>" +
                  "<tr><td align=\"left\">Note: <i>If you have multiple 
cryptographic providers installed, you should select the one
named " +
                  "&quot;Software Security Device&quot; (you will be 
prompted)</i>.</td></tr>" +
                  "<tr><td>&nbsp;</td></tr>" +
                  "<tr><td align=\"center\"><input type=\"button\" value=\"Give 
me a certificate please!\"
onclick=\"doit()\"></td></tr>" +
                  "<tr><td height=\"20\"></td></tr>" +
                  "<tr><td align=\"left\">After successfully obtaining a 
certificate you may immediately try it out at:<br>" +
                  "<a 
href=\"https://www.apache-ssl.org/cgi/cert-export\";>https://www.apache-ssl.org/cgi/cert-export</a></td></tr>"
+
                  "</td></tr></table></td></tr></form></table></body></html>");
        response.setContentType ("text/html; charset=utf-8");
        response.setHeader ("Pragma", "No-Cache");
        response.setDateHeader ("EXPIRES", -1);
        response.getOutputStream ().print (s.toString ());
      }
    public void doGet (HttpServletRequest request, HttpServletResponse 
response) throws IOException, ServletException
      {
        print (request, response, false);
      }


    public void doPost (HttpServletRequest request, HttpServletResponse 
response) throws IOException, ServletException
      {
        String crmf64 = request.getParameter ("request");
        if (crmf64 == null || crmf64.startsWith ("error:") || 
!crmf64.startsWith ("MII"))
          {
            print (request, response, true);
            return;
          }
        byte[] crmf = new Base64 ().getBinaryFromBase64String (crmf64);
        ASN1Sequence o = ParseUtil.sequence (ParseUtil.sequence 
(ParseUtil.sequence (ParseUtil.sequence (DerDecoder.decode
(crmf)).get (0)).get (0)).get (1));
        PublicKey pub_key = null;
        KeyUsageBits[] key_usage = null;
        try
          {
            for (int i = 0; i < o.size (); i++)
              {
                if (ParseUtil.isCompositeContext (o.get (i), 6))
                  {
                    BaseASN1Object pub_key_cc = ParseUtil.compositeContext 
(o.get (i), 6, 2);
                    ParseUtil.seqOIDNull (pub_key_cc.get (0), 
AsymEncryptionAlgorithms.RSA_PKCS_1.getOID ());
                    ASN1Sequence pub_key_asn1 = ParseUtil.sequence 
(DerDecoder.decode (ParseUtil.bitstring (pub_key_cc.get (1))));
                    pub_key = KeyFactory.getInstance ("RSA").generatePublic (
                            new RSAPublicKeySpec (ParseUtil.integer 
(pub_key_asn1.get (0)).value (),
                                                  ParseUtil.integer 
(pub_key_asn1.get (1)).value ()));
                    break;
                  }
              }
            if (pub_key == null)
              {
                throw new IOException ("No public key found!");
              }
            for (int i = 0; i < o.size (); i++)
              {
                if (ParseUtil.isCompositeContext (o.get (i), 9))
                  {
                    ASN1Sequence key_usage_asn1 = ParseUtil.sequence 
(ParseUtil.compositeContext (o.get (i), 9, 1).get (0), 3);
                    ParseUtil.oid (key_usage_asn1.get (0), 
CertificateExtensions.KEY_USAGE.getOID ());
                    ASN1BitString ku = (ASN1BitString) DerDecoder.decode 
(ParseUtil.octet (key_usage_asn1.get (2)));
                    byte[] value = ku.value ();
                    if (value.length != 1 || (value[0] & 0xFF) != 0xE0)
                      {
                        throw new IOException ("Unexpected key usage!");
                      }
                    key_usage = new KeyUsageBits[] 
{KeyUsageBits.digitalSignature,
                                                    KeyUsageBits.nonRepudiation,
                                                    
KeyUsageBits.keyEncipherment};
                    break;
                  }
              }
            if (key_usage == null)
              {
                throw new IOException ("No key usage found!");
              }
            CertSpec cert_spec = new CertSpec ();
            for (KeyUsageBits kub : key_usage)
              {
                cert_spec.setKeyUsageBit (kub);
              }
            cert_spec.setEndEntityConstraint ();
            cert_spec.setSubject (SUBJECT_DN);

            GregorianCalendar start = new GregorianCalendar ();
            start.set (GregorianCalendar.DAY_OF_YEAR, 1);
            start.set (GregorianCalendar.HOUR_OF_DAY, 0);
            start.set (GregorianCalendar.HOUR, 0);
            start.set (GregorianCalendar.SECOND, 0);
            start.set (GregorianCalendar.MINUTE, 0);
            GregorianCalendar end = (GregorianCalendar) start.clone ();
            end.set (GregorianCalendar.YEAR, end.get (GregorianCalendar.YEAR) + 
5);
            X509Certificate signer_cert =
                new CA ().createCert (cert_spec,
                                      DistinguishedName.subjectDN 
((X509Certificate) DemoKeyStore.getSubCAKeyStore ().getCertificate
("mykey")),
                                      new BigInteger (String.valueOf (new Date 
().getTime ())),
                                      start.getTime (), end.getTime (),
                                      SignatureAlgorithms.RSA_SHA1,
                                      new CASignature (),
                                      pub_key);
            response.setContentType ("application/x-x509-user-cert");
            response.setHeader ("Pragma", "No-Cache");
            response.setDateHeader ("EXPIRES", -1);
            response.getOutputStream ().write (signer_cert.getEncoded ());
          }
        catch (GeneralSecurityException gse)
          {
            throw new IOException (gse.getMessage ());
          }
      }
  }

_______________________________________________
dev-tech-crypto mailing list
dev-tech-crypto@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-crypto

Reply via email to