org.kopi.ebics.certificate.X509Generator.java Source code

Java tutorial

Introduction

Here is the source code for org.kopi.ebics.certificate.X509Generator.java

Source

/*
 * Copyright (c) 1990-2012 kopiLeft Development SARL, Bizerte, Tunisia
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * $Id$
 */

package org.kopi.ebics.certificate;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.x509.X509V3CertificateGenerator;

/**
 * An X509 certificate generator for EBICS protocol.
 * Generated certificates are self signed certificates.
 *
 * @author hachani
 *
 */
@SuppressWarnings("deprecation")
public class X509Generator {

    /**
     * Generates the signature certificate for the EBICS protocol
     * @param keypair the key pair
     * @param issuer the certificate issuer
     * @param notBefore the begin validity date
     * @param notAfter the end validity date
     * @return the signature certificate
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public X509Certificate generateA005Certificate(KeyPair keypair, String issuer, Date notBefore, Date notAfter)
            throws GeneralSecurityException, IOException {
        return generate(keypair, issuer, notBefore, notAfter, X509Constants.SIGNATURE_KEY_USAGE);
    }

    /**
     * Generates the authentication certificate for the EBICS protocol
     * @param keypair the key pair
     * @param issuer the certificate issuer
     * @param notBefore the begin validity date
     * @param notAfter the end validity date
     * @return the authentication certificate
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public X509Certificate generateX002Certificate(KeyPair keypair, String issuer, Date notBefore, Date notAfter)
            throws GeneralSecurityException, IOException {
        return generate(keypair, issuer, notBefore, notAfter, X509Constants.AUTHENTICATION_KEY_USAGE);
    }

    /**
     * Generates the encryption certificate for the EBICS protocol
     * @param keypair the key pair
     * @param issuer the certificate issuer
     * @param notBefore the begin validity date
     * @param notAfter the end validity date
     * @return the encryption certificate
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public X509Certificate generateE002Certificate(KeyPair keypair, String issuer, Date notBefore, Date notAfter)
            throws GeneralSecurityException, IOException {
        return generate(keypair, issuer, notBefore, notAfter, X509Constants.ENCRYPTION_KEY_USAGE);
    }

    /**
     * Returns an <code>X509Certificate</code> from a given
     * <code>KeyPair</code> and limit dates validations
     * @param keypair the given key pair
     * @param issuer the certificate issuer
     * @param notBefore the begin validity date
     * @param notAfter the end validity date
     * @param keyusage the certificate key usage
     * @return the X509 certificate
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public X509Certificate generate(KeyPair keypair, String issuer, Date notBefore, Date notAfter, int keyusage)
            throws GeneralSecurityException, IOException {
        X509V3CertificateGenerator generator;
        BigInteger serial;
        X509Certificate certificate;
        ASN1EncodableVector vector;

        serial = BigInteger.valueOf(generateSerial());
        generator = new X509V3CertificateGenerator();
        generator.setSerialNumber(serial);
        generator.setIssuerDN(new X509Principal(issuer));
        generator.setNotBefore(notBefore);
        generator.setNotAfter(notAfter);
        generator.setSubjectDN(new X509Principal(issuer));
        generator.setPublicKey(keypair.getPublic());
        generator.setSignatureAlgorithm(X509Constants.SIGNATURE_ALGORITHM);
        generator.addExtension(X509Extensions.BasicConstraints, false, new BasicConstraints(true));
        generator.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                getSubjectKeyIdentifier(keypair.getPublic()));
        generator.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                getAuthorityKeyIdentifier(keypair.getPublic(), issuer, serial));
        vector = new ASN1EncodableVector();
        vector.add(KeyPurposeId.id_kp_emailProtection);

        generator.addExtension(X509Extensions.ExtendedKeyUsage, false,
                new ExtendedKeyUsage(new DERSequence(vector)));

        switch (keyusage) {
        case X509Constants.SIGNATURE_KEY_USAGE:
            generator.addExtension(X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.nonRepudiation));
            break;
        case X509Constants.AUTHENTICATION_KEY_USAGE:
            generator.addExtension(X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.digitalSignature));
            break;
        case X509Constants.ENCRYPTION_KEY_USAGE:
            generator.addExtension(X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.keyAgreement));
            break;
        default:
            generator.addExtension(X509Extensions.KeyUsage, false,
                    new KeyUsage(KeyUsage.keyEncipherment | KeyUsage.digitalSignature));
            break;
        }

        certificate = generator.generate(keypair.getPrivate(), "BC", new SecureRandom());
        certificate.checkValidity(new Date());
        certificate.verify(keypair.getPublic());

        return certificate;
    }

    /**
     * Returns the <code>AuthorityKeyIdentifier</code> corresponding
     * to a given <code>PublicKey</code>
     * @param publicKey the given public key
     * @param issuer the certificate issuer
     * @param serial the certificate serial number
     * @return the authority key identifier of the public key
     * @throws IOException
     */
    private AuthorityKeyIdentifier getAuthorityKeyIdentifier(PublicKey publicKey, String issuer, BigInteger serial)
            throws IOException {
        InputStream input;
        SubjectPublicKeyInfo keyInfo;
        ASN1EncodableVector vector;

        input = new ByteArrayInputStream(publicKey.getEncoded());
        keyInfo = new SubjectPublicKeyInfo((ASN1Sequence) new ASN1InputStream(input).readObject());
        vector = new ASN1EncodableVector();
        vector.add(new GeneralName(new X509Name(issuer)));

        return new AuthorityKeyIdentifier(keyInfo, new GeneralNames(new DERSequence(vector)), serial);
    }

    /**
     * Returns the <code>SubjectKeyIdentifier</code> corresponding
     * to a given <code>PublicKey</code>
     * @param publicKey the given public key
     * @return the subject key identifier
     * @throws IOException
     */
    private SubjectKeyIdentifier getSubjectKeyIdentifier(PublicKey publicKey) throws IOException {
        InputStream input;
        SubjectPublicKeyInfo keyInfo;

        input = new ByteArrayInputStream(publicKey.getEncoded());
        keyInfo = new SubjectPublicKeyInfo((ASN1Sequence) new ASN1InputStream(input).readObject());

        return new SubjectKeyIdentifier(keyInfo);
    }

    /**
     * Generates a random serial number
     *
     * @return the serial number
     */
    private long generateSerial() {
        Date now;

        now = new Date();
        String sNow = sdfSerial.format(now);

        return Long.valueOf(sNow).longValue();
    }

    // --------------------------------------------------------------------
    // DATA MEMBERS
    // --------------------------------------------------------------------

    private static SimpleDateFormat sdfSerial;

    static {
        sdfSerial = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        TimeZone tz = TimeZone.getTimeZone("UTC");
        sdfSerial.setTimeZone(tz);
    }
}