All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xbib.helianthus.common.security.SelfSignedCertificate Maven / Gradle / Ivy

package org.xbib.helianthus.common.security;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.base64.Base64;
import io.netty.util.CharsetUtil;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateIssuerName;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateSubjectName;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Generates a temporary self-signed certificate for testing purposes.
 */
public final class SelfSignedCertificate {

    private static final Logger logger = Logger.getLogger(SelfSignedCertificate.class.getName());

    /** Current time minus 1 year, just in case software clock goes back due to time synchronization */
    private static final Date DEFAULT_NOT_BEFORE = new Date(System.currentTimeMillis() - 86400000L * 365);

    /** The maximum possible value in X.509 specification: 9999-12-31 23:59:59 */
    private static final Date DEFAULT_NOT_AFTER = new Date(253402300799000L);

    private String certText;
    private String keyText;
    private X509Certificate cert;
    private PrivateKey key;

    public SelfSignedCertificate() throws CertificateException, NoSuchAlgorithmException, IOException,
            SignatureException, NoSuchProviderException, InvalidKeyException {
        this("example.com");
    }

    public SelfSignedCertificate(String fqdn) throws CertificateException, NoSuchAlgorithmException,
            IOException, SignatureException, NoSuchProviderException, InvalidKeyException {
        this(fqdn, new SecureRandom(), 2048);
    }

    /**
     * Creates a new instance.
     *
     * @param fqdn a fully qualified domain name
     * @param random the {@link SecureRandom} to use
     * @param bits the number of bits of the generated private key
     * @throws NoSuchAlgorithmException if algorithm does not exist
     * @throws CertificateException if certificate is not valid
     * @throws SignatureException if signature is invalid
     * @throws NoSuchProviderException if provider does not exist
     * @throws InvalidKeyException if key is invalid
     * @throws IOException if generation fails
     */
    public SelfSignedCertificate(String fqdn, SecureRandom random, int bits) throws NoSuchAlgorithmException,
            CertificateException, SignatureException, NoSuchProviderException, InvalidKeyException, IOException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(bits, random);
        KeyPair keypair = keyGen.generateKeyPair();
        generate(fqdn, keypair, random);
    }

    /**
     * Returns the generated X.509 certificate file in PEM format.
     * @return input stream of certificate
     */
    public InputStream certificate() {
        return new ByteArrayInputStream(certText.getBytes(CharsetUtil.US_ASCII));
    }

    /**
     * Returns the generated RSA private key file in PEM format.
     * @return input stream of private key
     */
    public InputStream privateKey() {
        return new ByteArrayInputStream(keyText.getBytes(CharsetUtil.US_ASCII));
    }

    /**
     *  Returns the generated X.509 certificate.
     * @return certificate
     */
    public X509Certificate cert() {
        return cert;
    }

    /**
     * Returns the generated RSA private key.
     * @return private key
     */
    public PrivateKey key() {
        return key;
    }

    private void generate(String fqdn, KeyPair keypair, SecureRandom random)
            throws IOException, CertificateException, NoSuchProviderException, NoSuchAlgorithmException,
            InvalidKeyException, SignatureException {
        PrivateKey key = keypair.getPrivate();
        X509CertInfo info = new X509CertInfo();
        X500Name owner = new X500Name("CN=" + fqdn);
        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new BigInteger(64, random)));
        try {
            info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
        } catch (CertificateException e) {
            logger.log(Level.FINE, e.getMessage(), e);
            info.set(X509CertInfo.SUBJECT, owner);
        }
        try {
            info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
        } catch (CertificateException e) {
            logger.log(Level.FINE, e.getMessage(), e);
            info.set(X509CertInfo.ISSUER, owner);
        }
        info.set(X509CertInfo.VALIDITY, new CertificateValidity(DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER));
        info.set(X509CertInfo.KEY, new CertificateX509Key(keypair.getPublic()));
        info.set(X509CertInfo.ALGORITHM_ID,
                new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.sha1WithRSAEncryption_oid)));
        X509CertImpl cert = new X509CertImpl(info);
        cert.sign(key, "SHA1withRSA");
        info.set(CertificateAlgorithmId.NAME + '.' + CertificateAlgorithmId.ALGORITHM, cert.get(X509CertImpl.SIG_ALG));
        cert = new X509CertImpl(info);
        cert.sign(key, "SHA1withRSA");
        cert.verify(keypair.getPublic());
        ByteBuf wrappedBuf = Unpooled.wrappedBuffer(key.getEncoded());
        ByteBuf encodedBuf;
        try {
            encodedBuf = Base64.encode(wrappedBuf, true);
            try {
                this.keyText = "-----BEGIN PRIVATE KEY-----\n" +
                          encodedBuf.toString(CharsetUtil.US_ASCII) +
                          "\n-----END PRIVATE KEY-----\n";
            } finally {
                encodedBuf.release();
            }
        } finally {
            wrappedBuf.release();
        }
        wrappedBuf = Unpooled.wrappedBuffer(cert.getEncoded());
        try {
            encodedBuf = Base64.encode(wrappedBuf, true);
            try {
                // Encode the certificate into a CRT file.
                certText = "-----BEGIN CERTIFICATE-----\n" +
                           encodedBuf.toString(CharsetUtil.US_ASCII) +
                           "\n-----END CERTIFICATE-----\n";
            } finally {
                encodedBuf.release();
            }
        } finally {
            wrappedBuf.release();
        }
        ByteArrayInputStream certStream = new ByteArrayInputStream(certText.getBytes(CharsetUtil.US_ASCII));
        this.key = keypair.getPrivate();
        this.cert = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(certStream);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy