证书格式为X.509。将证书直接写在服务端代码内,尝试用Java解析证书并获取公钥
代码如下:
try{
CertificateFactory CF = CertificateFactory.getInstance("X.509"); // 从证书工厂中获取X.509的单例类
InputStream fileIn = new FileInputStream("F:\XH3.0\Base64X509.cer"); // 将本地证书读入文件流
Certificate C = CF.generateCertificate(fileIn); // 将文件流的证书转化为证书类
String certificateStr = C.toString();
System.out.println("使用[自带库函数]读入证书结果如下:");
System.out.print(certificateStr);
System.out.println("--------------------------------------\n证书主要字段:");
X509Certificate cer = (X509Certificate)C;
System.out.println("版本号:" + cer.getVersion());
System.out.println("序列号:" + cer.getSerialNumber().toString());
System.out.println("颁发者:" + cer.getSubjectDN()); // System.out.println("颁发者唯一标识符: " + cer.getSubjectUniqueID().toString());
System.out.println("使用者:" + cer.getIssuerDN());
// System.out.println("使用者唯一标识符: " + cer.getIssuerUniqueID().toString());
System.out.println("有效期:from:" + cer.getNotBefore() + " to: " + cer.getNotAfter());
System.out.println("签发算法" + cer.getSigAlgName());
System.out.println("签发算法ID:" + cer.getSigAlgOID());
System.out.println("证书签名:" + cer.getSignature().toString());
byte [] sig = cer.getSigAlgParams();
PublicKey publicKey = cer.getPublicKey();
byte [] pkenc = publicKey.getEncoded();
System.out.println("解析出的公钥:" + Base64.getEncoder().encodeToString(pkenc));
System.out.println("公钥:");
for(int i = 0; i < pkenc.length; i++){
System.out.print(pkenc[i]);
}
} catch(Exception e){
e.printStackTrace();
}
运行后报错
java.security.cert.CertificateParsingException: java.io.IOException: Unknown named curve: 1.2.156.10197.1.301
at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:169)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1855)
at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:104)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at com.yunyong.ufs.api.bank.executor.client.Test.main(Test.java:89)
上网搜索得知:国密证书使用了自有的椭圆曲线,所以无法使用JDK自带的java.security解析证书(http://www.jonllen.com/jonllen/work/162.aspx)。经过调研,需要引入BouncyCastle,BC库支持国密算法。参考这篇文章(https://blog.csdn.net/jinhill/article/details/9996117)修改代码,在pom.xml增加BC库依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.61</version>
</dependency>
修改测试代码为
try{
// 引入BC库
Security.addProvider(new BouncyCastleProvider());
// 使用BC解析X.509证书
CertificateFactory CF = CertificateFactory.getInstance("X.509", "BC"); // 从证书工厂中获取X.509的单例类
InputStream fileIn = new FileInputStream("F:\XH3.0\Base64X509.cer"); // 将本地证书读入文件流
Certificate C = CF.generateCertificate(fileIn); // 将文件流的证书转化为证书类
String certificateStr = C.toString();
System.out.println("使用[自带库函数]读入证书结果如下:");
System.out.print(certificateStr);
System.out.println("--------------------------------------\n证书主要字段:");
X509Certificate cer = (X509Certificate)C;
System.out.println("版本号:" + cer.getVersion());
System.out.println("序列号:" + cer.getSerialNumber().toString());
System.out.println("颁发者:" + cer.getSubjectDN()); // System.out.println("颁发者唯一标识符: " + cer.getSubjectUniqueID().toString());
System.out.println("使用者:" + cer.getIssuerDN());
// System.out.println("使用者唯一标识符: " + cer.getIssuerUniqueID().toString());
System.out.println("有效期:from:" + cer.getNotBefore() + " to: " + cer.getNotAfter());
System.out.println("签发算法" + cer.getSigAlgName());
System.out.println("签发算法ID:" + cer.getSigAlgOID());
System.out.println("证书签名:" + cer.getSignature().toString());
byte [] sig = cer.getSigAlgParams();
PublicKey publicKey = cer.getPublicKey();
byte [] pkenc = publicKey.getEncoded();
System.out.println("解析出的公钥:" + Base64.getEncoder().encodeToString(pkenc));
System.out.println("公钥:");
for(int i = 0; i < pkenc.length; i++){
System.out.print(pkenc[i]);
}
} catch(Exception e){
e.printStackTrace();
}
经测试,可以正常读取证书内容