用java实现签发数字证书

最近研究了一下数字签名和关于证书相关。
证书必须通过CA权威机构签发,但在开发期间有多种途径实现签发证书用于测试:
1)去相关ca获取测试证书,一般有效期在15-30天
2)用keytool工具可以生成证书,但不能实现签发.
3)用openssl实现,不过对c或c++不熟悉的用起来比较麻烦
4)利用weblogic提供的CertGen实现签发。

综合上述几种途径(这几中方法多少都要配合keytool实现),第一种是最简单的,
但为了深入了解证书签发过程,我自己写了个工具实现了证书签发。
下面是工具的代码,编译后直接运行,供大家学习参考:

package com.app;
import java.io.*;
import java.security.*;
import java.security.cert.*;
import sun.security.x509.*;
import java.util.*;
/**
?*

Title:签发证书


?*

Description: 用于根证书签发


?*

Copyright: Copyright (c) 2004.8.12


?*

Company: smartcomm


?* @author 大脸猫(billdengyj)
?* @version 1.0
?*/
public class SignCertificate
{
? private String mKeystore=""; //密锁库路径
? private char[] mKeystorePass=null;//密锁库密码
? private char[] mSignPrivateKeyPass=null;//取得签发者私锁所需的密码
? private String mSignCertAlias="";//签发者别名
? private String mSignedCert=""; //被签证书
? private String mNewCert=""; //签发后的新证书全名
? private int mValidityDay=3; //签发后的新证书有效期(天)

? private PrivateKey mSignPrivateKey=null;//签发者的私锁
? private X509CertInfo mSignCertInfo=null;//签发证书信息
? private X509CertInfo mSignedCertInfo=null;//被签证书信息

? public static void main(String args[])
? {
??? /**
???? * 参数检查
???? */
??? String vArgs0=null;
??? if(args.length==0 || (args.length!=7 && !args[0].equals("/?")))
??? {
????? System.out.println("参数错误,可以加参数'/?'查询用法");
????? System.exit(1);
??? }
??? vArgs0=args[0];
??? if(vArgs0.equals("/?"))
??? {
????? System.out.println(
????????? "语法:********************************************************************");
????? System.out.println("java com.app.SignCertificate keystore keystorepass " +
???????????????????????? "signCertAlias signPrivateKeyPass signedCert newCert validity");
????? System.out.println(
????????? "说明:********************************************************************");
????? System.out.println("keystore:密锁库完整地址");
????? System.out.println("keystorepass:打开密锁库的密码");
????? System.out.println("signCertAlias:用于签名的证书别名");
????? System.out.println("signPrivateKeyPass:用取得签名待签证书的私锁密码");
????? System.out.println("signedCert:待签名证书完整路径");
????? System.out.println("newCert:被签名后的新证书保存路径全名");
????? System.out.println("validity:被签名后的新证书有效期(天)");
????? System.out.println(
????????? "=======================================================================");
????? System.out.println("必须提供签名证书保存的密锁库、待签名证书等信息,最后被签名的证书(.cer)被保存到新文件中");
????? System.exit(1);
??? }???
??? SignCertificate vSignCert=new SignCertificate();
??? vSignCert.mKeystore=vArgs0;
??? vSignCert.mKeystorePass=args[1].toCharArray();
??? vSignCert.mSignCertAlias=args[2];
??? vSignCert.mSignPrivateKeyPass=args[3].toCharArray();
??? vSignCert.mSignedCert=args[4];
??? vSignCert.mNewCert=args[5];
??? vSignCert.mValidityDay=Integer.parseInt(args[6]);
??? try
??? {
????? /**
?????? * 证书签名
?????? */
????? vSignCert.getSignCertInfo(); //获取签名证书信息
????? vSignCert.signCertificate(); //用签名证书信息签发待签名证书
????? vSignCert.createNewCertificate(); //创建并保存签名后的新证书
??? }catch(Exception e)
??? {
????? System.out.println("Error:"+e.getMessage());
??? }


? }
? /**
?? * 取得签名证书信息
?? * @throws Exception
?? */
? private void getSignCertInfo() throws Exception
? {
??? FileInputStream vFin=null;
??? KeyStore vKeyStore=null;
??? java.security.cert.Certificate vCert=null;
??? X509CertImpl vCertImpl=null;
??? byte[] vCertData=null;

??? //获取签名证书密锁库?
??? vFin=new FileInputStream(mKeystore);???
??? vKeyStore=KeyStore.getInstance("JKS");
??? vKeyStore.load(vFin,mKeystorePass);
??? //获取签名证书
??? vCert= vKeyStore.getCertificate(mSignCertAlias);
??? vCertData=vCert.getEncoded();
??? vCertImpl=new X509CertImpl(vCertData);
??? //获取签名证书信息
??? mSignCertInfo=(X509CertInfo)vCertImpl.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
??? mSignPrivateKey=(PrivateKey)vKeyStore.getKey(mSignCertAlias,mSignPrivateKeyPass);
??? vFin.close();
? }
? /**
?? * 取得待签证书信息,并签名待签证书
?? * @throws Exception
?? */
? private void signCertificate() throws Exception
? {
??? FileInputStream vFin=null;
??? java.security.cert.Certificate vCert=null;
??? CertificateFactory vCertFactory=null;
??? byte[] vCertData=null;
??? X509CertImpl vCertImpl=null;
???
??? //获取待签名证书
??? vFin=new FileInputStream(mSignedCert);
??? vCertFactory=CertificateFactory.getInstance("X.509");
??? vCert=vCertFactory.generateCertificate(vFin);
??? vFin.close();
??? vCertData=vCert.getEncoded();
??? //设置签名证书信息:有效日期、序列号、签名者、数字签名算发
??? vCertImpl=new X509CertImpl(vCertData);
??? mSignedCertInfo=(X509CertInfo)vCertImpl.get(X509CertImpl.NAME+"."+X509CertImpl.INFO);
??? mSignedCertInfo.set(X509CertInfo.VALIDITY,getCertValidity());
??? mSignedCertInfo.set(X509CertInfo.SERIAL_NUMBER,getCertSerualNumber());
??? mSignedCertInfo.set(X509CertInfo.ISSUER+"."+CertificateIssuerName.DN_NAME,
????????????????? mSignCertInfo.get(X509CertInfo.SUBJECT+"."+CertificateIssuerName.DN_NAME));
??? mSignedCertInfo.set(CertificateAlgorithmId.NAME+"."+CertificateAlgorithmId.ALGORITHM,getAlgorithm());

? }
? /**
?? * 待签签证书被签名后,保存新证书
?? * @throws Exception
?? */
? private void createNewCertificate() throws Exception
? {?
??? FileOutputStream vOut=null;
??? X509CertImpl vCertImpl=null;??
??? //用新证书信息封成为新X.509证书
??? vCertImpl=new X509CertImpl(mSignedCertInfo);
??? //生成新正书验证码
??? vCertImpl.sign(mSignPrivateKey,"MD5WithRSA");
??? vOut=new FileOutputStream(mNewCert+".cer");
??? //保存为der编码二进制X.509格式证书
??? vCertImpl.derEncode(vOut);
??? vOut.close();
??
? }
?
//辅助方法===========================================================================
?
? /**
?? * 得到新证书有效日期
?? * @throws Exception
?? * @return CertificateValidity
?? */
? private CertificateValidity getCertValidity() throws Exception
? {
??? long vValidity=(60*60*24*1000L)*mValidityDay;
??? Calendar vCal=null;
??? Date vBeginDate=null,vEndDate=null;
??? vCal=Calendar.getInstance();
??? vBeginDate=vCal.getTime();
??? vEndDate=vCal.getTime();
??? vEndDate.setTime(vBeginDate.getTime()+vValidity);
??? return new CertificateValidity(vBeginDate,vEndDate);
? }
? /**
?? * 得到新证书的序列号
?? * @return CertificateSerialNumber
?? */
? private CertificateSerialNumber getCertSerualNumber()
? {
???? Calendar vCal=null;
???? vCal=Calendar.getInstance();
???? int vSerialNum=0;
???? vSerialNum=(int)(vCal.getTimeInMillis()/1000);
???? return new CertificateSerialNumber(vSerialNum);
? }
? /**
?? * 得到新证书的签名算法
?? * @return AlgorithmId
?? */
? private AlgorithmId getAlgorithm()
? {
??? AlgorithmId vAlgorithm=new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
??? return vAlgorithm;
? }
}

**************************************************************************************************
使用方法:
这个工具是用来做签名的,所以在使用前必须有几个准备工作:
1)用keytool工具生成用于签名的根证书,密锁库为serverstore:
c:/keytool -genkey -keystore ./serverstore -alias root -keyalg RSA -keysize 1024
---期间会有相关提问。特别注意分清keystore密码和privateKey密码!!!!!!

2)用keytool工具生成待签名的证书,密锁库为serverstore:
c:/keytool -genkey -keystore ./serverstore -alias daniel -keyalg RSA -keysize 1024
---期间会有相关提问。特别注意分清keystore密码和privateKey密码!!!!!!

3)导出待签名证书:
c:/keytool -import -keystore ./serverstore -alias daniel -files ./daniel.cer
4)使用编译后的工具,用root签名daniel证书(见(2)(3))
java com.app.SignCertificate keystore keystorepass signCertAlias signPrivateKeyPass signedCert newCert validity
--使用语法可以用 ”java com.app.SignCertificate /?“ 查询。
keystore:密锁库完整地址
keystorepass:打开密锁库的密码
signCertAlias:用于签名的证书别名
signPrivateKeyPass:提取签名证书私锁的密码
signedCert:待签名证书完整路径
newCert:被签名后的新证书保存路径全名
validity:被签名后的新证书有效期(天)

5)第4步完成后,会生成你指定的newCert证书,这个证书是被root签名过的。

6)验证证书是否有效:
在windows下你可以先导出root证书:c:/keytool -import -keystore ./serverstore -alias root -files ./root.cer
双击root.cer安装,在安装daniel.cer,你会发现daniel.cer是有效的。

具体签名后的证书用途可以参考相关资料,这里就不多说了。以上代码在jdk1.4.2.05下通过。

***********************************************************************************
程序的关键是使用了sun.security.x509.X509CertImpl和sun.security.x509.X509CertInfo类
X509CertImpl继承了java.security.cert.Certificate,主要实现了x509证书信息的设置、而
标准的java.security.cert.X509Certificate 有实现;X509CertInfo实现了x509证书信息封装,
在标准的java安全库里是没有的。
***********************************************************************************

参考资料:java安全手册/tomcat双向ssl配置/weblogic server 配置策略/jdk api

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值