Java使用X509Certificate获取证书详情

场景

我们在进行加密相关项目的开发时会使用到各种证书,证书文件以.cer后缀结尾。双击打开后可以看到证书的详细信息,包括版本、序列号、签名算法、颁发者、使用者、有效期、公钥等信息。那么我们如何使用java程序获取相应的信息返回给前端展示呢?

java读取证书pem java获取证书序列号_序列号

证书的内容和意义如表所示:

证书内容

意义

Version

告诉这个X.509证书是哪个版本的,目前有v1、V2、v3

Serial Number

由证书分发机构设置证书的序列号

Signature Algorithm Identifier

证书采用什么样的签名算法

Issuer Name

证书发行者名,也就是给这个证书签名的机构名

Validity Period

证书有效时间范围

Subject Name

被证书发行机构签名后的公钥拥有者或实体的名字,采用X.500协议,在Internet上的标志是惟一的。例如:CN=Java,OU=Infosec,O=Infosec Lab,C=CN表示一个subject name。

最终效果

{
  "code": 200,
  "data": {
    "effDate": "2023-07-03 17:44:47",
    "serialNumber": "00a4cbbc64a19f000003",
    "issuerDN": "CN=1111, C=CN",
    "type": "EC",
    "expDate": "2024-07-02 17:44:47",
    "subjectDN": "CN=52000000121320000000_5200000012, O=123, O=00, L=123, L=123, C=CN",
    "sigAlgName": "SM3的SM2签名"
  },
  "msg": "成功"
}

代码实现

/**
     * 
     * @param fileName
     * @return 证书详情
     */
public Object getCert(String fileName){
        fileName =filePath+File.separator+fileName;
        JSONObject jsonObject = new JSONObject();
        CertificateFactory cf = null;
        X509Certificate cert = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            FileInputStream in = new FileInputStream(fileName);
            cert = (X509Certificate) cf.generateCertificate(in);
        } catch (CertificateException e) {
            throw new RuntimeException(e);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        //签发者
        String subjectDN = cert.getSubjectDN().toString();
        //使用者
        String issuerDN = cert.getIssuerDN().toString();
        //序列号(十进制转十六进制,左补零)
        String serialNumber =  String.format("%" + 20 + "s", cert.getSerialNumber().toString(16)).replace(' ', '0');
        //生效时间
        Date effDate = cert.getNotBefore();
        //过期时间
        Date expDate = cert.getNotAfter();
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String effStr = null;
        String expStr = null;
        try {
            effStr = sdf.format(effDate);
            expStr = sdf.format(expDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //秘钥类型
        String type = cert.getPublicKey().getAlgorithm();
        //签名哈希算法
        String sigAlgName = cert.getSigAlgName();

        jsonObject.put("subjectDN",subjectDN);
        jsonObject.put("issuerDN",issuerDN);
        jsonObject.put("serialNumber",serialNumber);
        jsonObject.put("effDate",effStr);
        jsonObject.put("expDate",expStr);
        jsonObject.put("type",type);
        jsonObject.put("sigAlgName", CertType.getNameByCode(sigAlgName));
        return jsonObject;
    }
/**
     * 
     * 枚举类,实现数字证书对象标识Oid与名称的转换
     */
public enum CertType {

    rsaEncryption("1.2.840.113549.1.1.1", "RSA"),
    sha1withRSAEncryption("1.2.840.113549.1.1.5", "SHA1"),
    ECC("1.2.840.10045.2.1", "ECC"),
    SM2("1.2.156.10197.1.301", "SM2"),
    SM3WithSM2("1.2.156.10197.1.501", "SM3的SM2签名"),
    sha1withSM2("1.2.156.10197.1.502", "SHA1的SM2签名"),
    sha256withSM2("1.2.156.10197.1.503", "SHA256的SM2签名"),
    sm3withRSAEncryption("1.2.156.10197.1.504", "SM3的RSA签名"),
    commonName("2.5.4.3", "主体名"),
    emailAddress("1.2.840.113549.1.9.1", "邮箱"),
    cRLDistributionPoints("2.5.29.31", "CRL分发点"),
    extKeyUsage("2.5.29.37", "扩展密钥用法"),
    subjectAltName("2.5.29.17", "使用者备用名称"),
    CP("2.5.29.32", "证书策略"),
    clientAuth("1.3.6.1.5.5.7.3.2", "客户端认证");


    CertType(String code, String name) {
        this.code = code;
        this.name = name;
    }

    private String code;

    private String name;


    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static String getNameByCode(String code){
        CertType[] values = CertType.values();
        for(CertType plateColorEnum:values){
            if(code.equals(plateColorEnum.getCode())){
                return plateColorEnum.getName();
            }
        }
        return null;
    }

    public static String getCodeByName(String name){
        CertType[] values = CertType.values();
        for(CertType plateColorEnum:values){
            if(name.equals(plateColorEnum.getName())){
                return String.valueOf(plateColorEnum.getCode());
            }
        }
        return null;
    }

}

数字证书的对象标识符

数字证书的每项都有对象标识Oid,SM2数字证书的主要区别就是公钥算法、公钥参数、签名算法标识不一样,其余的都是X509里标准项。数字证书常见得对象标识有如下:

对象标识符

名称

OID

rsaEncryption

RSA算法标识

1.2.840.113549.1.1.1

sha1withRSAEncryption

SHA1的RSA签名

1.2.840.113549.1.1.5

ECC

ECC算法标识

1.2.840.10045.2.1

SM2

SM2算法标识

1.2.156.10197.1.301

SM3WithSM2

SM3的SM2签名

1.2.156.10197.1.501

sha1withSM2

SHA1的SM2签名

1.2.156.10197.1.502

sha256withSM2

SHA256的SM2签名

1.2.156.10197.1.503

sm3withRSAEncryption

SM3的RSA签名

1.2.156.10197.1.504

commonName

主体名

2.5.4.3

emailAddress

邮箱

1.2.840.113549.1.9.1

cRLDistributionPoints

CRL分发点

2.5.29.31

extKeyUsage

扩展密钥用法

2.5.29.37

subjectAltName

使用者备用名称

2.5.29.17

CP

证书策略

2.5.29.32

clientAuth

客户端认证

1.3.6.1.5.5.7.3.2