org.glite.voms.contact.VOMSProxyBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.glite.voms.contact.VOMSProxyBuilder.java

Source

/**
 * *******************************************************************
 *
 * Authors:
 *
 * Vincenzo Ciaschini - vincenzo.ciaschini@cnaf.infn.it Andrea Ceccanti -
 * andrea.ceccanti@cnaf.infn.it
 *
 * Uses some code originally developed by: Gidon Moont - g.moont@imperial.ac.uk
 *
 * Copyright (c) 2002, 2003, 2004, 2005, 2006 INFN-CNAF on behalf of the EGEE
 * project.
 *
 * For license conditions see LICENSE
 *
 * Parts of this code may be based upon or even include verbatim pieces,
 * originally written by other people, in which case the original header
 * follows.
 *
 ********************************************************************
 */
/*
 This file is licensed under the terms of the Globus Toolkit Public
 License, found at http://www.globus.org/toolkit/download/license.html.
 */
package org.glite.voms.contact;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.KeyPairGenerator;
import java.security.KeyPair;

import java.security.cert.X509Certificate;

import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
import java.util.Random;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import java.math.BigInteger;
import java.security.cert.CertificateEncodingException;
import java.util.logging.Level;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;

import org.bouncycastle.asn1.DEREncodableVector;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERObjectIdentifier;

import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.x509.X509V3CertificateGenerator;

import org.glite.voms.ac.AttributeCertificate;
import org.globus.gsi.CredentialException;
import org.globus.gsi.GSIConstants;
import org.globus.gsi.GSIConstants.CertificateType;
import org.globus.gsi.GSIConstants.DelegationType;
import org.globus.gsi.X509Credential;

import org.globus.gsi.bc.BouncyCastleCertProcessingFactory;

import org.globus.gsi.proxy.ext.ProxyPolicy;
import org.globus.gsi.util.ProxyCertificateUtil;

/**
 *
 * This class implements VOMS X509 proxy certificates creation.
 *
 * @author Andrea Ceccanti
 *
 *
 */
public class VOMSProxyBuilder {

    private static final Logger log = Logger.getLogger(VOMSProxyBuilder.class);
    public static final CertificateType GT2_PROXY = CertificateType.GSI_2_PROXY;
    public static final CertificateType GT3_PROXY = CertificateType.GSI_3_IMPERSONATION_PROXY;
    public static final CertificateType GT4_PROXY = CertificateType.GSI_4_IMPERSONATION_PROXY;
    public static final CertificateType DEFAULT_PROXY_TYPE = CertificateType.GSI_2_PROXY;
    public static final DelegationType DEFAULT_DELEGATION_TYPE = DelegationType.FULL;
    public static final int DEFAULT_PROXY_LIFETIME = 86400;
    public static final int DEFAULT_PROXY_SIZE = 1024;
    private static final String PROXY_CERT_INFO_V3_OID = "1.3.6.1.4.1.3536.1.222";
    private static final String PROXY_CERT_INFO_V4_OID = "1.3.6.1.5.5.7.1.14";

    /**
     *
     * This methods buils an {@link AttributeCertificate} (AC) object starting
     * from an array of bytes.
     *
     * @param acBytes, the byte array containing the attribute certificate.
     * @return the {@link AttributeCertificate} object
     * @throws VOMSException, in case of parsing errors.
     */
    public static AttributeCertificate buildAC(byte[] acBytes) {

        ByteArrayInputStream bai = new ByteArrayInputStream(acBytes);
        AttributeCertificate ac;

        try {
            ac = AttributeCertificate.getInstance(bai);
            return ac;

        } catch (IOException e) {
            log.error("Error parsing attribute certificate:" + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);

        }
    }

    /**
     * This methods creates a non-voms proxy using the {@link UserCredentials}
     * passed as arguments. The proxy is created with a default lifetime of 3600
     * seconds.
     *
     * @param cred, the {@link UserCredentials} from which the proxy must be
     * created.
     * @return a {@link GlobusCredential} object that represents the proxy.
     */
    public static X509Credential buildProxy(UserCredentials cred) {
        // return buildProxy( cred, 3600, DEFAULT_PROXY_TYPE );
        return buildProxy(cred, 3600, DEFAULT_DELEGATION_TYPE);
    }

    /**
     * This methods creates a non-voms proxy using the {@link UserCredentials}
     * passed as arguments.
     *
     * @param cred, the {@link UserCredentials} from which the proxy must be
     * created.
     * @param lifetime, the lifetime (in seconds) of the generated proxy.
     * @return a {@link GlobusCredential} object that represents the proxy.
     */
    public static X509Credential buildProxy(UserCredentials cred, int lifetime,
            GSIConstants.DelegationType delegationMode) {

        BouncyCastleCertProcessingFactory factory = BouncyCastleCertProcessingFactory.getDefault();

        try {

            // factory.createCredential(cred.getUserChain(),  cred.getUserKey().getPrivateKey(),512, lifetime, GSIConstants.DELEGATION_FULL );
            return factory.createCredential(cred.getUserChain(), cred.getUserKey(), 512, lifetime, delegationMode);

        } catch (GeneralSecurityException e) {
            log.error("Error creating temp proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        } catch (Throwable e) {

            log.error("Error creating temp proxy: " + e.getMessage());
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e.getMessage(), e.getCause());

        }
    }

    /**
    * This methods creates a non-voms proxy using the {@link UserCredentials}
    * passed as arguments.
    *
    * @param cred, the {@link UserCredentials} from which the proxy must be
    * created.
    * @param lifetime, the lifetime (in seconds) of the generated proxy.
    * @return a {@link GlobusCredential} object that represents the proxy.
    */
    public static X509Credential buildProxy(UserCredentials cred, int lifetime, CertificateType certype) {

        BouncyCastleCertProcessingFactory factory = BouncyCastleCertProcessingFactory.getDefault();

        try {

            // factory.createCredential(cred.getUserChain(),  cred.getUserKey().getPrivateKey(),512, lifetime, GSIConstants.DELEGATION_FULL );
            return factory.createCredential(cred.getUserChain(), cred.getUserKey(), 512, lifetime, certype);

        } catch (GeneralSecurityException e) {
            log.error("Error creating temp proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        } catch (Throwable e) {

            log.error("Error creating temp proxy: " + e.getMessage());
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e.getMessage(), e.getCause());

        }
    }

    /**
     *
     * This method is used to create a VOMS proxy starting from the
     * {@link UserCredentials} passed as arguments and including a list of
     * {@link AttributeCertificate} objects that will be included in the proxy.
     *
     * @param cred, the {@link UserCredentials} from which the proxy must be
     * created.
     * @param ACs, the list of {@link AttributeCertificate} objects.
     * @param lifetime, the lifetime in seconds of the generated proxy.
     * @return a {@link GlobusCredential} object that represents the proxy.
     * @throws {@link VOMSException}, if something goes wrong.
     *
     * @author Andrea Ceccanti
     * @author Gidon Moont
     *
     *
     */
    public static X509Credential buildProxy(UserCredentials cred, List ACs, int lifetime) {
        try {
            return buildProxy(cred, ACs, lifetime, DEFAULT_PROXY_SIZE, DEFAULT_PROXY_TYPE, DEFAULT_DELEGATION_TYPE,
                    null);
        } catch (Throwable e) {

            log.error("Error creating proxy: " + e.getMessage());
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e.getMessage(), e.getCause());

        }

    }

    /**
     *
     * This method is used to create a VOMS proxy starting from the
     * {@link UserCredentials} passed as arguments and including a list of
     * {@link AttributeCertificate} objects that will be included in the proxy.
     *
     * @param cred, the {@link UserCredentials} from which the proxy must be
     * created.
     * @param ACs, the list of {@link AttributeCertificate} objects.
     * @param lifetime, the lifetime in seconds of the generated proxy.
     * @param version, the version of globus to which the proxy conforms
     * @return a {@link GlobusCredential} object that represents the proxy.
     * @throws {@link VOMSException}, if something goes wrong.
     *
     * @author Vincenzo Ciaschini
     * @author Andrea Ceccanti
     *
     *
     */
    public static X509Credential buildProxy(UserCredentials cred, List ACs, int bits, int lifetime,
            CertificateType gtVersion, DelegationType delegType, String policyType) {

        if (ACs.isEmpty()) {
            throw new VOMSException(
                    "Please specify a non-empty list of attribute certificate to build a voms-proxy.");
        }

        Iterator i = ACs.iterator();

        DEREncodableVector acVector = new DEREncodableVector();

        while (i.hasNext()) {
            acVector.add((AttributeCertificate) i.next());
        }

        HashMap extensions = new HashMap();

        if (ACs.size() != 0) {
            DERSequence seqac = new DERSequence(acVector);
            DERSequence seqacwrap = new DERSequence(seqac);
            extensions.put("1.3.6.1.4.1.8005.100.100.5",
                    ExtensionData.creator("1.3.6.1.4.1.8005.100.100.5", seqacwrap));
        }

        KeyUsage keyUsage = new KeyUsage(
                KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment);
        extensions.put("2.5.29.15", ExtensionData.creator("2.5.29.15", keyUsage.toASN1Primitive()));

        //        try {
        X509Credential proxy = myCreateCredential(cred.getUserChain(), cred.getUserKey(), bits, lifetime, delegType,
                gtVersion, extensions, policyType);

        return proxy;

        //         } catch ( GeneralSecurityException e ) {

        //             log.error( "Error generating voms proxy: " + e.getMessage() );

        //             if ( log.isDebugEnabled() )
        //                 log.error( e.getMessage(), e );

        //             throw new VOMSException( e );

        //         }

    }

    private static X509Credential myCreateCredential(X509Certificate[] certs, PrivateKey privateKey, int bits,
            int lifetime, DelegationType delegationMode, CertificateType gtVersion, HashMap extensions,
            String policyType) {
        KeyPairGenerator keys = null;

        try {
            keys = KeyPairGenerator.getInstance("RSA", "BC");
        } catch (NoSuchAlgorithmException e) {
            log.error("Error activating bouncycastle: " + e.getMessage());
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e.getMessage(), e.getCause());
        } catch (NoSuchProviderException e) {
            log.error("Error activating bouncycastle: " + e.getMessage());
            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e.getMessage(), e.getCause());
        }

        keys.initialize(bits);
        KeyPair pair = keys.genKeyPair();

        X509Certificate proxy = myCreateProxyCertificate(certs[0], privateKey, pair.getPublic(), lifetime,
                delegationMode, gtVersion, extensions, policyType);

        X509Certificate[] newCerts = new X509Certificate[certs.length + 1];
        newCerts[0] = proxy;
        System.arraycopy(certs, 0, newCerts, 1, certs.length);

        return new X509Credential(pair.getPrivate(), newCerts);
    }

    private static X509Certificate myCreateProxyCertificate(X509Certificate cert, PrivateKey issuerKey,
            PublicKey publicKey, int lifetime, DelegationType delegationMode, CertificateType gtVersion,
            HashMap extensions, String policyType) {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();

        String cnValue = null;
        ProxyPolicy policy = null;
        BigInteger serialNum = null;

        switch (delegationMode) {
        case LIMITED:
            cnValue = "limited proxy";
            break;
        case FULL:
            cnValue = "proxy";
            break;
        default:
            break;
        }

        switch (gtVersion) {
        case GSI_2_PROXY:
            policy = new ProxyPolicy(ProxyPolicy.IMPERSONATION);
            serialNum = cert.getSerialNumber();
        case GSI_2_LIMITED_PROXY:
            policy = new ProxyPolicy(ProxyPolicy.LIMITED);
            serialNum = cert.getSerialNumber();
            break;
        case GSI_3_IMPERSONATION_PROXY:
        case GSI_3_INDEPENDENT_PROXY:
        case GSI_3_LIMITED_PROXY:
        case GSI_3_RESTRICTED_PROXY:
        case GSI_4_IMPERSONATION_PROXY:
        case GSI_4_INDEPENDENT_PROXY:
        case GSI_4_LIMITED_PROXY:
        case GSI_4_RESTRICTED_PROXY:
            Random rand = new Random();
            int number = Math.abs(rand.nextInt());
            cnValue = String.valueOf(number);
            serialNum = new BigInteger(String.valueOf(number));

            ExtensionData data = (ExtensionData) extensions.get(PROXY_CERT_INFO_V3_OID);
            if (data == null) {
                if (policyType == null) {

                    switch (gtVersion) {
                    case GSI_3_LIMITED_PROXY:
                    case GSI_4_LIMITED_PROXY:
                        policy = new ProxyPolicy(ProxyPolicy.LIMITED);
                        break;
                    case GSI_3_IMPERSONATION_PROXY:
                    case GSI_4_IMPERSONATION_PROXY:
                        policy = new ProxyPolicy(ProxyPolicy.IMPERSONATION);
                        break;
                    case GSI_3_INDEPENDENT_PROXY:
                    case GSI_4_INDEPENDENT_PROXY:
                        policy = new ProxyPolicy(ProxyPolicy.INDEPENDENT);
                        break;
                    default:
                        throw new IllegalArgumentException("Invalid proxyType " + gtVersion);

                    }
                } else {
                    try {
                        policy = new ProxyPolicy(new ASN1ObjectIdentifier(policyType));
                    } catch (IllegalArgumentException e) {
                        throw new VOMSException("OID required as policyType");
                    }
                }

                if (ProxyCertificateUtil.isGsi3Proxy(gtVersion)) {
                    extensions.put(PROXY_CERT_INFO_V3_OID, ExtensionData.creator(PROXY_CERT_INFO_V3_OID,
                            new MyProxyCertInfo(policy, gtVersion).toASN1Primitive()));
                } else if (ProxyCertificateUtil.isGsi4Proxy(gtVersion)) {
                    extensions.put(PROXY_CERT_INFO_V4_OID, ExtensionData.creator(PROXY_CERT_INFO_V4_OID, true,
                            new MyProxyCertInfo(policy, gtVersion).toASN1Primitive()));
                }

            }
        }

        ExtensionData[] exts = (ExtensionData[]) extensions.values().toArray(new ExtensionData[] {});
        for (int i = 0; i < exts.length; i++) {
            certGen.addExtension(exts[i].getOID(), exts[i].getCritical(), exts[i].getObj());
        }

        X509Name issuerDN = (X509Name) cert.getSubjectDN();

        X509NameHelper issuer = new X509NameHelper(issuerDN);

        X509NameHelper subject = new X509NameHelper(issuerDN);
        subject.add(X509Name.CN, cnValue);

        certGen.setSubjectDN(subject.getAsName());
        certGen.setIssuerDN(issuer.getAsName());

        certGen.setSerialNumber(serialNum);
        certGen.setPublicKey(publicKey);
        certGen.setSignatureAlgorithm(cert.getSigAlgName());

        GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
        /* Allow for a five minute clock skew here. */
        date.add(Calendar.MINUTE, -5);
        certGen.setNotBefore(date.getTime());

        /* If hours = 0, then cert lifetime is set to user cert */
        if (lifetime <= 0) {
            certGen.setNotAfter(cert.getNotAfter());
        } else {
            date.add(Calendar.MINUTE, 5);
            date.add(Calendar.SECOND, lifetime);
            certGen.setNotAfter(date.getTime());
        }

        try {
            return certGen.generate(issuerKey);

        } catch (SignatureException e) {
            log.error("Error creating proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        } catch (InvalidKeyException e) {
            log.error("Error creating proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        } catch (CertificateEncodingException e) {
            log.error("Error creating proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        } catch (IllegalStateException e) {
            log.error("Error creating proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        } catch (NoSuchAlgorithmException e) {
            log.error("Error creating proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }

            throw new VOMSException(e);
        }

    }

    /**
     * This method is write a globus proxy to an output stream.
     *
     * @param cred
     * @param os
     */
    public static void saveProxy(X509Credential cred, OutputStream os) {

        try {

            cred.save(os);
        } catch (IOException e) {
            log.error("Error saving generated proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }
            throw new VOMSException("Error saving generated proxy: " + e.getMessage(), e);
        } catch (CertificateEncodingException e) {
            log.error("Error saving generated proxy: " + e.getMessage());

            if (log.isDebugEnabled()) {
                log.error(e.getMessage(), e);
            }
            throw new VOMSException("Error saving generated proxy: " + e.getMessage(), e);
        }

    }

    /**
     * This method saves a globus proxy to a file.
     *
     * @param cred
     * @param filename
     * @throws FileNotFoundException
     */
    public static void saveProxy(X509Credential cred, String filename) throws FileNotFoundException {

        saveProxy(cred, new FileOutputStream(filename));
    }
}