org.tastefuljava.minica.X509CertificateBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.tastefuljava.minica.X509CertificateBuilder.java

Source

/*
Minica, a very simple certificate authority
Copyright (C) 2011  Maurice Perry <maurice@perry.ch>
    
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 org.tastefuljava.minica;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

public class X509CertificateBuilder {
    private BigInteger sn;
    private X500Principal principal;
    private Date start = today();
    private Date end = addYears(start, 2);
    private String algorithm = "RSA";
    private int keySize = 1024;
    private String signatureAlgorithm = "SHA1withRSA";
    private PublicKey publicKey;
    private PrivateKey privateKey;
    private X500Principal issuer;
    private PrivateKey issuerKey;
    private int basicConstraints = Integer.MAX_VALUE;

    public X509CertificateBuilder(BigInteger sn, X500Principal principal) {
        this.sn = sn;
        this.principal = principal;
    }

    public X509CertificateBuilder(X509Certificate cert) {
        this.sn = cert.getSerialNumber();
        this.principal = cert.getSubjectX500Principal();
        this.start = cert.getNotBefore();
        this.end = cert.getNotAfter();
        this.publicKey = cert.getPublicKey();
        this.algorithm = publicKey.getAlgorithm();
        this.signatureAlgorithm = cert.getSigAlgName();
        this.issuer = cert.getIssuerX500Principal();
        this.basicConstraints = cert.getBasicConstraints();
    }

    public void setStart(Date start) {
        this.start = start;
    }

    public void setEnd(Date end) {
        this.end = end;
    }

    public void setSignatureAlgorithm(String newValue) {
        this.signatureAlgorithm = newValue;
    }

    public void setAlgorithm(String algorithm, int keySize) {
        this.algorithm = algorithm;
        this.keySize = keySize;
    }

    public void setIssuer(X500Principal issuer, PrivateKey issuerKey) {
        this.issuer = issuer;
        this.issuerKey = issuerKey;
    }

    public void setBasicConstraints(int newValue) {
        basicConstraints = newValue;
    }

    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    public X509Certificate build()
            throws OperatorCreationException, CertificateException, IOException, NoSuchAlgorithmException {
        if (publicKey == null) {
            KeyPair pair = generateKeyPair(algorithm, keySize);
            publicKey = pair.getPublic();
            privateKey = pair.getPrivate();
        }
        if (issuer == null) {
            issuer = principal;
            issuerKey = privateKey;
        }
        JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(issuer, sn, start, end, principal,
                publicKey);
        if (basicConstraints < 0) {
            certGen.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(false));
        } else if (basicConstraints != Integer.MAX_VALUE) {
            certGen.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(basicConstraints));
        }
        JcaContentSignerBuilder builder = new JcaContentSignerBuilder(signatureAlgorithm);
        builder.setProvider("BC");
        ContentSigner signr = builder.build(issuerKey);
        X509CertificateHolder certHolder = certGen.build(signr);
        return decode(certHolder.getEncoded());
    }

    private static KeyPair generateKeyPair(String algorithm, int keySize) throws NoSuchAlgorithmException {
        KeyPairGenerator gen = KeyPairGenerator.getInstance(algorithm);
        gen.initialize(keySize);
        return gen.generateKeyPair();
    }

    public static X509Certificate decode(byte[] data) throws CertificateException, IOException {
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(data);
        try {
            return (X509Certificate) factory.generateCertificate(in);
        } finally {
            in.close();
        }
    }

    public static Date today() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    public static Date addYears(Date date, int count) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.YEAR, count);
        return cal.getTime();
    }
}