com.delcyon.capo.crypto.CertificateRequestProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.delcyon.capo.crypto.CertificateRequestProcessor.java

Source

/**
Copyright (C) 2012  Delcyon, Inc.
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.delcyon.capo.crypto;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;
import java.util.logging.Level;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DHParameterSpec;
import javax.xml.bind.DatatypeConverter;

import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.delcyon.capo.CapoApplication;
import com.delcyon.capo.Configuration;
import com.delcyon.capo.Configuration.PREFERENCE;
import com.delcyon.capo.controller.server.ControllerProcessingException;
import com.delcyon.capo.protocol.server.AbstractClientRequestProcessor;
import com.delcyon.capo.protocol.server.ClientRequest;
import com.delcyon.capo.protocol.server.ClientRequestProcessor;
import com.delcyon.capo.protocol.server.ClientRequestProcessorProvider;
import com.delcyon.capo.protocol.server.ClientRequestXMLProcessor;
import com.delcyon.capo.server.CapoServer;
import com.delcyon.capo.server.CapoServer.Preferences;
import com.delcyon.capo.xml.XPath;
import com.delcyon.capo.xml.cdom.CNode;

/**
 * @author jeremiah
 *
 */
@ClientRequestProcessorProvider(name = "CertificateRequest")
public class CertificateRequestProcessor extends AbstractClientRequestProcessor implements ClientRequestProcessor {

    private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;

    private String sessionID = null;

    @Override
    public String getSessionId() {
        return sessionID;
    }

    @Override
    public void init(ClientRequestXMLProcessor clientRequestXMLProcessor, String sessionID,
            HashMap<String, String> sessionHashMap, String requestName) throws Exception {
        this.sessionID = sessionID;
    }

    @Override
    public void process(ClientRequest clientRequest) throws Exception {

        String type = XPath.selectSingleNodeValue(clientRequest.getRequestDocument().getDocumentElement(),
                "//CertificateRequest/@" + CertificateRequest.Attributes.TYPE);

        if (type == null || type.trim().isEmpty()) {
            throw new ControllerProcessingException("CertificateRequest missing type attribute",
                    clientRequest.getRequestDocument());
        } else {

            Element certificateRequestElement = (Element) XPath.selectSingleNode(
                    clientRequest.getRequestDocument().getDocumentElement(), "//CertificateRequest");
            String publicKeyString = XPath.selectSingleNodeValue(
                    clientRequest.getRequestDocument().getDocumentElement(),
                    "//CertificateRequest/@" + CertificateRequest.Attributes.CLIENT_PUBLIC_KEY);
            String dhGeneratorString = XPath.selectSingleNodeValue(
                    clientRequest.getRequestDocument().getDocumentElement(),
                    "//CertificateRequest/@" + CertificateRequest.Attributes.DH_GENERATOR);
            String dhLengthString = XPath.selectSingleNodeValue(
                    clientRequest.getRequestDocument().getDocumentElement(),
                    "//CertificateRequest/@" + CertificateRequest.Attributes.DH_LENGTH);
            String dhPrimeString = XPath.selectSingleNodeValue(
                    clientRequest.getRequestDocument().getDocumentElement(),
                    "//CertificateRequest/@" + CertificateRequest.Attributes.DH_PRIME);
            String clientID = XPath.selectSingleNodeValue(clientRequest.getRequestDocument().getDocumentElement(),
                    "//CertificateRequest/@" + CertificateRequest.Attributes.CLIENT_ID);

            //process clientID
            //check to see if client ID is a valid client id, if not, we need to create a new one
            if (clientID == null || clientID.matches("capo\\.client\\.0")
                    || clientID.matches("capo\\.client\\.\\d+") == false) {
                clientID = "capo.client." + CapoApplication.getDataManager().nextValue("client_id_sequence") + "";
            }

            //create parameter specs 
            BigInteger dhParameterSpecGenerator = new BigInteger(dhGeneratorString, 16);
            BigInteger dhParameterSpecPrime = new BigInteger(dhPrimeString, 16);
            int dhParameterSpecLength = Integer.parseInt(dhLengthString);

            //on remote generate a key pair using original specs
            KeyPairGenerator keyPairGenerator2 = KeyPairGenerator.getInstance("DH");
            DHParameterSpec dhParameterSpec2 = new DHParameterSpec(dhParameterSpecPrime, dhParameterSpecGenerator,
                    dhParameterSpecLength);
            keyPairGenerator2.initialize(dhParameterSpec2);

            //generate remote key pair
            KeyPair keyPair2 = keyPairGenerator2.generateKeyPair();
            byte[] encodedPublicKey2 = keyPair2.getPublic().getEncoded();

            //start remote key agreement
            KeyAgreement keyAgreement2 = KeyAgreement.getInstance("DH");
            keyAgreement2.init(keyPair2.getPrivate());

            //read in keyspec
            KeyFactory keyFactory2 = KeyFactory.getInstance("DH");
            X509EncodedKeySpec x509Spec2 = new X509EncodedKeySpec(
                    DatatypeConverter.parseBase64Binary(publicKeyString));

            //load keyspec, and finish key agreement
            PublicKey publicKey1 = keyFactory2.generatePublic(x509Spec2);
            keyAgreement2.doPhase(publicKey1, true);

            //get remote secret key
            byte secret2[] = keyAgreement2.generateSecret();

            //use our secret to generate our remote secret key
            SecretKeyFactory secretKeyFactory2 = SecretKeyFactory.getInstance("DES");
            DESKeySpec desKeySpec2 = new DESKeySpec(secret2);
            SecretKey secretKey2 = secretKeyFactory2.generateSecret(desKeySpec2);

            //encrypt message
            Cipher cipher2 = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher2.init(Cipher.ENCRYPT_MODE, secretKey2);
            byte encryptedMessage[] = cipher2.doFinal(CapoApplication.getCeritifcate());

            //populate attributes
            certificateRequestElement.setAttribute(CertificateRequest.Attributes.SERVER_PUBLIC_KEY.toString(),
                    DatatypeConverter.printBase64Binary(encodedPublicKey2));
            certificateRequestElement.setAttribute(CertificateRequest.Attributes.PAYLOAD.toString(),
                    DatatypeConverter.printBase64Binary(encryptedMessage));
            certificateRequestElement.setAttribute(CertificateRequest.Attributes.SERVER_ID.toString(),
                    CapoApplication.getConfiguration().getValue(CapoServer.Preferences.SERVER_ID));
            certificateRequestElement.setAttribute(CertificateRequest.Attributes.CLIENT_ID.toString(), clientID);

            String oneTimePassword = CapoApplication.getConfiguration()
                    .getValue(PREFERENCE.CLIENT_VERIFICATION_PASSWORD);
            if (oneTimePassword.isEmpty()) {
                oneTimePassword = (new Random().nextInt(Integer.MAX_VALUE)) + "";
                CapoApplication.logger.log(Level.INFO,
                        "One time client verification password = '" + oneTimePassword + "'");
            }
            Document originalRequestDocument = clientRequest.getRequestDocument();
            //chnage this to a response, and send it back
            ((CNode) originalRequestDocument.getDocumentElement()).setNodeName("ServerResponse");
            ((CNode) originalRequestDocument.getDocumentElement().getElementsByTagName("CertificateRequest")
                    .item(0)).setNodeName("CertificateRequestResponse");
            clientRequest.getXmlStreamProcessor().writeDocument(originalRequestDocument);
            Document requestDocument = clientRequest.getXmlStreamProcessor().readNextDocument();

            byte[] encryptedPayload = DatatypeConverter
                    .parseBase64Binary(XPath.selectSingleNodeValue(requestDocument.getDocumentElement(),
                            "//CertificateRequest/@" + CertificateRequest.Attributes.PAYLOAD));

            //decrypt message

            cipher2.init(Cipher.DECRYPT_MODE, secretKey2);
            String returnedPassword = new String(cipher2.doFinal(encryptedPayload));
            if (oneTimePassword.equals(returnedPassword)) {
                //create certificate from public key
                byte[] clientPublicKeyBytes = DatatypeConverter
                        .parseBase64Binary(XPath.selectSingleNodeValue(requestDocument.getDocumentElement(),
                                "//CertificateRequest/@" + CertificateRequest.Attributes.CLIENT_PUBLIC_KEY));
                KeyFactory keyFactory3 = KeyFactory.getInstance("RSA");
                X509EncodedKeySpec x509Spec3 = new X509EncodedKeySpec(clientPublicKeyBytes);

                //load keyspec, and finish key agreement
                PublicKey clientPublicKey = keyFactory3.generatePublic(x509Spec3);

                X500NameBuilder x500NameBuilder = new X500NameBuilder(BCStyle.INSTANCE);
                String clientAlias = clientID + ".cert";
                x500NameBuilder.addRDN(BCStyle.CN, clientAlias);

                String serverAlias = CapoApplication.getConfiguration().getValue(Preferences.SERVER_ID)
                        + ".private";

                RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) CapoApplication.getKeyStore().getKey(serverAlias,
                        CapoApplication.getConfiguration().getValue(Configuration.PREFERENCE.KEYSTORE_PASSWORD)
                                .toCharArray());

                ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC)
                        .build(rsaPrivateKey);

                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.MONTH,
                        CapoApplication.getConfiguration().getIntValue(Preferences.KEY_MONTHS_VALID));

                X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(
                        x500NameBuilder.build(), BigInteger.valueOf(System.currentTimeMillis()),
                        new Date(System.currentTimeMillis() - 50000), calendar.getTime(), x500NameBuilder.build(),
                        clientPublicKey);

                X509Certificate certificate = new JcaX509CertificateConverter().setProvider(BC)
                        .getCertificate(certificateBuilder.build(contentSigner));
                CapoApplication.getKeyStore().setCertificateEntry(clientAlias, certificate);
                ((CapoServer) CapoApplication.getApplication()).writeKeyStore(CapoApplication.getKeyStore());
                Document responseDocument = CapoApplication.getDefaultDocument("default_response.xml");
                responseDocument.getDocumentElement().setAttribute("result", "SUCCESS");
                clientRequest.getXmlStreamProcessor().writeDocument(responseDocument);
            } else {
                Document responseDocument = CapoApplication.getDefaultDocument("default_response.xml");
                responseDocument.getDocumentElement().setAttribute("result", "WRONG_PASSWORD");
                clientRequest.getXmlStreamProcessor().writeDocument(responseDocument);
            }

        }
    }

    @Override
    public Document readNextDocument() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

}