引入:
在密码学中,证书是一个非常重要的概念,我这里不想展开了, 通常的证书都是基于X.509规范的,有兴趣的同学可以去看对应介绍:http://en.wikipedia.org/wiki/X509
实践:
其实证书无处不在,我们的浏览器里面一般都会可以看到一些证书,有些是自动添加进去的,有些可以手动添加进去,比如我自己机器上用Chrome:在chrome://settings/advanced里面
你往下看到HTTPS/SSL ,点击Manage Certificates...按钮: 就会看出被管理的证书列表:
我们选出其中某个证书,比如Alibaba.com,然后导出到本地,然后用java提供的Certificate类来分析这个证书。
为了分析证书,我们写了一个工具类:
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
package
com.charles.certificatestudy;
import
java.io.FileInputStream;
import
java.math.BigInteger;
import
java.security.PublicKey;
import
java.security.cert.CRL;
import
java.security.cert.Certificate;
import
java.security.cert.CertificateFactory;
import
java.security.cert.X509Certificate;
import
java.util.Date;
import
javax.security.auth.x500.X500Principal;
import
sun.misc.BASE64Encoder;
/**
*
* Description: 这个工具类提供了证书的一般操作
*
* @author charles.wang
* @created Oct 29, 2013 2:57:58 PM
*
*/
public
class
CertificateUtil {
public
static
X509Certificate getX509certFromCertificatePath(String certificateName)
throws
Exception{
CertificateFactory certificateFactory = CertificateFactory.getInstance(
"X.509"
);
// 获得证书文件的输入流
FileInputStream in =
new
FileInputStream(certificateName);
// 获得证书
Certificate certificate = certificateFactory.generateCertificate(in);
// 获取证书的类型
String certType = certificate.getType();
System.out.println(
"证书类型:"
+ certType);
X509Certificate x509cert = (X509Certificate) certificate;
// 关闭流
in.close();
return
x509cert;
}
/**
* 分析证书文件
* @param certficateName 被分析的证书路径名
* @throws Exception
*/
public
static
void
parseX509Certificate(X509Certificate x509cert)
throws
Exception {
// 开始用证书的API提取相关信息:
// 读取证书版本号,这个证书的版本号识别用于该证书的X.509标准的版本,它可以用来影响证书所能指定的信息
// 迄今为止,已经定义了3个版本
int
version = x509cert.getVersion();
System.out.println(
"\n证书版本号为:"
+ version);
// 读取证书序列号
BigInteger serialNumber = x509cert.getSerialNumber();
System.out.println(
"\n证书序列号为:"
+ (
new
BASE64Encoder()).encode(serialNumber.toByteArray()));
// 读取证书的签名算法名,CA用此算法来签名证书
String algName = x509cert.getSigAlgName();
System.out.println(
"\n证书的签名算法名为:"
+ algName);
// 获得证书的签发者,其名字采用X.500标准,并且给出信息
// 这个证书的签发者通常是一个CA,使用该证书意味着信任签写该证书的实体
X500Principal issuerPrincipal = x509cert.getIssuerX500Principal();
System.out.println(
"\n证书的发布者为:"
+ issuerPrincipal.getName());
// 读取出证书的有效期
Date notAfter = x509cert.getNotAfter();
Date notBefore = x509cert.getNotBefore();
System.out.println(
"\n证书的有效期为:"
+ notBefore.toLocaleString() +
" 之后,"
+ notAfter.toLocaleString() +
" 之前"
);
// 读取证书的主体,它代表的是公钥的实体,其名字仍然使用X.500标准
X500Principal subjectPrincipal = x509cert.getSubjectX500Principal();
System.out.println(
"证书主题为:"
+ subjectPrincipal.getName());
// 读取证书的公钥
PublicKey publicKey = x509cert.getPublicKey();
System.out.println(
"\n获取证书的公钥信息"
);
System.out.println(
"证书的公钥的算法为:"
+ publicKey.getAlgorithm());
System.out.println(
"证书公钥的格式为:"
+ publicKey.getFormat());
// 获得公钥的字节数组
byte
[] publicKeyBytes = publicKey.getEncoded();
System.out.println(
"证书公钥为:"
+ (
new
BASE64Encoder()).encode(publicKeyBytes));
// 读取证书的基本约束
System.out.println(
"\n证书路径的长度为:"
+ x509cert.getBasicConstraints());
// 证书所含公钥所能完成的功能或者服务
boolean
[] keyUsages = x509cert.getKeyUsage();
// KeyUsage ::= BIT STRING {
// digitalSignature (0),
// nonRepudiation (1),
// keyEncipherment (2),
// dataEncipherment (3),
// keyAgreement (4),
// keyCertSign (5),
// cRLSign (6),
// encipherOnly (7),
// decipherOnly (8) }
if
(keyUsages[
0
])
System.out.println(
"此证书的公钥可以用来数字签名"
);
if
(keyUsages[
1
])
System.out.println(
"此证书的公钥具有不可否认性"
);
if
(keyUsages[
2
])
System.out.println(
"此证书的公钥可以用于加密"
);
if
(keyUsages[
3
])
System.out.println(
"此证书的公钥用于将用户数据加密"
);
if
(keyUsages[
4
])
System.out.println(
"此证书的公钥用于密钥协议"
);
if
(keyUsages[
5
])
System.out.println(
"此证书的公钥用于验证在证书上的签名"
);
if
(keyUsages[
6
])
System.out.println(
"此证书的公钥用于验证有关撤销消息"
);
if
(keyUsages[
7
])
System.out.println(
"此证书的公钥只可以用于加密,并且履行密钥协议"
);
if
(keyUsages[
8
])
System.out.println(
"此证书的公钥只可以用于解密,并且履行密钥协议"
);
// 读取证书的签名算法的OID字符串
String algOIDString = x509cert.getSigAlgOID();
System.out.println(
"\n证书的签名算法OID字符串为:"
+ algOIDString);
x509cert.getSigAlgParams();
// 读取证书的签名值
byte
[] certSignature = x509cert.getSignature();
System.out.println(
"\n证书的签名值为:"
+ (
new
BASE64Encoder()).encode(certSignature));
x509cert.getSubjectAlternativeNames();
// 读取证书的DER编码的二进制证书信息
byte
[] tbsCertificate = x509cert.getTBSCertificate();
System.out.println(
"\n证书的DER编码的二进制证书信息为:"
+ (
new
BASE64Encoder()).encode(tbsCertificate));
}
/**
* 获取证书的撤销列表
* @param certificateName
* @return
* @throws Exception
*/
public
static
CRL getCRLForCertifate(String certificateName)
throws
Exception {
//实例化证书,并且指定证书的类型是X.509
CertificateFactory certifateFactory = CertificateFactory.getInstance(
"X.509"
);
//获取证书的输入流
FileInputStream in =
new
FileInputStream(certificateName);
//获取证书的撤销列表
CRL crl = certifateFactory.generateCRL(in);
in.close();
return
crl;
}
}
|
然后我们写一个测试类来测试这些方法,它会先读取证书文件,然后把其中的信息分离出来:
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
|
package
com.charles.certificatestudy;
import
java.security.cert.X509Certificate;
import
sun.misc.BASE64Encoder;
/**
*
* Description: 这个类用于演示Certificate的一般使用
*
* @author charles.wang
* @created Oct 29, 2013 12:03:51 PM
*
*/
public
class
CertificateDemo {
/**
* @param args
*/
public
static
void
main(String[] args)
throws
Exception {
String certificateFilePath=
"alibaba.cer"
;
//获取证书对象
X509Certificate x509cert=CertificateUtil.getX509certFromCertificatePath(certificateFilePath);
//分析证书
CertificateUtil.parseX509Certificate(x509cert);
}
}
|
我们运行例子,测试,会打印出指定的证书信息:
我们比较选择的证书文件:
可以看到,这信息和我们用API读取出来的信息是完全一致的。
本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1316841,如需转载请自行联系原作者