数字证书
# 概念
数字证书(digital certificate),又叫做公钥证书(public key certificate)或者身份证书(identity certificate),是一种证明公钥拥有者的电子文档,数字证书内容包括公钥、公钥拥有者的身份识别信息(一般称作 subject)和验证本证书内容的发行实体(一般称作发行者 issuer)的数字签名。
# 证书格式
数字证书的格式普遍采用的是 X.509 (opens new window) V3 国际标准,证书组成结构标准用ASN.1 (opens new window)(一种标准的语言)来进行描述. X.509 v3 数字证书 (opens new window)结构如下:
- 证书
- 版本号
- 序列号
- 签名算法
- 颁发者
- 证书有效期
- 此日期前无效
- 此日期后无效
- 主题
- 主题公钥信息
- 公钥算法
- 主题公钥
- 颁发者唯一身份信息(可选项)
- 主题唯一身份信息(可选项)
- 扩展信息(可选项)
- ...
- 证书签名算法
- 数字签名
X.509 定义了数字证书格式的标准,详情请参见维基百科词条 ,通过 Openssl 命令行 openssl x509 -in certificate.crt -text -noout
工具可以查看证书格式。
# 证书文件扩展名
X.509有多种常用的扩展名。不过其中的一些还用于其它用途,就是说具有这个扩展名的文件可能并不是证书,比如说可能只是保存了私钥。
.pem
– 隐私增强型电子邮件 (opens new window)(英语:Privacy-enhanced Electronic Mail (opens new window))格式,通常是Base64 (opens new window)格式的。.cer
,.crt
,.der
– 通常是DER (opens new window)(英语:X.690#DER_encoding (opens new window))二进制格式的。.p7b
,.p7c
– PKCS#7 (opens new window) SignedData structure without data, just certificate(s) or CRL (opens new window)(s).p12
– PKCS#12 (opens new window)格式,包含证书的同时可能还包含私钥 (opens new window).pfx
– PFX,PKCS#12之前的格式(通常用PKCS#12格式,比如由互联网资讯服务 (opens new window)产生的PFX文件)
PKCS#7 (opens new window) 是签名或加密数据的格式标准,官方称之为容器。由于证书是可验真的签名数据,所以可以用SignedData结构表述。 .P7C
文件是退化的SignedData结构,没有包括签名的数据。
PKCS#12 (opens new window) 由PFX进化而来的用于交换公共的和私有的对象的标准格式。[来源请求] (opens new window)
# 测试证书的内容
/**
* @author blog.unclezs.com
* @since 2022/5/19 15:25
*/
public class CertSample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://blog.unclezs.com");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.connect();
Certificate[] certs = connection.getServerCertificates();
int level = certs.length;
for (Certificate certificate : certs) {
System.out.printf("==========第 %s 级证书=========%n", level--);
JSONObject info = new JSONObject();
// 第一个就是服务器本身证书,后续的是证书链上的其他证书
X509CertImpl cert = (X509CertImpl) certificate;
info.set("版本", cert.getVersion());
info.set("序列号", cert.getSerialNumber());
info.set("签名算法", cert.getSigAlgName());
info.set("在此之前无效", DateUtil.formatDateTime(cert.getNotBefore()));
info.set("在此之后无效", DateUtil.formatDateTime(cert.getNotAfter()));
info.set("公钥", Base64.encode(cert.getPublicKey().getEncoded()));
info.set("公钥算法", cert.getPublicKey().getAlgorithm());
if ("RSA".equals(cert.getPublicKey().getAlgorithm())) {
info.set("公钥长度", ((RSAPublicKeyImpl) cert.getPublicKey()).getModulus().bitLength());
}
JSONObject subject = new JSONObject();
info.set("主体", subject);
fillX500Name(subject, X500Name.asX500Name(cert.getSubjectX500Principal()));
JSONObject issuer = new JSONObject();
info.set("签发者", issuer);
fillX500Name(issuer, X500Name.asX500Name(cert.getIssuerX500Principal()));
JSONObject ext = new JSONObject();
info.set("扩展字段", ext);
// https://www.alvestrand.no/objectid/2.5.29.html
ext.set("密匙使用", Hex.toHexString(cert.getExtensionValue("2.5.29.15")));
ext.set("基本约束", Hex.toHexString(cert.getExtensionValue("2.5.29.19")));
ext.set("主题密钥标识符", Hex.toHexString(cert.getExtensionValue("2.5.29.14")));
ext.set("授权密钥标识符", Hex.toHexString(cert.getExtensionValue("2.5.29.35")));
System.out.println(JSONUtil.toJsonPrettyStr(info));
}
connection.disconnect();
}
private static void fillX500Name(JSONObject obj, X500Name x500Name) throws IOException {
obj.set("名称", x500Name.getName());
obj.set("国家", x500Name.getCountry());
obj.set("组织", x500Name.getOrganization());
obj.set("组织单位", x500Name.getOrganizationalUnit());
obj.set("状态", x500Name.getState());
obj.set("常用名称", x500Name.getCommonName());
obj.set("主体", x500Name.getDomain());
obj.set("缩写", x500Name.getInitials());
obj.set("IP", x500Name.getIP());
obj.set("姓名", x500Name.getSurname());
obj.set("类型", x500Name.getType());
obj.set("位置", x500Name.getLocality());
}
}
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
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
输出
==========第 2 级证书=========
{
"版本": 3,
"序列号": 12980270420499143934014341116320976846,
"签名算法": "SHA256withRSA",
"在此之前无效": "2022-04-14 08:00:00",
"在此之后无效": "2023-04-15 07:59:59",
"公钥": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7u3jiEwbcitobvdjw87Y07AL1ZABgUX2JHck15sMkCZurOt4RCd6PBiZc+TH2XZ6xI8RatGWEzWeatJtvUDGRvZ/5J819Gwc1ktFsXLDUkOMvUBeB1xm+9HOamQ4WAAoZO0wy21ZkD+r3LBIPtpzjvm4Zj0JlJREEu0xpkWPCVFYmPB1lSTLGWD8T8uvcxZP+f9dhAVQVeVAiOz2eLjfGnQ4r0Or7zyor2uhzo2TCgXUvtRNEqAyWXFURBw67RAXPEYZBCR9kN46e1m17b3QSOo4b+d5ZkCY/b1T/XrZ4gjZa4e0nkubpRWuoiq042kMkayrho5+ye1psy8LKt8X3QIDAQAB",
"公钥算法": "RSA",
"公钥长度": 2048,
"主体": {
"名称": "CN=blog.unclezs.com",
"常用名称": "blog.unclezs.com",
"类型": 4
},
"签发者": {
"名称": "CN=Encryption Everywhere DV TLS CA - G1, OU=www.digicert.com, O=DigiCert Inc, C=US",
"国家": "US",
"组织": "DigiCert Inc",
"组织单位": "www.digicert.com",
"常用名称": "Encryption Everywhere DV TLS CA - G1",
"类型": 4
},
"扩展字段": {
"密匙使用": "0404030205a0",
"基本约束": "04023000",
"主题密钥标识符": "04160414d8cb740505120fffc05707fee56e267dc1f7f48f",
"授权密钥标识符": "04183016801455744fb2724ff560ba50d1d7e6515c9a01871ad7"
}
}
==========第 1 级证书=========
{
"版本": 3,
"序列号": 3290217995900168375215973871519570865,
"签名算法": "SHA256withRSA",
"在此之前无效": "2017-11-27 20:46:10",
"在此之后无效": "2027-11-27 20:46:10",
"公钥": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs94/rCRpvjV3JCHqYpygeq3eNEjFbkwO9/1DKI5HtV8XArrnp6zRQWIhvvg32lGe3MXVSBjMMa7emllUx2iVvGGbp1ZL04r+UV6Eo1PQ5gj1qqToX5TtwDqPFIL6IME9fB0XiuzcpHKndpCfqmOmnXKvsgHpjjO/vYR78+Vn/qsroicLpakrSc9U5hHuf2IO497UTgjFQwEf9Pff7eHK4fd29+CJZQ5SSN2kxvLFf5c2V7m4QiLIGyLgi9txMKHyu6J8IiLmYNeRmucxPyfB9gJXq/qQN1eRuAZEsqxHim5xsm1sqoiRQbG5kja3ul97ApFzmdZ5y8MFl/f6nUykDwIDAQAB",
"公钥算法": "RSA",
"公钥长度": 2048,
"主体": {
"名称": "CN=Encryption Everywhere DV TLS CA - G1, OU=www.digicert.com, O=DigiCert Inc, C=US",
"国家": "US",
"组织": "DigiCert Inc",
"组织单位": "www.digicert.com",
"常用名称": "Encryption Everywhere DV TLS CA - G1",
"类型": 4
},
"签发者": {
"名称": "CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US",
"国家": "US",
"组织": "DigiCert Inc",
"组织单位": "www.digicert.com",
"常用名称": "DigiCert Global Root CA",
"类型": 4
},
"扩展字段": {
"密匙使用": "040403020186",
"基本约束": "040830060101ff020100",
"主题密钥标识符": "0416041455744fb2724ff560ba50d1d7e6515c9a01871ad7",
"授权密钥标识符": "04183016801403de503556d14cbb66f0a3e21b1bc397b23dd155"
}
}
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
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
# 证书的作用
在 GitHub 编辑此页 (opens new window)
上次更新: 2024/02/25, 12:11:11