org.qipki.crypto.x509.X509GeneratorImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.qipki.crypto.x509.X509GeneratorImpl.java

Source

/*
 * Copyright (c) 2010, Paul Merlin. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.qipki.crypto.x509;

import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Vector;

import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.Attribute;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V2CRLGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;

import org.qi4j.api.injection.scope.Service;

import org.qipki.crypto.CryptoContext;
import org.qipki.crypto.CryptoFailure;
import org.qipki.crypto.algorithms.SignatureAlgorithm;
import org.qipki.crypto.constants.Time;

import org.joda.time.DateTime;
import org.joda.time.Duration;

public class X509GeneratorImpl implements X509Generator {

    private CryptoContext cryptoContext;

    public X509GeneratorImpl(@Service CryptoContext cryptoContext) {
        this.cryptoContext = cryptoContext;
    }

    @Override
    public PKCS10CertificationRequest generatePKCS10(DistinguishedName distinguishedName, KeyPair keyPair) {
        try {
            return new PKCS10CertificationRequest(SignatureAlgorithm.SHA256withRSA.jcaString(),
                    distinguishedName.toX500Principal(), keyPair.getPublic(), null, keyPair.getPrivate(),
                    cryptoContext.providerName());
        } catch (GeneralSecurityException ex) {
            throw new CryptoFailure("Unable to generate PKCS#10", ex);
        }
    }

    @Override
    public PKCS10CertificationRequest generatePKCS10(DistinguishedName distinguishedName, KeyPair keyPair,
            GeneralNames subjectAlternativeNames) {
        try {
            return new PKCS10CertificationRequest(SignatureAlgorithm.SHA256withRSA.jcaString(),
                    distinguishedName.toX500Principal(), keyPair.getPublic(),
                    generateSANAttribute(subjectAlternativeNames), keyPair.getPrivate(),
                    cryptoContext.providerName());
        } catch (GeneralSecurityException ex) {
            throw new CryptoFailure("Unable to generate PKCS#10", ex);
        }
    }

    @Override
    public X509Certificate generateX509Certificate(PrivateKey privateKey, DistinguishedName issuerDN,
            BigInteger serialNumber, DistinguishedName subjectDN, PublicKey publicKey, Duration validity,
            List<X509ExtensionHolder> x509Extensions) {
        try {

            X509V3CertificateGenerator x509v3Generator = new X509V3CertificateGenerator();

            DateTime now = new DateTime();

            x509v3Generator.setSerialNumber(serialNumber);
            x509v3Generator.setSubjectDN(subjectDN.toX500Principal());
            x509v3Generator.setIssuerDN(issuerDN.toX500Principal());
            x509v3Generator.setNotBefore(now.minus(Time.CLOCK_SKEW).toDate());
            x509v3Generator.setNotAfter(now.plus(validity).minus(Time.CLOCK_SKEW).toDate());
            x509v3Generator.setSignatureAlgorithm(SignatureAlgorithm.SHA256withRSA.jcaString());
            x509v3Generator.setPublicKey(publicKey);

            for (X509ExtensionHolder eachExtensionHolder : x509Extensions) {
                x509v3Generator.addExtension(eachExtensionHolder.getDerOID(), eachExtensionHolder.isCritical(),
                        eachExtensionHolder.getValue());
            }

            return x509v3Generator.generate(privateKey, cryptoContext.providerName());

        } catch (GeneralSecurityException ex) {
            throw new CryptoFailure("Unable to generate X509Certificate", ex);
        } catch (IllegalStateException ex) {
            throw new CryptoFailure("Unable to generate X509Certificate", ex);
        }
    }

    @Override
    public X509CRL generateX509CRL(X509Certificate caCertificate, PrivateKey caPrivateKey) {
        try {
            X509V2CRLGenerator crlGen = new X509V2CRLGenerator();
            crlGen.setIssuerDN(caCertificate.getSubjectX500Principal());
            crlGen.setThisUpdate(new DateTime().minus(Time.CLOCK_SKEW).toDate());
            crlGen.setNextUpdate(new DateTime().minus(Time.CLOCK_SKEW).plusHours(12).toDate());
            crlGen.setSignatureAlgorithm(SignatureAlgorithm.SHA256withRSA.jcaString());
            crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                    new AuthorityKeyIdentifierStructure(caCertificate));
            crlGen.addExtension(X509Extensions.CRLNumber, false, new CRLNumber(BigInteger.ONE));
            return crlGen.generate(caPrivateKey, BouncyCastleProvider.PROVIDER_NAME);
        } catch (GeneralSecurityException ex) {
            throw new CryptoFailure("Unable to generate CRL", ex);
        }
    }

    @Override
    public X509CRL updateX509CRL(X509Certificate caCertificate, PrivateKey caPrivateKey,
            X509Certificate revokedCertificate, RevocationReason reason, X509CRL previousCRL,
            BigInteger lastCRLNumber) {
        try {
            X509V2CRLGenerator crlGen = new X509V2CRLGenerator();
            crlGen.setIssuerDN(caCertificate.getSubjectX500Principal());
            DateTime skewedNow = new DateTime().minus(Time.CLOCK_SKEW);
            crlGen.setThisUpdate(skewedNow.toDate());
            crlGen.setNextUpdate(skewedNow.plusHours(12).toDate());
            crlGen.setSignatureAlgorithm(SignatureAlgorithm.SHA256withRSA.jcaString());
            crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                    new AuthorityKeyIdentifierStructure(caCertificate));
            crlGen.addExtension(X509Extensions.CRLNumber, false, new CRLNumber(lastCRLNumber));
            crlGen.addCRL(previousCRL);
            crlGen.addCRLEntry(revokedCertificate.getSerialNumber(), skewedNow.toDate(), reason.reason());
            return crlGen.generate(caPrivateKey, BouncyCastleProvider.PROVIDER_NAME);
        } catch (GeneralSecurityException ex) {
            throw new CryptoFailure("Unable to update CRL", ex);
        }
    }

    @SuppressWarnings({ "UseOfObsoleteCollectionType", "unchecked" })
    private DERSet generateSANAttribute(GeneralNames subGeneralNames) {
        if (subGeneralNames == null) {
            return new DERSet();
        }
        Vector oids = new Vector();
        Vector values = new Vector();
        oids.add(X509Extensions.SubjectAlternativeName);
        values.add(new X509Extension(false, new DEROctetString(subGeneralNames)));
        X509Extensions extensions = new X509Extensions(oids, values);
        Attribute attribute = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
                new DERSet(extensions));
        return new DERSet(attribute);
    }

}