证书在计算机及网络中起着非常重要的作用,那如何查看本地计算机有没有安装某个证书呢。
开始运行中输入certmgr.msc注意事项 不要轻易删除证书。
在密码学中,证书是一个非常重要的概念,我这里不想展开了, 通常的证书都是基于X.509规范的,有兴趣的同学可以去看对应介绍:http://en.wikipedia.org/wiki/X509
其实证书无处不在,我们的浏览器里面一般都会可以看到一些证书,有些是自动添加进去的,有些可以手动添加进去,比如我自己机器上用Chrome:在chrome://settings/advanced里面
你往下看到HTTPS/SSL ,点击Manage Certificates...按钮: 就会看出被管理的证书列表:
我们选出其中某个证书,比如Alibaba.com,然后导出到本地,然后用java提供的Certificate类来分析这个证书。
为了分析证书,我们写了一个工具类:
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;
}
}
然后我们写一个测试类来测试这些方法,它会先读取证书文件,然后把其中的信息分离出来:
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);
}
}
我们运行例子,测试,会打印出指定的证书信息: