Java 中如何实现动态生成证书,像 Go 那样。

比如 Go

func main() {

    ln, _ := tls.Listen("tcp", ":433", &tls.Config{
        GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
            // 使用 info.ServerName 从 DB 或者临时生成
            cert := generateX509Certificate(info.ServerName)
            return cert, nil
        },
    })

    http.ServeTLS(ln, nil, "", "")

}

Java 有类似的机制吗。哪怕是并发请求,也可以控制只有一个请求触发生成证书,其他请求 hold 住,等证书一旦生成成功,所有请求立刻进行接下来的握手(超时的不算)

Java 中不同的框架处理方式一样吗?

比如 javax.net.ssl.SSLContext 和使用 netty 的 spring 全家桶都适用的方法?

讨论数量: 3

这是动态的吗?

2年前 评论
cevin (楼主) 2年前

在Java中,可以使用Bouncy Castle库来动态生成证书。Bouncy Castle是一个流行的加密库,提供了许多Java中缺少的加密算法和工具,包括证书生成和管理。

import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Date;

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.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;

public class CertificateGenerator {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        // Generate a key pair
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
        keyPairGenerator.initialize(2048, new SecureRandom());
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // Create the certificate issuer and subject
        X500Name issuerName = new X500Name("CN=Issuer");
        X500Name subjectName = new X500Name("CN=Subject");

        // Set the certificate serial number and validity period
        BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
        Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
        Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);

        // Create the certificate builder
        X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuerName, serialNumber, startDate, endDate, subjectName, keyPair.getPublic());

        // Add the basic constraints extension
        certBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));

        // Add the key usage extension
        certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));

        // Sign the certificate with the issuer's private key
        ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
        X509CertificateHolder certHolder = certBuilder.build(signer);

        // Verify the certificate signature
        ContentVerifierProvider verifierProvider = new JcaContentVerifierProviderBuilder().build(keyPair.getPublic());
        boolean signatureValid = certHolder.isSignatureValid(verifierProvider);

        // Convert the certificate holder to an X509Certificate object
        X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certHolder);

        // Save the certificate to a file
        FileOutputStream fos = new FileOutputStream("test.crt");
        fos.write(cert.getEncoded());
        fos.close();
    }
}
2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!