Certificate 超详细解析cer证书(序列号,颁发者,公钥等)

Posted 爱编程的小仙女

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Certificate 超详细解析cer证书(序列号,颁发者,公钥等)相关的知识,希望对你有一定的参考价值。

我们一般说的证书就是数字证书:数字证书是指在互联网通讯中标志通讯各方身份信息的一个数字认证,人们可以在网上用它来识别对方的身份

一般有两种:PFX证书、CER证书

PFX证书:
由Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀名。

一般RSA证书比较多,现在国内的RSA根证到期,有些企业已经不用了。

SM2证书:
1.二进制编码的证书
证书中没有私钥,DER 编码二进制格式的证书文件,以cer作为证书文件后缀名。
2.Base64编码的证书
证书中没有私钥,BASE64 编码格式的证书文件,也是以cer作为证书文件后缀名。

一般简称SM2证书也为cer证书

下面就着重讲一下SM2证书
申请流程:
一般个人/企业在设备上生成csr文件,包含身份信息一起提交给CA,CA会给你制作一本证书,这证书具有一定的法律效应的哦。

证书信息
一般CA返回的是证书base64编码形式,直接把保存到记事本以.cer结尾,双击就可以看到证书的相关信息

下面是证书的示例:


是不是可以看到证书的相关信息。

我们可以用证书来进行签名验签,加解密等操作;我们还会提取证书的相关信息。

下面重点来了,我们讲一下怎么获取到证书的相关信息,这才是本文的重中之重

解析证书我们离不开一个依赖包,就是bc包,这个bc包很重要

		<dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.64</version>
        </dependency>

这个bc包里面的一些方法,如:Certificate 就是专门用来为证书服务的,在证书行业以及工程中必不可少

步骤

  1. 将证书base64编码转换为byte类型
byte[] buffer = Base64.decodeBase64(certBase64);

2.将byte转换为普通stream型

ByteArrayInputStream bIn = new ByteArrayInputStream(buffer);

3.将普通stream转为证书服务所需特定的stream型

ASN1InputStream dIn = new ASN1InputStream(bIn);
ASN1Sequence asq = (ASN1Sequence) dIn.readObject();

4.转证书

 Certificate certificate = Certificate.getInstance(asq);

5.解析证书内容

//            系列号解析
            String serialNo = certificate.getSerialNumber().getValue().toString(16);
            System.out.println("序列号:" + serialNo);

解析签名算法,一般证书实际的签名算法是字符串,但是解析出来的是特定形式,这个特定形式国际上就是用来代表某种算法,所以要特别注意下

// 签名算法 1.2.156.10197.1.501 表示SM2算法
            String algorithm = certificate.getSignatureAlgorithm().getAlgorithm().toString();
            System.out.println("算法:" + algorithm);
 // 颁发者
            String issuer = certificate.getIssuer().toString();
            System.out.println("颁发者:" + issuer);

解析出来的时间是date类型的,如果你不想要date类型而是获取string类型,一定要注意:你获取到的是GMT格式的字符串,这个字符串和实际的背景时间相差8小时,所以还是老老实实按照的方法获取date再进行格式转换

DateUtils.getDateString是我自己写的时间转换工具类。下一篇中我再贴出来。

Date startTime = certificate.getStartDate().getDate();
            String startTimeStr = DateUtils.getDateString(startTime, "yyyy-MM-dd HH:mm:ss");
            System.out.println("有效期:" + startTimeStr);
Date endTime = certificate.getEndDate().getDate();
            String endTimeStr = DateUtils.getDateString(endTime, "yyyy-MM-dd HH:mm:ss");
            System.out.println("失效日:" + endTimeStr);

这是获取使用者中CN项,如果你不想要CN而是想要获取整个使用者,可以直接到certificate.getSubject()为止

org.bouncycastle.asn1.x500.RDN rdn = certificate.getSubject().getRDNs(BCStyle.CN)[0];
            String cn = rdn.getFirst().getValue().toString();
            System.out.println("CN:" + cn);

这是解析公钥,一般比较重要,每家CA的公钥格式可能不一样,所以获取到的结果有细微差别,就是前缀是否带有:04标识

DERBitString publicKeyData = certificate.getSubjectPublicKeyInfo().getPublicKeyData();
            String publicKeyDataStr = publicKeyData.toString().replaceAll("#034200", "");
            System.out.println("公钥:" + publicKeyDataStr);

附加解析:现在主流的CA都会有家扩展项,就是oid,我们有时候也需要解析下oid的值,oid的解析一般用循环解析方式。

			Extensions exes=  certificate.getTBSCertificate().getExtensions();
            ASN1ObjectIdentifier[] list = exes.getExtensionOIDs();

            for (ASN1ObjectIdentifier a:list) 

                Extension el = exes.getExtension(a);

                String oid = el.getExtnId().toString();
                String value = new String(el.getExtnValue().getOctets());

                System.out.println("oid:" + oid + "->" + "value:" + value);
            

特别说明:扩展项中我们这是解析出所有扩展项,有些扩展项的value是乱码,目前还不知道每家CA这些扩展项到底是啥编码格式。我试过了主流的编码格式,都不行,都是乱码,只有纯字符串的才正常。

来看下实际效果:

由于证书是比较重要的东西,一般不随便泄露,所以重要信息已经打码,悉知。

一般用到的扩展项有两种:个人扩展项,企业扩展项,这两种都有国际标准
个人身份标识码 IdentifyCode
oid固定为:1.2.156.10260.4.1.1
企业组织机构代码
oid固定为:1.2.156. 10260.4.1.4

这是亲手实践出来的, 目前在各网站还未知道详细的解析方式。尊重原创,谢谢!!

最后附上全部源码

package jp.utils;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;

import java.io.ByteArrayInputStream;
import java.util.Date;

public class DecodeCertUtils 

    public static void main(String[] args) 

        String certBase64 = "";

        try 

            byte[] buffer = Base64.decodeBase64(certBase64);
            ByteArrayInputStream bIn = new ByteArrayInputStream(buffer);
            ASN1InputStream dIn = new ASN1InputStream(bIn);
            ASN1Sequence asq = (ASN1Sequence) dIn.readObject();

            Certificate certificate = Certificate.getInstance(asq);

            Extensions exes=  certificate.getTBSCertificate().getExtensions();
            ASN1ObjectIdentifier[] list = exes.getExtensionOIDs();

            for (ASN1ObjectIdentifier a:list) 

                Extension el = exes.getExtension(a);

                String oid = el.getExtnId().toString();
                String value = new String(el.getExtnValue().getOctets());

                System.out.println("oid:" + oid + "->" + "value:" + value);
            

//            系列号解析
            String serialNo = certificate.getSerialNumber().getValue().toString(16);
            System.out.println("序列号:" + serialNo);

            // 签名算法 1.2.156.10197.1.501 表示SM2算法
            String algorithm = certificate.getSignatureAlgorithm().getAlgorithm().toString();
            System.out.println("算法:" + algorithm);

            // 颁发者
            String issuer = certificate.getIssuer().toString();
            System.out.println("颁发者:" + issuer);

            Date startTime = certificate.getStartDate().getDate();
            String startTimeStr = DateUtils.getDateString(startTime, "yyyy-MM-dd HH:mm:ss");
            System.out.println("有效期:" + startTimeStr);

            Date endTime = certificate.getEndDate().getDate();
            String endTimeStr = DateUtils.getDateString(endTime, "yyyy-MM-dd HH:mm:ss");
            System.out.println("失效日:" + endTimeStr);

            org.bouncycastle.asn1.x500.RDN rdn = certificate.getSubject().getRDNs(BCStyle.CN)[0];
            String cn = rdn.getFirst().getValue().toString();
            System.out.println("CN:" + cn);

            DERBitString publicKeyData = certificate.getSubjectPublicKeyInfo().getPublicKeyData();
            String publicKeyDataStr = publicKeyData.toString().replaceAll("#034200", "");
            System.out.println("公钥:" + publicKeyDataStr);

            bIn.close();
            dIn.close();
         catch (Exception e) 
            e.printStackTrace();
        
    


C#导入PFX和Cer证书的工具类

代码:

public class CertificationHelper
    {
        public static bool importPFX(string certPath, string certPass)
        {
            // Create a collection object and populate it using the PFX file
            X509Certificate2Collection collection = new X509Certificate2Collection();
            try
            {
                collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet);

                foreach (X509Certificate2 cert in collection)
                {
                    X509Store store = new X509Store();
                    store.Open(OpenFlags.MaxAllowed);
                    store.Add(cert);
                    store.Close();
                    // Import the certificate into an X509Store object
                }
            }
            catch (Exception e)
            {
                //throw(e);
                return false;
            }
            return true;
        }
        public static bool importCER(string cerFileName)
        {
            try
            {
                X509Certificate2 certificate = new X509Certificate2(cerFileName);
                X509Store store = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine);

                store.Open(OpenFlags.ReadWrite);
                store.Add(certificate);
                store.Close();
            }
            catch
            {
                return false;
            }
            return true;
        }
    }

  具体使用的命名空间已经忘了,可以自己去找找。

以上是关于Certificate 超详细解析cer证书(序列号,颁发者,公钥等)的主要内容,如果未能解决你的问题,请参考以下文章

certificate是啥意思啊

cer格式证书转pem格式

将证书导出为 BASE-64 编码的 .cer

使用X509Certificate2类操作证书文件

MicrosoftRootCertificateAuthority2011.cer 下载

证书类文件转换pem转换为cer