
package org.expeditee.warp;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;

import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;

public class SelfSignedPkcs12Generator {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void generate(Path pkcs12Path, String password) throws Exception {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        long now = System.currentTimeMillis();
        Date notBefore = new Date(now - 60_000L);
        Date notAfter  = new Date(now + 3650L * 24 * 60 * 60 * 1000L); // ~10 years

        X500Name subject = new X500Name("CN=localhost");
        BigInteger serial = new BigInteger(160, new SecureRandom()).abs();

        SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());

        X509v3CertificateBuilder builder = new X509v3CertificateBuilder(
            subject, serial, notBefore, notAfter, subject, spki
        );

        builder.addExtension(Extension.keyUsage, true,
            new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));

        builder.addExtension(Extension.extendedKeyUsage, false,
            new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));

        GeneralNames sans = new GeneralNames(new GeneralName[] {
            new GeneralName(GeneralName.dNSName, "localhost"),
            new GeneralName(GeneralName.iPAddress, "127.0.0.1")
        });
        builder.addExtension(Extension.subjectAlternativeName, false, sans);

        ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA")
            .build(kp.getPrivate());

        X509CertificateHolder holder = builder.build(signer);

        X509Certificate cert = new JcaX509CertificateConverter()
            .setProvider("BC")
            .getCertificate(holder);

        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(null, null);
        ks.setKeyEntry("localhost", kp.getPrivate(), password.toCharArray(),
            new java.security.cert.Certificate[] { cert });

        try (OutputStream os = Files.newOutputStream(pkcs12Path, CREATE, TRUNCATE_EXISTING, WRITE)) {
            ks.store(os, password.toCharArray());
        }
    }
}
