【SSL】什么是自签名证书及使用Java生成SSL自签名证书

【SSL】使用Java生成SSL自签名证书

  • 1.自签名证书介绍
    • [1.1 什么是自签名证书](#1.1 什么是自签名证书)
    • [1.2 主要作用](#1.2 主要作用)
  • 2.代码实现
    • [2.1 添加pom.xml](#2.1 添加pom.xml)
    • [2.1 初始化Bouncy Castle 扩展](#2.1 初始化Bouncy Castle 扩展)
    • [2.2 生成自签名证书](#2.2 生成自签名证书)
      • [2.2.1 证书生成核心代码](#2.2.1 证书生成核心代码)
      • [2.2.2 转化为通用的证书、公钥、私钥格式](#2.2.2 转化为通用的证书、公钥、私钥格式)
    • 3.完整实现

1.自签名证书介绍

1.1 什么是自签名证书

特性维度 自签名证书 CA签发证书
颁发者 使用者自己 受信任的CA机构颁发
信任机制 需要手动在各客户端信任,​不被浏览器/操作系统默认信任​ 被操作系统和浏览器预置根证书全局信任​
成本 免费 按年付费
签发速度 随时生成 不同版本签发效率不同
安全性 存在显著风险 安全性高具有OSSP、CRL
适用场景 内部测试、开发环境、内网等 公网

1.2 主要作用

  • 本地开发与测试环境​

    这是自签名证书最常用也最合适的场景。在开发网站或应用程序时,如果需要测试HTTPS功能(例如,测试单点登录SSO、支付回调等),配置受信任的CA证书流程繁琐。使用自签名证书可以快速搭建一个加密的测试环境,确保功能开发顺利进行

  • 封闭的内部网络应用​

    对于一些仅限于内部员工访问的系统,如公司内网的Wiki、监控平台、设备管理后台等,如果所有访问客户端(如员工电脑)可以统一安装并信任该自签名证书,那么它也能提供安全的加密通信,同时节省成本

  • ​物联网设备初始配置与内部通信​

    一些智能物联网设备在初次启动配置时,可能会使用自签名证书提供一个临时的加密通道在微服务架构或设备集群内部,服务间的通信有时也会使用自签名证书进行身份验证和加密。

2.代码实现

2.1 添加pom.xml

xml 复制代码
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version> <!-- 请使用最新稳定版本 -->
</dependency>

2.1 初始化Bouncy Castle 扩展

java 复制代码
static {
        Security.addProvider(new BouncyCastleProvider());
    }

2.2 生成自签名证书

java 复制代码
public static Map<String, String> gen(String commonName, String o, String i, String st) throws Exception {
    Map<String, String> certMap = Maps.newHashMap();
    
    // 1. 生成RSA密钥对
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", CertToolConstants.ECC_BC_STR);
    kpg.initialize(2048);
    KeyPair keyPair = kpg.generateKeyPair();
    
    // 2. 生成自签名证书
    Certificate cert = generateSelfSignedCertificate(keyPair, commonName, o, i, st);
    
    // 3. 转换为PEM格式并返回
    certMap.put("证书文件", encodeCertificateToPEMString(cert));
    certMap.put("私钥", encodePrivateKeyToPEMString(keyPair.getPrivate()));
    certMap.put("公钥", encodeKeyToPEMString(keyPair.getPublic()));
    
    return certMap;
}

2.2.1 证书生成核心代码

java 复制代码
public static Certificate generateSelfSignedCertificate(KeyPair keyPair, String commonName, String O, String l, String st) throws Exception {
    X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
    X500Principal dnName = new X500Principal("CN=" + commonName + ", OU=IT Dept, O=" + O + ", L=" + l + ", ST=" + st + ", C=CN");
    X500Principal is = new X500Principal("CN=xzq717.com, OU=IT Dept, O=Xcc Trust OV, L=Beijing, ST=Beijing, C=CN");
    //自签名证书序列号
    certGen.setSerialNumber(BigInteger.probablePrime(128, new SecureRandom()));
    certGen.setIssuerDN(dnName);        // 颁发者
    certGen.setSubjectDN(is);           // 证书主体
    certGen.setPublicKey(keyPair.getPublic());
    certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
    //设置证书开始日期
    certGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24));
    //设置证书截止日期
    certGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365)));
    certGen.addExtension(org.bouncycastle.asn1.x509.Extension.basicConstraints, true, 
                        new org.bouncycastle.asn1.x509.BasicConstraints(true));
    
    return certGen.generate(keyPair.getPrivate(), CertToolConstants.ECC_BC_STR);
}

2.2.2 转化为通用的证书、公钥、私钥格式

java 复制代码
public static String toPemString(byte[] contentBytes, String type) throws IOException {
        StringWriter stringWriter = new StringWriter();
        try (PemWriter pemWriter = new PemWriter(stringWriter)) {
            PemObject pemObject = new PemObject(type, contentBytes);
            pemWriter.writeObject(pemObject);
        }
        return stringWriter.toString();
    }

    public static String encodeCertificateToPEMString(Certificate certificate) throws Exception {
        return toPemString(certificate.getEncoded(), "CERTIFICATE");
    }

    public static String encodeKeyToPEMString(PublicKey publicKey) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey.getEncoded());
        return toPemString(keySpec.getEncoded(), "PUBLIC KEY");
    }

    public static String encodePrivateKeyToPEMString(PrivateKey privateKey) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
        return toPemString(keySpec.getEncoded(), "PRIVATE KEY");
    }

3.完整实现

java 复制代码
package com.xzq717.utils;

import com.google.common.collect.Maps;
import com.xcc.tools.constants.CertToolConstants;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
import org.bouncycastle.x509.X509V3CertificateGenerator;

import javax.security.auth.x500.X500Principal;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class SelfSignedCertGenerator {

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

    public static Certificate generateSelfSignedCertificate(KeyPair keyPair, String commonName, String O, String l, String st) throws Exception {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        X500Principal dnName = new X500Principal("CN=" + commonName + ", OU=IT Dept, O=" + O + ", L=" + l + ", ST=" + st + ", C=CN");
        X500Principal is = new X500Principal("CN=xzq717.com, OU=IT Dept, O=Xcc Trust OV, L=Beijing, ST=Beijing, C=CN");
        certGen.setSerialNumber(BigInteger.probablePrime(128, new SecureRandom()));
        certGen.setIssuerDN(dnName);
        certGen.setSubjectDN(is);
        certGen.setPublicKey(keyPair.getPublic());
        certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
        certGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24));
        certGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365)));
        certGen.addExtension(org.bouncycastle.asn1.x509.Extension.basicConstraints, true, new org.bouncycastle.asn1.x509.BasicConstraints(true));
        return certGen.generate(keyPair.getPrivate(), CertToolConstants.ECC_BC_STR);
    }

    public static Map<String, String> gen(String commonName, String o, String i, String st) throws Exception {
        Map<String, String> certMap = Maps.newHashMap();
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", CertToolConstants.ECC_BC_STR);
        kpg.initialize(2048);
        KeyPair keyPair = kpg.generateKeyPair();
        Certificate cert = generateSelfSignedCertificate(keyPair, commonName, o, i, st);
        // 保存为 PEM 文件
        certMap.put("证书文件", encodeCertificateToPEMString(cert));
        certMap.put("私钥", encodePrivateKeyToPEMString(keyPair.getPrivate()));
        certMap.put("公钥", encodeKeyToPEMString(keyPair.getPublic()));
        return certMap;
    }

    public static String toPemString(byte[] contentBytes, String type) throws IOException {
        StringWriter stringWriter = new StringWriter();
        try (PemWriter pemWriter = new PemWriter(stringWriter)) {
            PemObject pemObject = new PemObject(type, contentBytes);
            pemWriter.writeObject(pemObject);
        }
        return stringWriter.toString();
    }

    public static String encodeCertificateToPEMString(Certificate certificate) throws Exception {
        return toPemString(certificate.getEncoded(), "CERTIFICATE");
    }

    public static String encodeKeyToPEMString(PublicKey publicKey) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey.getEncoded());
        return toPemString(keySpec.getEncoded(), "PUBLIC KEY");
    }

    public static String encodePrivateKeyToPEMString(PrivateKey privateKey) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
        return toPemString(keySpec.getEncoded(), "PRIVATE KEY");
    }


}
相关推荐
Kay_Liang2 小时前
Spring中@Controller与@RestController核心解析
java·开发语言·spring boot·后端·spring·mvc·注解
行思理2 小时前
Spring MVC 注释新手教程
java·spring·mvc
moxiaoran57533 小时前
PocketBase轻量级后端解决方案
java·pocketbase
捷米研发三部3 小时前
EtherNet/IP转EtherNet/IP协议转换网关实现欧姆龙 PLC与罗克韦尔PLC通讯的配置案例
网络·网络协议
陈果然DeepVersion3 小时前
Java大厂面试真题:Spring Boot+Kafka+AI智能客服场景全流程解析(七)
java·人工智能·spring boot·微服务·kafka·面试题·rag
小武~3 小时前
嵌入式网络编程深度优化 --网络协议栈配置实战指南
linux·网络·网络协议
4Forsee3 小时前
【Android】消息机制
android·java·前端
骚戴3 小时前
PDF或Word转图片(多线程+aspose+函数式接口)
java·开发语言
姓蔡小朋友3 小时前
SpringDataRedis
java·开发语言·redis