org.clever.Common.XMPPCommunicator.ScepRequest.java Source code

Java tutorial

Introduction

Here is the source code for org.clever.Common.XMPPCommunicator.ScepRequest.java

Source

/*
 *  Copyright (c) 2011 Sergio Marino
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use,
 *  copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following
 *  conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 */
package org.clever.Common.XMPPCommunicator;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.CertificationRequest;
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.X509Principal;
import org.jscep.CertificateVerificationCallback;
import org.jscep.client.Client;
import org.jscep.transaction.EnrolmentTransaction;
import org.jscep.transaction.FailInfo;
import org.jscep.transaction.Transaction.State;
import org.jscep.x509.X509Util;

public class ScepRequest implements CallbackHandler {

    private java.security.PrivateKey key = null;
    private java.security.cert.X509Certificate cert = null;
    private String password = "secret";
    private KeyPair keyPair = null;
    private String CN = null;
    private String C = "EU";
    private String O = "Clever";
    private String OU = "Applications";
    private String domain = "clever.unime.it";
    private String requestPassword = null;
    private String hostname = null;
    private String keystorePath = null;

    public ScepRequest(String CApath, String CApassword, String CAserver, String hostname, String requestPassword,
            String keystorePath)
            throws MalformedURLException, GeneralSecurityException, IOException, InterruptedException {

        this.requestPassword = requestPassword;
        this.hostname = hostname;
        this.keystorePath = keystorePath;

        System.setProperty("javax.net.ssl.trustStore", CApath);
        System.setProperty("javax.net.ssl.trustStorePassword", CApassword);

        URL server = new URL("https://" + CAserver + "/cgi-bin/pki/scep/pkiclient.exe");
        generateKeys(hostname);

        String profile = "PublicCA";
        Client client = new Client(server, cert, this.keyPair.getPrivate(), (CallbackHandler) this, profile);

        CertificationRequest csr = this.createCsr(cert.getIssuerX500Principal(), this.keyPair.getPublic(),
                this.keyPair.getPrivate(), this.requestPassword.toCharArray());

        EnrolmentTransaction trs = client.enrol(csr);
        EnrolmentTransaction.State state = trs.send();

        switch (state) {
        case CERT_ISSUED:
            break;
        case CERT_REQ_PENDING:
            System.out.println(state);
            while (state != State.CERT_ISSUED) {
                Thread.sleep(2000);
                state = trs.poll();
            }
            CertStore store = trs.getCertStore();
            X509Certificate xcert = null;
            X509Certificate[] certificate_chain = null;
            try {
                Collection<X509Certificate> certs = (Collection<X509Certificate>) store.getCertificates(null);
                ArrayList chain = new ArrayList<X509Certificate>(certs);
                int numCerts = chain.size();
                if (numCerts == 2) {
                    final X509Certificate ca = selectCA(chain);
                    int caIndex = chain.indexOf(ca);
                    int certIndex = 1 - caIndex;
                    xcert = (X509Certificate) chain.get(certIndex);
                    certificate_chain = new X509Certificate[2];
                    certificate_chain[0] = ca;
                    certificate_chain[1] = xcert;
                    this.makeKeyStore(keyPair, certificate_chain, password.toCharArray(), keystorePath);

                } else if (numCerts == 1) {
                    certificate_chain = new X509Certificate[1];
                    xcert = (X509Certificate) chain.get(0);
                    certificate_chain[0] = xcert;
                    this.makeKeyStore(keyPair, certificate_chain, password.toCharArray(), keystorePath);

                } else {

                    throw new IllegalStateException();
                }

            } catch (CertStoreException ex) {
                Logger.getLogger(ScepRequest.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println("Stato REQ_PENDING");
            break;
        case CERT_NON_EXISTANT:
            FailInfo fail = trs.getFailInfo();
            System.err.println(fail);
            break;
        }
        System.out.println(state);

    }

    public final void generateKeys(String hostname) {
        try {
            KeyPairGenerator kg = null;
            try {
                kg = KeyPairGenerator.getInstance("RSA");
            } catch (NoSuchAlgorithmException ex) {
                Logger.getLogger(ScepRequest.class.getName()).log(Level.SEVERE, null, ex);
            }
            kg.initialize(2048);
            this.keyPair = kg.generateKeyPair();
            this.cert = X509Util.createEphemeralCertificate(new X500Principal("CN=" + hostname), keyPair);
        } catch (GeneralSecurityException ex) {
            Logger.getLogger(ScepRequest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private char[] readPassword(InputStream in) throws IOException {
        return "secret".toCharArray();
    }

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof TextOutputCallback) {

                // display the message according to the specified type
                TextOutputCallback toc = (TextOutputCallback) callbacks[i];
                switch (toc.getMessageType()) {
                case TextOutputCallback.INFORMATION:
                    System.out.println(toc.getMessage());
                    break;
                case TextOutputCallback.ERROR:
                    System.out.println("ERROR: " + toc.getMessage());
                    break;
                case TextOutputCallback.WARNING:
                    System.out.println("WARNING: " + toc.getMessage());
                    break;
                default:
                    throw new IOException("Unsupported message type: " + toc.getMessageType());
                }

            } else if (callbacks[i] instanceof NameCallback) {

                NameCallback nc = (NameCallback) callbacks[i];

                System.err.print(nc.getPrompt());
                System.err.flush();
                nc.setName((new BufferedReader(new InputStreamReader(System.in))).readLine());

            } else if (callbacks[i] instanceof PasswordCallback) {

                PasswordCallback pc = (PasswordCallback) callbacks[i];
                System.err.print(pc.getPrompt());
                System.err.flush();
                pc.setPassword(readPassword(System.in));

            } else if (callbacks[i] instanceof CertificateVerificationCallback) {
                CertificateVerificationCallback callback = (CertificateVerificationCallback) callbacks[i];
                callback.setVerified(true);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                        "Unrecognized Callback " + callbacks[i].toString());
            }
        }
    }

    public CertificationRequest createCsr(X500Principal subject, PublicKey pubKey, PrivateKey priKey,
            char[] password) throws GeneralSecurityException, IOException {
        AlgorithmIdentifier sha1withRsa = new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption);

        ASN1Set cpSet = new DERSet(new DERPrintableString(new String(password)));
        Attribute challengePassword = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_challengePassword, cpSet);
        ASN1Set attrs = new DERSet(challengePassword);

        SubjectPublicKeyInfo pkInfo = new SubjectPublicKeyInfo(
                (ASN1Sequence) ASN1Object.fromByteArray(pubKey.getEncoded()));

        Properties ht = new Properties();
        ht.put(X509Principal.CN, this.hostname);
        ht.put(X509Principal.C, this.C);
        ht.put(X509Principal.O, this.O);
        ht.put(X509Principal.OU, this.OU);
        ht.put(X509Principal.EmailAddress, this.hostname + "@" + this.domain);
        X509Name nn = new X509Name(ht);

        X509Name name = new X509Name(subject.toString());

        CertificationRequestInfo requestInfo = new CertificationRequestInfo(nn, pkInfo, attrs);

        Signature signer = Signature.getInstance("SHA1withRSA");
        signer.initSign(priKey);
        signer.update(requestInfo.getEncoded());
        byte[] signatureBytes = signer.sign();
        DERBitString signature = new DERBitString(signatureBytes);

        return new CertificationRequest(requestInfo, sha1withRsa, signature);
    }

    private KeyStore makeKeyStore(KeyPair kp, X509Certificate[] certificate_chain, char[] passwd,
            String keystorePath) throws KeyStoreException, FileNotFoundException, IOException,
            NoSuchAlgorithmException, CertificateException {

        KeyStore ks = KeyStore.getInstance("pkcs12");
        ks.load(null, null);
        System.out.println("certificate_chain.length " + certificate_chain.length);
        ks.setKeyEntry(this.hostname, kp.getPrivate(), passwd, certificate_chain);

        FileOutputStream fos = null;
        try {

            fos = new FileOutputStream(keystorePath + this.hostname + ".p12");
            ks.store(fos, passwd);
        } finally {
            if (fos != null) {
                fos.close();
            }
        }

        return ks;
    }

    private X509Certificate selectCA(List<X509Certificate> certs) {
        if (certs.size() == 1) {
            return certs.get(0);
        }

        final X509Certificate first = certs.get(0);
        final X509Certificate second = certs.get(1);
        try {

            first.verify(second.getPublicKey());

            return second;
        } catch (InvalidKeyException e) {
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            second.verify(first.getPublicKey());

            return first;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}