cert-signer.git

ref: 07e125e188474a7c521df749ba9a1e0173bb4972

src/main/java/net/lulli/certsigner/ca/CertificateIssue.java


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
/* 
 * This file is part of cert-signer
 * Copyright (c) 2024 Paolo Lulli.
 * 
 * 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, version 3.
 *
 * 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 net.lulli.certsigner.ca;

import net.lulli.certsigner.Settings;
import net.lulli.certsigner.util.ValidityUtil;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;

import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

public class CertificateIssue {
    private CertificateIssue(){}
    public static X509Certificate rootCertificate(
            PublicKey publicKey,
            PrivateKey privateKey,
            String subject)
            throws Exception {
        BigInteger rootSerialNum = new BigInteger(Long.toString(new SecureRandom().nextLong()));

        X500Name rootCertIssuer = new X500Name(subject);
        X500Name rootCertSubject = rootCertIssuer;
        ContentSigner rootCertContentSigner = new JcaContentSignerBuilder(Settings.SIGNATURE_ALGORITHM).setProvider(Settings.BC_PROVIDER).build(privateKey);
        X509v3CertificateBuilder rootCertBuilder =
                new JcaX509v3CertificateBuilder(rootCertIssuer, rootSerialNum, ValidityUtil.yesterday(), ValidityUtil.plusYears(1), rootCertSubject, publicKey);

        JcaX509ExtensionUtils rootCertExtUtils = new JcaX509ExtensionUtils();
        rootCertBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
        rootCertBuilder.addExtension(Extension.subjectKeyIdentifier, false, rootCertExtUtils.createSubjectKeyIdentifier(publicKey));

        X509CertificateHolder rootCertHolder = rootCertBuilder.build(rootCertContentSigner);
        return new JcaX509CertificateConverter().setProvider(Settings.BC_PROVIDER).getCertificate(rootCertHolder);
    }



    public static X509Certificate clientCertificate(
            PrivateKey privateKey,
            String certificateSubject,
            X509Certificate rootCert,
            PKCS10CertificationRequest csr
    ) {
        try {

            X500Name issuedCertSubject = new X500Name(certificateSubject);
            BigInteger issuedCertSerialNum = new BigInteger(Long.toString(new SecureRandom().nextLong()));

            //PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(issuedCertSubject, issuedCertKeyPair.getPublic());
            JcaContentSignerBuilder csrBuilder = new JcaContentSignerBuilder(Settings.SIGNATURE_ALGORITHM).setProvider(Settings.BC_PROVIDER);

            ContentSigner csrContentSigner = csrBuilder.build(privateKey);

            X509v3CertificateBuilder issuedCertBuilder = new X509v3CertificateBuilder(new X500Name("CN=root-cert"), issuedCertSerialNum, ValidityUtil.yesterday(), ValidityUtil.plusYears(1), csr.getSubject(), csr.getSubjectPublicKeyInfo());

            JcaX509ExtensionUtils issuedCertExtUtils = new JcaX509ExtensionUtils();
            issuedCertBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
            issuedCertBuilder.addExtension(Extension.authorityKeyIdentifier, false, issuedCertExtUtils.createAuthorityKeyIdentifier(rootCert));
            issuedCertBuilder.addExtension(Extension.subjectKeyIdentifier, false, issuedCertExtUtils.createSubjectKeyIdentifier(csr.getSubjectPublicKeyInfo()));
            issuedCertBuilder.addExtension(Extension.keyUsage, false, new KeyUsage(KeyUsage.keyEncipherment));

            // Add DNS name is cert is to used for SSL
            /*
            issuedCertBuilder.addExtension(Extension.subjectAlternativeName, false, new DERSequence(new ASN1Encodable[]{
                    new GeneralName(GeneralName.dNSName, "mydomain.local"),
                    new GeneralName(GeneralName.iPAddress, "127.0.0.1")
            }));

             */

            X509CertificateHolder issuedCertHolder = issuedCertBuilder.build(csrContentSigner);
            return new JcaX509CertificateConverter().setProvider(Settings.BC_PROVIDER).getCertificate(issuedCertHolder);
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage());
        }
    }
}