密码学研究-证书

引入:

在密码学中,证书是一个非常重要的概念,我这里不想展开了, 通常的证书都是基于X.509规范的,有兴趣的同学可以去看对应介绍:http://en.wikipedia.org/wiki/X509


实践:

其实证书无处不在,我们的浏览器里面一般都会可以看到一些证书,有些是自动添加进去的,有些可以手动添加进去,比如我自己机器上用Chrome:在chrome://settings/advanced里面

你往下看到HTTPS/SSL ,点击Manage Certificates...按钮: 就会看出被管理的证书列表:

161615114.png

161705736.png


我们选出其中某个证书,比如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);
                                           
    }
}



我们运行例子,测试,会打印出指定的证书信息:

162044199.png


我们比较选择的证书文件:

162108330.png


可以看到,这信息和我们用API读取出来的信息是完全一致的。


你可能感兴趣的:(证书,certificate,密码学研究)