依赖

Java SSL相关功能需要引入bouncycastle相关依赖,它与java.security有很好的集成

1
2
3
4
5
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>

代码

下面是根据bouncycastle实现的一套代码

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
public static void main(String[] args) throws Exception {
// 创建密钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

// 初始化密钥对生成器
keyPairGenerator.initialize(2048);

// 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();

// 获取私钥和公钥
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();

StringWriter stringWriter = new StringWriter();
JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter);

pemWriter.writeObject(privateKey);
pemWriter.close();

FileOutputStream fos = new FileOutputStream("C:\\Users\\pengtong\\Desktop\\cert\\certificate.key");
fos.write(stringWriter.toString().getBytes());
fos.close();

// 创建证书构造器
JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(
new X500Principal("CN=localhost"),
BigInteger.valueOf(System.currentTimeMillis()),
new Date(), new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000),
new X500Principal("CN=localhost"),
publicKey
);

//添加扩展程序
DERSequence subjectAlternativeNames = new DERSequence(new ASN1Encodable[] {
new GeneralName(GeneralName.dNSName, "localhost"),
new GeneralName(GeneralName.iPAddress, "127.0.0.1"),
});
certificateBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAlternativeNames);

X509CertificateHolder certificateHolder = certificateBuilder.build(new JcaContentSignerBuilder("SHA256WITHRSA").build(privateKey));

StringWriter stringWriter1 = new StringWriter();
JcaPEMWriter pemWriter1 = new JcaPEMWriter(stringWriter1);

pemWriter1.writeObject(certificateHolder);
pemWriter1.close();

// 将证书保存为pem/crt文件
FileOutputStream fos1 = new FileOutputStream("C:\\Users\\pengtong\\Desktop\\cert\\certificate.crt");
fos1.write(stringWriter1.toString().getBytes());
fos1.close();

System.out.println("Certificate generated successfully.");

}

对于证书的生成,还可以参考netty的io.netty.handler.ssl.util.SelfSignedCertificate类的构造方法,其中包括bouncycastle和sun.security两套生成证书的方法

代码解释

具体参数意思可以参考浏览器中的证书信息,https网站都会有一个证书,无论是有效的还是无效的

  1. JcaX509v3CertificateBuilder:代码中的JcaX509v3CertificateBuilder使用了六个构造函数的方法,分别是
    1. Issuer:颁发者,对应上图的颁发者
    2. SerialNumber:序列号,对应上图的序列号
    3. StartDate:有效期-不早于,对应上图的有效期-不早于
    4. EndDate:有效期-不晚于,对应上图的有效期-不晚于
    5. Subject:主题背景,其包含被授权网站,对应上图的主题背景
    6. SubjectPublicKeyInfo:证书持有者的公共密钥信息,对应上图的证书持有者公共密钥信息
  2. certificateBuilder.addExtension:这是JcaX509v3CertificateBuilder的addExtension方法,它是由参数的,只是在代码中没写,因为注释了,所以没有影响而已,它的作用是配置扩展程序,就是上图的扩展程序
  3. new JcaContentSignerBuilder(“SHA256WITHRSA”).build(privateKey):这是JcaContentSignerBuilder的构建方法,返回的是一个ContentSigner对象,其中两部分的作用分别是:
    1. new JcaContentSignerBuilder(“SHA256WITHRSA”):ContentSigner的算法是SHA256WITHRSA,为带“有 RSA 加密的 SHA-256”,即上图中的sha-256指纹
    2. build(privateKey):设置密钥,这里的密钥和上面的SubjectPublicKeyInfo中的公钥必须是密钥对,在上图不会有展示
  4. JcaPEMWriter:因为生成的证书都是二进制格式的,即der格式,nginx无法使用,需要JcaPEMWriter转为文本格式,即pem格式

让浏览器信任自签名

如果直接使用生成等待自签名证书,浏览器会显示以上警告,显示操作系统不信任该证书,一般CA认证中心发布的证书,都是直接得到操作系统信任的,因为我们是自签名证书,所以不会直接得到信任,这时候我们将证书加入到操作系统信任

双击生成的crt文件(pem文件无法直接打开,所以生成crt),点击安装证书,将证书放入到“受信任的根证书颁发机构”,这时候重启浏览器,重新访问

这时候浏览器有报警显示该证书没有指定主题备用名称,这个可能是每个浏览器有限制,我们为证书添加主题备用名称并重新生成

1
2
3
4
5
DERSequence subjectAlternativeNames = new DERSequence(new ASN1Encodable[] {
new GeneralName(GeneralName.dNSName, "localhost"),
new GeneralName(GeneralName.iPAddress, "127.0.0.1"),
});
certificateBuilder.addExtension(Extension.subjectAlternativeName, false, subjectAlternativeNames);

生成后,按照上述步骤,将证书添加操作系统信任中,重新打开浏览器访问

看到上面灰色的锁,证明证书已经通过浏览器,没有报警

der、cer、pem

.der扩展名

DER是一种编码方法,本身可以表示任何类型的数据,但通常用来编码证书。证书的结构使用ASN.1(Abstract Syntax Notation One 一种数据描述语言)描述。 BER和DER都是二进制编码方法。

.pem扩展名

PEM是一种将二进制数据编码为字符串的方法。它包含header和footer,用来指定数据的开始和结束,header和footer中间是base64数据。如果数据是证书,那么会简单的编码DER证书。crt格式是pem的证书格式,pem扩展名文件无法打开,需要将扩展名替换成crt才会被定义为证书文件。都是PEM代表Privacy Enhanced Mail;PEM格式如下

1
2
3
-----BEGIN <whatever>----- 
data
-----END <whatever>----

whatever可以是private keys, public keys, X509 certificates,比如

1
2
3
4
-----BEGIN CERTIFICATE-----
... base 64 encoding of the DER encoded certificate
with line endings and padding with equals signs ...
-----END CERTIFICATE-----

代码中生成的pem文件即为上述格式

1
2
3
-----BEGIN  PRIVATE KEY-----
base 64 encoding of the private key
-----END PRIVATE KEY-----

代码中生成的key文件即为上述格式

PEM文件也可以包含一个完整的证书链,证书链以叶子/结尾证书服务开始,紧跟着签名它的证书,通常直到根证书(一般不包含根证书)。所以如果缺失证书,你也会首先check一下第一个证书。。由此可知PEM既可以包含公钥、也可以包含私钥。

.cer扩展名

.cer指的是证书certificate,通常是DER编码格式的,但是windows也可以接受PEM格式。


本站总访问量:次本站总访问数:人
本站由 Peng Tong 使用 Stellar 1.29.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。