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) adObject();
4.转证书
Certificate certificate = Instance(asq);
5.解析证书内容
//            系列号解析
String serialNo = SerialNumber().getValue().toString(16);
System.out.println("序列号:"+ serialNo);
解析签名算法,⼀般证书实际的签名算法是字符串,但是解析出来的是特定形式,这个特定形式国际上就是⽤来代表某种算法,所以要特别注意下
// 签名算法 1.2.156.10197.1.501 表⽰SM2算法
String algorithm = SignatureAlgorithm().getAlgorithm().toString();
System.out.println("算法:"+ algorithm);
// 颁发者
String issuer = Issuer().toString();
System.out.println("颁发者:"+ issuer);
解析出来的时间是date类型的,如果你不想要date类型⽽是获取string类型,⼀定要注意:你获取到的是GMT格式的字符串,这个字符串和实际的背景时间相差8⼩时,所以还是⽼⽼实实按照的⽅法获取date再进⾏格式转换
Date startTime = StartDate().getDate();
String startTimeStr = DateString(startTime,"yyyy-MM-dd HH:mm:ss");
System.out.println("有效期:"+ startTimeStr);
Date endTime = EndDate().getDate();
String endTimeStr = DateString(endTime,"yyyy-MM-dd HH:mm:ss");
System.out.println("失效⽇:"+ endTimeStr);
这是获取使⽤者中CN项,如果你不想要CN⽽是想要获取整个使⽤者,可以直接到Subject()为⽌
org.bouncycastle.asn1.x500.RDN rdn = Subject().getRDNs(BCStyle.CN)[0];
String cn = First().getValue().toString();
System.out.println("CN:"+ cn);
这是解析公钥,⼀般⽐较重要,每家CA的公钥格式可能不⼀样,所以获取到的结果有细微差别,就是前缀是否带有:04标识
DERBitString publicKeyData = SubjectPublicKeyInfo().getPublicKeyData();
String publicKeyDataStr = String().replaceAll("#034200","");
System.out.println("公钥:"+ publicKeyDataStr);
附加解析:现在主流的CA都会有家扩展项,就是oid,我们有时候也需要解析下oid的值,oid的解析⼀般⽤循环解析⽅式。
Extensions exes=  TBSCertificate().getExtensions();
ASN1ObjectIdentifier[] list = ExtensionOIDs();
for(ASN1ObjectIdentifier a:list){
Extension el = Extension(a);
String oid = el.getExtnId().toString();
String value =new ExtnValue().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 dec.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) adObject();
Certificate certificate = Instance(asq);
Extensions exes=  TBSCertificate().getExtensions();
ASN1ObjectIdentifier[] list = ExtensionOIDs();
for(ASN1ObjectIdentifier a:list){
Extension el = Extension(a);
String oid = el.getExtnId().toString();
String value =new ExtnValue().getOctets());
System.out.println("oid:"+ oid +"->"+"value:"+ value);
}
//            系列号解析
String serialNo = SerialNumber().getValue().toString(16);
System.out.println("序列号:"+ serialNo);
// 签名算法 1.2.156.10197.1.501 表⽰SM2算法
String algorithm = SignatureAlgorithm().getAlgorithm().toString();
System.out.println("算法:"+ algorithm);
// 颁发者
String issuer = Issuer().toString();
System.out.println("颁发者:"+ issuer);
Date startTime = StartDate().getDate();
String startTimeStr = DateString(startTime,"yyyy-MM-dd HH:mm:ss");
System.out.println("有效期:"+ startTimeStr);
Date endTime = EndDate().getDate();
String endTimeStr = DateString(endTime,"yyyy-MM-dd HH:mm:ss");
System.out.println("失效⽇:"+ endTimeStr);
org.bouncycastle.asn1.x500.RDN rdn = Subject().getRDNs(BCStyle.CN)[0];            String cn = First().getValue().toString();
System.out.println("CN:"+ cn);
DERBitString publicKeyData = SubjectPublicKeyInfo().getPublicKeyData();            String publicKeyDataStr = String().replaceAll("#034200","");replaceall()
System.out.println("公钥:"+ publicKeyDataStr);
bIn.close();
dIn.close();
}catch(Exception e){
e.printStackTrace();
}
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。